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