xref: /vim-8.2.3635/src/hardcopy.c (revision ed37d9b3)
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 
10 /*
11  * hardcopy.c: printing to paper
12  */
13 
14 #include "vim.h"
15 #include "version.h"
16 
17 #if defined(FEAT_PRINTER) || defined(PROTO)
18 /*
19  * To implement printing on a platform, the following functions must be
20  * defined:
21  *
22  * int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit)
23  * Called once.  Code should display printer dialogue (if appropriate) and
24  * determine printer font and margin settings.  Reset has_color if the printer
25  * doesn't support colors at all.
26  * Returns FAIL to abort.
27  *
28  * int mch_print_begin(prt_settings_T *settings)
29  * Called to start the print job.
30  * Return FALSE to abort.
31  *
32  * int mch_print_begin_page(char_u *msg)
33  * Called at the start of each page.
34  * "msg" indicates the progress of the print job, can be NULL.
35  * Return FALSE to abort.
36  *
37  * int mch_print_end_page()
38  * Called at the end of each page.
39  * Return FALSE to abort.
40  *
41  * int mch_print_blank_page()
42  * Called to generate a blank page for collated, duplex, multiple copy
43  * document.  Return FALSE to abort.
44  *
45  * void mch_print_end(prt_settings_T *psettings)
46  * Called at normal end of print job.
47  *
48  * void mch_print_cleanup()
49  * Called if print job ends normally or is abandoned. Free any memory, close
50  * devices and handles.  Also called when mch_print_begin() fails, but not
51  * when mch_print_init() fails.
52  *
53  * void mch_print_set_font(int Bold, int Italic, int Underline);
54  * Called whenever the font style changes.
55  *
56  * void mch_print_set_bg(long_u bgcol);
57  * Called to set the background color for the following text. Parameter is an
58  * RGB value.
59  *
60  * void mch_print_set_fg(long_u fgcol);
61  * 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
78 static 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 
84 static 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 
92 static int		current_syn_id;
93 #endif
94 
95 #define PRCOLOR_BLACK	(long_u)0
96 #define PRCOLOR_WHITE	(long_u)0xFFFFFFL
97 
98 static int	curr_italic;
99 static int	curr_bold;
100 static int	curr_underline;
101 static long_u	curr_bg;
102 static long_u	curr_fg;
103 static int	page_count;
104 
105 #if defined(FEAT_POSTSCRIPT)
106 # define OPT_MBFONT_USECOURIER  0
107 # define OPT_MBFONT_ASCII       1
108 # define OPT_MBFONT_REGULAR     2
109 # define OPT_MBFONT_BOLD	3
110 # define OPT_MBFONT_OBLIQUE     4
111 # define OPT_MBFONT_BOLDOBLIQUE 5
112 # define OPT_MBFONT_NUM_OPTIONS 6
113 
114 static 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  */
128 typedef struct
129 {
130     int		lead_spaces;	    // remaining spaces for a TAB
131     int		print_pos;	    // virtual column for computing TABs
132     colnr_T	column;		    // byte column
133     linenr_T	file_line;	    // line nr in the buffer
134     long_u	bytes_printed;	    // bytes printed so far
135     int		ff;		    // seen form feed character
136 } prt_pos_T;
137 
138 static char *parse_list_options(char_u *option_str, option_table_T *table, int table_size);
139 
140 static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T *ppos);
141 
142 /*
143  * Parse 'printoptions' and set the flags in "printer_opts".
144  * Returns an error message or NULL;
145  */
146     char *
147 parse_printoptions(void)
148 {
149     return parse_list_options(p_popt, printer_opts, OPT_PRINT_NUM_OPTIONS);
150 }
151 
152 #if defined(FEAT_POSTSCRIPT) || defined(PROTO)
153 /*
154  * Parse 'printmbfont' and set the flags in "mbfont_opts".
155  * Returns an error message or NULL;
156  */
157     char *
158 parse_printmbfont(void)
159 {
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  */
173     static char *
174 parse_list_options(
175     char_u		*option_str,
176     option_table_T	*table,
177     int			table_size)
178 {
179     option_table_T *old_opts;
180     char	*ret = NULL;
181     char_u	*stringp;
182     char_u	*colonp;
183     char_u	*commap;
184     char_u	*p;
185     int		idx = 0;		// init for GCC
186     int		len;
187 
188     // Save the old values, so that they can be restored in case of an error.
189     old_opts = ALLOC_MULT(option_table_T, table_size);
190     if (old_opts == NULL)
191 	return NULL;
192 
193     for (idx = 0; idx < table_size; ++idx)
194     {
195 	old_opts[idx] = table[idx];
196 	table[idx].present = FALSE;
197     }
198 
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)
207 	{
208 	    ret = N_("E550: Missing colon");
209 	    break;
210 	}
211 	commap = vim_strchr(stringp, ',');
212 	if (commap == NULL)
213 	    commap = option_str + STRLEN(option_str);
214 
215 	len = (int)(colonp - stringp);
216 
217 	for (idx = 0; idx < table_size; ++idx)
218 	    if (STRNICMP(stringp, table[idx].name, len) == 0)
219 		break;
220 
221 	if (idx == table_size)
222 	{
223 	    ret = N_("E551: Illegal component");
224 	    break;
225 	}
226 	p = colonp + 1;
227 	table[idx].present = TRUE;
228 
229 	if (table[idx].hasnum)
230 	{
231 	    if (!VIM_ISDIGIT(*p))
232 	    {
233 		ret = N_("E552: digit expected");
234 		break;
235 	    }
236 
237 	    table[idx].number = getdigits(&p); // advances p
238 	}
239 
240 	table[idx].string = p;
241 	table[idx].strlen = (int)(commap - p);
242 
243 	stringp = commap;
244 	if (*stringp == ',')
245 	    ++stringp;
246     }
247 
248     if (ret != NULL)
249     {
250 	// Restore old options in case of error
251 	for (idx = 0; idx < table_size; ++idx)
252 	    table[idx] = old_opts[idx];
253     }
254     vim_free(old_opts);
255     return ret;
256 }
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
265 darken_rgb(long_u rgb)
266 {
267     return	((rgb >> 17) << 16)
268 	    +	(((rgb & 0xff00) >> 9) << 8)
269 	    +	((rgb & 0xff) >> 1);
270 }
271 
272     static long_u
273 prt_get_term_color(int colorindex)
274 {
275     // TODO: Should check for xterm with 88 or 256 colors.
276     if (t_colors > 8)
277 	return cterm_color_16[colorindex % 16];
278     return cterm_color_8[colorindex % 8];
279 }
280 
281     static void
282 prt_get_attr(
283     int			hl_id,
284     prt_text_attr_T	*pattr,
285     int			modec)
286 {
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);
296 
297 # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
298     if (USE_24BIT)
299     {
300 	bg_color = highlight_gui_color_rgb(hl_id, FALSE);
301 	if (bg_color == PRCOLOR_BLACK)
302 	    bg_color = PRCOLOR_WHITE;
303 
304 	fg_color = highlight_gui_color_rgb(hl_id, TRUE);
305     }
306     else
307 # endif
308     {
309 	bg_color = PRCOLOR_WHITE;
310 
311 	color = (char *)highlight_color(hl_id, (char_u *)"fg", modec);
312 	if (color == NULL)
313 	    colorindex = 0;
314 	else
315 	    colorindex = atoi(color);
316 
317 	if (colorindex >= 0 && colorindex < t_colors)
318 	    fg_color = prt_get_term_color(colorindex);
319 	else
320 	    fg_color = PRCOLOR_BLACK;
321     }
322 
323     if (fg_color == PRCOLOR_WHITE)
324 	fg_color = PRCOLOR_BLACK;
325     else if (*p_bg == 'd')
326 	fg_color = darken_rgb(fg_color);
327 
328     pattr->fg_color = fg_color;
329     pattr->bg_color = bg_color;
330 }
331 #endif // FEAT_SYN_HL
332 
333     static void
334 prt_set_fg(long_u fg)
335 {
336     if (fg != curr_fg)
337     {
338 	curr_fg = fg;
339 	mch_print_set_fg(fg);
340     }
341 }
342 
343     static void
344 prt_set_bg(long_u bg)
345 {
346     if (bg != curr_bg)
347     {
348 	curr_bg = bg;
349 	mch_print_set_bg(bg);
350     }
351 }
352 
353     static void
354 prt_set_font(int bold, int italic, int underline)
355 {
356     if (curr_bold != bold
357 	    || curr_italic != italic
358 	    || curr_underline != underline)
359     {
360 	curr_underline = underline;
361 	curr_italic = italic;
362 	curr_bold = bold;
363 	mch_print_set_font(bold, italic, underline);
364     }
365 }
366 
367 /*
368  * Print the line number in the left margin.
369  */
370     static void
371 prt_line_number(
372     prt_settings_T *psettings,
373     int		page_line,
374     linenr_T	lnum)
375 {
376     int		i;
377     char_u	tbuf[20];
378 
379     prt_set_fg(psettings->number.fg_color);
380     prt_set_bg(psettings->number.bg_color);
381     prt_set_font(psettings->number.bold, psettings->number.italic, psettings->number.underline);
382     mch_print_start_line(TRUE, page_line);
383 
384     // Leave two spaces between the number and the text; depends on
385     // PRINT_NUMBER_WIDTH.
386     sprintf((char *)tbuf, "%6ld", (long)lnum);
387     for (i = 0; i < 6; i++)
388 	(void)mch_print_text_out(&tbuf[i], 1);
389 
390 #ifdef FEAT_SYN_HL
391     if (psettings->do_syntax)
392 	// Set colors for next character.
393 	current_syn_id = -1;
394     else
395 #endif
396     {
397 	// Set colors and font back to normal.
398 	prt_set_fg(PRCOLOR_BLACK);
399 	prt_set_bg(PRCOLOR_WHITE);
400 	prt_set_font(FALSE, FALSE, FALSE);
401     }
402 }
403 
404 /*
405  * Get the currently effective header height.
406  */
407     int
408 prt_header_height(void)
409 {
410     if (printer_opts[OPT_PRINT_HEADERHEIGHT].present)
411 	return printer_opts[OPT_PRINT_HEADERHEIGHT].number;
412     return 2;
413 }
414 
415 /*
416  * Return TRUE if using a line number for printing.
417  */
418     int
419 prt_use_number(void)
420 {
421     return (printer_opts[OPT_PRINT_NUMBER].present
422 	    && TOLOWER_ASC(printer_opts[OPT_PRINT_NUMBER].string[0]) == 'y');
423 }
424 
425 /*
426  * Return the unit used in a margin item in 'printoptions'.
427  * Returns PRT_UNIT_NONE if not recognized.
428  */
429     int
430 prt_get_unit(int idx)
431 {
432     int		u = PRT_UNIT_NONE;
433     int		i;
434     static char *(units[4]) = PRT_UNIT_NAMES;
435 
436     if (printer_opts[idx].present)
437 	for (i = 0; i < 4; ++i)
438 	    if (STRNICMP(printer_opts[idx].string, units[i], 2) == 0)
439 	    {
440 		u = i;
441 		break;
442 	    }
443     return u;
444 }
445 
446 /*
447  * Print the page header.
448  */
449     static void
450 prt_header(
451     prt_settings_T  *psettings,
452     int		pagenum,
453     linenr_T	lnum UNUSED)
454 {
455     int		width = psettings->chars_per_line;
456     int		page_line;
457     char_u	*tbuf;
458     char_u	*p;
459     int		l;
460 
461     // Also use the space for the line number.
462     if (prt_use_number())
463 	width += PRINT_NUMBER_WIDTH;
464 
465     tbuf = alloc(width + IOSIZE);
466     if (tbuf == NULL)
467 	return;
468 
469 #ifdef FEAT_STL_OPT
470     if (*p_header != NUL)
471     {
472 	linenr_T	tmp_lnum, tmp_topline, tmp_botline;
473 	int		use_sandbox = FALSE;
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 
489 # ifdef FEAT_EVAL
490 	use_sandbox = was_set_insecurely((char_u *)"printheader", 0);
491 # endif
492 	build_stl_str_hl(curwin, tbuf, (size_t)(width + IOSIZE),
493 						  p_header, use_sandbox,
494 						  ' ', width, NULL, NULL);
495 
496 	// Reset line numbers
497 	curwin->w_cursor.lnum = tmp_lnum;
498 	curwin->w_topline = tmp_topline;
499 	curwin->w_botline = tmp_botline;
500     }
501     else
502 #endif
503 	sprintf((char *)tbuf, _("Page %d"), pagenum);
504 
505     prt_set_fg(PRCOLOR_BLACK);
506     prt_set_bg(PRCOLOR_WHITE);
507     prt_set_font(TRUE, FALSE, FALSE);
508 
509     // Use a negative line number to indicate printing in the top margin.
510     page_line = 0 - prt_header_height();
511     mch_print_start_line(TRUE, page_line);
512     for (p = tbuf; *p != NUL; )
513     {
514 	if (mch_print_text_out(p, (l = (*mb_ptr2len)(p))))
515 	{
516 	    ++page_line;
517 	    if (page_line >= 0) // out of room in header
518 		break;
519 	    mch_print_start_line(TRUE, page_line);
520 	}
521 	p += l;
522     }
523 
524     vim_free(tbuf);
525 
526 #ifdef FEAT_SYN_HL
527     if (psettings->do_syntax)
528 	// Set colors for next character.
529 	current_syn_id = -1;
530     else
531 #endif
532     {
533 	// Set colors and font back to normal.
534 	prt_set_fg(PRCOLOR_BLACK);
535 	prt_set_bg(PRCOLOR_WHITE);
536 	prt_set_font(FALSE, FALSE, FALSE);
537     }
538 }
539 
540 /*
541  * Display a print status message.
542  */
543     static void
544 prt_message(char_u *s)
545 {
546     screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
547     screen_puts(s, (int)Rows - 1, 0, HL_ATTR(HLF_R));
548     out_flush();
549 }
550 
551     void
552 ex_hardcopy(exarg_T *eap)
553 {
554     linenr_T		lnum;
555     int			collated_copies, uncollated_copies;
556     prt_settings_T	settings;
557     long_u		bytes_to_print = 0;
558     int			page_line;
559     int			jobsplit;
560 
561     CLEAR_FIELD(settings);
562     settings.has_color = TRUE;
563 
564 # ifdef FEAT_POSTSCRIPT
565     if (*eap->arg == '>')
566     {
567 	char	*errormsg = NULL;
568 
569 	// Expand things like "%.ps".
570 	if (expand_filename(eap, eap->cmdlinep, &errormsg) == FAIL)
571 	{
572 	    if (errormsg != NULL)
573 		emsg(errormsg);
574 	    return;
575 	}
576 	settings.outfile = skipwhite(eap->arg + 1);
577     }
578     else if (*eap->arg != NUL)
579 	settings.arguments = eap->arg;
580 # endif
581 
582     /*
583      * Initialise for printing.  Ask the user for settings, unless forceit is
584      * set.
585      * The mch_print_init() code should set up margins if applicable. (It may
586      * not be a real printer - for example the engine might generate HTML or
587      * PS.)
588      */
589     if (mch_print_init(&settings,
590 			curbuf->b_fname == NULL
591 			    ? (char_u *)buf_spname(curbuf)
592 			    : curbuf->b_sfname == NULL
593 				? curbuf->b_fname
594 				: curbuf->b_sfname,
595 			eap->forceit) == FAIL)
596 	return;
597 
598 #ifdef FEAT_SYN_HL
599 # ifdef  FEAT_GUI
600     if (gui.in_use)
601 	settings.modec = 'g';
602     else
603 # endif
604 	if (t_colors > 1)
605 	    settings.modec = 'c';
606 	else
607 	    settings.modec = 't';
608 
609     if (!syntax_present(curwin))
610 	settings.do_syntax = FALSE;
611     else if (printer_opts[OPT_PRINT_SYNTAX].present
612 	    && TOLOWER_ASC(printer_opts[OPT_PRINT_SYNTAX].string[0]) != 'a')
613 	settings.do_syntax =
614 	       (TOLOWER_ASC(printer_opts[OPT_PRINT_SYNTAX].string[0]) == 'y');
615     else
616 	settings.do_syntax = settings.has_color;
617 #endif
618 
619     // Set up printing attributes for line numbers
620     settings.number.fg_color = PRCOLOR_BLACK;
621     settings.number.bg_color = PRCOLOR_WHITE;
622     settings.number.bold = FALSE;
623     settings.number.italic = TRUE;
624     settings.number.underline = FALSE;
625 #ifdef FEAT_SYN_HL
626     /*
627      * Syntax highlighting of line numbers.
628      */
629     if (prt_use_number() && settings.do_syntax)
630     {
631 	int		id;
632 
633 	id = syn_name2id((char_u *)"LineNr");
634 	if (id > 0)
635 	    id = syn_get_final_id(id);
636 
637 	prt_get_attr(id, &settings.number, settings.modec);
638     }
639 #endif
640 
641     /*
642      * Estimate the total lines to be printed
643      */
644     for (lnum = eap->line1; lnum <= eap->line2; lnum++)
645 	bytes_to_print += (long_u)STRLEN(skipwhite(ml_get(lnum)));
646     if (bytes_to_print == 0)
647     {
648 	msg(_("No text to be printed"));
649 	goto print_fail_no_begin;
650     }
651 
652     // Set colors and font to normal.
653     curr_bg = (long_u)0xffffffffL;
654     curr_fg = (long_u)0xffffffffL;
655     curr_italic = MAYBE;
656     curr_bold = MAYBE;
657     curr_underline = MAYBE;
658 
659     prt_set_fg(PRCOLOR_BLACK);
660     prt_set_bg(PRCOLOR_WHITE);
661     prt_set_font(FALSE, FALSE, FALSE);
662 #ifdef FEAT_SYN_HL
663     current_syn_id = -1;
664 #endif
665 
666     jobsplit = (printer_opts[OPT_PRINT_JOBSPLIT].present
667 	   && TOLOWER_ASC(printer_opts[OPT_PRINT_JOBSPLIT].string[0]) == 'y');
668 
669     if (!mch_print_begin(&settings))
670 	goto print_fail_no_begin;
671 
672     /*
673      * Loop over collated copies: 1 2 3, 1 2 3, ...
674      */
675     page_count = 0;
676     for (collated_copies = 0;
677 	    collated_copies < settings.n_collated_copies;
678 	    collated_copies++)
679     {
680 	prt_pos_T	prtpos;		// current print position
681 	prt_pos_T	page_prtpos;	// print position at page start
682 	int		side;
683 
684 	CLEAR_FIELD(page_prtpos);
685 	page_prtpos.file_line = eap->line1;
686 	prtpos = page_prtpos;
687 
688 	if (jobsplit && collated_copies > 0)
689 	{
690 	    // Splitting jobs: Stop a previous job and start a new one.
691 	    mch_print_end(&settings);
692 	    if (!mch_print_begin(&settings))
693 		goto print_fail_no_begin;
694 	}
695 
696 	/*
697 	 * Loop over all pages in the print job: 1 2 3 ...
698 	 */
699 	for (page_count = 0; prtpos.file_line <= eap->line2; ++page_count)
700 	{
701 	    /*
702 	     * Loop over uncollated copies: 1 1 1, 2 2 2, 3 3 3, ...
703 	     * For duplex: 12 12 12 34 34 34, ...
704 	     */
705 	    for (uncollated_copies = 0;
706 		    uncollated_copies < settings.n_uncollated_copies;
707 		    uncollated_copies++)
708 	    {
709 		// Set the print position to the start of this page.
710 		prtpos = page_prtpos;
711 
712 		/*
713 		 * Do front and rear side of a page.
714 		 */
715 		for (side = 0; side <= settings.duplex; ++side)
716 		{
717 		    /*
718 		     * Print one page.
719 		     */
720 
721 		    // Check for interrupt character every page.
722 		    ui_breakcheck();
723 		    if (got_int || settings.user_abort)
724 			goto print_fail;
725 
726 		    sprintf((char *)IObuff, _("Printing page %d (%d%%)"),
727 			    page_count + 1 + side,
728 			    prtpos.bytes_printed > 1000000
729 				? (int)(prtpos.bytes_printed /
730 						       (bytes_to_print / 100))
731 				: (int)((prtpos.bytes_printed * 100)
732 							   / bytes_to_print));
733 		    if (!mch_print_begin_page(IObuff))
734 			goto print_fail;
735 
736 		    if (settings.n_collated_copies > 1)
737 			sprintf((char *)IObuff + STRLEN(IObuff),
738 				_(" Copy %d of %d"),
739 				collated_copies + 1,
740 				settings.n_collated_copies);
741 		    prt_message(IObuff);
742 
743 		    /*
744 		     * Output header if required
745 		     */
746 		    if (prt_header_height() > 0)
747 			prt_header(&settings, page_count + 1 + side,
748 							prtpos.file_line);
749 
750 		    for (page_line = 0; page_line < settings.lines_per_page;
751 								  ++page_line)
752 		    {
753 			prtpos.column = hardcopy_line(&settings,
754 							   page_line, &prtpos);
755 			if (prtpos.column == 0)
756 			{
757 			    // finished a file line
758 			    prtpos.bytes_printed +=
759 				  STRLEN(skipwhite(ml_get(prtpos.file_line)));
760 			    if (++prtpos.file_line > eap->line2)
761 				break; // reached the end
762 			}
763 			else if (prtpos.ff)
764 			{
765 			    // Line had a formfeed in it - start new page but
766 			    // stay on the current line
767 			    break;
768 			}
769 		    }
770 
771 		    if (!mch_print_end_page())
772 			goto print_fail;
773 		    if (prtpos.file_line > eap->line2)
774 			break; // reached the end
775 		}
776 
777 		/*
778 		 * Extra blank page for duplexing with odd number of pages and
779 		 * more copies to come.
780 		 */
781 		if (prtpos.file_line > eap->line2 && settings.duplex
782 								 && side == 0
783 		    && uncollated_copies + 1 < settings.n_uncollated_copies)
784 		{
785 		    if (!mch_print_blank_page())
786 			goto print_fail;
787 		}
788 	    }
789 	    if (settings.duplex && prtpos.file_line <= eap->line2)
790 		++page_count;
791 
792 	    // Remember the position where the next page starts.
793 	    page_prtpos = prtpos;
794 	}
795 
796 	vim_snprintf((char *)IObuff, IOSIZE, _("Printed: %s"),
797 							    settings.jobname);
798 	prt_message(IObuff);
799     }
800 
801 print_fail:
802     if (got_int || settings.user_abort)
803     {
804 	sprintf((char *)IObuff, "%s", _("Printing aborted"));
805 	prt_message(IObuff);
806     }
807     mch_print_end(&settings);
808 
809 print_fail_no_begin:
810     mch_print_cleanup();
811 }
812 
813 /*
814  * Print one page line.
815  * Return the next column to print, or zero if the line is finished.
816  */
817     static colnr_T
818 hardcopy_line(
819     prt_settings_T	*psettings,
820     int			page_line,
821     prt_pos_T		*ppos)
822 {
823     colnr_T	col;
824     char_u	*line;
825     int		need_break = FALSE;
826     int		outputlen;
827     int		tab_spaces;
828     long_u	print_pos;
829 #ifdef FEAT_SYN_HL
830     prt_text_attr_T attr;
831     int		id;
832 #endif
833 
834     if (ppos->column == 0 || ppos->ff)
835     {
836 	print_pos = 0;
837 	tab_spaces = 0;
838 	if (!ppos->ff && prt_use_number())
839 	    prt_line_number(psettings, page_line, ppos->file_line);
840 	ppos->ff = FALSE;
841     }
842     else
843     {
844 	// left over from wrap halfway a tab
845 	print_pos = ppos->print_pos;
846 	tab_spaces = ppos->lead_spaces;
847     }
848 
849     mch_print_start_line(0, page_line);
850     line = ml_get(ppos->file_line);
851 
852     /*
853      * Loop over the columns until the end of the file line or right margin.
854      */
855     for (col = ppos->column; line[col] != NUL && !need_break; col += outputlen)
856     {
857 	outputlen = 1;
858 	if (has_mbyte && (outputlen = (*mb_ptr2len)(line + col)) < 1)
859 	    outputlen = 1;
860 #ifdef FEAT_SYN_HL
861 	/*
862 	 * syntax highlighting stuff.
863 	 */
864 	if (psettings->do_syntax)
865 	{
866 	    id = syn_get_id(curwin, ppos->file_line, col, 1, NULL, FALSE);
867 	    if (id > 0)
868 		id = syn_get_final_id(id);
869 	    else
870 		id = 0;
871 	    // Get the line again, a multi-line regexp may invalidate it.
872 	    line = ml_get(ppos->file_line);
873 
874 	    if (id != current_syn_id)
875 	    {
876 		current_syn_id = id;
877 		prt_get_attr(id, &attr, psettings->modec);
878 		prt_set_font(attr.bold, attr.italic, attr.underline);
879 		prt_set_fg(attr.fg_color);
880 		prt_set_bg(attr.bg_color);
881 	    }
882 	}
883 #endif
884 
885 	/*
886 	 * Appropriately expand any tabs to spaces.
887 	 */
888 	if (line[col] == TAB || tab_spaces != 0)
889 	{
890 	    if (tab_spaces == 0)
891 #ifdef FEAT_VARTABS
892 		tab_spaces = tabstop_padding(print_pos, curbuf->b_p_ts,
893 							curbuf->b_p_vts_array);
894 #else
895 		tab_spaces = (int)(curbuf->b_p_ts - (print_pos % curbuf->b_p_ts));
896 #endif
897 
898 	    while (tab_spaces > 0)
899 	    {
900 		need_break = mch_print_text_out((char_u *)" ", 1);
901 		print_pos++;
902 		tab_spaces--;
903 		if (need_break)
904 		    break;
905 	    }
906 	    // Keep the TAB if we didn't finish it.
907 	    if (need_break && tab_spaces > 0)
908 		break;
909 	}
910 	else if (line[col] == FF
911 		&& printer_opts[OPT_PRINT_FORMFEED].present
912 		&& TOLOWER_ASC(printer_opts[OPT_PRINT_FORMFEED].string[0])
913 								       == 'y')
914 	{
915 	    ppos->ff = TRUE;
916 	    need_break = 1;
917 	}
918 	else
919 	{
920 	    need_break = mch_print_text_out(line + col, outputlen);
921 	    if (has_mbyte)
922 		print_pos += (*mb_ptr2cells)(line + col);
923 	    else
924 		print_pos++;
925 	}
926     }
927 
928     ppos->lead_spaces = tab_spaces;
929     ppos->print_pos = (int)print_pos;
930 
931     /*
932      * Start next line of file if we clip lines, or have reached end of the
933      * line, unless we are doing a formfeed.
934      */
935     if (!ppos->ff
936 	    && (line[col] == NUL
937 		|| (printer_opts[OPT_PRINT_WRAP].present
938 		    && TOLOWER_ASC(printer_opts[OPT_PRINT_WRAP].string[0])
939 								     == 'n')))
940 	return 0;
941     return col;
942 }
943 
944 # if defined(FEAT_POSTSCRIPT) || defined(PROTO)
945 
946 /*
947  * PS printer stuff.
948  *
949  * Sources of information to help maintain the PS printing code:
950  *
951  * 1. PostScript Language Reference, 3rd Edition,
952  *      Addison-Wesley, 1999, ISBN 0-201-37922-8
953  * 2. PostScript Language Program Design,
954  *      Addison-Wesley, 1988, ISBN 0-201-14396-8
955  * 3. PostScript Tutorial and Cookbook,
956  *      Addison Wesley, 1985, ISBN 0-201-10179-3
957  * 4. PostScript Language Document Structuring Conventions Specification,
958  *    version 3.0,
959  *      Adobe Technote 5001, 25th September 1992
960  * 5. PostScript Printer Description File Format Specification, Version 4.3,
961  *      Adobe technote 5003, 9th February 1996
962  * 6. Adobe Font Metrics File Format Specification, Version 4.1,
963  *      Adobe Technote 5007, 7th October 1998
964  * 7. Adobe CMap and CIDFont Files Specification, Version 1.0,
965  *      Adobe Technote 5014, 8th October 1996
966  * 8. Adobe CJKV Character Collections and CMaps for CID-Keyed Fonts,
967  *      Adoboe Technote 5094, 8th September, 2001
968  * 9. CJKV Information Processing, 2nd Edition,
969  *      O'Reilly, 2002, ISBN 1-56592-224-7
970  *
971  * Some of these documents can be found in PDF form on Adobe's web site -
972  * http://www.adobe.com
973  */
974 
975 #define NUM_ELEMENTS(arr)   (sizeof(arr)/sizeof((arr)[0]))
976 
977 #define PRT_PS_DEFAULT_DPI	    (72)    // Default user space resolution
978 #define PRT_PS_DEFAULT_FONTSIZE     (10)
979 #define PRT_PS_DEFAULT_BUFFER_SIZE  (80)
980 
981 struct prt_mediasize_S
982 {
983     char	*name;
984     float	width;		// width and height in points for portrait
985     float	height;
986 };
987 
988 #define PRT_MEDIASIZE_LEN  (sizeof(prt_mediasize) / sizeof(struct prt_mediasize_S))
989 
990 static struct prt_mediasize_S prt_mediasize[] =
991 {
992     {"A4",		595.0,  842.0},
993     {"letter",		612.0,  792.0},
994     {"10x14",		720.0, 1008.0},
995     {"A3",		842.0, 1191.0},
996     {"A5",		420.0,  595.0},
997     {"B4",		729.0, 1032.0},
998     {"B5",		516.0,  729.0},
999     {"executive",	522.0,  756.0},
1000     {"folio",		595.0,  935.0},
1001     {"ledger",	       1224.0,  792.0},   // Yes, it is wider than taller!
1002     {"legal",		612.0, 1008.0},
1003     {"quarto",		610.0,  780.0},
1004     {"statement",	396.0,  612.0},
1005     {"tabloid",		792.0, 1224.0}
1006 };
1007 
1008 // PS font names, must be in Roman, Bold, Italic, Bold-Italic order
1009 struct prt_ps_font_S
1010 {
1011     int		wx;
1012     int		uline_offset;
1013     int		uline_width;
1014     int		bbox_min_y;
1015     int		bbox_max_y;
1016     char	*(ps_fontname[4]);
1017 };
1018 
1019 #define PRT_PS_FONT_ROMAN	(0)
1020 #define PRT_PS_FONT_BOLD	(1)
1021 #define PRT_PS_FONT_OBLIQUE	(2)
1022 #define PRT_PS_FONT_BOLDOBLIQUE (3)
1023 
1024 // Standard font metrics for Courier family
1025 static struct prt_ps_font_S prt_ps_courier_font =
1026 {
1027     600,
1028     -100, 50,
1029     -250, 805,
1030     {"Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique"}
1031 };
1032 
1033 // Generic font metrics for multi-byte fonts
1034 static struct prt_ps_font_S prt_ps_mb_font =
1035 {
1036     1000,
1037     -100, 50,
1038     -250, 805,
1039     {NULL, NULL, NULL, NULL}
1040 };
1041 
1042 // Pointer to current font set being used
1043 static struct prt_ps_font_S* prt_ps_font;
1044 
1045 // Structures to map user named encoding and mapping to PS equivalents for
1046 // building CID font name
1047 struct prt_ps_encoding_S
1048 {
1049     char	*encoding;
1050     char	*cmap_encoding;
1051     int		needs_charset;
1052 };
1053 
1054 struct prt_ps_charset_S
1055 {
1056     char	*charset;
1057     char	*cmap_charset;
1058     int		has_charset;
1059 };
1060 
1061 
1062 #define CS_JIS_C_1978   (0x01)
1063 #define CS_JIS_X_1983   (0x02)
1064 #define CS_JIS_X_1990   (0x04)
1065 #define CS_NEC		(0x08)
1066 #define CS_MSWINDOWS	(0x10)
1067 #define CS_CP932	(0x20)
1068 #define CS_KANJITALK6	(0x40)
1069 #define CS_KANJITALK7   (0x80)
1070 
1071 // Japanese encodings and charsets
1072 static struct prt_ps_encoding_S j_encodings[] =
1073 {
1074     {"iso-2022-jp", NULL,       (CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_1990|
1075 								    CS_NEC)},
1076     {"euc-jp",	    "EUC",	(CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_1990)},
1077     {"sjis",	    "RKSJ",	(CS_JIS_C_1978|CS_JIS_X_1983|CS_MSWINDOWS|
1078 						CS_KANJITALK6|CS_KANJITALK7)},
1079     {"cp932",       "RKSJ",     CS_JIS_X_1983},
1080     {"ucs-2",       "UCS2",     CS_JIS_X_1990},
1081     {"utf-8",       "UTF8" ,    CS_JIS_X_1990}
1082 };
1083 static struct prt_ps_charset_S j_charsets[] =
1084 {
1085     {"JIS_C_1978",  "78",       CS_JIS_C_1978},
1086     {"JIS_X_1983",  NULL,       CS_JIS_X_1983},
1087     {"JIS_X_1990",  "Hojo",     CS_JIS_X_1990},
1088     {"NEC",	    "Ext",	CS_NEC},
1089     {"MSWINDOWS",   "90ms",     CS_MSWINDOWS},
1090     {"CP932",       "90ms",     CS_JIS_X_1983},
1091     {"KANJITALK6",  "83pv",     CS_KANJITALK6},
1092     {"KANJITALK7",  "90pv",     CS_KANJITALK7}
1093 };
1094 
1095 #define CS_GB_2312_80       (0x01)
1096 #define CS_GBT_12345_90     (0x02)
1097 #define CS_GBK2K	    (0x04)
1098 #define CS_SC_MAC	    (0x08)
1099 #define CS_GBT_90_MAC	    (0x10)
1100 #define CS_GBK		    (0x20)
1101 #define CS_SC_ISO10646      (0x40)
1102 
1103 // Simplified Chinese encodings and charsets
1104 static struct prt_ps_encoding_S sc_encodings[] =
1105 {
1106     {"iso-2022",    NULL,       (CS_GB_2312_80|CS_GBT_12345_90)},
1107     {"gb18030",     NULL,       CS_GBK2K},
1108     {"euc-cn",      "EUC",      (CS_GB_2312_80|CS_GBT_12345_90|CS_SC_MAC|
1109 								CS_GBT_90_MAC)},
1110     {"gbk",	    "EUC",	CS_GBK},
1111     {"ucs-2",       "UCS2",     CS_SC_ISO10646},
1112     {"utf-8",       "UTF8",     CS_SC_ISO10646}
1113 };
1114 static struct prt_ps_charset_S sc_charsets[] =
1115 {
1116     {"GB_2312-80",  "GB",       CS_GB_2312_80},
1117     {"GBT_12345-90","GBT",      CS_GBT_12345_90},
1118     {"MAC",	    "GBpc",	CS_SC_MAC},
1119     {"GBT-90_MAC",  "GBTpc",	CS_GBT_90_MAC},
1120     {"GBK",	    "GBK",	CS_GBK},
1121     {"GB18030",     "GBK2K",    CS_GBK2K},
1122     {"ISO10646",    "UniGB",    CS_SC_ISO10646}
1123 };
1124 
1125 #define CS_CNS_PLANE_1      (0x01)
1126 #define CS_CNS_PLANE_2      (0x02)
1127 #define CS_CNS_PLANE_1_2    (0x04)
1128 #define CS_B5		    (0x08)
1129 #define CS_ETEN		    (0x10)
1130 #define CS_HK_GCCS	    (0x20)
1131 #define CS_HK_SCS	    (0x40)
1132 #define CS_HK_SCS_ETEN	    (0x80)
1133 #define CS_MTHKL	    (0x100)
1134 #define CS_MTHKS	    (0x200)
1135 #define CS_DLHKL	    (0x400)
1136 #define CS_DLHKS	    (0x800)
1137 #define CS_TC_ISO10646	    (0x1000)
1138 
1139 // Traditional Chinese encodings and charsets
1140 static struct prt_ps_encoding_S tc_encodings[] =
1141 {
1142     {"iso-2022",    NULL,       (CS_CNS_PLANE_1|CS_CNS_PLANE_2)},
1143     {"euc-tw",      "EUC",      CS_CNS_PLANE_1_2},
1144     {"big5",	    "B5",	(CS_B5|CS_ETEN|CS_HK_GCCS|CS_HK_SCS|
1145 				    CS_HK_SCS_ETEN|CS_MTHKL|CS_MTHKS|CS_DLHKL|
1146 								    CS_DLHKS)},
1147     {"cp950",       "B5",       CS_B5},
1148     {"ucs-2",       "UCS2",     CS_TC_ISO10646},
1149     {"utf-8",       "UTF8",     CS_TC_ISO10646},
1150     {"utf-16",      "UTF16",    CS_TC_ISO10646},
1151     {"utf-32",      "UTF32",    CS_TC_ISO10646}
1152 };
1153 static struct prt_ps_charset_S tc_charsets[] =
1154 {
1155     {"CNS_1992_1",  "CNS1",     CS_CNS_PLANE_1},
1156     {"CNS_1992_2",  "CNS2",     CS_CNS_PLANE_2},
1157     {"CNS_1993",    "CNS",      CS_CNS_PLANE_1_2},
1158     {"BIG5",	    NULL,	CS_B5},
1159     {"CP950",	    NULL,	CS_B5},
1160     {"ETEN",	    "ETen",	CS_ETEN},
1161     {"HK_GCCS",     "HKgccs",	CS_HK_GCCS},
1162     {"SCS",	    "HKscs",	CS_HK_SCS},
1163     {"SCS_ETEN",    "ETHK",     CS_HK_SCS_ETEN},
1164     {"MTHKL",       "HKm471",   CS_MTHKL},
1165     {"MTHKS",       "HKm314",   CS_MTHKS},
1166     {"DLHKL",       "HKdla",    CS_DLHKL},
1167     {"DLHKS",       "HKdlb",    CS_DLHKS},
1168     {"ISO10646",    "UniCNS",   CS_TC_ISO10646}
1169 };
1170 
1171 #define CS_KR_X_1992	    (0x01)
1172 #define CS_KR_MAC	    (0x02)
1173 #define CS_KR_X_1992_MS     (0x04)
1174 #define CS_KR_ISO10646      (0x08)
1175 
1176 // Korean encodings and charsets
1177 static struct prt_ps_encoding_S k_encodings[] =
1178 {
1179     {"iso-2022-kr", NULL,       CS_KR_X_1992},
1180     {"euc-kr",      "EUC",      (CS_KR_X_1992|CS_KR_MAC)},
1181     {"johab",       "Johab",    CS_KR_X_1992},
1182     {"cp1361",      "Johab",    CS_KR_X_1992},
1183     {"uhc",	    "UHC",	CS_KR_X_1992_MS},
1184     {"cp949",       "UHC",      CS_KR_X_1992_MS},
1185     {"ucs-2",       "UCS2",     CS_KR_ISO10646},
1186     {"utf-8",       "UTF8",     CS_KR_ISO10646}
1187 };
1188 static struct prt_ps_charset_S k_charsets[] =
1189 {
1190     {"KS_X_1992",   "KSC",      CS_KR_X_1992},
1191     {"CP1361",      "KSC",      CS_KR_X_1992},
1192     {"MAC",	    "KSCpc",	CS_KR_MAC},
1193     {"MSWINDOWS",   "KSCms",    CS_KR_X_1992_MS},
1194     {"CP949",       "KSCms",    CS_KR_X_1992_MS},
1195     {"WANSUNG",     "KSCms",    CS_KR_X_1992_MS},
1196     {"ISO10646",    "UniKS",    CS_KR_ISO10646}
1197 };
1198 
1199 // Collections of encodings and charsets for multi-byte printing
1200 struct prt_ps_mbfont_S
1201 {
1202     int				num_encodings;
1203     struct prt_ps_encoding_S	*encodings;
1204     int				num_charsets;
1205     struct prt_ps_charset_S	*charsets;
1206     char			*ascii_enc;
1207     char			*defcs;
1208 };
1209 
1210 static struct prt_ps_mbfont_S prt_ps_mbfonts[] =
1211 {
1212     {
1213 	NUM_ELEMENTS(j_encodings),
1214 	j_encodings,
1215 	NUM_ELEMENTS(j_charsets),
1216 	j_charsets,
1217 	"jis_roman",
1218 	"JIS_X_1983"
1219     },
1220     {
1221 	NUM_ELEMENTS(sc_encodings),
1222 	sc_encodings,
1223 	NUM_ELEMENTS(sc_charsets),
1224 	sc_charsets,
1225 	"gb_roman",
1226 	"GB_2312-80"
1227     },
1228     {
1229 	NUM_ELEMENTS(tc_encodings),
1230 	tc_encodings,
1231 	NUM_ELEMENTS(tc_charsets),
1232 	tc_charsets,
1233 	"cns_roman",
1234 	"BIG5"
1235     },
1236     {
1237 	NUM_ELEMENTS(k_encodings),
1238 	k_encodings,
1239 	NUM_ELEMENTS(k_charsets),
1240 	k_charsets,
1241 	"ks_roman",
1242 	"KS_X_1992"
1243     }
1244 };
1245 
1246 struct prt_ps_resource_S
1247 {
1248     char_u  name[64];
1249     char_u  filename[MAXPATHL + 1];
1250     int     type;
1251     char_u  title[256];
1252     char_u  version[256];
1253 };
1254 
1255 // Types of PS resource file currently used
1256 #define PRT_RESOURCE_TYPE_PROCSET   (0)
1257 #define PRT_RESOURCE_TYPE_ENCODING  (1)
1258 #define PRT_RESOURCE_TYPE_CMAP      (2)
1259 
1260 // The PS prolog file version number has to match - if the prolog file is
1261 // updated, increment the number in the file and here.  Version checking was
1262 // added as of VIM 6.2.
1263 // The CID prolog file version number behaves as per PS prolog.
1264 // Table of VIM and prolog versions:
1265 //
1266 // VIM      Prolog  CIDProlog
1267 // 6.2      1.3
1268 // 7.0      1.4	    1.0
1269 #define PRT_PROLOG_VERSION  ((char_u *)"1.4")
1270 #define PRT_CID_PROLOG_VERSION  ((char_u *)"1.0")
1271 
1272 // String versions of PS resource types - indexed by constants above so don't
1273 // re-order!
1274 static char *prt_resource_types[] =
1275 {
1276     "procset",
1277     "encoding",
1278     "cmap"
1279 };
1280 
1281 // Strings to look for in a PS resource file
1282 #define PRT_RESOURCE_HEADER	    "%!PS-Adobe-"
1283 #define PRT_RESOURCE_RESOURCE	    "Resource-"
1284 #define PRT_RESOURCE_PROCSET	    "ProcSet"
1285 #define PRT_RESOURCE_ENCODING	    "Encoding"
1286 #define PRT_RESOURCE_CMAP	    "CMap"
1287 
1288 
1289 // Data for table based DSC comment recognition, easy to extend if VIM needs to
1290 // read more comments.
1291 #define PRT_DSC_MISC_TYPE	    (-1)
1292 #define PRT_DSC_TITLE_TYPE	    (1)
1293 #define PRT_DSC_VERSION_TYPE	    (2)
1294 #define PRT_DSC_ENDCOMMENTS_TYPE    (3)
1295 
1296 #define PRT_DSC_TITLE		    "%%Title:"
1297 #define PRT_DSC_VERSION		    "%%Version:"
1298 #define PRT_DSC_ENDCOMMENTS	    "%%EndComments:"
1299 
1300 struct prt_dsc_comment_S
1301 {
1302     char	*string;
1303     int		len;
1304     int		type;
1305 };
1306 
1307 struct prt_dsc_line_S
1308 {
1309     int		type;
1310     char_u	*string;
1311     int		len;
1312 };
1313 
1314 
1315 #define SIZEOF_CSTR(s)      (sizeof(s) - 1)
1316 static struct prt_dsc_comment_S prt_dsc_table[] =
1317 {
1318     {PRT_DSC_TITLE,       SIZEOF_CSTR(PRT_DSC_TITLE),     PRT_DSC_TITLE_TYPE},
1319     {PRT_DSC_VERSION,     SIZEOF_CSTR(PRT_DSC_VERSION),
1320 							PRT_DSC_VERSION_TYPE},
1321     {PRT_DSC_ENDCOMMENTS, SIZEOF_CSTR(PRT_DSC_ENDCOMMENTS),
1322 						     PRT_DSC_ENDCOMMENTS_TYPE}
1323 };
1324 
1325 static void prt_write_file_len(char_u *buffer, int bytes);
1326 static int prt_next_dsc(struct prt_dsc_line_S *p_dsc_line);
1327 
1328 /*
1329  * Variables for the output PostScript file.
1330  */
1331 static FILE *prt_ps_fd;
1332 static int prt_file_error;
1333 static char_u *prt_ps_file_name = NULL;
1334 
1335 /*
1336  * Various offsets and dimensions in default PostScript user space (points).
1337  * Used for text positioning calculations
1338  */
1339 static float prt_page_width;
1340 static float prt_page_height;
1341 static float prt_left_margin;
1342 static float prt_right_margin;
1343 static float prt_top_margin;
1344 static float prt_bottom_margin;
1345 static float prt_line_height;
1346 static float prt_first_line_height;
1347 static float prt_char_width;
1348 static float prt_number_width;
1349 static float prt_bgcol_offset;
1350 static float prt_pos_x_moveto = 0.0;
1351 static float prt_pos_y_moveto = 0.0;
1352 
1353 /*
1354  * Various control variables used to decide when and how to change the
1355  * PostScript graphics state.
1356  */
1357 static int prt_need_moveto;
1358 static int prt_do_moveto;
1359 static int prt_need_font;
1360 static int prt_font;
1361 static int prt_need_underline;
1362 static int prt_underline;
1363 static int prt_do_underline;
1364 static int prt_need_fgcol;
1365 static int prt_fgcol;
1366 static int prt_need_bgcol;
1367 static int prt_do_bgcol;
1368 static int prt_bgcol;
1369 static int prt_new_bgcol;
1370 static int prt_attribute_change;
1371 static float prt_text_run;
1372 static int prt_page_num;
1373 static int prt_bufsiz;
1374 
1375 /*
1376  * Variables controlling physical printing.
1377  */
1378 static int prt_media;
1379 static int prt_portrait;
1380 static int prt_num_copies;
1381 static int prt_duplex;
1382 static int prt_tumble;
1383 static int prt_collate;
1384 
1385 /*
1386  * Buffers used when generating PostScript output
1387  */
1388 static char_u prt_line_buffer[257];
1389 static garray_T prt_ps_buffer;
1390 
1391 static int prt_do_conv;
1392 static vimconv_T prt_conv;
1393 
1394 static int prt_out_mbyte;
1395 static int prt_custom_cmap;
1396 static char prt_cmap[80];
1397 static int prt_use_courier;
1398 static int prt_in_ascii;
1399 static int prt_half_width;
1400 static char *prt_ascii_encoding;
1401 static char_u prt_hexchar[] = "0123456789abcdef";
1402 
1403     static void
1404 prt_write_file_raw_len(char_u *buffer, int bytes)
1405 {
1406     if (!prt_file_error
1407 	    && fwrite(buffer, sizeof(char_u), bytes, prt_ps_fd)
1408 							     != (size_t)bytes)
1409     {
1410 	emsg(_("E455: Error writing to PostScript output file"));
1411 	prt_file_error = TRUE;
1412     }
1413 }
1414 
1415     static void
1416 prt_write_file(char_u *buffer)
1417 {
1418     prt_write_file_len(buffer, (int)STRLEN(buffer));
1419 }
1420 
1421     static void
1422 prt_write_file_len(char_u *buffer, int bytes)
1423 {
1424 #ifdef EBCDIC
1425     ebcdic2ascii(buffer, bytes);
1426 #endif
1427     prt_write_file_raw_len(buffer, bytes);
1428 }
1429 
1430 /*
1431  * Write a string.
1432  */
1433     static void
1434 prt_write_string(char *s)
1435 {
1436     vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer), "%s", s);
1437     prt_write_file(prt_line_buffer);
1438 }
1439 
1440 /*
1441  * Write an int and a space.
1442  */
1443     static void
1444 prt_write_int(int i)
1445 {
1446     sprintf((char *)prt_line_buffer, "%d ", i);
1447     prt_write_file(prt_line_buffer);
1448 }
1449 
1450 /*
1451  * Write a boolean and a space.
1452  */
1453     static void
1454 prt_write_boolean(int b)
1455 {
1456     sprintf((char *)prt_line_buffer, "%s ", (b ? "T" : "F"));
1457     prt_write_file(prt_line_buffer);
1458 }
1459 
1460 /*
1461  * Write PostScript to re-encode and define the font.
1462  */
1463     static void
1464 prt_def_font(
1465     char	*new_name,
1466     char	*encoding,
1467     int		height,
1468     char	*font)
1469 {
1470     vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1471 			  "/_%s /VIM-%s /%s ref\n", new_name, encoding, font);
1472     prt_write_file(prt_line_buffer);
1473     if (prt_out_mbyte)
1474 	sprintf((char *)prt_line_buffer, "/%s %d %f /_%s sffs\n",
1475 		       new_name, height, 500./prt_ps_courier_font.wx, new_name);
1476     else
1477 	vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1478 			     "/%s %d /_%s ffs\n", new_name, height, new_name);
1479     prt_write_file(prt_line_buffer);
1480 }
1481 
1482 /*
1483  * Write a line to define the CID font.
1484  */
1485     static void
1486 prt_def_cidfont(char *new_name, int height, char *cidfont)
1487 {
1488     vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1489 	      "/_%s /%s[/%s] vim_composefont\n", new_name, prt_cmap, cidfont);
1490     prt_write_file(prt_line_buffer);
1491     vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1492 			     "/%s %d /_%s ffs\n", new_name, height, new_name);
1493     prt_write_file(prt_line_buffer);
1494 }
1495 
1496 /*
1497  * Write a line to define a duplicate of a CID font
1498  */
1499     static void
1500 prt_dup_cidfont(char *original_name, char *new_name)
1501 {
1502     vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1503 				       "/%s %s d\n", new_name, original_name);
1504     prt_write_file(prt_line_buffer);
1505 }
1506 
1507 /*
1508  * Convert a real value into an integer and fractional part as integers, with
1509  * the fractional part being in the range [0,10^precision).  The fractional part
1510  * is also rounded based on the precision + 1'th fractional digit.
1511  */
1512     static void
1513 prt_real_bits(
1514     double      real,
1515     int		precision,
1516     int		*pinteger,
1517     int		*pfraction)
1518 {
1519     int     i;
1520     int     integer;
1521     float   fraction;
1522 
1523     integer = (int)real;
1524     fraction = (float)(real - integer);
1525     if (real < (double)integer)
1526 	fraction = -fraction;
1527     for (i = 0; i < precision; i++)
1528 	fraction *= 10.0;
1529 
1530     *pinteger = integer;
1531     *pfraction = (int)(fraction + 0.5);
1532 }
1533 
1534 /*
1535  * Write a real and a space.  Save bytes if real value has no fractional part!
1536  * We use prt_real_bits() as %f in sprintf uses the locale setting to decide
1537  * what decimal point character to use, but PS always requires a '.'.
1538  */
1539     static void
1540 prt_write_real(double val, int prec)
1541 {
1542     int     integer;
1543     int     fraction;
1544 
1545     prt_real_bits(val, prec, &integer, &fraction);
1546     // Emit integer part
1547     sprintf((char *)prt_line_buffer, "%d", integer);
1548     prt_write_file(prt_line_buffer);
1549     // Only emit fraction if necessary
1550     if (fraction != 0)
1551     {
1552 	// Remove any trailing zeros
1553 	while ((fraction % 10) == 0)
1554 	{
1555 	    prec--;
1556 	    fraction /= 10;
1557 	}
1558 	// Emit fraction left padded with zeros
1559 	sprintf((char *)prt_line_buffer, ".%0*d", prec, fraction);
1560 	prt_write_file(prt_line_buffer);
1561     }
1562     sprintf((char *)prt_line_buffer, " ");
1563     prt_write_file(prt_line_buffer);
1564 }
1565 
1566 /*
1567  * Write a line to define a numeric variable.
1568  */
1569     static void
1570 prt_def_var(char *name, double value, int prec)
1571 {
1572     vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1573 								"/%s ", name);
1574     prt_write_file(prt_line_buffer);
1575     prt_write_real(value, prec);
1576     sprintf((char *)prt_line_buffer, "d\n");
1577     prt_write_file(prt_line_buffer);
1578 }
1579 
1580 // Convert size from font space to user space at current font scale
1581 #define PRT_PS_FONT_TO_USER(scale, size)    ((size) * ((scale)/1000.0))
1582 
1583     static void
1584 prt_flush_buffer(void)
1585 {
1586     if (prt_ps_buffer.ga_len > 0)
1587     {
1588 	// Any background color must be drawn first
1589 	if (prt_do_bgcol && (prt_new_bgcol != PRCOLOR_WHITE))
1590 	{
1591 	    int     r, g, b;
1592 
1593 	    if (prt_do_moveto)
1594 	    {
1595 		prt_write_real(prt_pos_x_moveto, 2);
1596 		prt_write_real(prt_pos_y_moveto, 2);
1597 		prt_write_string("m\n");
1598 		prt_do_moveto = FALSE;
1599 	    }
1600 
1601 	    // Size of rect of background color on which text is printed
1602 	    prt_write_real(prt_text_run, 2);
1603 	    prt_write_real(prt_line_height, 2);
1604 
1605 	    // Lastly add the color of the background
1606 	    r = ((unsigned)prt_new_bgcol & 0xff0000) >> 16;
1607 	    g = ((unsigned)prt_new_bgcol & 0xff00) >> 8;
1608 	    b = prt_new_bgcol & 0xff;
1609 	    prt_write_real(r / 255.0, 3);
1610 	    prt_write_real(g / 255.0, 3);
1611 	    prt_write_real(b / 255.0, 3);
1612 	    prt_write_string("bg\n");
1613 	}
1614 	// Draw underlines before the text as it makes it slightly easier to
1615 	// find the starting point.
1616 	if (prt_do_underline)
1617 	{
1618 	    if (prt_do_moveto)
1619 	    {
1620 		prt_write_real(prt_pos_x_moveto, 2);
1621 		prt_write_real(prt_pos_y_moveto, 2);
1622 		prt_write_string("m\n");
1623 		prt_do_moveto = FALSE;
1624 	    }
1625 
1626 	    // Underline length of text run
1627 	    prt_write_real(prt_text_run, 2);
1628 	    prt_write_string("ul\n");
1629 	}
1630 	// Draw the text
1631 	// Note: we write text out raw - EBCDIC conversion is handled in the
1632 	// PostScript world via the font encoding vector.
1633 	if (prt_out_mbyte)
1634 	    prt_write_string("<");
1635 	else
1636 	    prt_write_string("(");
1637 	prt_write_file_raw_len(prt_ps_buffer.ga_data, prt_ps_buffer.ga_len);
1638 	if (prt_out_mbyte)
1639 	    prt_write_string(">");
1640 	else
1641 	    prt_write_string(")");
1642 	// Add a moveto if need be and use the appropriate show procedure
1643 	if (prt_do_moveto)
1644 	{
1645 	    prt_write_real(prt_pos_x_moveto, 2);
1646 	    prt_write_real(prt_pos_y_moveto, 2);
1647 	    // moveto and a show
1648 	    prt_write_string("ms\n");
1649 	    prt_do_moveto = FALSE;
1650 	}
1651 	else // Simple show
1652 	    prt_write_string("s\n");
1653 
1654 	ga_clear(&prt_ps_buffer);
1655 	ga_init2(&prt_ps_buffer, (int)sizeof(char), prt_bufsiz);
1656     }
1657 }
1658 
1659 
1660     static void
1661 prt_resource_name(char_u *filename, void *cookie)
1662 {
1663     char_u *resource_filename = cookie;
1664 
1665     if (STRLEN(filename) >= MAXPATHL)
1666 	*resource_filename = NUL;
1667     else
1668 	STRCPY(resource_filename, filename);
1669 }
1670 
1671     static int
1672 prt_find_resource(char *name, struct prt_ps_resource_S *resource)
1673 {
1674     char_u	*buffer;
1675     int		retval;
1676 
1677     buffer = alloc(MAXPATHL + 1);
1678     if (buffer == NULL)
1679 	return FALSE;
1680 
1681     vim_strncpy(resource->name, (char_u *)name, 63);
1682     // Look for named resource file in runtimepath
1683     STRCPY(buffer, "print");
1684     add_pathsep(buffer);
1685     vim_strcat(buffer, (char_u *)name, MAXPATHL);
1686     vim_strcat(buffer, (char_u *)".ps", MAXPATHL);
1687     resource->filename[0] = NUL;
1688     retval = (do_in_runtimepath(buffer, 0, prt_resource_name,
1689 							   resource->filename)
1690 	    && resource->filename[0] != NUL);
1691     vim_free(buffer);
1692     return retval;
1693 }
1694 
1695 // PS CR and LF characters have platform independent values
1696 #define PSLF  (0x0a)
1697 #define PSCR  (0x0d)
1698 
1699 // Static buffer to read initial comments in a resource file, some can have a
1700 // couple of KB of comments!
1701 #define PRT_FILE_BUFFER_LEN (2048)
1702 struct prt_resfile_buffer_S
1703 {
1704     char_u  buffer[PRT_FILE_BUFFER_LEN];
1705     int     len;
1706     int     line_start;
1707     int     line_end;
1708 };
1709 
1710 static struct prt_resfile_buffer_S prt_resfile;
1711 
1712     static int
1713 prt_resfile_next_line(void)
1714 {
1715     int     idx;
1716 
1717     // Move to start of next line and then find end of line
1718     idx = prt_resfile.line_end + 1;
1719     while (idx < prt_resfile.len)
1720     {
1721 	if (prt_resfile.buffer[idx] != PSLF && prt_resfile.buffer[idx] != PSCR)
1722 	    break;
1723 	idx++;
1724     }
1725     prt_resfile.line_start = idx;
1726 
1727     while (idx < prt_resfile.len)
1728     {
1729 	if (prt_resfile.buffer[idx] == PSLF || prt_resfile.buffer[idx] == PSCR)
1730 	    break;
1731 	idx++;
1732     }
1733     prt_resfile.line_end = idx;
1734 
1735     return (idx < prt_resfile.len);
1736 }
1737 
1738     static int
1739 prt_resfile_strncmp(int offset, char *string, int len)
1740 {
1741     // Force not equal if string is longer than remainder of line
1742     if (len > (prt_resfile.line_end - (prt_resfile.line_start + offset)))
1743 	return 1;
1744 
1745     return STRNCMP(&prt_resfile.buffer[prt_resfile.line_start + offset],
1746 								string, len);
1747 }
1748 
1749     static int
1750 prt_resfile_skip_nonws(int offset)
1751 {
1752     int     idx;
1753 
1754     idx = prt_resfile.line_start + offset;
1755     while (idx < prt_resfile.line_end)
1756     {
1757 	if (isspace(prt_resfile.buffer[idx]))
1758 	    return idx - prt_resfile.line_start;
1759 	idx++;
1760     }
1761     return -1;
1762 }
1763 
1764     static int
1765 prt_resfile_skip_ws(int offset)
1766 {
1767     int     idx;
1768 
1769     idx = prt_resfile.line_start + offset;
1770     while (idx < prt_resfile.line_end)
1771     {
1772 	if (!isspace(prt_resfile.buffer[idx]))
1773 	    return idx - prt_resfile.line_start;
1774 	idx++;
1775     }
1776     return -1;
1777 }
1778 
1779 // prt_next_dsc() - returns detail on next DSC comment line found.  Returns true
1780 // if a DSC comment is found, else false
1781     static int
1782 prt_next_dsc(struct prt_dsc_line_S *p_dsc_line)
1783 {
1784     int     comment;
1785     int     offset;
1786 
1787     // Move to start of next line
1788     if (!prt_resfile_next_line())
1789 	return FALSE;
1790 
1791     // DSC comments always start %%
1792     if (prt_resfile_strncmp(0, "%%", 2) != 0)
1793 	return FALSE;
1794 
1795     // Find type of DSC comment
1796     for (comment = 0; comment < (int)NUM_ELEMENTS(prt_dsc_table); comment++)
1797 	if (prt_resfile_strncmp(0, prt_dsc_table[comment].string,
1798 					    prt_dsc_table[comment].len) == 0)
1799 	    break;
1800 
1801     if (comment != NUM_ELEMENTS(prt_dsc_table))
1802     {
1803 	// Return type of comment
1804 	p_dsc_line->type = prt_dsc_table[comment].type;
1805 	offset = prt_dsc_table[comment].len;
1806     }
1807     else
1808     {
1809 	// Unrecognised DSC comment, skip to ws after comment leader
1810 	p_dsc_line->type = PRT_DSC_MISC_TYPE;
1811 	offset = prt_resfile_skip_nonws(0);
1812 	if (offset == -1)
1813 	    return FALSE;
1814     }
1815 
1816     // Skip ws to comment value
1817     offset = prt_resfile_skip_ws(offset);
1818     if (offset == -1)
1819 	return FALSE;
1820 
1821     p_dsc_line->string = &prt_resfile.buffer[prt_resfile.line_start + offset];
1822     p_dsc_line->len = prt_resfile.line_end - (prt_resfile.line_start + offset);
1823 
1824     return TRUE;
1825 }
1826 
1827 /*
1828  * Improved hand crafted parser to get the type, title, and version number of a
1829  * PS resource file so the file details can be added to the DSC header comments.
1830  */
1831     static int
1832 prt_open_resource(struct prt_ps_resource_S *resource)
1833 {
1834     int		offset;
1835     int		seen_all;
1836     int		seen_title;
1837     int		seen_version;
1838     FILE	*fd_resource;
1839     struct prt_dsc_line_S dsc_line;
1840 
1841     fd_resource = mch_fopen((char *)resource->filename, READBIN);
1842     if (fd_resource == NULL)
1843     {
1844 	semsg(_("E624: Can't open file \"%s\""), resource->filename);
1845 	return FALSE;
1846     }
1847     CLEAR_FIELD(prt_resfile.buffer);
1848 
1849     // Parse first line to ensure valid resource file
1850     prt_resfile.len = (int)fread((char *)prt_resfile.buffer, sizeof(char_u),
1851 					    PRT_FILE_BUFFER_LEN, fd_resource);
1852     if (ferror(fd_resource))
1853     {
1854 	semsg(_("E457: Can't read PostScript resource file \"%s\""),
1855 		resource->filename);
1856 	fclose(fd_resource);
1857 	return FALSE;
1858     }
1859     fclose(fd_resource);
1860 
1861     prt_resfile.line_end = -1;
1862     prt_resfile.line_start = 0;
1863     if (!prt_resfile_next_line())
1864 	return FALSE;
1865 
1866     offset = 0;
1867 
1868     if (prt_resfile_strncmp(offset, PRT_RESOURCE_HEADER,
1869 				       (int)STRLEN(PRT_RESOURCE_HEADER)) != 0)
1870     {
1871 	semsg(_("E618: file \"%s\" is not a PostScript resource file"),
1872 		resource->filename);
1873 	return FALSE;
1874     }
1875 
1876     // Skip over any version numbers and following ws
1877     offset += (int)STRLEN(PRT_RESOURCE_HEADER);
1878     offset = prt_resfile_skip_nonws(offset);
1879     if (offset == -1)
1880 	return FALSE;
1881     offset = prt_resfile_skip_ws(offset);
1882     if (offset == -1)
1883 	return FALSE;
1884 
1885     if (prt_resfile_strncmp(offset, PRT_RESOURCE_RESOURCE,
1886 				     (int)STRLEN(PRT_RESOURCE_RESOURCE)) != 0)
1887     {
1888 	semsg(_("E619: file \"%s\" is not a supported PostScript resource file"),
1889 		resource->filename);
1890 	return FALSE;
1891     }
1892     offset += (int)STRLEN(PRT_RESOURCE_RESOURCE);
1893 
1894     // Decide type of resource in the file
1895     if (prt_resfile_strncmp(offset, PRT_RESOURCE_PROCSET,
1896 				      (int)STRLEN(PRT_RESOURCE_PROCSET)) == 0)
1897 	resource->type = PRT_RESOURCE_TYPE_PROCSET;
1898     else if (prt_resfile_strncmp(offset, PRT_RESOURCE_ENCODING,
1899 				     (int)STRLEN(PRT_RESOURCE_ENCODING)) == 0)
1900 	resource->type = PRT_RESOURCE_TYPE_ENCODING;
1901     else if (prt_resfile_strncmp(offset, PRT_RESOURCE_CMAP,
1902 					 (int)STRLEN(PRT_RESOURCE_CMAP)) == 0)
1903 	resource->type = PRT_RESOURCE_TYPE_CMAP;
1904     else
1905     {
1906 	semsg(_("E619: file \"%s\" is not a supported PostScript resource file"),
1907 		resource->filename);
1908 	return FALSE;
1909     }
1910 
1911     // Look for title and version of resource
1912     resource->title[0] = '\0';
1913     resource->version[0] = '\0';
1914     seen_title = FALSE;
1915     seen_version = FALSE;
1916     seen_all = FALSE;
1917     while (!seen_all && prt_next_dsc(&dsc_line))
1918     {
1919 	switch (dsc_line.type)
1920 	{
1921 	case PRT_DSC_TITLE_TYPE:
1922 	    vim_strncpy(resource->title, dsc_line.string, dsc_line.len);
1923 	    seen_title = TRUE;
1924 	    if (seen_version)
1925 		seen_all = TRUE;
1926 	    break;
1927 
1928 	case PRT_DSC_VERSION_TYPE:
1929 	    vim_strncpy(resource->version, dsc_line.string, dsc_line.len);
1930 	    seen_version = TRUE;
1931 	    if (seen_title)
1932 		seen_all = TRUE;
1933 	    break;
1934 
1935 	case PRT_DSC_ENDCOMMENTS_TYPE:
1936 	    // Wont find title or resource after this comment, stop searching
1937 	    seen_all = TRUE;
1938 	    break;
1939 
1940 	case PRT_DSC_MISC_TYPE:
1941 	    // Not interested in whatever comment this line had
1942 	    break;
1943 	}
1944     }
1945 
1946     if (!seen_title || !seen_version)
1947     {
1948 	semsg(_("E619: file \"%s\" is not a supported PostScript resource file"),
1949 		resource->filename);
1950 	return FALSE;
1951     }
1952 
1953     return TRUE;
1954 }
1955 
1956     static int
1957 prt_check_resource(struct prt_ps_resource_S *resource, char_u *version)
1958 {
1959     // Version number m.n should match, the revision number does not matter
1960     if (STRNCMP(resource->version, version, STRLEN(version)))
1961     {
1962 	semsg(_("E621: \"%s\" resource file has wrong version"),
1963 		resource->name);
1964 	return FALSE;
1965     }
1966 
1967     // Other checks to be added as needed
1968     return TRUE;
1969 }
1970 
1971     static void
1972 prt_dsc_start(void)
1973 {
1974     prt_write_string("%!PS-Adobe-3.0\n");
1975 }
1976 
1977     static void
1978 prt_dsc_noarg(char *comment)
1979 {
1980     vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1981 							 "%%%%%s\n", comment);
1982     prt_write_file(prt_line_buffer);
1983 }
1984 
1985     static void
1986 prt_dsc_textline(char *comment, char *text)
1987 {
1988     vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1989 					       "%%%%%s: %s\n", comment, text);
1990     prt_write_file(prt_line_buffer);
1991 }
1992 
1993     static void
1994 prt_dsc_text(char *comment, char *text)
1995 {
1996     // TODO - should scan 'text' for any chars needing escaping!
1997     vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
1998 					     "%%%%%s: (%s)\n", comment, text);
1999     prt_write_file(prt_line_buffer);
2000 }
2001 
2002 #define prt_dsc_atend(c)	prt_dsc_text((c), "atend")
2003 
2004     static void
2005 prt_dsc_ints(char *comment, int count, int *ints)
2006 {
2007     int		i;
2008 
2009     vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
2010 							  "%%%%%s:", comment);
2011     prt_write_file(prt_line_buffer);
2012 
2013     for (i = 0; i < count; i++)
2014     {
2015 	sprintf((char *)prt_line_buffer, " %d", ints[i]);
2016 	prt_write_file(prt_line_buffer);
2017     }
2018 
2019     prt_write_string("\n");
2020 }
2021 
2022     static void
2023 prt_dsc_resources(
2024     char	*comment,	// if NULL add to previous
2025     char	*type,
2026     char	*string)
2027 {
2028     if (comment != NULL)
2029 	vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
2030 						 "%%%%%s: %s", comment, type);
2031     else
2032 	vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
2033 							    "%%%%+ %s", type);
2034     prt_write_file(prt_line_buffer);
2035 
2036     vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
2037 							     " %s\n", string);
2038     prt_write_file(prt_line_buffer);
2039 }
2040 
2041     static void
2042 prt_dsc_font_resource(char *resource, struct prt_ps_font_S *ps_font)
2043 {
2044     int     i;
2045 
2046     prt_dsc_resources(resource, "font",
2047 				    ps_font->ps_fontname[PRT_PS_FONT_ROMAN]);
2048     for (i = PRT_PS_FONT_BOLD ; i <= PRT_PS_FONT_BOLDOBLIQUE ; i++)
2049 	if (ps_font->ps_fontname[i] != NULL)
2050 	    prt_dsc_resources(NULL, "font", ps_font->ps_fontname[i]);
2051 }
2052 
2053     static void
2054 prt_dsc_requirements(
2055     int		duplex,
2056     int		tumble,
2057     int		collate,
2058     int		color,
2059     int		num_copies)
2060 {
2061     // Only output the comment if we need to.
2062     // Note: tumble is ignored if we are not duplexing
2063     if (!(duplex || collate || color || (num_copies > 1)))
2064 	return;
2065 
2066     sprintf((char *)prt_line_buffer, "%%%%Requirements:");
2067     prt_write_file(prt_line_buffer);
2068 
2069     if (duplex)
2070     {
2071 	prt_write_string(" duplex");
2072 	if (tumble)
2073 	    prt_write_string("(tumble)");
2074     }
2075     if (collate)
2076 	prt_write_string(" collate");
2077     if (color)
2078 	prt_write_string(" color");
2079     if (num_copies > 1)
2080     {
2081 	prt_write_string(" numcopies(");
2082 	// Note: no space wanted so don't use prt_write_int()
2083 	sprintf((char *)prt_line_buffer, "%d", num_copies);
2084 	prt_write_file(prt_line_buffer);
2085 	prt_write_string(")");
2086     }
2087     prt_write_string("\n");
2088 }
2089 
2090     static void
2091 prt_dsc_docmedia(
2092     char	*paper_name,
2093     double	width,
2094     double	height,
2095     double	weight,
2096     char	*colour,
2097     char	*type)
2098 {
2099     vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
2100 					"%%%%DocumentMedia: %s ", paper_name);
2101     prt_write_file(prt_line_buffer);
2102     prt_write_real(width, 2);
2103     prt_write_real(height, 2);
2104     prt_write_real(weight, 2);
2105     if (colour == NULL)
2106 	prt_write_string("()");
2107     else
2108 	prt_write_string(colour);
2109     prt_write_string(" ");
2110     if (type == NULL)
2111 	prt_write_string("()");
2112     else
2113 	prt_write_string(type);
2114     prt_write_string("\n");
2115 }
2116 
2117     void
2118 mch_print_cleanup(void)
2119 {
2120     if (prt_out_mbyte)
2121     {
2122 	int     i;
2123 
2124 	// Free off all CID font names created, but first clear duplicate
2125 	// pointers to the same string (when the same font is used for more than
2126 	// one style).
2127 	for (i = PRT_PS_FONT_ROMAN; i <= PRT_PS_FONT_BOLDOBLIQUE; i++)
2128 	{
2129 	    if (prt_ps_mb_font.ps_fontname[i] != NULL)
2130 		VIM_CLEAR(prt_ps_mb_font.ps_fontname[i]);
2131 	}
2132     }
2133 
2134     if (prt_do_conv)
2135     {
2136 	convert_setup(&prt_conv, NULL, NULL);
2137 	prt_do_conv = FALSE;
2138     }
2139     if (prt_ps_fd != NULL)
2140     {
2141 	fclose(prt_ps_fd);
2142 	prt_ps_fd = NULL;
2143 	prt_file_error = FALSE;
2144     }
2145     if (prt_ps_file_name != NULL)
2146 	VIM_CLEAR(prt_ps_file_name);
2147 }
2148 
2149     static float
2150 to_device_units(int idx, double physsize, int def_number)
2151 {
2152     float	ret;
2153     int		u;
2154     int		nr;
2155 
2156     u = prt_get_unit(idx);
2157     if (u == PRT_UNIT_NONE)
2158     {
2159 	u = PRT_UNIT_PERC;
2160 	nr = def_number;
2161     }
2162     else
2163 	nr = printer_opts[idx].number;
2164 
2165     switch (u)
2166     {
2167 	case PRT_UNIT_INCH:
2168 	    ret = (float)(nr * PRT_PS_DEFAULT_DPI);
2169 	    break;
2170 	case PRT_UNIT_MM:
2171 	    ret = (float)(nr * PRT_PS_DEFAULT_DPI) / (float)25.4;
2172 	    break;
2173 	case PRT_UNIT_POINT:
2174 	    ret = (float)nr;
2175 	    break;
2176 	case PRT_UNIT_PERC:
2177 	default:
2178 	    ret = (float)(physsize * nr) / 100;
2179 	    break;
2180     }
2181 
2182     return ret;
2183 }
2184 
2185 /*
2186  * Calculate margins for given width and height from printoptions settings.
2187  */
2188     static void
2189 prt_page_margins(
2190     double	width,
2191     double	height,
2192     double	*left,
2193     double	*right,
2194     double	*top,
2195     double	*bottom)
2196 {
2197     *left   = to_device_units(OPT_PRINT_LEFT, width, 10);
2198     *right  = width - to_device_units(OPT_PRINT_RIGHT, width, 5);
2199     *top    = height - to_device_units(OPT_PRINT_TOP, height, 5);
2200     *bottom = to_device_units(OPT_PRINT_BOT, height, 5);
2201 }
2202 
2203     static void
2204 prt_font_metrics(int font_scale)
2205 {
2206     prt_line_height = (float)font_scale;
2207     prt_char_width = (float)PRT_PS_FONT_TO_USER(font_scale, prt_ps_font->wx);
2208 }
2209 
2210 
2211     static int
2212 prt_get_cpl(void)
2213 {
2214     if (prt_use_number())
2215     {
2216 	prt_number_width = PRINT_NUMBER_WIDTH * prt_char_width;
2217 	// If we are outputting multi-byte characters then line numbers will be
2218 	// printed with half width characters
2219 	if (prt_out_mbyte)
2220 	    prt_number_width /= 2;
2221 	prt_left_margin += prt_number_width;
2222     }
2223     else
2224 	prt_number_width = 0.0;
2225 
2226     return (int)((prt_right_margin - prt_left_margin) / prt_char_width);
2227 }
2228 
2229     static int
2230 prt_build_cid_fontname(int font, char_u *name, int name_len)
2231 {
2232     char    *fontname;
2233 
2234     fontname = alloc(name_len + 1);
2235     if (fontname == NULL)
2236 	return FALSE;
2237     vim_strncpy((char_u *)fontname, name, name_len);
2238     prt_ps_mb_font.ps_fontname[font] = fontname;
2239 
2240     return TRUE;
2241 }
2242 
2243 /*
2244  * Get number of lines of text that fit on a page (excluding the header).
2245  */
2246     static int
2247 prt_get_lpp(void)
2248 {
2249     int lpp;
2250 
2251     /*
2252      * Calculate offset to lower left corner of background rect based on actual
2253      * font height (based on its bounding box) and the line height, handling the
2254      * case where the font height can exceed the line height.
2255      */
2256     prt_bgcol_offset = (float)PRT_PS_FONT_TO_USER(prt_line_height,
2257 					   prt_ps_font->bbox_min_y);
2258     if ((prt_ps_font->bbox_max_y - prt_ps_font->bbox_min_y) < 1000.0)
2259     {
2260 	prt_bgcol_offset -= (float)PRT_PS_FONT_TO_USER(prt_line_height,
2261 				(1000.0 - (prt_ps_font->bbox_max_y -
2262 					    prt_ps_font->bbox_min_y)) / 2);
2263     }
2264 
2265     // Get height for topmost line based on background rect offset.
2266     prt_first_line_height = prt_line_height + prt_bgcol_offset;
2267 
2268     // Calculate lpp
2269     lpp = (int)((prt_top_margin - prt_bottom_margin) / prt_line_height);
2270 
2271     // Adjust top margin if there is a header
2272     prt_top_margin -= prt_line_height * prt_header_height();
2273 
2274     return lpp - prt_header_height();
2275 }
2276 
2277     static int
2278 prt_match_encoding(
2279     char			*p_encoding,
2280     struct prt_ps_mbfont_S	*p_cmap,
2281     struct prt_ps_encoding_S	**pp_mbenc)
2282 {
2283     int				mbenc;
2284     int				enc_len;
2285     struct prt_ps_encoding_S	*p_mbenc;
2286 
2287     *pp_mbenc = NULL;
2288     // Look for recognised encoding
2289     enc_len = (int)STRLEN(p_encoding);
2290     p_mbenc = p_cmap->encodings;
2291     for (mbenc = 0; mbenc < p_cmap->num_encodings; mbenc++)
2292     {
2293 	if (STRNICMP(p_mbenc->encoding, p_encoding, enc_len) == 0)
2294 	{
2295 	    *pp_mbenc = p_mbenc;
2296 	    return TRUE;
2297 	}
2298 	p_mbenc++;
2299     }
2300     return FALSE;
2301 }
2302 
2303     static int
2304 prt_match_charset(
2305     char		    *p_charset,
2306     struct prt_ps_mbfont_S  *p_cmap,
2307     struct prt_ps_charset_S **pp_mbchar)
2308 {
2309     int			    mbchar;
2310     int			    char_len;
2311     struct prt_ps_charset_S *p_mbchar;
2312 
2313     // Look for recognised character set, using default if one is not given
2314     if (*p_charset == NUL)
2315 	p_charset = p_cmap->defcs;
2316     char_len = (int)STRLEN(p_charset);
2317     p_mbchar = p_cmap->charsets;
2318     for (mbchar = 0; mbchar < p_cmap->num_charsets; mbchar++)
2319     {
2320 	if (STRNICMP(p_mbchar->charset, p_charset, char_len) == 0)
2321 	{
2322 	    *pp_mbchar = p_mbchar;
2323 	    return TRUE;
2324 	}
2325 	p_mbchar++;
2326     }
2327     return FALSE;
2328 }
2329 
2330     int
2331 mch_print_init(
2332     prt_settings_T *psettings,
2333     char_u	*jobname,
2334     int		forceit UNUSED)
2335 {
2336     int		i;
2337     char	*paper_name;
2338     int		paper_strlen;
2339     int		fontsize;
2340     char_u	*p;
2341     double      left;
2342     double      right;
2343     double      top;
2344     double      bottom;
2345     int		props;
2346     int		cmap = 0;
2347     char_u	*p_encoding;
2348     struct prt_ps_encoding_S *p_mbenc;
2349     struct prt_ps_encoding_S *p_mbenc_first;
2350     struct prt_ps_charset_S  *p_mbchar = NULL;
2351 
2352 #if 0
2353     /*
2354      * TODO:
2355      * If "forceit" is false: pop up a dialog to select:
2356      *	- printer name
2357      *	- copies
2358      *	- collated/uncollated
2359      *	- duplex off/long side/short side
2360      *	- paper size
2361      *	- portrait/landscape
2362      *	- font size
2363      *
2364      * If "forceit" is true: use the default printer and settings
2365      */
2366     if (forceit)
2367 	s_pd.Flags |= PD_RETURNDEFAULT;
2368 #endif
2369 
2370     /*
2371      * Set up font and encoding.
2372      */
2373     p_encoding = enc_skip(p_penc);
2374     if (*p_encoding == NUL)
2375 	p_encoding = enc_skip(p_enc);
2376 
2377     // Look for a multi-byte font that matches the encoding and character set.
2378     // Only look if multi-byte character set is defined, or using multi-byte
2379     // encoding other than Unicode.  This is because a Unicode encoding does not
2380     // uniquely identify a CJK character set to use.
2381     p_mbenc = NULL;
2382     props = enc_canon_props(p_encoding);
2383     if (!(props & ENC_8BIT) && ((*p_pmcs != NUL) || !(props & ENC_UNICODE)))
2384     {
2385 	int cmap_first = 0;
2386 
2387 	p_mbenc_first = NULL;
2388 	for (cmap = 0; cmap < (int)NUM_ELEMENTS(prt_ps_mbfonts); cmap++)
2389 	    if (prt_match_encoding((char *)p_encoding, &prt_ps_mbfonts[cmap],
2390 								    &p_mbenc))
2391 	    {
2392 		if (p_mbenc_first == NULL)
2393 		{
2394 		    p_mbenc_first = p_mbenc;
2395 		    cmap_first = cmap;
2396 		}
2397 		if (prt_match_charset((char *)p_pmcs, &prt_ps_mbfonts[cmap],
2398 								   &p_mbchar))
2399 		    break;
2400 	    }
2401 
2402 	// Use first encoding matched if no charset matched
2403 	if (p_mbchar == NULL && p_mbenc_first != NULL)
2404 	{
2405 	    p_mbenc = p_mbenc_first;
2406 	    cmap = cmap_first;
2407 	}
2408     }
2409 
2410     prt_out_mbyte = (p_mbenc != NULL);
2411     if (prt_out_mbyte)
2412     {
2413 	// Build CMap name - will be same for all multi-byte fonts used
2414 	prt_cmap[0] = NUL;
2415 
2416 	prt_custom_cmap = (p_mbchar == NULL);
2417 	if (!prt_custom_cmap)
2418 	{
2419 	    // Check encoding and character set are compatible
2420 	    if ((p_mbenc->needs_charset & p_mbchar->has_charset) == 0)
2421 	    {
2422 		emsg(_("E673: Incompatible multi-byte encoding and character set."));
2423 		return FALSE;
2424 	    }
2425 
2426 	    // Add charset name if not empty
2427 	    if (p_mbchar->cmap_charset != NULL)
2428 	    {
2429 		vim_strncpy((char_u *)prt_cmap,
2430 		      (char_u *)p_mbchar->cmap_charset, sizeof(prt_cmap) - 3);
2431 		STRCAT(prt_cmap, "-");
2432 	    }
2433 	}
2434 	else
2435 	{
2436 	    // Add custom CMap character set name
2437 	    if (*p_pmcs == NUL)
2438 	    {
2439 		emsg(_("E674: printmbcharset cannot be empty with multi-byte encoding."));
2440 		return FALSE;
2441 	    }
2442 	    vim_strncpy((char_u *)prt_cmap, p_pmcs, sizeof(prt_cmap) - 3);
2443 	    STRCAT(prt_cmap, "-");
2444 	}
2445 
2446 	// CMap name ends with (optional) encoding name and -H for horizontal
2447 	if (p_mbenc->cmap_encoding != NULL && STRLEN(prt_cmap)
2448 		      + STRLEN(p_mbenc->cmap_encoding) + 3 < sizeof(prt_cmap))
2449 	{
2450 	    STRCAT(prt_cmap, p_mbenc->cmap_encoding);
2451 	    STRCAT(prt_cmap, "-");
2452 	}
2453 	STRCAT(prt_cmap, "H");
2454 
2455 	if (!mbfont_opts[OPT_MBFONT_REGULAR].present)
2456 	{
2457 	    emsg(_("E675: No default font specified for multi-byte printing."));
2458 	    return FALSE;
2459 	}
2460 
2461 	// Derive CID font names with fallbacks if not defined
2462 	if (!prt_build_cid_fontname(PRT_PS_FONT_ROMAN,
2463 				    mbfont_opts[OPT_MBFONT_REGULAR].string,
2464 				    mbfont_opts[OPT_MBFONT_REGULAR].strlen))
2465 	    return FALSE;
2466 	if (mbfont_opts[OPT_MBFONT_BOLD].present)
2467 	    if (!prt_build_cid_fontname(PRT_PS_FONT_BOLD,
2468 					mbfont_opts[OPT_MBFONT_BOLD].string,
2469 					mbfont_opts[OPT_MBFONT_BOLD].strlen))
2470 		return FALSE;
2471 	if (mbfont_opts[OPT_MBFONT_OBLIQUE].present)
2472 	    if (!prt_build_cid_fontname(PRT_PS_FONT_OBLIQUE,
2473 					mbfont_opts[OPT_MBFONT_OBLIQUE].string,
2474 					mbfont_opts[OPT_MBFONT_OBLIQUE].strlen))
2475 		return FALSE;
2476 	if (mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].present)
2477 	    if (!prt_build_cid_fontname(PRT_PS_FONT_BOLDOBLIQUE,
2478 				   mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].string,
2479 				  mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].strlen))
2480 		return FALSE;
2481 
2482 	// Check if need to use Courier for ASCII code range, and if so pick up
2483 	// the encoding to use
2484 	prt_use_courier = mbfont_opts[OPT_MBFONT_USECOURIER].present &&
2485 	    (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_USECOURIER].string[0]) == 'y');
2486 	if (prt_use_courier)
2487 	{
2488 	    // Use national ASCII variant unless ASCII wanted
2489 	    if (mbfont_opts[OPT_MBFONT_ASCII].present &&
2490 		(TOLOWER_ASC(mbfont_opts[OPT_MBFONT_ASCII].string[0]) == 'y'))
2491 		prt_ascii_encoding = "ascii";
2492 	    else
2493 		prt_ascii_encoding = prt_ps_mbfonts[cmap].ascii_enc;
2494 	}
2495 
2496 	prt_ps_font = &prt_ps_mb_font;
2497     }
2498     else
2499     {
2500 	prt_use_courier = FALSE;
2501 	prt_ps_font = &prt_ps_courier_font;
2502     }
2503 
2504     /*
2505      * Find the size of the paper and set the margins.
2506      */
2507     prt_portrait = (!printer_opts[OPT_PRINT_PORTRAIT].present
2508 	   || TOLOWER_ASC(printer_opts[OPT_PRINT_PORTRAIT].string[0]) == 'y');
2509     if (printer_opts[OPT_PRINT_PAPER].present)
2510     {
2511 	paper_name = (char *)printer_opts[OPT_PRINT_PAPER].string;
2512 	paper_strlen = printer_opts[OPT_PRINT_PAPER].strlen;
2513     }
2514     else
2515     {
2516 	paper_name = "A4";
2517 	paper_strlen = 2;
2518     }
2519     for (i = 0; i < (int)PRT_MEDIASIZE_LEN; ++i)
2520 	if (STRLEN(prt_mediasize[i].name) == (unsigned)paper_strlen
2521 		&& STRNICMP(prt_mediasize[i].name, paper_name,
2522 							   paper_strlen) == 0)
2523 	    break;
2524     if (i == PRT_MEDIASIZE_LEN)
2525 	i = 0;
2526     prt_media = i;
2527 
2528     /*
2529      * Set PS pagesize based on media dimensions and print orientation.
2530      * Note: Media and page sizes have defined meanings in PostScript and should
2531      * be kept distinct.  Media is the paper (or transparency, or ...) that is
2532      * printed on, whereas the page size is the area that the PostScript
2533      * interpreter renders into.
2534      */
2535     if (prt_portrait)
2536     {
2537 	prt_page_width = prt_mediasize[i].width;
2538 	prt_page_height = prt_mediasize[i].height;
2539     }
2540     else
2541     {
2542 	prt_page_width = prt_mediasize[i].height;
2543 	prt_page_height = prt_mediasize[i].width;
2544     }
2545 
2546     /*
2547      * Set PS page margins based on the PS pagesize, not the mediasize - this
2548      * needs to be done before the cpl and lpp are calculated.
2549      */
2550     prt_page_margins(prt_page_width, prt_page_height, &left, &right, &top,
2551 								    &bottom);
2552     prt_left_margin = (float)left;
2553     prt_right_margin = (float)right;
2554     prt_top_margin = (float)top;
2555     prt_bottom_margin = (float)bottom;
2556 
2557     /*
2558      * Set up the font size.
2559      */
2560     fontsize = PRT_PS_DEFAULT_FONTSIZE;
2561     for (p = p_pfn; (p = vim_strchr(p, ':')) != NULL; ++p)
2562 	if (p[1] == 'h' && VIM_ISDIGIT(p[2]))
2563 	    fontsize = atoi((char *)p + 2);
2564     prt_font_metrics(fontsize);
2565 
2566     /*
2567      * Return the number of characters per line, and lines per page for the
2568      * generic print code.
2569      */
2570     psettings->chars_per_line = prt_get_cpl();
2571     psettings->lines_per_page = prt_get_lpp();
2572 
2573     // Catch margin settings that leave no space for output!
2574     if (psettings->chars_per_line <= 0 || psettings->lines_per_page <= 0)
2575 	return FAIL;
2576 
2577     /*
2578      * Sort out the number of copies to be printed.  PS by default will do
2579      * uncollated copies for you, so once we know how many uncollated copies are
2580      * wanted cache it away and lie to the generic code that we only want one
2581      * uncollated copy.
2582      */
2583     psettings->n_collated_copies = 1;
2584     psettings->n_uncollated_copies = 1;
2585     prt_num_copies = 1;
2586     prt_collate = (!printer_opts[OPT_PRINT_COLLATE].present
2587 	    || TOLOWER_ASC(printer_opts[OPT_PRINT_COLLATE].string[0]) == 'y');
2588     if (prt_collate)
2589     {
2590 	// TODO: Get number of collated copies wanted.
2591 	psettings->n_collated_copies = 1;
2592     }
2593     else
2594     {
2595 	// TODO: Get number of uncollated copies wanted and update the cached
2596 	// count.
2597 	prt_num_copies = 1;
2598     }
2599 
2600     psettings->jobname = jobname;
2601 
2602     /*
2603      * Set up printer duplex and tumble based on Duplex option setting - default
2604      * is long sided duplex printing (i.e. no tumble).
2605      */
2606     prt_duplex = TRUE;
2607     prt_tumble = FALSE;
2608     psettings->duplex = 1;
2609     if (printer_opts[OPT_PRINT_DUPLEX].present)
2610     {
2611 	if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "off", 3) == 0)
2612 	{
2613 	    prt_duplex = FALSE;
2614 	    psettings->duplex = 0;
2615 	}
2616 	else if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "short", 5)
2617 									 == 0)
2618 	    prt_tumble = TRUE;
2619     }
2620 
2621     // For now user abort not supported
2622     psettings->user_abort = 0;
2623 
2624     // If the user didn't specify a file name, use a temp file.
2625     if (psettings->outfile == NULL)
2626     {
2627 	prt_ps_file_name = vim_tempname('p', TRUE);
2628 	if (prt_ps_file_name == NULL)
2629 	{
2630 	    emsg(_(e_notmp));
2631 	    return FAIL;
2632 	}
2633 	prt_ps_fd = mch_fopen((char *)prt_ps_file_name, WRITEBIN);
2634     }
2635     else
2636     {
2637 	p = expand_env_save(psettings->outfile);
2638 	if (p != NULL)
2639 	{
2640 	    prt_ps_fd = mch_fopen((char *)p, WRITEBIN);
2641 	    vim_free(p);
2642 	}
2643     }
2644     if (prt_ps_fd == NULL)
2645     {
2646 	emsg(_("E324: Can't open PostScript output file"));
2647 	mch_print_cleanup();
2648 	return FAIL;
2649     }
2650 
2651     prt_bufsiz = psettings->chars_per_line;
2652     if (prt_out_mbyte)
2653 	prt_bufsiz *= 2;
2654     ga_init2(&prt_ps_buffer, (int)sizeof(char), prt_bufsiz);
2655 
2656     prt_page_num = 0;
2657 
2658     prt_attribute_change = FALSE;
2659     prt_need_moveto = FALSE;
2660     prt_need_font = FALSE;
2661     prt_need_fgcol = FALSE;
2662     prt_need_bgcol = FALSE;
2663     prt_need_underline = FALSE;
2664 
2665     prt_file_error = FALSE;
2666 
2667     return OK;
2668 }
2669 
2670     static int
2671 prt_add_resource(struct prt_ps_resource_S *resource)
2672 {
2673     FILE*	fd_resource;
2674     char_u	resource_buffer[512];
2675     size_t	bytes_read;
2676 
2677     fd_resource = mch_fopen((char *)resource->filename, READBIN);
2678     if (fd_resource == NULL)
2679     {
2680 	semsg(_("E456: Can't open file \"%s\""), resource->filename);
2681 	return FALSE;
2682     }
2683     prt_dsc_resources("BeginResource", prt_resource_types[resource->type],
2684 						     (char *)resource->title);
2685 
2686     prt_dsc_textline("BeginDocument", (char *)resource->filename);
2687 
2688     for (;;)
2689     {
2690 	bytes_read = fread((char *)resource_buffer, sizeof(char_u),
2691 			   sizeof(resource_buffer), fd_resource);
2692 	if (ferror(fd_resource))
2693 	{
2694 	    semsg(_("E457: Can't read PostScript resource file \"%s\""),
2695 							    resource->filename);
2696 	    fclose(fd_resource);
2697 	    return FALSE;
2698 	}
2699 	if (bytes_read == 0)
2700 	    break;
2701 	prt_write_file_raw_len(resource_buffer, (int)bytes_read);
2702 	if (prt_file_error)
2703 	{
2704 	    fclose(fd_resource);
2705 	    return FALSE;
2706 	}
2707     }
2708     fclose(fd_resource);
2709 
2710     prt_dsc_noarg("EndDocument");
2711 
2712     prt_dsc_noarg("EndResource");
2713 
2714     return TRUE;
2715 }
2716 
2717     int
2718 mch_print_begin(prt_settings_T *psettings)
2719 {
2720     int		bbox[4];
2721     double      left;
2722     double      right;
2723     double      top;
2724     double      bottom;
2725     struct prt_ps_resource_S *res_prolog;
2726     struct prt_ps_resource_S *res_encoding;
2727     char	buffer[256];
2728     char_u      *p_encoding;
2729     struct prt_ps_resource_S *res_cidfont;
2730     struct prt_ps_resource_S *res_cmap;
2731     int		retval = FALSE;
2732 
2733     res_prolog = (struct prt_ps_resource_S *)
2734 				      alloc(sizeof(struct prt_ps_resource_S));
2735     res_encoding = (struct prt_ps_resource_S *)
2736 				      alloc(sizeof(struct prt_ps_resource_S));
2737     res_cidfont = (struct prt_ps_resource_S *)
2738 				      alloc(sizeof(struct prt_ps_resource_S));
2739     res_cmap = (struct prt_ps_resource_S *)
2740 				      alloc(sizeof(struct prt_ps_resource_S));
2741     if (res_prolog == NULL || res_encoding == NULL
2742 	    || res_cidfont == NULL || res_cmap == NULL)
2743 	goto theend;
2744 
2745     /*
2746      * PS DSC Header comments - no PS code!
2747      */
2748     prt_dsc_start();
2749     prt_dsc_textline("Title", (char *)psettings->jobname);
2750     if (!get_user_name((char_u *)buffer, 256))
2751 	STRCPY(buffer, "Unknown");
2752     prt_dsc_textline("For", buffer);
2753     prt_dsc_textline("Creator", VIM_VERSION_LONG);
2754     // Note: to ensure Clean8bit I don't think we can use LC_TIME
2755 
2756     prt_dsc_textline("CreationDate", get_ctime(time(NULL), FALSE));
2757     prt_dsc_textline("DocumentData", "Clean8Bit");
2758     prt_dsc_textline("Orientation", "Portrait");
2759     prt_dsc_atend("Pages");
2760     prt_dsc_textline("PageOrder", "Ascend");
2761     // The bbox does not change with orientation - it is always in the default
2762     // user coordinate system!  We have to recalculate right and bottom
2763     // coordinates based on the font metrics for the bbox to be accurate.
2764     prt_page_margins(prt_mediasize[prt_media].width,
2765 					    prt_mediasize[prt_media].height,
2766 					    &left, &right, &top, &bottom);
2767     bbox[0] = (int)left;
2768     if (prt_portrait)
2769     {
2770 	// In portrait printing the fixed point is the top left corner so we
2771 	// derive the bbox from that point.  We have the expected cpl chars
2772 	// across the media and lpp lines down the media.
2773 	bbox[1] = (int)(top - (psettings->lines_per_page + prt_header_height())
2774 							    * prt_line_height);
2775 	bbox[2] = (int)(left + psettings->chars_per_line * prt_char_width
2776 									+ 0.5);
2777 	bbox[3] = (int)(top + 0.5);
2778     }
2779     else
2780     {
2781 	// In landscape printing the fixed point is the bottom left corner so we
2782 	// derive the bbox from that point.  We have lpp chars across the media
2783 	// and cpl lines up the media.
2784 	bbox[1] = (int)bottom;
2785 	bbox[2] = (int)(left + ((psettings->lines_per_page
2786 			      + prt_header_height()) * prt_line_height) + 0.5);
2787 	bbox[3] = (int)(bottom + psettings->chars_per_line * prt_char_width
2788 									+ 0.5);
2789     }
2790     prt_dsc_ints("BoundingBox", 4, bbox);
2791     // The media width and height does not change with landscape printing!
2792     prt_dsc_docmedia(prt_mediasize[prt_media].name,
2793 				prt_mediasize[prt_media].width,
2794 				prt_mediasize[prt_media].height,
2795 				(double)0, NULL, NULL);
2796     // Define fonts needed
2797     if (!prt_out_mbyte || prt_use_courier)
2798 	prt_dsc_font_resource("DocumentNeededResources", &prt_ps_courier_font);
2799     if (prt_out_mbyte)
2800     {
2801 	prt_dsc_font_resource((prt_use_courier ? NULL
2802 				 : "DocumentNeededResources"), &prt_ps_mb_font);
2803 	if (!prt_custom_cmap)
2804 	    prt_dsc_resources(NULL, "cmap", prt_cmap);
2805     }
2806 
2807     // Search for external resources VIM supplies
2808     if (!prt_find_resource("prolog", res_prolog))
2809     {
2810 	emsg(_("E456: Can't find PostScript resource file \"prolog.ps\""));
2811 	goto theend;
2812     }
2813     if (!prt_open_resource(res_prolog))
2814 	goto theend;
2815     if (!prt_check_resource(res_prolog, PRT_PROLOG_VERSION))
2816 	goto theend;
2817     if (prt_out_mbyte)
2818     {
2819 	// Look for required version of multi-byte printing procset
2820 	if (!prt_find_resource("cidfont", res_cidfont))
2821 	{
2822 	    emsg(_("E456: Can't find PostScript resource file \"cidfont.ps\""));
2823 	    goto theend;
2824 	}
2825 	if (!prt_open_resource(res_cidfont))
2826 	    goto theend;
2827 	if (!prt_check_resource(res_cidfont, PRT_CID_PROLOG_VERSION))
2828 	    goto theend;
2829     }
2830 
2831     // Find an encoding to use for printing.
2832     // Check 'printencoding'. If not set or not found, then use 'encoding'. If
2833     // that cannot be found then default to "latin1".
2834     // Note: VIM specific encoding header is always skipped.
2835     if (!prt_out_mbyte)
2836     {
2837 	p_encoding = enc_skip(p_penc);
2838 	if (*p_encoding == NUL
2839 		|| !prt_find_resource((char *)p_encoding, res_encoding))
2840 	{
2841 	    // 'printencoding' not set or not supported - find alternate
2842 	    int		props;
2843 
2844 	    p_encoding = enc_skip(p_enc);
2845 	    props = enc_canon_props(p_encoding);
2846 	    if (!(props & ENC_8BIT)
2847 		    || !prt_find_resource((char *)p_encoding, res_encoding))
2848 		// 8-bit 'encoding' is not supported
2849 	    {
2850 		// Use latin1 as default printing encoding
2851 		p_encoding = (char_u *)"latin1";
2852 		if (!prt_find_resource((char *)p_encoding, res_encoding))
2853 		{
2854 		    semsg(_("E456: Can't find PostScript resource file \"%s.ps\""),
2855 			    p_encoding);
2856 		    goto theend;
2857 		}
2858 	    }
2859 	}
2860 	if (!prt_open_resource(res_encoding))
2861 	    goto theend;
2862 	// For the moment there are no checks on encoding resource files to
2863 	// perform
2864     }
2865     else
2866     {
2867 	p_encoding = enc_skip(p_penc);
2868 	if (*p_encoding == NUL)
2869 	    p_encoding = enc_skip(p_enc);
2870 	if (prt_use_courier)
2871 	{
2872 	    // Include ASCII range encoding vector
2873 	    if (!prt_find_resource(prt_ascii_encoding, res_encoding))
2874 	    {
2875 		semsg(_("E456: Can't find PostScript resource file \"%s.ps\""),
2876 							  prt_ascii_encoding);
2877 		goto theend;
2878 	    }
2879 	    if (!prt_open_resource(res_encoding))
2880 		goto theend;
2881 	    // For the moment there are no checks on encoding resource files to
2882 	    // perform
2883 	}
2884     }
2885 
2886     prt_conv.vc_type = CONV_NONE;
2887     if (!(enc_canon_props(p_enc) & enc_canon_props(p_encoding) & ENC_8BIT)) {
2888 	// Set up encoding conversion if required
2889 	if (FAIL == convert_setup(&prt_conv, p_enc, p_encoding))
2890 	{
2891 	    semsg(_("E620: Unable to convert to print encoding \"%s\""),
2892 		    p_encoding);
2893 	    goto theend;
2894 	}
2895 	prt_do_conv = TRUE;
2896     }
2897     prt_do_conv = prt_conv.vc_type != CONV_NONE;
2898 
2899     if (prt_out_mbyte && prt_custom_cmap)
2900     {
2901 	// Find user supplied CMap
2902 	if (!prt_find_resource(prt_cmap, res_cmap))
2903 	{
2904 	    semsg(_("E456: Can't find PostScript resource file \"%s.ps\""),
2905 								    prt_cmap);
2906 	    goto theend;
2907 	}
2908 	if (!prt_open_resource(res_cmap))
2909 	    goto theend;
2910     }
2911 
2912     // List resources supplied
2913     STRCPY(buffer, res_prolog->title);
2914     STRCAT(buffer, " ");
2915     STRCAT(buffer, res_prolog->version);
2916     prt_dsc_resources("DocumentSuppliedResources", "procset", buffer);
2917     if (prt_out_mbyte)
2918     {
2919 	STRCPY(buffer, res_cidfont->title);
2920 	STRCAT(buffer, " ");
2921 	STRCAT(buffer, res_cidfont->version);
2922 	prt_dsc_resources(NULL, "procset", buffer);
2923 
2924 	if (prt_custom_cmap)
2925 	{
2926 	    STRCPY(buffer, res_cmap->title);
2927 	    STRCAT(buffer, " ");
2928 	    STRCAT(buffer, res_cmap->version);
2929 	    prt_dsc_resources(NULL, "cmap", buffer);
2930 	}
2931     }
2932     if (!prt_out_mbyte || prt_use_courier)
2933     {
2934 	STRCPY(buffer, res_encoding->title);
2935 	STRCAT(buffer, " ");
2936 	STRCAT(buffer, res_encoding->version);
2937 	prt_dsc_resources(NULL, "encoding", buffer);
2938     }
2939     prt_dsc_requirements(prt_duplex, prt_tumble, prt_collate,
2940 #ifdef FEAT_SYN_HL
2941 					psettings->do_syntax
2942 #else
2943 					0
2944 #endif
2945 					, prt_num_copies);
2946     prt_dsc_noarg("EndComments");
2947 
2948     /*
2949      * PS Document page defaults
2950      */
2951     prt_dsc_noarg("BeginDefaults");
2952 
2953     // List font resources most likely common to all pages
2954     if (!prt_out_mbyte || prt_use_courier)
2955 	prt_dsc_font_resource("PageResources", &prt_ps_courier_font);
2956     if (prt_out_mbyte)
2957     {
2958 	prt_dsc_font_resource((prt_use_courier ? NULL : "PageResources"),
2959 							    &prt_ps_mb_font);
2960 	if (!prt_custom_cmap)
2961 	    prt_dsc_resources(NULL, "cmap", prt_cmap);
2962     }
2963 
2964     // Paper will be used for all pages
2965     prt_dsc_textline("PageMedia", prt_mediasize[prt_media].name);
2966 
2967     prt_dsc_noarg("EndDefaults");
2968 
2969     /*
2970      * PS Document prolog inclusion - all required procsets.
2971      */
2972     prt_dsc_noarg("BeginProlog");
2973 
2974     // Add required procsets - NOTE: order is important!
2975     if (!prt_add_resource(res_prolog))
2976 	goto theend;
2977     if (prt_out_mbyte)
2978     {
2979 	// Add CID font procset, and any user supplied CMap
2980 	if (!prt_add_resource(res_cidfont))
2981 	    goto theend;
2982 	if (prt_custom_cmap && !prt_add_resource(res_cmap))
2983 	    goto theend;
2984     }
2985 
2986     if (!prt_out_mbyte || prt_use_courier)
2987 	// There will be only one Roman font encoding to be included in the PS
2988 	// file.
2989 	if (!prt_add_resource(res_encoding))
2990 	    goto theend;
2991 
2992     prt_dsc_noarg("EndProlog");
2993 
2994     /*
2995      * PS Document setup - must appear after the prolog
2996      */
2997     prt_dsc_noarg("BeginSetup");
2998 
2999     // Device setup - page size and number of uncollated copies
3000     prt_write_int((int)prt_mediasize[prt_media].width);
3001     prt_write_int((int)prt_mediasize[prt_media].height);
3002     prt_write_int(0);
3003     prt_write_string("sps\n");
3004     prt_write_int(prt_num_copies);
3005     prt_write_string("nc\n");
3006     prt_write_boolean(prt_duplex);
3007     prt_write_boolean(prt_tumble);
3008     prt_write_string("dt\n");
3009     prt_write_boolean(prt_collate);
3010     prt_write_string("c\n");
3011 
3012     // Font resource inclusion and definition
3013     if (!prt_out_mbyte || prt_use_courier)
3014     {
3015 	// When using Courier for ASCII range when printing multi-byte, need to
3016 	// pick up ASCII encoding to use with it.
3017 	if (prt_use_courier)
3018 	    p_encoding = (char_u *)prt_ascii_encoding;
3019 	prt_dsc_resources("IncludeResource", "font",
3020 			  prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]);
3021 	prt_def_font("F0", (char *)p_encoding, (int)prt_line_height,
3022 		     prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]);
3023 	prt_dsc_resources("IncludeResource", "font",
3024 			  prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]);
3025 	prt_def_font("F1", (char *)p_encoding, (int)prt_line_height,
3026 		     prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]);
3027 	prt_dsc_resources("IncludeResource", "font",
3028 			  prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
3029 	prt_def_font("F2", (char *)p_encoding, (int)prt_line_height,
3030 		     prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
3031 	prt_dsc_resources("IncludeResource", "font",
3032 			  prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
3033 	prt_def_font("F3", (char *)p_encoding, (int)prt_line_height,
3034 		     prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
3035     }
3036     if (prt_out_mbyte)
3037     {
3038 	// Define the CID fonts to be used in the job.	Typically CJKV fonts do
3039 	// not have an italic form being a western style, so where no font is
3040 	// defined for these faces VIM falls back to an existing face.
3041 	// Note: if using Courier for the ASCII range then the printout will
3042 	// have bold/italic/bolditalic regardless of the setting of printmbfont.
3043 	prt_dsc_resources("IncludeResource", "font",
3044 			  prt_ps_mb_font.ps_fontname[PRT_PS_FONT_ROMAN]);
3045 	if (!prt_custom_cmap)
3046 	    prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
3047 	prt_def_cidfont("CF0", (int)prt_line_height,
3048 			prt_ps_mb_font.ps_fontname[PRT_PS_FONT_ROMAN]);
3049 
3050 	if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD] != NULL)
3051 	{
3052 	    prt_dsc_resources("IncludeResource", "font",
3053 			      prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]);
3054 	    if (!prt_custom_cmap)
3055 		prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
3056 	    prt_def_cidfont("CF1", (int)prt_line_height,
3057 			    prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]);
3058 	}
3059 	else
3060 	    // Use ROMAN for BOLD
3061 	    prt_dup_cidfont("CF0", "CF1");
3062 
3063 	if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE] != NULL)
3064 	{
3065 	    prt_dsc_resources("IncludeResource", "font",
3066 			      prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
3067 	    if (!prt_custom_cmap)
3068 		prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
3069 	    prt_def_cidfont("CF2", (int)prt_line_height,
3070 			    prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
3071 	}
3072 	else
3073 	    // Use ROMAN for OBLIQUE
3074 	    prt_dup_cidfont("CF0", "CF2");
3075 
3076 	if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE] != NULL)
3077 	{
3078 	    prt_dsc_resources("IncludeResource", "font",
3079 			      prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
3080 	    if (!prt_custom_cmap)
3081 		prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
3082 	    prt_def_cidfont("CF3", (int)prt_line_height,
3083 			    prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
3084 	}
3085 	else
3086 	    // Use BOLD for BOLDOBLIQUE
3087 	    prt_dup_cidfont("CF1", "CF3");
3088     }
3089 
3090     // Misc constant vars used for underlining and background rects
3091     prt_def_var("UO", PRT_PS_FONT_TO_USER(prt_line_height,
3092 						prt_ps_font->uline_offset), 2);
3093     prt_def_var("UW", PRT_PS_FONT_TO_USER(prt_line_height,
3094 						 prt_ps_font->uline_width), 2);
3095     prt_def_var("BO", prt_bgcol_offset, 2);
3096 
3097     prt_dsc_noarg("EndSetup");
3098 
3099     // Fail if any problems writing out to the PS file
3100     retval = !prt_file_error;
3101 
3102 theend:
3103     vim_free(res_prolog);
3104     vim_free(res_encoding);
3105     vim_free(res_cidfont);
3106     vim_free(res_cmap);
3107 
3108     return retval;
3109 }
3110 
3111     void
3112 mch_print_end(prt_settings_T *psettings)
3113 {
3114     prt_dsc_noarg("Trailer");
3115 
3116     /*
3117      * Output any info we don't know in toto until we finish
3118      */
3119     prt_dsc_ints("Pages", 1, &prt_page_num);
3120 
3121     prt_dsc_noarg("EOF");
3122 
3123     // Write CTRL-D to close serial communication link if used.
3124     // NOTHING MUST BE WRITTEN AFTER THIS!
3125     prt_write_file((char_u *)IF_EB("\004", "\067"));
3126 
3127     if (!prt_file_error && psettings->outfile == NULL
3128 					&& !got_int && !psettings->user_abort)
3129     {
3130 	// Close the file first.
3131 	if (prt_ps_fd != NULL)
3132 	{
3133 	    fclose(prt_ps_fd);
3134 	    prt_ps_fd = NULL;
3135 	}
3136 	prt_message((char_u *)_("Sending to printer..."));
3137 
3138 	// Not printing to a file: use 'printexpr' to print the file.
3139 	if (eval_printexpr(prt_ps_file_name, psettings->arguments) == FAIL)
3140 	    emsg(_("E365: Failed to print PostScript file"));
3141 	else
3142 	    prt_message((char_u *)_("Print job sent."));
3143     }
3144 
3145     mch_print_cleanup();
3146 }
3147 
3148     int
3149 mch_print_end_page(void)
3150 {
3151     prt_flush_buffer();
3152 
3153     prt_write_string("re sp\n");
3154 
3155     prt_dsc_noarg("PageTrailer");
3156 
3157     return !prt_file_error;
3158 }
3159 
3160     int
3161 mch_print_begin_page(char_u *str UNUSED)
3162 {
3163     int		page_num[2];
3164 
3165     prt_page_num++;
3166 
3167     page_num[0] = page_num[1] = prt_page_num;
3168     prt_dsc_ints("Page", 2, page_num);
3169 
3170     prt_dsc_noarg("BeginPageSetup");
3171 
3172     prt_write_string("sv\n0 g\n");
3173     prt_in_ascii = !prt_out_mbyte;
3174     if (prt_out_mbyte)
3175 	prt_write_string("CF0 sf\n");
3176     else
3177 	prt_write_string("F0 sf\n");
3178     prt_fgcol = PRCOLOR_BLACK;
3179     prt_bgcol = PRCOLOR_WHITE;
3180     prt_font = PRT_PS_FONT_ROMAN;
3181 
3182     // Set up page transformation for landscape printing.
3183     if (!prt_portrait)
3184     {
3185 	prt_write_int(-((int)prt_mediasize[prt_media].width));
3186 	prt_write_string("sl\n");
3187     }
3188 
3189     prt_dsc_noarg("EndPageSetup");
3190 
3191     // We have reset the font attributes, force setting them again.
3192     curr_bg = (long_u)0xffffffff;
3193     curr_fg = (long_u)0xffffffff;
3194     curr_bold = MAYBE;
3195 
3196     return !prt_file_error;
3197 }
3198 
3199     int
3200 mch_print_blank_page(void)
3201 {
3202     return (mch_print_begin_page(NULL) ? (mch_print_end_page()) : FALSE);
3203 }
3204 
3205 static float prt_pos_x = 0;
3206 static float prt_pos_y = 0;
3207 
3208     void
3209 mch_print_start_line(int margin, int page_line)
3210 {
3211     prt_pos_x = prt_left_margin;
3212     if (margin)
3213 	prt_pos_x -= prt_number_width;
3214 
3215     prt_pos_y = prt_top_margin - prt_first_line_height -
3216 					page_line * prt_line_height;
3217 
3218     prt_attribute_change = TRUE;
3219     prt_need_moveto = TRUE;
3220     prt_half_width = FALSE;
3221 }
3222 
3223     int
3224 mch_print_text_out(char_u *textp, int len UNUSED)
3225 {
3226     char_u	*p = textp;
3227     int		need_break;
3228     char_u	ch;
3229     char_u      ch_buff[8];
3230     float       char_width;
3231     float       next_pos;
3232     int		in_ascii;
3233     int		half_width;
3234     char_u	*tofree = NULL;
3235 
3236     char_width = prt_char_width;
3237 
3238     // Ideally VIM would create a rearranged CID font to combine a Roman and
3239     // CJKV font to do what VIM is doing here - use a Roman font for characters
3240     // in the ASCII range, and the original CID font for everything else.
3241     // The problem is that GhostScript still (as of 8.13) does not support
3242     // rearranged fonts even though they have been documented by Adobe for 7
3243     // years!  If they ever do, a lot of this code will disappear.
3244     if (prt_use_courier)
3245     {
3246 	in_ascii = (len == 1 && *p < 0x80);
3247 	if (prt_in_ascii)
3248 	{
3249 	    if (!in_ascii)
3250 	    {
3251 		// No longer in ASCII range - need to switch font
3252 		prt_in_ascii = FALSE;
3253 		prt_need_font = TRUE;
3254 		prt_attribute_change = TRUE;
3255 	    }
3256 	}
3257 	else if (in_ascii)
3258 	{
3259 	    // Now in ASCII range - need to switch font
3260 	    prt_in_ascii = TRUE;
3261 	    prt_need_font = TRUE;
3262 	    prt_attribute_change = TRUE;
3263 	}
3264     }
3265     if (prt_out_mbyte)
3266     {
3267 	half_width = ((*mb_ptr2cells)(p) == 1);
3268 	if (half_width)
3269 	    char_width /= 2;
3270 	if (prt_half_width)
3271 	{
3272 	    if (!half_width)
3273 	    {
3274 		prt_half_width = FALSE;
3275 		prt_pos_x += prt_char_width/4;
3276 		prt_need_moveto = TRUE;
3277 		prt_attribute_change = TRUE;
3278 	    }
3279 	}
3280 	else if (half_width)
3281 	{
3282 	    prt_half_width = TRUE;
3283 	    prt_pos_x += prt_char_width/4;
3284 	    prt_need_moveto = TRUE;
3285 	    prt_attribute_change = TRUE;
3286 	}
3287     }
3288 
3289     // Output any required changes to the graphics state, after flushing any
3290     // text buffered so far.
3291     if (prt_attribute_change)
3292     {
3293 	prt_flush_buffer();
3294 	// Reset count of number of chars that will be printed
3295 	prt_text_run = 0;
3296 
3297 	if (prt_need_moveto)
3298 	{
3299 	    prt_pos_x_moveto = prt_pos_x;
3300 	    prt_pos_y_moveto = prt_pos_y;
3301 	    prt_do_moveto = TRUE;
3302 
3303 	    prt_need_moveto = FALSE;
3304 	}
3305 	if (prt_need_font)
3306 	{
3307 	    if (!prt_in_ascii)
3308 		prt_write_string("CF");
3309 	    else
3310 		prt_write_string("F");
3311 	    prt_write_int(prt_font);
3312 	    prt_write_string("sf\n");
3313 	    prt_need_font = FALSE;
3314 	}
3315 	if (prt_need_fgcol)
3316 	{
3317 	    int     r, g, b;
3318 	    r = ((unsigned)prt_fgcol & 0xff0000) >> 16;
3319 	    g = ((unsigned)prt_fgcol & 0xff00) >> 8;
3320 	    b = prt_fgcol & 0xff;
3321 
3322 	    prt_write_real(r / 255.0, 3);
3323 	    if (r == g && g == b)
3324 		prt_write_string("g\n");
3325 	    else
3326 	    {
3327 		prt_write_real(g / 255.0, 3);
3328 		prt_write_real(b / 255.0, 3);
3329 		prt_write_string("r\n");
3330 	    }
3331 	    prt_need_fgcol = FALSE;
3332 	}
3333 
3334 	if (prt_bgcol != PRCOLOR_WHITE)
3335 	{
3336 	    prt_new_bgcol = prt_bgcol;
3337 	    if (prt_need_bgcol)
3338 		prt_do_bgcol = TRUE;
3339 	}
3340 	else
3341 	    prt_do_bgcol = FALSE;
3342 	prt_need_bgcol = FALSE;
3343 
3344 	if (prt_need_underline)
3345 	    prt_do_underline = prt_underline;
3346 	prt_need_underline = FALSE;
3347 
3348 	prt_attribute_change = FALSE;
3349     }
3350 
3351     if (prt_do_conv)
3352     {
3353 	// Convert from multi-byte to 8-bit encoding
3354 	tofree = p = string_convert(&prt_conv, p, &len);
3355 	if (p == NULL)
3356 	{
3357 	    p = (char_u *)"";
3358 	    len = 0;
3359 	}
3360     }
3361 
3362     if (prt_out_mbyte)
3363     {
3364 	// Multi-byte character strings are represented more efficiently as hex
3365 	// strings when outputting clean 8 bit PS.
3366 	while (len-- > 0)
3367 	{
3368 	    ch = prt_hexchar[(unsigned)(*p) >> 4];
3369 	    ga_append(&prt_ps_buffer, ch);
3370 	    ch = prt_hexchar[(*p) & 0xf];
3371 	    ga_append(&prt_ps_buffer, ch);
3372 	    p++;
3373 	}
3374     }
3375     else
3376     {
3377 	// Add next character to buffer of characters to output.
3378 	// Note: One printed character may require several PS characters to
3379 	// represent it, but we only count them as one printed character.
3380 	ch = *p;
3381 	if (ch < 32 || ch == '(' || ch == ')' || ch == '\\')
3382 	{
3383 	    // Convert non-printing characters to either their escape or octal
3384 	    // sequence, ensures PS sent over a serial line does not interfere
3385 	    // with the comms protocol.  Note: For EBCDIC we need to write out
3386 	    // the escape sequences as ASCII codes!
3387 	    // Note 2: Char codes < 32 are identical in EBCDIC and ASCII AFAIK!
3388 	    ga_append(&prt_ps_buffer, IF_EB('\\', 0134));
3389 	    switch (ch)
3390 	    {
3391 		case BS:   ga_append(&prt_ps_buffer, IF_EB('b', 0142)); break;
3392 		case TAB:  ga_append(&prt_ps_buffer, IF_EB('t', 0164)); break;
3393 		case NL:   ga_append(&prt_ps_buffer, IF_EB('n', 0156)); break;
3394 		case FF:   ga_append(&prt_ps_buffer, IF_EB('f', 0146)); break;
3395 		case CAR:  ga_append(&prt_ps_buffer, IF_EB('r', 0162)); break;
3396 		case '(':  ga_append(&prt_ps_buffer, IF_EB('(', 0050)); break;
3397 		case ')':  ga_append(&prt_ps_buffer, IF_EB(')', 0051)); break;
3398 		case '\\': ga_append(&prt_ps_buffer, IF_EB('\\', 0134)); break;
3399 
3400 		default:
3401 			   sprintf((char *)ch_buff, "%03o", (unsigned int)ch);
3402 #ifdef EBCDIC
3403 			   ebcdic2ascii(ch_buff, 3);
3404 #endif
3405 			   ga_append(&prt_ps_buffer, ch_buff[0]);
3406 			   ga_append(&prt_ps_buffer, ch_buff[1]);
3407 			   ga_append(&prt_ps_buffer, ch_buff[2]);
3408 			   break;
3409 	    }
3410 	}
3411 	else
3412 	    ga_append(&prt_ps_buffer, ch);
3413     }
3414 
3415     // Need to free any translated characters
3416     vim_free(tofree);
3417 
3418     prt_text_run += char_width;
3419     prt_pos_x += char_width;
3420 
3421     // The downside of fp - use relative error on right margin check
3422     next_pos = prt_pos_x + prt_char_width;
3423     need_break = (next_pos > prt_right_margin) &&
3424 		    ((next_pos - prt_right_margin) > (prt_right_margin*1e-5));
3425 
3426     if (need_break)
3427 	prt_flush_buffer();
3428 
3429     return need_break;
3430 }
3431 
3432     void
3433 mch_print_set_font(int iBold, int iItalic, int iUnderline)
3434 {
3435     int		font = 0;
3436 
3437     if (iBold)
3438 	font |= 0x01;
3439     if (iItalic)
3440 	font |= 0x02;
3441 
3442     if (font != prt_font)
3443     {
3444 	prt_font = font;
3445 	prt_attribute_change = TRUE;
3446 	prt_need_font = TRUE;
3447     }
3448     if (prt_underline != iUnderline)
3449     {
3450 	prt_underline = iUnderline;
3451 	prt_attribute_change = TRUE;
3452 	prt_need_underline = TRUE;
3453     }
3454 }
3455 
3456     void
3457 mch_print_set_bg(long_u bgcol)
3458 {
3459     prt_bgcol = (int)bgcol;
3460     prt_attribute_change = TRUE;
3461     prt_need_bgcol = TRUE;
3462 }
3463 
3464     void
3465 mch_print_set_fg(long_u fgcol)
3466 {
3467     if (fgcol != (long_u)prt_fgcol)
3468     {
3469 	prt_fgcol = (int)fgcol;
3470 	prt_attribute_change = TRUE;
3471 	prt_need_fgcol = TRUE;
3472     }
3473 }
3474 
3475 # endif //FEAT_POSTSCRIPT
3476 #endif //FEAT_PRINTER
3477