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