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