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