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