1 /* vi:set ts=8 sts=4 sw=4: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * 5 * Do ":help uganda" in Vim to read copying and usage conditions. 6 * Do ":help credits" in Vim to see a list of people who contributed. 7 * See README.txt for an overview of the Vim source code. 8 */ 9 10 /* 11 * ex_cmds2.c: some more functions for command line commands 12 */ 13 14 #if defined(WIN32) && defined(FEAT_CSCOPE) 15 # include <io.h> 16 #endif 17 18 #include "vim.h" 19 20 #if defined(WIN32) && defined(FEAT_CSCOPE) 21 # include <fcntl.h> 22 #endif 23 24 #include "version.h" 25 26 static void cmd_source __ARGS((char_u *fname, exarg_T *eap)); 27 28 #if defined(FEAT_EVAL) || defined(PROTO) 29 static int debug_greedy = FALSE; /* batch mode debugging: don't save 30 and restore typeahead. */ 31 32 /* 33 * do_debug(): Debug mode. 34 * Repeatedly get Ex commands, until told to continue normal execution. 35 */ 36 void 37 do_debug(cmd) 38 char_u *cmd; 39 { 40 int save_msg_scroll = msg_scroll; 41 int save_State = State; 42 int save_did_emsg = did_emsg; 43 int save_cmd_silent = cmd_silent; 44 int save_msg_silent = msg_silent; 45 int save_emsg_silent = emsg_silent; 46 int save_redir_off = redir_off; 47 tasave_T typeaheadbuf; 48 # ifdef FEAT_EX_EXTRA 49 int save_ex_normal_busy; 50 # endif 51 int n; 52 char_u *cmdline = NULL; 53 char_u *p; 54 char *tail = NULL; 55 static int last_cmd = 0; 56 #define CMD_CONT 1 57 #define CMD_NEXT 2 58 #define CMD_STEP 3 59 #define CMD_FINISH 4 60 #define CMD_QUIT 5 61 #define CMD_INTERRUPT 6 62 63 #ifdef ALWAYS_USE_GUI 64 /* Can't do this when there is no terminal for input/output. */ 65 if (!gui.in_use) 66 { 67 /* Break as soon as possible. */ 68 debug_break_level = 9999; 69 return; 70 } 71 #endif 72 73 /* Make sure we are in raw mode and start termcap mode. Might have side 74 * effects... */ 75 settmode(TMODE_RAW); 76 starttermcap(); 77 78 ++RedrawingDisabled; /* don't redisplay the window */ 79 ++no_wait_return; /* don't wait for return */ 80 did_emsg = FALSE; /* don't use error from debugged stuff */ 81 cmd_silent = FALSE; /* display commands */ 82 msg_silent = FALSE; /* display messages */ 83 emsg_silent = FALSE; /* display error messages */ 84 redir_off = TRUE; /* don't redirect debug commands */ 85 86 State = NORMAL; 87 #ifdef FEAT_SNIFF 88 want_sniff_request = 0; /* No K_SNIFF wanted */ 89 #endif 90 91 if (!debug_did_msg) 92 MSG(_("Entering Debug mode. Type \"cont\" to continue.")); 93 if (sourcing_name != NULL) 94 msg(sourcing_name); 95 if (sourcing_lnum != 0) 96 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd); 97 else 98 msg_str((char_u *)_("cmd: %s"), cmd); 99 100 /* 101 * Repeat getting a command and executing it. 102 */ 103 for (;;) 104 { 105 msg_scroll = TRUE; 106 need_wait_return = FALSE; 107 #ifdef FEAT_SNIFF 108 ProcessSniffRequests(); 109 #endif 110 /* Save the current typeahead buffer and replace it with an empty one. 111 * This makes sure we get input from the user here and don't interfere 112 * with the commands being executed. Reset "ex_normal_busy" to avoid 113 * the side effects of using ":normal". Save the stuff buffer and make 114 * it empty. */ 115 # ifdef FEAT_EX_EXTRA 116 save_ex_normal_busy = ex_normal_busy; 117 ex_normal_busy = 0; 118 # endif 119 if (!debug_greedy) 120 save_typeahead(&typeaheadbuf); 121 122 cmdline = getcmdline_prompt('>', NULL, 0); 123 124 if (!debug_greedy) 125 restore_typeahead(&typeaheadbuf); 126 # ifdef FEAT_EX_EXTRA 127 ex_normal_busy = save_ex_normal_busy; 128 # endif 129 130 cmdline_row = msg_row; 131 if (cmdline != NULL) 132 { 133 /* If this is a debug command, set "last_cmd". 134 * If not, reset "last_cmd". 135 * For a blank line use previous command. */ 136 p = skipwhite(cmdline); 137 if (*p != NUL) 138 { 139 switch (*p) 140 { 141 case 'c': last_cmd = CMD_CONT; 142 tail = "ont"; 143 break; 144 case 'n': last_cmd = CMD_NEXT; 145 tail = "ext"; 146 break; 147 case 's': last_cmd = CMD_STEP; 148 tail = "tep"; 149 break; 150 case 'f': last_cmd = CMD_FINISH; 151 tail = "inish"; 152 break; 153 case 'q': last_cmd = CMD_QUIT; 154 tail = "uit"; 155 break; 156 case 'i': last_cmd = CMD_INTERRUPT; 157 tail = "nterrupt"; 158 break; 159 default: last_cmd = 0; 160 } 161 if (last_cmd != 0) 162 { 163 /* Check that the tail matches. */ 164 ++p; 165 while (*p != NUL && *p == *tail) 166 { 167 ++p; 168 ++tail; 169 } 170 if (ASCII_ISALPHA(*p)) 171 last_cmd = 0; 172 } 173 } 174 175 if (last_cmd != 0) 176 { 177 /* Execute debug command: decided where to break next and 178 * return. */ 179 switch (last_cmd) 180 { 181 case CMD_CONT: 182 debug_break_level = -1; 183 break; 184 case CMD_NEXT: 185 debug_break_level = ex_nesting_level; 186 break; 187 case CMD_STEP: 188 debug_break_level = 9999; 189 break; 190 case CMD_FINISH: 191 debug_break_level = ex_nesting_level - 1; 192 break; 193 case CMD_QUIT: 194 got_int = TRUE; 195 debug_break_level = -1; 196 break; 197 case CMD_INTERRUPT: 198 got_int = TRUE; 199 debug_break_level = 9999; 200 /* Do not repeat ">interrupt" cmd, continue stepping. */ 201 last_cmd = CMD_STEP; 202 break; 203 } 204 break; 205 } 206 207 /* don't debug this command */ 208 n = debug_break_level; 209 debug_break_level = -1; 210 (void)do_cmdline(cmdline, getexline, NULL, 211 DOCMD_VERBOSE|DOCMD_EXCRESET); 212 debug_break_level = n; 213 214 vim_free(cmdline); 215 } 216 lines_left = Rows - 1; 217 } 218 vim_free(cmdline); 219 220 --RedrawingDisabled; 221 --no_wait_return; 222 redraw_all_later(NOT_VALID); 223 need_wait_return = FALSE; 224 msg_scroll = save_msg_scroll; 225 lines_left = Rows - 1; 226 State = save_State; 227 did_emsg = save_did_emsg; 228 cmd_silent = save_cmd_silent; 229 msg_silent = save_msg_silent; 230 emsg_silent = save_emsg_silent; 231 redir_off = save_redir_off; 232 233 /* Only print the message again when typing a command before coming back 234 * here. */ 235 debug_did_msg = TRUE; 236 } 237 238 /* 239 * ":debug". 240 */ 241 void 242 ex_debug(eap) 243 exarg_T *eap; 244 { 245 int debug_break_level_save = debug_break_level; 246 247 debug_break_level = 9999; 248 do_cmdline_cmd(eap->arg); 249 debug_break_level = debug_break_level_save; 250 } 251 252 static char_u *debug_breakpoint_name = NULL; 253 static linenr_T debug_breakpoint_lnum; 254 255 /* 256 * When debugging or a breakpoint is set on a skipped command, no debug prompt 257 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and 258 * debug_skipped_name is then set to the source name in the breakpoint case. If 259 * a skipped command decides itself that a debug prompt should be displayed, it 260 * can do so by calling dbg_check_skipped(). 261 */ 262 static int debug_skipped; 263 static char_u *debug_skipped_name; 264 265 /* 266 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is 267 * at or below the break level. But only when the line is actually 268 * executed. Return TRUE and set breakpoint_name for skipped commands that 269 * decide to execute something themselves. 270 * Called from do_one_cmd() before executing a command. 271 */ 272 void 273 dbg_check_breakpoint(eap) 274 exarg_T *eap; 275 { 276 char_u *p; 277 278 debug_skipped = FALSE; 279 if (debug_breakpoint_name != NULL) 280 { 281 if (!eap->skip) 282 { 283 /* replace K_SNR with "<SNR>" */ 284 if (debug_breakpoint_name[0] == K_SPECIAL 285 && debug_breakpoint_name[1] == KS_EXTRA 286 && debug_breakpoint_name[2] == (int)KE_SNR) 287 p = (char_u *)"<SNR>"; 288 else 289 p = (char_u *)""; 290 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"), p, 291 debug_breakpoint_name + (*p == NUL ? 0 : 3), 292 (long)debug_breakpoint_lnum); 293 debug_breakpoint_name = NULL; 294 do_debug(eap->cmd); 295 } 296 else 297 { 298 debug_skipped = TRUE; 299 debug_skipped_name = debug_breakpoint_name; 300 debug_breakpoint_name = NULL; 301 } 302 } 303 else if (ex_nesting_level <= debug_break_level) 304 { 305 if (!eap->skip) 306 do_debug(eap->cmd); 307 else 308 { 309 debug_skipped = TRUE; 310 debug_skipped_name = NULL; 311 } 312 } 313 } 314 315 /* 316 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was 317 * set. Return TRUE when the debug mode is entered this time. 318 */ 319 int 320 dbg_check_skipped(eap) 321 exarg_T *eap; 322 { 323 int prev_got_int; 324 325 if (debug_skipped) 326 { 327 /* 328 * Save the value of got_int and reset it. We don't want a previous 329 * interruption cause flushing the input buffer. 330 */ 331 prev_got_int = got_int; 332 got_int = FALSE; 333 debug_breakpoint_name = debug_skipped_name; 334 /* eap->skip is TRUE */ 335 eap->skip = FALSE; 336 (void)dbg_check_breakpoint(eap); 337 eap->skip = TRUE; 338 got_int |= prev_got_int; 339 return TRUE; 340 } 341 return FALSE; 342 } 343 344 /* 345 * The list of breakpoints: dbg_breakp. 346 * This is a grow-array of structs. 347 */ 348 struct debuggy 349 { 350 int dbg_nr; /* breakpoint number */ 351 int dbg_type; /* DBG_FUNC or DBG_FILE */ 352 char_u *dbg_name; /* function or file name */ 353 regprog_T *dbg_prog; /* regexp program */ 354 linenr_T dbg_lnum; /* line number in function or file */ 355 }; 356 357 static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL}; 358 #define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx]) 359 static int last_breakp = 0; /* nr of last defined breakpoint */ 360 361 #define DBG_FUNC 1 362 #define DBG_FILE 2 363 364 static int dbg_parsearg __ARGS((char_u *arg)); 365 366 /* 367 * Parse the arguments of ":breakadd" or ":breakdel" and put them in the entry 368 * just after the last one in dbg_breakp. Note that "dbg_name" is allocated. 369 * Returns FAIL for failure. 370 */ 371 static int 372 dbg_parsearg(arg) 373 char_u *arg; 374 { 375 char_u *p = arg; 376 char_u *q; 377 struct debuggy *bp; 378 int here = FALSE; 379 380 if (ga_grow(&dbg_breakp, 1) == FAIL) 381 return FAIL; 382 bp = &BREAKP(dbg_breakp.ga_len); 383 384 /* Find "func" or "file". */ 385 if (STRNCMP(p, "func", 4) == 0) 386 bp->dbg_type = DBG_FUNC; 387 else if (STRNCMP(p, "file", 4) == 0) 388 bp->dbg_type = DBG_FILE; 389 else if (STRNCMP(p, "here", 4) == 0) 390 { 391 if (curbuf->b_ffname == NULL) 392 { 393 EMSG(_(e_noname)); 394 return FAIL; 395 } 396 bp->dbg_type = DBG_FILE; 397 here = TRUE; 398 } 399 else 400 { 401 EMSG2(_(e_invarg2), p); 402 return FAIL; 403 } 404 p = skipwhite(p + 4); 405 406 /* Find optional line number. */ 407 if (here) 408 bp->dbg_lnum = curwin->w_cursor.lnum; 409 else if (VIM_ISDIGIT(*p)) 410 { 411 bp->dbg_lnum = getdigits(&p); 412 p = skipwhite(p); 413 } 414 else 415 bp->dbg_lnum = 0; 416 417 /* Find the function or file name. Don't accept a function name with (). */ 418 if ((!here && *p == NUL) 419 || (here && *p != NUL) 420 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL)) 421 { 422 EMSG2(_(e_invarg2), arg); 423 return FAIL; 424 } 425 426 if (bp->dbg_type == DBG_FUNC) 427 bp->dbg_name = vim_strsave(p); 428 else if (here) 429 bp->dbg_name = vim_strsave(curbuf->b_ffname); 430 else 431 { 432 /* Expand the file name in the same way as do_source(). This means 433 * doing it twice, so that $DIR/file gets expanded when $DIR is 434 * "~/dir". */ 435 #ifdef RISCOS 436 q = mch_munge_fname(p); 437 #else 438 q = expand_env_save(p); 439 #endif 440 if (q == NULL) 441 return FAIL; 442 #ifdef RISCOS 443 p = mch_munge_fname(q); 444 #else 445 p = expand_env_save(q); 446 #endif 447 vim_free(q); 448 if (p == NULL) 449 return FAIL; 450 if (*p != '*') 451 { 452 bp->dbg_name = fix_fname(p); 453 vim_free(p); 454 } 455 else 456 bp->dbg_name = p; 457 #ifdef MACOS_CLASSIC 458 if (bp->dbg_name != NULL) 459 slash_n_colon_adjust(bp->dbg_name); 460 #endif 461 } 462 463 if (bp->dbg_name == NULL) 464 return FAIL; 465 return OK; 466 } 467 468 /* 469 * ":breakadd". 470 */ 471 void 472 ex_breakadd(eap) 473 exarg_T *eap; 474 { 475 struct debuggy *bp; 476 char_u *pat; 477 478 if (dbg_parsearg(eap->arg) == OK) 479 { 480 bp = &BREAKP(dbg_breakp.ga_len); 481 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE); 482 if (pat != NULL) 483 { 484 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING); 485 vim_free(pat); 486 } 487 if (pat == NULL || bp->dbg_prog == NULL) 488 vim_free(bp->dbg_name); 489 else 490 { 491 if (bp->dbg_lnum == 0) /* default line number is 1 */ 492 bp->dbg_lnum = 1; 493 BREAKP(dbg_breakp.ga_len++).dbg_nr = ++last_breakp; 494 --dbg_breakp.ga_room; 495 ++debug_tick; 496 } 497 } 498 } 499 500 /* 501 * ":debuggreedy". 502 */ 503 void 504 ex_debuggreedy(eap) 505 exarg_T *eap; 506 { 507 if (eap->addr_count == 0 || eap->line2 != 0) 508 debug_greedy = TRUE; 509 else 510 debug_greedy = FALSE; 511 } 512 513 /* 514 * ":breakdel". 515 */ 516 void 517 ex_breakdel(eap) 518 exarg_T *eap; 519 { 520 struct debuggy *bp, *bpi; 521 int nr; 522 int todel = -1; 523 int i; 524 linenr_T best_lnum = 0; 525 526 if (vim_isdigit(*eap->arg)) 527 { 528 /* ":breakdel {nr}" */ 529 nr = atol((char *)eap->arg); 530 for (i = 0; i < dbg_breakp.ga_len; ++i) 531 if (BREAKP(i).dbg_nr == nr) 532 { 533 todel = i; 534 break; 535 } 536 } 537 else 538 { 539 /* ":breakdel {func|file} [lnum] {name}" */ 540 if (dbg_parsearg(eap->arg) == FAIL) 541 return; 542 bp = &BREAKP(dbg_breakp.ga_len); 543 for (i = 0; i < dbg_breakp.ga_len; ++i) 544 { 545 bpi = &BREAKP(i); 546 if (bp->dbg_type == bpi->dbg_type 547 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0 548 && (bp->dbg_lnum == bpi->dbg_lnum 549 || (bp->dbg_lnum == 0 550 && (best_lnum == 0 551 || bpi->dbg_lnum < best_lnum)))) 552 { 553 todel = i; 554 best_lnum = bpi->dbg_lnum; 555 } 556 } 557 vim_free(bp->dbg_name); 558 } 559 560 if (todel < 0) 561 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg); 562 else 563 { 564 vim_free(BREAKP(todel).dbg_name); 565 vim_free(BREAKP(todel).dbg_prog); 566 --dbg_breakp.ga_len; 567 ++dbg_breakp.ga_room; 568 if (todel < dbg_breakp.ga_len) 569 mch_memmove(&BREAKP(todel), &BREAKP(todel + 1), 570 (dbg_breakp.ga_len - todel) * sizeof(struct debuggy)); 571 ++debug_tick; 572 } 573 } 574 575 /* 576 * ":breaklist". 577 */ 578 /*ARGSUSED*/ 579 void 580 ex_breaklist(eap) 581 exarg_T *eap; 582 { 583 struct debuggy *bp; 584 int i; 585 586 if (dbg_breakp.ga_len == 0) 587 MSG(_("No breakpoints defined")); 588 else 589 for (i = 0; i < dbg_breakp.ga_len; ++i) 590 { 591 bp = &BREAKP(i); 592 smsg((char_u *)_("%3d %s %s line %ld"), 593 bp->dbg_nr, 594 bp->dbg_type == DBG_FUNC ? "func" : "file", 595 bp->dbg_name, 596 (long)bp->dbg_lnum); 597 } 598 } 599 600 /* 601 * Find a breakpoint for a function or sourced file. 602 * Returns line number at which to break; zero when no matching breakpoint. 603 */ 604 linenr_T 605 dbg_find_breakpoint(file, fname, after) 606 int file; /* TRUE for a file, FALSE for a function */ 607 char_u *fname; /* file or function name */ 608 linenr_T after; /* after this line number */ 609 { 610 struct debuggy *bp; 611 int i; 612 linenr_T lnum = 0; 613 regmatch_T regmatch; 614 char_u *name = fname; 615 int prev_got_int; 616 617 /* Replace K_SNR in function name with "<SNR>". */ 618 if (!file && fname[0] == K_SPECIAL) 619 { 620 name = alloc((unsigned)STRLEN(fname) + 3); 621 if (name == NULL) 622 name = fname; 623 else 624 { 625 STRCPY(name, "<SNR>"); 626 STRCPY(name + 5, fname + 3); 627 } 628 } 629 630 for (i = 0; i < dbg_breakp.ga_len; ++i) 631 { 632 /* skip entries that are not useful or are for a line that is beyond 633 * an already found breakpoint */ 634 bp = &BREAKP(i); 635 if ((bp->dbg_type == DBG_FILE) == file 636 && bp->dbg_lnum > after 637 && (lnum == 0 || bp->dbg_lnum < lnum)) 638 { 639 regmatch.regprog = bp->dbg_prog; 640 regmatch.rm_ic = FALSE; 641 /* 642 * Save the value of got_int and reset it. We don't want a previous 643 * interruption cancel matching, only hitting CTRL-C while matching 644 * should abort it. 645 */ 646 prev_got_int = got_int; 647 got_int = FALSE; 648 if (vim_regexec(®match, name, (colnr_T)0)) 649 lnum = bp->dbg_lnum; 650 got_int |= prev_got_int; 651 } 652 } 653 if (name != fname) 654 vim_free(name); 655 656 return lnum; 657 } 658 659 /* 660 * Called when a breakpoint was encountered. 661 */ 662 void 663 dbg_breakpoint(name, lnum) 664 char_u *name; 665 linenr_T lnum; 666 { 667 /* We need to check if this line is actually executed in do_one_cmd() */ 668 debug_breakpoint_name = name; 669 debug_breakpoint_lnum = lnum; 670 } 671 #endif 672 673 /* 674 * If 'autowrite' option set, try to write the file. 675 * Careful: autocommands may make "buf" invalid! 676 * 677 * return FAIL for failure, OK otherwise 678 */ 679 int 680 autowrite(buf, forceit) 681 buf_T *buf; 682 int forceit; 683 { 684 if (!(p_aw || p_awa) || !p_write 685 #ifdef FEAT_QUICKFIX 686 /* never autowrite a "nofile" or "nowrite" buffer */ 687 || bt_dontwrite(buf) 688 #endif 689 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL) 690 return FAIL; 691 return buf_write_all(buf, forceit); 692 } 693 694 /* 695 * flush all buffers, except the ones that are readonly 696 */ 697 void 698 autowrite_all() 699 { 700 buf_T *buf; 701 702 if (!(p_aw || p_awa) || !p_write) 703 return; 704 for (buf = firstbuf; buf; buf = buf->b_next) 705 if (bufIsChanged(buf) && !buf->b_p_ro) 706 { 707 (void)buf_write_all(buf, FALSE); 708 #ifdef FEAT_AUTOCMD 709 /* an autocommand may have deleted the buffer */ 710 if (!buf_valid(buf)) 711 buf = firstbuf; 712 #endif 713 } 714 } 715 716 /* 717 * return TRUE if buffer was changed and cannot be abandoned. 718 */ 719 /*ARGSUSED*/ 720 int 721 check_changed(buf, checkaw, mult_win, forceit, allbuf) 722 buf_T *buf; 723 int checkaw; /* do autowrite if buffer was changed */ 724 int mult_win; /* check also when several wins for the buf */ 725 int forceit; 726 int allbuf; /* may write all buffers */ 727 { 728 if ( !forceit 729 && bufIsChanged(buf) 730 && (mult_win || buf->b_nwindows <= 1) 731 && (!checkaw || autowrite(buf, forceit) == FAIL)) 732 { 733 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) 734 if ((p_confirm || cmdmod.confirm) && p_write) 735 { 736 buf_T *buf2; 737 int count = 0; 738 739 if (allbuf) 740 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next) 741 if (bufIsChanged(buf2) 742 && (buf2->b_ffname != NULL 743 # ifdef FEAT_BROWSE 744 || cmdmod.browse 745 # endif 746 )) 747 ++count; 748 # ifdef FEAT_AUTOCMD 749 if (!buf_valid(buf)) 750 /* Autocommand deleted buffer, oops! It's not changed now. */ 751 return FALSE; 752 # endif 753 dialog_changed(buf, count > 1); 754 # ifdef FEAT_AUTOCMD 755 if (!buf_valid(buf)) 756 /* Autocommand deleted buffer, oops! It's not changed now. */ 757 return FALSE; 758 # endif 759 return bufIsChanged(buf); 760 } 761 #endif 762 EMSG(_(e_nowrtmsg)); 763 return TRUE; 764 } 765 return FALSE; 766 } 767 768 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO) 769 770 #if defined(FEAT_BROWSE) || defined(PROTO) 771 /* 772 * When wanting to write a file without a file name, ask the user for a name. 773 */ 774 void 775 browse_save_fname(buf) 776 buf_T *buf; 777 { 778 if (buf->b_fname == NULL) 779 { 780 char_u *fname; 781 782 fname = do_browse(TRUE, (char_u *)_("Save As"), NULL, NULL, NULL, 783 NULL, buf); 784 if (fname != NULL) 785 { 786 if (setfname(buf, fname, NULL, TRUE) == OK) 787 buf->b_flags |= BF_NOTEDITED; 788 vim_free(fname); 789 } 790 } 791 } 792 #endif 793 794 /* 795 * Ask the user what to do when abondoning a changed buffer. 796 * Must check 'write' option first! 797 */ 798 void 799 dialog_changed(buf, checkall) 800 buf_T *buf; 801 int checkall; /* may abandon all changed buffers */ 802 { 803 char_u buff[IOSIZE]; 804 int ret; 805 buf_T *buf2; 806 807 dialog_msg(buff, _("Save changes to \"%.*s\"?"), 808 (buf->b_fname != NULL) ? 809 buf->b_fname : (char_u *)_("Untitled")); 810 if (checkall) 811 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1); 812 else 813 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1); 814 815 if (ret == VIM_YES) 816 { 817 #ifdef FEAT_BROWSE 818 /* May get file name, when there is none */ 819 browse_save_fname(buf); 820 #endif 821 if (buf->b_fname != NULL) /* didn't hit Cancel */ 822 (void)buf_write_all(buf, FALSE); 823 } 824 else if (ret == VIM_NO) 825 { 826 unchanged(buf, TRUE); 827 } 828 else if (ret == VIM_ALL) 829 { 830 /* 831 * Write all modified files that can be written. 832 * Skip readonly buffers, these need to be confirmed 833 * individually. 834 */ 835 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next) 836 { 837 if (bufIsChanged(buf2) 838 && (buf2->b_ffname != NULL 839 #ifdef FEAT_BROWSE 840 || cmdmod.browse 841 #endif 842 ) 843 && !buf2->b_p_ro) 844 { 845 #ifdef FEAT_BROWSE 846 /* May get file name, when there is none */ 847 browse_save_fname(buf2); 848 #endif 849 if (buf2->b_fname != NULL) /* didn't hit Cancel */ 850 (void)buf_write_all(buf2, FALSE); 851 #ifdef FEAT_AUTOCMD 852 /* an autocommand may have deleted the buffer */ 853 if (!buf_valid(buf2)) 854 buf2 = firstbuf; 855 #endif 856 } 857 } 858 } 859 else if (ret == VIM_DISCARDALL) 860 { 861 /* 862 * mark all buffers as unchanged 863 */ 864 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next) 865 unchanged(buf2, TRUE); 866 } 867 } 868 #endif 869 870 /* 871 * Return TRUE if the buffer "buf" can be abandoned, either by making it 872 * hidden, autowriting it or unloading it. 873 */ 874 int 875 can_abandon(buf, forceit) 876 buf_T *buf; 877 int forceit; 878 { 879 return ( P_HID(buf) 880 || !bufIsChanged(buf) 881 || buf->b_nwindows > 1 882 || autowrite(buf, forceit) == OK 883 || forceit); 884 } 885 886 /* 887 * Return TRUE if any buffer was changed and cannot be abandoned. 888 * That changed buffer becomes the current buffer. 889 */ 890 int 891 check_changed_any(hidden) 892 int hidden; /* Only check hidden buffers */ 893 { 894 buf_T *buf; 895 int save; 896 #ifdef FEAT_WINDOWS 897 win_T *wp; 898 #endif 899 900 for (;;) 901 { 902 /* check curbuf first: if it was changed we can't abandon it */ 903 if (!hidden && curbufIsChanged()) 904 buf = curbuf; 905 else 906 { 907 for (buf = firstbuf; buf != NULL; buf = buf->b_next) 908 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf)) 909 break; 910 } 911 if (buf == NULL) /* No buffers changed */ 912 return FALSE; 913 914 if (check_changed(buf, p_awa, TRUE, FALSE, TRUE) && buf_valid(buf)) 915 break; /* didn't save - still changes */ 916 } 917 918 exiting = FALSE; 919 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) 920 /* 921 * When ":confirm" used, don't give an error message. 922 */ 923 if (!(p_confirm || cmdmod.confirm)) 924 #endif 925 { 926 /* There must be a wait_return for this message, do_buffer() 927 * may cause a redraw. But wait_return() is a no-op when vgetc() 928 * is busy (Quit used from window menu), then make sure we don't 929 * cause a scroll up. */ 930 if (vgetc_busy) 931 { 932 msg_row = cmdline_row; 933 msg_col = 0; 934 msg_didout = FALSE; 935 } 936 if (EMSG2(_("E162: No write since last change for buffer \"%s\""), 937 buf_spname(buf) != NULL ? (char_u *)buf_spname(buf) : 938 buf->b_fname)) 939 { 940 save = no_wait_return; 941 no_wait_return = FALSE; 942 wait_return(FALSE); 943 no_wait_return = save; 944 } 945 } 946 947 #ifdef FEAT_WINDOWS 948 /* Try to find a window that contains the buffer. */ 949 if (buf != curbuf) 950 for (wp = firstwin; wp != NULL; wp = wp->w_next) 951 if (wp->w_buffer == buf) 952 { 953 win_goto(wp); 954 # ifdef FEAT_AUTOCMD 955 /* Paranoia: did autocms wipe out the buffer with changes? */ 956 if (!buf_valid(buf)) 957 return TRUE; 958 # endif 959 break; 960 } 961 #endif 962 963 /* Open the changed buffer in the current window. */ 964 if (buf != curbuf) 965 set_curbuf(buf, DOBUF_GOTO); 966 967 return TRUE; 968 } 969 970 /* 971 * return FAIL if there is no file name, OK if there is one 972 * give error message for FAIL 973 */ 974 int 975 check_fname() 976 { 977 if (curbuf->b_ffname == NULL) 978 { 979 EMSG(_(e_noname)); 980 return FAIL; 981 } 982 return OK; 983 } 984 985 /* 986 * flush the contents of a buffer, unless it has no file name 987 * 988 * return FAIL for failure, OK otherwise 989 */ 990 int 991 buf_write_all(buf, forceit) 992 buf_T *buf; 993 int forceit; 994 { 995 int retval; 996 #ifdef FEAT_AUTOCMD 997 buf_T *old_curbuf = curbuf; 998 #endif 999 1000 retval = (buf_write(buf, buf->b_ffname, buf->b_fname, 1001 (linenr_T)1, buf->b_ml.ml_line_count, NULL, 1002 FALSE, forceit, TRUE, FALSE)); 1003 #ifdef FEAT_AUTOCMD 1004 if (curbuf != old_curbuf) 1005 { 1006 msg_source(hl_attr(HLF_W)); 1007 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)")); 1008 } 1009 #endif 1010 return retval; 1011 } 1012 1013 /* 1014 * Code to handle the argument list. 1015 */ 1016 1017 /* 1018 * Isolate one argument, taking quotes and backticks. 1019 * Changes the argument in-place, puts a NUL after it. 1020 * Quotes are removed, backticks remain. 1021 * Return a pointer to the start of the next argument. 1022 */ 1023 char_u * 1024 do_one_arg(str) 1025 char_u *str; 1026 { 1027 char_u *p; 1028 int inquote; 1029 int inbacktick; 1030 1031 inquote = FALSE; 1032 inbacktick = FALSE; 1033 for (p = str; *str; ++str) 1034 { 1035 /* 1036 * for MSDOS et.al. a backslash is part of a file name. 1037 * Only skip ", space and tab. 1038 */ 1039 if (rem_backslash(str)) 1040 { 1041 *p++ = *str++; 1042 *p++ = *str; 1043 } 1044 else 1045 { 1046 /* An item ends at a space not in quotes or backticks */ 1047 if (!inquote && !inbacktick && vim_isspace(*str)) 1048 break; 1049 if (!inquote && *str == '`') 1050 inbacktick ^= TRUE; 1051 if (!inbacktick && *str == '"') 1052 inquote ^= TRUE; 1053 else 1054 *p++ = *str; 1055 } 1056 } 1057 str = skipwhite(str); 1058 *p = NUL; 1059 1060 return str; 1061 } 1062 1063 static int do_arglist __ARGS((char_u *str, int what, int after)); 1064 static void alist_check_arg_idx __ARGS((void)); 1065 #ifdef FEAT_LISTCMDS 1066 static int alist_add_list __ARGS((int count, char_u **files, int after)); 1067 #endif 1068 #define AL_SET 1 1069 #define AL_ADD 2 1070 #define AL_DEL 3 1071 1072 #if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO) 1073 /* 1074 * Redefine the argument list. 1075 */ 1076 void 1077 set_arglist(str) 1078 char_u *str; 1079 { 1080 do_arglist(str, AL_SET, 0); 1081 } 1082 #endif 1083 1084 /* 1085 * "what" == AL_SET: Redefine the argument list to 'str'. 1086 * "what" == AL_ADD: add files in 'str' to the argument list after "after". 1087 * "what" == AL_DEL: remove files in 'str' from the argument list. 1088 * 1089 * Return FAIL for failure, OK otherwise. 1090 */ 1091 /*ARGSUSED*/ 1092 static int 1093 do_arglist(str, what, after) 1094 char_u *str; 1095 int what; 1096 int after; /* 0 means before first one */ 1097 { 1098 garray_T new_ga; 1099 int exp_count; 1100 char_u **exp_files; 1101 int i; 1102 #ifdef FEAT_LISTCMDS 1103 char_u *p; 1104 int match; 1105 #endif 1106 1107 /* 1108 * Collect all file name arguments in "new_ga". 1109 */ 1110 ga_init2(&new_ga, (int)sizeof(char_u *), 20); 1111 while (*str) 1112 { 1113 if (ga_grow(&new_ga, 1) == FAIL) 1114 { 1115 ga_clear(&new_ga); 1116 return FAIL; 1117 } 1118 ((char_u **)new_ga.ga_data)[new_ga.ga_len++] = str; 1119 --new_ga.ga_room; 1120 1121 /* Isolate one argument, change it in-place, put a NUL after it. */ 1122 str = do_one_arg(str); 1123 } 1124 1125 #ifdef FEAT_LISTCMDS 1126 if (what == AL_DEL) 1127 { 1128 regmatch_T regmatch; 1129 int didone; 1130 1131 /* 1132 * Delete the items: use each item as a regexp and find a match in the 1133 * argument list. 1134 */ 1135 #ifdef CASE_INSENSITIVE_FILENAME 1136 regmatch.rm_ic = TRUE; /* Always ignore case */ 1137 #else 1138 regmatch.rm_ic = FALSE; /* Never ignore case */ 1139 #endif 1140 for (i = 0; i < new_ga.ga_len && !got_int; ++i) 1141 { 1142 p = ((char_u **)new_ga.ga_data)[i]; 1143 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE); 1144 if (p == NULL) 1145 break; 1146 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0); 1147 if (regmatch.regprog == NULL) 1148 { 1149 vim_free(p); 1150 break; 1151 } 1152 1153 didone = FALSE; 1154 for (match = 0; match < ARGCOUNT; ++match) 1155 if (vim_regexec(®match, alist_name(&ARGLIST[match]), 1156 (colnr_T)0)) 1157 { 1158 didone = TRUE; 1159 vim_free(ARGLIST[match].ae_fname); 1160 mch_memmove(ARGLIST + match, ARGLIST + match + 1, 1161 (ARGCOUNT - match - 1) * sizeof(aentry_T)); 1162 --ALIST(curwin)->al_ga.ga_len; 1163 ++ALIST(curwin)->al_ga.ga_room; 1164 if (curwin->w_arg_idx > match) 1165 --curwin->w_arg_idx; 1166 --match; 1167 } 1168 1169 vim_free(regmatch.regprog); 1170 vim_free(p); 1171 if (!didone) 1172 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]); 1173 } 1174 ga_clear(&new_ga); 1175 } 1176 else 1177 #endif 1178 { 1179 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data, 1180 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND); 1181 ga_clear(&new_ga); 1182 if (i == FAIL) 1183 return FAIL; 1184 if (exp_count == 0) 1185 { 1186 EMSG(_(e_nomatch)); 1187 return FAIL; 1188 } 1189 1190 #ifdef FEAT_LISTCMDS 1191 if (what == AL_ADD) 1192 { 1193 (void)alist_add_list(exp_count, exp_files, after); 1194 vim_free(exp_files); 1195 } 1196 else /* what == AL_SET */ 1197 #endif 1198 alist_set(ALIST(curwin), exp_count, exp_files, FALSE); 1199 } 1200 1201 alist_check_arg_idx(); 1202 1203 return OK; 1204 } 1205 1206 /* 1207 * Check the validity of the arg_idx for each other window. 1208 */ 1209 static void 1210 alist_check_arg_idx() 1211 { 1212 #ifdef FEAT_WINDOWS 1213 win_T *win; 1214 1215 for (win = firstwin; win != NULL; win = win->w_next) 1216 if (win->w_alist == curwin->w_alist) 1217 check_arg_idx(win); 1218 #else 1219 check_arg_idx(curwin); 1220 #endif 1221 } 1222 1223 /* 1224 * Check if window "win" is editing the w_arg_idx file in its argument list. 1225 */ 1226 void 1227 check_arg_idx(win) 1228 win_T *win; 1229 { 1230 if (WARGCOUNT(win) > 1 1231 && (win->w_arg_idx >= WARGCOUNT(win) 1232 || (win->w_buffer->b_fnum 1233 != WARGLIST(win)[win->w_arg_idx].ae_fnum 1234 && (win->w_buffer->b_ffname == NULL 1235 || !(fullpathcmp( 1236 alist_name(&WARGLIST(win)[win->w_arg_idx]), 1237 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))) 1238 { 1239 /* We are not editing the current entry in the argument list. 1240 * Set "arg_had_last" if we are editing the last one. */ 1241 win->w_arg_idx_invalid = TRUE; 1242 if (win->w_arg_idx != WARGCOUNT(win) - 1 1243 && arg_had_last == FALSE 1244 #ifdef FEAT_WINDOWS 1245 && ALIST(win) == &global_alist 1246 #endif 1247 && GARGCOUNT > 0 1248 && win->w_arg_idx < GARGCOUNT 1249 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum 1250 || (win->w_buffer->b_ffname != NULL 1251 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]), 1252 win->w_buffer->b_ffname, TRUE) & FPC_SAME)))) 1253 arg_had_last = TRUE; 1254 } 1255 else 1256 { 1257 /* We are editing the current entry in the argument list. 1258 * Set "arg_had_last" if it's also the last one */ 1259 win->w_arg_idx_invalid = FALSE; 1260 if (win->w_arg_idx == WARGCOUNT(win) - 1 1261 #ifdef FEAT_WINDOWS 1262 && win->w_alist == &global_alist 1263 #endif 1264 ) 1265 arg_had_last = TRUE; 1266 } 1267 } 1268 1269 /* 1270 * ":args", ":argslocal" and ":argsglobal". 1271 */ 1272 void 1273 ex_args(eap) 1274 exarg_T *eap; 1275 { 1276 int i; 1277 1278 if (eap->cmdidx != CMD_args) 1279 { 1280 #if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS) 1281 alist_unlink(ALIST(curwin)); 1282 if (eap->cmdidx == CMD_argglobal) 1283 ALIST(curwin) = &global_alist; 1284 else /* eap->cmdidx == CMD_arglocal */ 1285 alist_new(); 1286 #else 1287 ex_ni(eap); 1288 return; 1289 #endif 1290 } 1291 1292 if (!ends_excmd(*eap->arg)) 1293 { 1294 /* 1295 * ":args file ..": define new argument list, handle like ":next" 1296 * Also for ":argslocal file .." and ":argsglobal file ..". 1297 */ 1298 ex_next(eap); 1299 } 1300 else 1301 #if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS) 1302 if (eap->cmdidx == CMD_args) 1303 #endif 1304 { 1305 /* 1306 * ":args": list arguments. 1307 */ 1308 if (ARGCOUNT > 0) 1309 { 1310 /* Overwrite the command, for a short list there is no scrolling 1311 * required and no wait_return(). */ 1312 gotocmdline(TRUE); 1313 for (i = 0; i < ARGCOUNT; ++i) 1314 { 1315 if (i == curwin->w_arg_idx) 1316 msg_putchar('['); 1317 msg_outtrans(alist_name(&ARGLIST[i])); 1318 if (i == curwin->w_arg_idx) 1319 msg_putchar(']'); 1320 msg_putchar(' '); 1321 } 1322 } 1323 } 1324 #if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS) 1325 else if (eap->cmdidx == CMD_arglocal) 1326 { 1327 garray_T *gap = &curwin->w_alist->al_ga; 1328 1329 /* 1330 * ":argslocal": make a local copy of the global argument list. 1331 */ 1332 if (ga_grow(gap, GARGCOUNT) == OK) 1333 for (i = 0; i < GARGCOUNT; ++i) 1334 if (GARGLIST[i].ae_fname != NULL) 1335 { 1336 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname = 1337 vim_strsave(GARGLIST[i].ae_fname); 1338 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum = 1339 GARGLIST[i].ae_fnum; 1340 ++gap->ga_len; 1341 --gap->ga_room; 1342 } 1343 } 1344 #endif 1345 } 1346 1347 /* 1348 * ":previous", ":sprevious", ":Next" and ":sNext". 1349 */ 1350 void 1351 ex_previous(eap) 1352 exarg_T *eap; 1353 { 1354 /* If past the last one already, go to the last one. */ 1355 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT) 1356 do_argfile(eap, ARGCOUNT - 1); 1357 else 1358 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2); 1359 } 1360 1361 /* 1362 * ":rewind", ":first", ":sfirst" and ":srewind". 1363 */ 1364 void 1365 ex_rewind(eap) 1366 exarg_T *eap; 1367 { 1368 do_argfile(eap, 0); 1369 } 1370 1371 /* 1372 * ":last" and ":slast". 1373 */ 1374 void 1375 ex_last(eap) 1376 exarg_T *eap; 1377 { 1378 do_argfile(eap, ARGCOUNT - 1); 1379 } 1380 1381 /* 1382 * ":argument" and ":sargument". 1383 */ 1384 void 1385 ex_argument(eap) 1386 exarg_T *eap; 1387 { 1388 int i; 1389 1390 if (eap->addr_count > 0) 1391 i = eap->line2 - 1; 1392 else 1393 i = curwin->w_arg_idx; 1394 do_argfile(eap, i); 1395 } 1396 1397 /* 1398 * Edit file "argn" of the argument lists. 1399 */ 1400 void 1401 do_argfile(eap, argn) 1402 exarg_T *eap; 1403 int argn; 1404 { 1405 int other; 1406 char_u *p; 1407 1408 if (argn < 0 || argn >= ARGCOUNT) 1409 { 1410 if (ARGCOUNT <= 1) 1411 EMSG(_("E163: There is only one file to edit")); 1412 else if (argn < 0) 1413 EMSG(_("E164: Cannot go before first file")); 1414 else 1415 EMSG(_("E165: Cannot go beyond last file")); 1416 } 1417 else 1418 { 1419 setpcmark(); 1420 #ifdef FEAT_GUI 1421 need_mouse_correct = TRUE; 1422 #endif 1423 1424 #ifdef FEAT_WINDOWS 1425 if (*eap->cmd == 's') /* split window first */ 1426 { 1427 if (win_split(0, 0) == FAIL) 1428 return; 1429 # ifdef FEAT_SCROLLBIND 1430 curwin->w_p_scb = FALSE; 1431 # endif 1432 } 1433 else 1434 #endif 1435 { 1436 /* 1437 * if 'hidden' set, only check for changed file when re-editing 1438 * the same buffer 1439 */ 1440 other = TRUE; 1441 if (P_HID(curbuf)) 1442 { 1443 p = fix_fname(alist_name(&ARGLIST[argn])); 1444 other = otherfile(p); 1445 vim_free(p); 1446 } 1447 if ((!P_HID(curbuf) || !other) 1448 && check_changed(curbuf, TRUE, !other, eap->forceit, FALSE)) 1449 return; 1450 } 1451 1452 curwin->w_arg_idx = argn; 1453 if (argn == ARGCOUNT - 1 1454 #ifdef FEAT_WINDOWS 1455 && curwin->w_alist == &global_alist 1456 #endif 1457 ) 1458 arg_had_last = TRUE; 1459 1460 /* Edit the file; always use the last known line number. */ 1461 (void)do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL, 1462 eap, ECMD_LAST, 1463 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0) + 1464 (eap->forceit ? ECMD_FORCEIT : 0)); 1465 1466 /* like Vi: set the mark where the cursor is in the file. */ 1467 if (eap->cmdidx != CMD_argdo) 1468 setmark('\''); 1469 } 1470 } 1471 1472 /* 1473 * ":next", and commands that behave like it. 1474 */ 1475 void 1476 ex_next(eap) 1477 exarg_T *eap; 1478 { 1479 int i; 1480 1481 /* 1482 * check for changed buffer now, if this fails the argument list is not 1483 * redefined. 1484 */ 1485 if ( P_HID(curbuf) 1486 || eap->cmdidx == CMD_snext 1487 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE)) 1488 { 1489 if (*eap->arg != NUL) /* redefine file list */ 1490 { 1491 if (do_arglist(eap->arg, AL_SET, 0) == FAIL) 1492 return; 1493 i = 0; 1494 } 1495 else 1496 i = curwin->w_arg_idx + (int)eap->line2; 1497 do_argfile(eap, i); 1498 } 1499 } 1500 1501 #ifdef FEAT_LISTCMDS 1502 /* 1503 * ":argedit" 1504 */ 1505 void 1506 ex_argedit(eap) 1507 exarg_T *eap; 1508 { 1509 int fnum; 1510 int i; 1511 char_u *s; 1512 1513 /* Add the argument to the buffer list and get the buffer number. */ 1514 fnum = buflist_add(eap->arg, BLN_LISTED); 1515 1516 /* Check if this argument is already in the argument list. */ 1517 for (i = 0; i < ARGCOUNT; ++i) 1518 if (ARGLIST[i].ae_fnum == fnum) 1519 break; 1520 if (i == ARGCOUNT) 1521 { 1522 /* Can't find it, add it to the argument list. */ 1523 s = vim_strsave(eap->arg); 1524 if (s == NULL) 1525 return; 1526 i = alist_add_list(1, &s, 1527 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1); 1528 if (i < 0) 1529 return; 1530 curwin->w_arg_idx = i; 1531 } 1532 1533 alist_check_arg_idx(); 1534 1535 /* Edit the argument. */ 1536 do_argfile(eap, i); 1537 } 1538 1539 /* 1540 * ":argadd" 1541 */ 1542 void 1543 ex_argadd(eap) 1544 exarg_T *eap; 1545 { 1546 do_arglist(eap->arg, AL_ADD, 1547 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1); 1548 #ifdef FEAT_TITLE 1549 maketitle(); 1550 #endif 1551 } 1552 1553 /* 1554 * ":argdelete" 1555 */ 1556 void 1557 ex_argdelete(eap) 1558 exarg_T *eap; 1559 { 1560 int i; 1561 int n; 1562 1563 if (eap->addr_count > 0) 1564 { 1565 /* ":1,4argdel": Delete all arguments in the range. */ 1566 if (eap->line2 > ARGCOUNT) 1567 eap->line2 = ARGCOUNT; 1568 n = eap->line2 - eap->line1 + 1; 1569 if (*eap->arg != NUL || n <= 0) 1570 EMSG(_(e_invarg)); 1571 else 1572 { 1573 for (i = eap->line1; i <= eap->line2; ++i) 1574 vim_free(ARGLIST[i - 1].ae_fname); 1575 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2, 1576 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T))); 1577 ALIST(curwin)->al_ga.ga_len -= n; 1578 ALIST(curwin)->al_ga.ga_room += n; 1579 if (curwin->w_arg_idx >= eap->line2) 1580 curwin->w_arg_idx -= n; 1581 else if (curwin->w_arg_idx > eap->line1) 1582 curwin->w_arg_idx = eap->line1; 1583 } 1584 } 1585 else if (*eap->arg == NUL) 1586 EMSG(_(e_argreq)); 1587 else 1588 do_arglist(eap->arg, AL_DEL, 0); 1589 #ifdef FEAT_TITLE 1590 maketitle(); 1591 #endif 1592 } 1593 1594 /* 1595 * ":argdo", ":windo", ":bufdo" 1596 */ 1597 void 1598 ex_listdo(eap) 1599 exarg_T *eap; 1600 { 1601 int i; 1602 #ifdef FEAT_WINDOWS 1603 win_T *win; 1604 #endif 1605 buf_T *buf; 1606 int next_fnum = 0; 1607 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL) 1608 char_u *save_ei = NULL; 1609 char_u *new_ei; 1610 #endif 1611 1612 #ifndef FEAT_WINDOWS 1613 if (eap->cmdidx == CMD_windo) 1614 { 1615 ex_ni(eap); 1616 return; 1617 } 1618 #endif 1619 1620 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL) 1621 if (eap->cmdidx != CMD_windo) 1622 { 1623 /* Add "Syntax" to 'eventignore' to skip loading syntax highlighting 1624 * for every buffer loaded into the window. A considerable speed 1625 * improvement. */ 1626 save_ei = vim_strsave(p_ei); 1627 if (save_ei != NULL) 1628 { 1629 new_ei = vim_strnsave(p_ei, (int)STRLEN(p_ei) + 8); 1630 if (new_ei != NULL) 1631 { 1632 STRCAT(new_ei, ",Syntax"); 1633 set_string_option_direct((char_u *)"ei", -1, new_ei, OPT_FREE); 1634 vim_free(new_ei); 1635 } 1636 } 1637 } 1638 #endif 1639 1640 if (eap->cmdidx == CMD_windo 1641 || P_HID(curbuf) 1642 || !check_changed(curbuf, TRUE, FALSE, eap->forceit, FALSE)) 1643 { 1644 /* start at the first argument/window/buffer */ 1645 i = 0; 1646 #ifdef FEAT_WINDOWS 1647 win = firstwin; 1648 #endif 1649 /* set pcmark now */ 1650 if (eap->cmdidx == CMD_bufdo) 1651 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0); 1652 else 1653 setpcmark(); 1654 listcmd_busy = TRUE; /* avoids setting pcmark below */ 1655 1656 while (!got_int) 1657 { 1658 if (eap->cmdidx == CMD_argdo) 1659 { 1660 /* go to argument "i" */ 1661 if (i == ARGCOUNT) 1662 break; 1663 /* Don't call do_argfile() when already there, it will try 1664 * reloading the file. */ 1665 if (curwin->w_arg_idx != i) 1666 do_argfile(eap, i); 1667 if (curwin->w_arg_idx != i) 1668 break; 1669 ++i; 1670 } 1671 #ifdef FEAT_WINDOWS 1672 else if (eap->cmdidx == CMD_windo) 1673 { 1674 /* go to window "win" */ 1675 if (!win_valid(win)) 1676 break; 1677 win_goto(win); 1678 win = win->w_next; 1679 } 1680 #endif 1681 else if (eap->cmdidx == CMD_bufdo) 1682 { 1683 /* Remember the number of the next listed buffer, in case 1684 * ":bwipe" is used or autocommands do something strange. */ 1685 next_fnum = -1; 1686 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next) 1687 if (buf->b_p_bl) 1688 { 1689 next_fnum = buf->b_fnum; 1690 break; 1691 } 1692 } 1693 1694 /* execute the command */ 1695 do_cmdline(eap->arg, eap->getline, eap->cookie, 1696 DOCMD_VERBOSE + DOCMD_NOWAIT); 1697 1698 if (eap->cmdidx == CMD_bufdo) 1699 { 1700 /* Done? */ 1701 if (next_fnum < 0) 1702 break; 1703 /* Check if the buffer still exists. */ 1704 for (buf = firstbuf; buf != NULL; buf = buf->b_next) 1705 if (buf->b_fnum == next_fnum) 1706 break; 1707 if (buf == NULL) 1708 break; 1709 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum); 1710 /* If autocommands took us elsewhere, quit here */ 1711 if (curbuf->b_fnum != next_fnum) 1712 break; 1713 } 1714 1715 if (eap->cmdidx == CMD_windo) 1716 { 1717 validate_cursor(); /* cursor may have moved */ 1718 #ifdef FEAT_SCROLLBIND 1719 /* required when 'scrollbind' has been set */ 1720 if (curwin->w_p_scb) 1721 do_check_scrollbind(TRUE); 1722 #endif 1723 } 1724 } 1725 listcmd_busy = FALSE; 1726 } 1727 1728 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL) 1729 if (save_ei != NULL) 1730 { 1731 set_string_option_direct((char_u *)"ei", -1, save_ei, OPT_FREE); 1732 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn, 1733 curbuf->b_fname, TRUE, curbuf); 1734 vim_free(save_ei); 1735 } 1736 #endif 1737 } 1738 1739 /* 1740 * Add files[count] to the arglist of the current window after arg "after". 1741 * The file names in files[count] must have been allocated and are taken over. 1742 * Files[] itself is not taken over. 1743 * Returns index of first added argument. Returns -1 when failed (out of mem). 1744 */ 1745 static int 1746 alist_add_list(count, files, after) 1747 int count; 1748 char_u **files; 1749 int after; /* where to add: 0 = before first one */ 1750 { 1751 int i; 1752 1753 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK) 1754 { 1755 if (after < 0) 1756 after = 0; 1757 if (after > ARGCOUNT) 1758 after = ARGCOUNT; 1759 if (after < ARGCOUNT) 1760 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]), 1761 (ARGCOUNT - after) * sizeof(aentry_T)); 1762 for (i = 0; i < count; ++i) 1763 { 1764 ARGLIST[after + i].ae_fname = files[i]; 1765 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED); 1766 } 1767 ALIST(curwin)->al_ga.ga_len += count; 1768 ALIST(curwin)->al_ga.ga_room -= count; 1769 if (curwin->w_arg_idx >= after) 1770 ++curwin->w_arg_idx; 1771 return after; 1772 } 1773 1774 for (i = 0; i < count; ++i) 1775 vim_free(files[i]); 1776 return -1; 1777 } 1778 1779 #endif /* FEAT_LISTCMDS */ 1780 1781 #ifdef FEAT_EVAL 1782 /* 1783 * ":compiler[!] {name}" 1784 */ 1785 void 1786 ex_compiler(eap) 1787 exarg_T *eap; 1788 { 1789 char_u *buf; 1790 char_u *old_cur_comp = NULL; 1791 char_u *p; 1792 1793 if (*eap->arg == NUL) 1794 { 1795 /* List all compiler scripts. */ 1796 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')"); 1797 /* ) keep the indenter happy... */ 1798 } 1799 else 1800 { 1801 buf = alloc((unsigned)(STRLEN(eap->arg) + 14)); 1802 if (buf != NULL) 1803 { 1804 if (eap->forceit) 1805 { 1806 /* ":compiler! {name}" sets global options */ 1807 do_cmdline_cmd((char_u *) 1808 "command -nargs=* CompilerSet set <args>"); 1809 } 1810 else 1811 { 1812 /* ":compiler! {name}" sets local options. 1813 * To remain backwards compatible "current_compiler" is always 1814 * used. A user's compiler plugin may set it, the distributed 1815 * plugin will then skip the settings. Afterwards set 1816 * "b:current_compiler" and restore "current_compiler". */ 1817 old_cur_comp = get_var_value((char_u *)"current_compiler"); 1818 if (old_cur_comp != NULL) 1819 old_cur_comp = vim_strsave(old_cur_comp); 1820 do_cmdline_cmd((char_u *) 1821 "command -nargs=* CompilerSet setlocal <args>"); 1822 } 1823 do_unlet((char_u *)"current_compiler"); 1824 do_unlet((char_u *)"b:current_compiler"); 1825 1826 sprintf((char *)buf, "compiler/%s.vim", eap->arg); 1827 if (cmd_runtime(buf, TRUE) == FAIL) 1828 EMSG2(_("E666: compiler not supported: %s"), eap->arg); 1829 vim_free(buf); 1830 1831 do_cmdline_cmd((char_u *)":delcommand CompilerSet"); 1832 1833 /* Set "b:current_compiler" from "current_compiler". */ 1834 p = get_var_value((char_u *)"current_compiler"); 1835 if (p != NULL) 1836 set_internal_string_var((char_u *)"b:current_compiler", p); 1837 1838 /* Restore "current_compiler" for ":compiler {name}". */ 1839 if (!eap->forceit) 1840 { 1841 if (old_cur_comp != NULL) 1842 { 1843 set_internal_string_var((char_u *)"current_compiler", 1844 old_cur_comp); 1845 vim_free(old_cur_comp); 1846 } 1847 else 1848 do_unlet((char_u *)"current_compiler"); 1849 } 1850 } 1851 } 1852 } 1853 #endif 1854 1855 /* 1856 * ":runtime {name}" 1857 */ 1858 void 1859 ex_runtime(eap) 1860 exarg_T *eap; 1861 { 1862 cmd_runtime(eap->arg, eap->forceit); 1863 } 1864 1865 static void source_callback __ARGS((char_u *fname)); 1866 1867 static void 1868 source_callback(fname) 1869 char_u *fname; 1870 { 1871 (void)do_source(fname, FALSE, FALSE); 1872 } 1873 1874 /* 1875 * Source the file "name" from all directories in 'runtimepath'. 1876 * "name" can contain wildcards. 1877 * When "all" is TRUE, source all files, otherwise only the first one. 1878 * return FAIL when no file could be sourced, OK otherwise. 1879 */ 1880 int 1881 cmd_runtime(name, all) 1882 char_u *name; 1883 int all; 1884 { 1885 return do_in_runtimepath(name, all, source_callback); 1886 } 1887 1888 /* 1889 * Find "name" in 'runtimepath'. When found, call the "callback" function for 1890 * it. 1891 * When "all" is TRUE repeat for all matches, otherwise only the first one is 1892 * used. 1893 * Returns OK when at least one match found, FAIL otherwise. 1894 */ 1895 int 1896 do_in_runtimepath(name, all, callback) 1897 char_u *name; 1898 int all; 1899 void (*callback)__ARGS((char_u *fname)); 1900 { 1901 char_u *rtp; 1902 char_u *np; 1903 char_u *buf; 1904 char_u *rtp_copy; 1905 char_u *tail; 1906 int num_files; 1907 char_u **files; 1908 int i; 1909 int did_one = FALSE; 1910 #ifdef AMIGA 1911 struct Process *proc = (struct Process *)FindTask(0L); 1912 APTR save_winptr = proc->pr_WindowPtr; 1913 1914 /* Avoid a requester here for a volume that doesn't exist. */ 1915 proc->pr_WindowPtr = (APTR)-1L; 1916 #endif 1917 1918 /* Make a copy of 'runtimepath'. Invoking the callback may change the 1919 * value. */ 1920 rtp_copy = vim_strsave(p_rtp); 1921 buf = alloc(MAXPATHL); 1922 if (buf != NULL && rtp_copy != NULL) 1923 { 1924 if (p_verbose > 1) 1925 smsg((char_u *)_("Searching for \"%s\" in \"%s\""), 1926 (char *)name, (char *)p_rtp); 1927 /* Loop over all entries in 'runtimepath'. */ 1928 rtp = rtp_copy; 1929 while (*rtp != NUL && (all || !did_one)) 1930 { 1931 /* Copy the path from 'runtimepath' to buf[]. */ 1932 copy_option_part(&rtp, buf, MAXPATHL, ","); 1933 if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL) 1934 { 1935 add_pathsep(buf); 1936 tail = buf + STRLEN(buf); 1937 1938 /* Loop over all patterns in "name" */ 1939 np = name; 1940 while (*np != NUL && (all || !did_one)) 1941 { 1942 /* Append the pattern from "name" to buf[]. */ 1943 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)), 1944 "\t "); 1945 1946 if (p_verbose > 2) 1947 msg_str((char_u *)_("Searching for \"%s\""), buf); 1948 1949 /* Expand wildcards, invoke the callback for each match. */ 1950 if (gen_expand_wildcards(1, &buf, &num_files, &files, 1951 EW_FILE) == OK) 1952 { 1953 for (i = 0; i < num_files; ++i) 1954 { 1955 (*callback)(files[i]); 1956 did_one = TRUE; 1957 if (!all) 1958 break; 1959 } 1960 FreeWild(num_files, files); 1961 } 1962 } 1963 } 1964 } 1965 } 1966 vim_free(buf); 1967 vim_free(rtp_copy); 1968 if (p_verbose > 0 && !did_one) 1969 msg_str((char_u *)_("not found in 'runtimepath': \"%s\""), name); 1970 1971 #ifdef AMIGA 1972 proc->pr_WindowPtr = save_winptr; 1973 #endif 1974 1975 return did_one ? OK : FAIL; 1976 } 1977 1978 #if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD) 1979 /* 1980 * ":options" 1981 */ 1982 /*ARGSUSED*/ 1983 void 1984 ex_options(eap) 1985 exarg_T *eap; 1986 { 1987 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL); 1988 } 1989 #endif 1990 1991 /* 1992 * ":source {fname}" 1993 */ 1994 void 1995 ex_source(eap) 1996 exarg_T *eap; 1997 { 1998 #ifdef FEAT_BROWSE 1999 if (cmdmod.browse) 2000 { 2001 char_u *fname = NULL; 2002 2003 fname = do_browse(FALSE, (char_u *)_("Source Vim script"), eap->arg, 2004 NULL, NULL, BROWSE_FILTER_MACROS, NULL); 2005 if (fname != NULL) 2006 { 2007 cmd_source(fname, eap); 2008 vim_free(fname); 2009 } 2010 } 2011 else 2012 #endif 2013 cmd_source(eap->arg, eap); 2014 } 2015 2016 static void 2017 cmd_source(fname, eap) 2018 char_u *fname; 2019 exarg_T *eap; 2020 { 2021 if (*fname == NUL) 2022 EMSG(_(e_argreq)); 2023 2024 /* ":source!" read vi commands */ 2025 else if (eap != NULL && eap->forceit) 2026 /* Need to execute the commands directly when: 2027 * - ":g" command busy 2028 * - after ":argdo", ":windo" or ":bufdo" 2029 * - another command follows 2030 * - inside a loop 2031 */ 2032 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL 2033 #ifdef FEAT_EVAL 2034 || eap->cstack->cs_idx >= 0 2035 #endif 2036 ); 2037 2038 /* ":source" read ex commands */ 2039 else if (do_source(fname, FALSE, FALSE) == FAIL) 2040 EMSG2(_(e_notopen), fname); 2041 } 2042 2043 /* 2044 * ":source" and associated commands. 2045 */ 2046 /* 2047 * Structure used to store info for each sourced file. 2048 * It is shared between do_source() and getsourceline(). 2049 * This is required, because it needs to be handed to do_cmdline() and 2050 * sourcing can be done recursively. 2051 */ 2052 struct source_cookie 2053 { 2054 FILE *fp; /* opened file for sourcing */ 2055 char_u *nextline; /* if not NULL: line that was read ahead */ 2056 int finished; /* ":finish" used */ 2057 #if defined (USE_CRNL) || defined (USE_CR) 2058 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */ 2059 int error; /* TRUE if LF found after CR-LF */ 2060 #endif 2061 #ifdef FEAT_EVAL 2062 linenr_T breakpoint; /* next line with breakpoint or zero */ 2063 char_u *fname; /* name of sourced file */ 2064 int dbg_tick; /* debug_tick when breakpoint was set */ 2065 int level; /* top nesting level of sourced file */ 2066 #endif 2067 #ifdef FEAT_MBYTE 2068 vimconv_T conv; /* type of conversion */ 2069 #endif 2070 }; 2071 2072 #ifdef FEAT_EVAL 2073 /* 2074 * Return the address holding the next breakpoint line for a source cookie. 2075 */ 2076 linenr_T * 2077 source_breakpoint(cookie) 2078 void *cookie; 2079 { 2080 return &((struct source_cookie *)cookie)->breakpoint; 2081 } 2082 2083 /* 2084 * Return the address holding the debug tick for a source cookie. 2085 */ 2086 int * 2087 source_dbg_tick(cookie) 2088 void *cookie; 2089 { 2090 return &((struct source_cookie *)cookie)->dbg_tick; 2091 } 2092 2093 /* 2094 * Return the nesting level for a source cookie. 2095 */ 2096 int 2097 source_level(cookie) 2098 void *cookie; 2099 { 2100 return ((struct source_cookie *)cookie)->level; 2101 } 2102 #endif 2103 2104 static char_u *get_one_sourceline __ARGS((struct source_cookie *sp)); 2105 2106 #ifdef FEAT_EVAL 2107 /* Growarray to store the names of sourced scripts. 2108 * For Unix also store the dev/ino, so that we don't have to stat() each 2109 * script when going through the list. */ 2110 struct scriptstuff 2111 { 2112 char_u *name; 2113 # ifdef UNIX 2114 int dev; 2115 ino_t ino; 2116 # endif 2117 }; 2118 static garray_T script_names = {0, 0, sizeof(struct scriptstuff), 4, NULL}; 2119 #define SCRIPT_NAME(id) (((struct scriptstuff *)script_names.ga_data)[(id) - 1].name) 2120 #define SCRIPT_DEV(id) (((struct scriptstuff *)script_names.ga_data)[(id) - 1].dev) 2121 #define SCRIPT_INO(id) (((struct scriptstuff *)script_names.ga_data)[(id) - 1].ino) 2122 #endif 2123 2124 #if defined(WIN32) && defined(FEAT_CSCOPE) 2125 static FILE *fopen_noinh_readbin __ARGS((char *filename)); 2126 2127 /* 2128 * Special function to open a file without handle inheritance. 2129 */ 2130 static FILE * 2131 fopen_noinh_readbin(filename) 2132 char *filename; 2133 { 2134 int fd_tmp = open(filename, O_RDONLY | O_BINARY | O_NOINHERIT); 2135 2136 if (fd_tmp == -1) 2137 return NULL; 2138 return fdopen(fd_tmp, READBIN); 2139 } 2140 #endif 2141 2142 2143 /* 2144 * do_source: Read the file "fname" and execute its lines as EX commands. 2145 * 2146 * This function may be called recursively! 2147 * 2148 * return FAIL if file could not be opened, OK otherwise 2149 */ 2150 int 2151 do_source(fname, check_other, is_vimrc) 2152 char_u *fname; 2153 int check_other; /* check for .vimrc and _vimrc */ 2154 int is_vimrc; /* call vimrc_found() when file exists */ 2155 { 2156 struct source_cookie cookie; 2157 char_u *save_sourcing_name; 2158 linenr_T save_sourcing_lnum; 2159 char_u *p; 2160 char_u *fname_exp; 2161 int retval = FAIL; 2162 #ifdef FEAT_EVAL 2163 scid_T save_current_SID; 2164 static scid_T last_current_SID = 0; 2165 void *save_funccalp; 2166 int save_debug_break_level = debug_break_level; 2167 # ifdef UNIX 2168 struct stat st; 2169 int stat_ok; 2170 # endif 2171 #endif 2172 #ifdef STARTUPTIME 2173 struct timeval tv_rel; 2174 struct timeval tv_start; 2175 #endif 2176 2177 #ifdef RISCOS 2178 p = mch_munge_fname(fname); 2179 #else 2180 p = expand_env_save(fname); 2181 #endif 2182 if (p == NULL) 2183 return retval; 2184 fname_exp = fix_fname(p); 2185 vim_free(p); 2186 if (fname_exp == NULL) 2187 return retval; 2188 #ifdef MACOS_CLASSIC 2189 slash_n_colon_adjust(fname_exp); 2190 #endif 2191 if (mch_isdir(fname_exp)) 2192 { 2193 msg_str((char_u *)_("Cannot source a directory: \"%s\""), fname); 2194 goto theend; 2195 } 2196 2197 #if defined(WIN32) && defined(FEAT_CSCOPE) 2198 cookie.fp = fopen_noinh_readbin((char *)fname_exp); 2199 #else 2200 cookie.fp = mch_fopen((char *)fname_exp, READBIN); 2201 #endif 2202 if (cookie.fp == NULL && check_other) 2203 { 2204 /* 2205 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa, 2206 * and ".exrc" by "_exrc" or vice versa. 2207 */ 2208 p = gettail(fname_exp); 2209 if ((*p == '.' || *p == '_') 2210 && (STRICMP(p + 1, "vimrc") == 0 2211 || STRICMP(p + 1, "gvimrc") == 0 2212 || STRICMP(p + 1, "exrc") == 0)) 2213 { 2214 if (*p == '_') 2215 *p = '.'; 2216 else 2217 *p = '_'; 2218 #if defined(WIN32) && defined(FEAT_CSCOPE) 2219 cookie.fp = fopen_noinh_readbin((char *)fname_exp); 2220 #else 2221 cookie.fp = mch_fopen((char *)fname_exp, READBIN); 2222 #endif 2223 } 2224 } 2225 2226 if (cookie.fp == NULL) 2227 { 2228 if (p_verbose > 0) 2229 { 2230 if (sourcing_name == NULL) 2231 msg_str((char_u *)_("could not source \"%s\""), fname); 2232 else 2233 smsg((char_u *)_("line %ld: could not source \"%s\""), 2234 sourcing_lnum, fname); 2235 } 2236 goto theend; 2237 } 2238 2239 /* 2240 * The file exists. 2241 * - In verbose mode, give a message. 2242 * - For a vimrc file, may want to set 'compatible', call vimrc_found(). 2243 */ 2244 if (p_verbose > 1) 2245 { 2246 if (sourcing_name == NULL) 2247 msg_str((char_u *)_("sourcing \"%s\""), fname); 2248 else 2249 smsg((char_u *)_("line %ld: sourcing \"%s\""), 2250 sourcing_lnum, fname); 2251 } 2252 if (is_vimrc) 2253 vimrc_found(); 2254 2255 #ifdef USE_CRNL 2256 /* If no automatic file format: Set default to CR-NL. */ 2257 if (*p_ffs == NUL) 2258 cookie.fileformat = EOL_DOS; 2259 else 2260 cookie.fileformat = EOL_UNKNOWN; 2261 cookie.error = FALSE; 2262 #endif 2263 2264 #ifdef USE_CR 2265 /* If no automatic file format: Set default to CR. */ 2266 if (*p_ffs == NUL) 2267 cookie.fileformat = EOL_MAC; 2268 else 2269 cookie.fileformat = EOL_UNKNOWN; 2270 cookie.error = FALSE; 2271 #endif 2272 2273 cookie.nextline = NULL; 2274 cookie.finished = FALSE; 2275 2276 #ifdef FEAT_EVAL 2277 /* 2278 * Check if this script has a breakpoint. 2279 */ 2280 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0); 2281 cookie.fname = fname_exp; 2282 cookie.dbg_tick = debug_tick; 2283 2284 cookie.level = ex_nesting_level; 2285 #endif 2286 #ifdef FEAT_MBYTE 2287 cookie.conv.vc_type = CONV_NONE; /* no conversion */ 2288 2289 /* Try reading the first few bytes to check for a UTF-8 BOM. */ 2290 { 2291 char_u buf[3]; 2292 2293 if (fread((char *)buf, sizeof(char_u), (size_t)3, cookie.fp) 2294 == (size_t)3 2295 && buf[0] == 0xef && buf[1] == 0xbb && buf[2] == 0xbf) 2296 /* Found BOM, setup conversion and skip over it. */ 2297 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc); 2298 else 2299 /* No BOM found, rewind. */ 2300 fseek(cookie.fp, 0L, SEEK_SET); 2301 } 2302 #endif 2303 2304 /* 2305 * Keep the sourcing name/lnum, for recursive calls. 2306 */ 2307 save_sourcing_name = sourcing_name; 2308 sourcing_name = fname_exp; 2309 save_sourcing_lnum = sourcing_lnum; 2310 sourcing_lnum = 0; 2311 2312 #ifdef STARTUPTIME 2313 time_push(&tv_rel, &tv_start); 2314 #endif 2315 2316 #ifdef FEAT_EVAL 2317 /* 2318 * Check if this script was sourced before to finds its SID. 2319 * If it's new, generate a new SID. 2320 */ 2321 save_current_SID = current_SID; 2322 # ifdef UNIX 2323 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0); 2324 # endif 2325 for (current_SID = script_names.ga_len; current_SID > 0; --current_SID) 2326 if (SCRIPT_NAME(current_SID) != NULL 2327 && ( 2328 # ifdef UNIX 2329 /* compare dev/ino when possible, it catches symbolic 2330 * links */ 2331 (stat_ok && SCRIPT_DEV(current_SID) != -1) 2332 ? (SCRIPT_DEV(current_SID) == st.st_dev 2333 && SCRIPT_INO(current_SID) == st.st_ino) : 2334 # endif 2335 fnamecmp(SCRIPT_NAME(current_SID), fname_exp) == 0)) 2336 break; 2337 if (current_SID == 0) 2338 { 2339 current_SID = ++last_current_SID; 2340 if (ga_grow(&script_names, (int)(current_SID - script_names.ga_len)) 2341 == OK) 2342 { 2343 while (script_names.ga_len < current_SID) 2344 { 2345 SCRIPT_NAME(script_names.ga_len + 1) = NULL; 2346 ++script_names.ga_len; 2347 --script_names.ga_room; 2348 } 2349 SCRIPT_NAME(current_SID) = fname_exp; 2350 # ifdef UNIX 2351 if (stat_ok) 2352 { 2353 SCRIPT_DEV(current_SID) = st.st_dev; 2354 SCRIPT_INO(current_SID) = st.st_ino; 2355 } 2356 else 2357 SCRIPT_DEV(current_SID) = -1; 2358 # endif 2359 fname_exp = NULL; 2360 } 2361 /* Allocate the local script variables to use for this script. */ 2362 new_script_vars(current_SID); 2363 } 2364 2365 /* Don't use local function variables, if called from a function */ 2366 save_funccalp = save_funccal(); 2367 #endif 2368 2369 /* 2370 * Call do_cmdline, which will call getsourceline() to get the lines. 2371 */ 2372 do_cmdline(NULL, getsourceline, (void *)&cookie, 2373 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT); 2374 2375 retval = OK; 2376 fclose(cookie.fp); 2377 vim_free(cookie.nextline); 2378 #ifdef FEAT_MBYTE 2379 convert_setup(&cookie.conv, NULL, NULL); 2380 #endif 2381 2382 if (got_int) 2383 EMSG(_(e_interr)); 2384 sourcing_name = save_sourcing_name; 2385 sourcing_lnum = save_sourcing_lnum; 2386 #ifdef FEAT_EVAL 2387 current_SID = save_current_SID; 2388 restore_funccal(save_funccalp); 2389 #endif 2390 if (p_verbose > 1) 2391 { 2392 msg_str((char_u *)_("finished sourcing %s"), fname); 2393 if (sourcing_name != NULL) 2394 msg_str((char_u *)_("continuing in %s"), sourcing_name); 2395 } 2396 #ifdef STARTUPTIME 2397 # ifdef HAVE_SNPRINTF 2398 snprintf(IObuff, IOSIZE, "sourcing %s", fname); 2399 # else 2400 sprintf(IObuff, "sourcing %s", fname); 2401 # endif 2402 time_msg(IObuff, &tv_start); 2403 time_pop(&tv_rel); 2404 #endif 2405 2406 #ifdef FEAT_EVAL 2407 /* 2408 * After a "finish" in debug mode, need to break at first command of next 2409 * sourced file. 2410 */ 2411 if (save_debug_break_level > ex_nesting_level 2412 && debug_break_level == ex_nesting_level) 2413 ++debug_break_level; 2414 #endif 2415 2416 theend: 2417 vim_free(fname_exp); 2418 return retval; 2419 } 2420 2421 #if defined(FEAT_EVAL) || defined(PROTO) 2422 /* 2423 * ":scriptnames" 2424 */ 2425 /*ARGSUSED*/ 2426 void 2427 ex_scriptnames(eap) 2428 exarg_T *eap; 2429 { 2430 int i; 2431 2432 for (i = 1; i <= script_names.ga_len && !got_int; ++i) 2433 if (SCRIPT_NAME(i) != NULL) 2434 smsg((char_u *)"%3d: %s", i, SCRIPT_NAME(i)); 2435 } 2436 2437 # if defined(BACKSLASH_IN_FILENAME) || defined(PROTO) 2438 /* 2439 * Fix slashes in the list of script names for 'shellslash'. 2440 */ 2441 void 2442 scriptnames_slash_adjust() 2443 { 2444 int i; 2445 2446 for (i = 1; i <= script_names.ga_len; ++i) 2447 if (SCRIPT_NAME(i) != NULL) 2448 slash_adjust(SCRIPT_NAME(i)); 2449 } 2450 # endif 2451 2452 /* 2453 * Get a pointer to a script name. Used for ":verbose set". 2454 */ 2455 char_u * 2456 get_scriptname(id) 2457 scid_T id; 2458 { 2459 if (id == SID_MODELINE) 2460 return (char_u *)"modeline"; 2461 if (id == SID_CMDARG) 2462 return (char_u *)"--cmd argument"; 2463 if (id == SID_CARG) 2464 return (char_u *)"-c argument"; 2465 if (id == SID_ENV) 2466 return (char_u *)"environment variable"; 2467 return SCRIPT_NAME(id); 2468 } 2469 #endif 2470 2471 #if defined(USE_CR) || defined(PROTO) 2472 2473 # if defined(__MSL__) && (__MSL__ >= 22) 2474 /* 2475 * Newer version of the Metrowerks library handle DOS and UNIX files 2476 * without help. 2477 * Test with earlier versions, MSL 2.2 is the library supplied with 2478 * Codewarrior Pro 2. 2479 */ 2480 char * 2481 fgets_cr(s, n, stream) 2482 char *s; 2483 int n; 2484 FILE *stream; 2485 { 2486 return fgets(s, n, stream); 2487 } 2488 # else 2489 /* 2490 * Version of fgets() which also works for lines ending in a <CR> only 2491 * (Macintosh format). 2492 * For older versions of the Metrowerks library. 2493 * At least CodeWarrior 9 needed this code. 2494 */ 2495 char * 2496 fgets_cr(s, n, stream) 2497 char *s; 2498 int n; 2499 FILE *stream; 2500 { 2501 int c = 0; 2502 int char_read = 0; 2503 2504 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1) 2505 { 2506 c = fgetc(stream); 2507 s[char_read++] = c; 2508 /* If the file is in DOS format, we need to skip a NL after a CR. I 2509 * thought it was the other way around, but this appears to work... */ 2510 if (c == '\n') 2511 { 2512 c = fgetc(stream); 2513 if (c != '\r') 2514 ungetc(c, stream); 2515 } 2516 } 2517 2518 s[char_read] = 0; 2519 if (char_read == 0) 2520 return NULL; 2521 2522 if (feof(stream) && char_read == 1) 2523 return NULL; 2524 2525 return s; 2526 } 2527 # endif 2528 #endif 2529 2530 /* 2531 * Get one full line from a sourced file. 2532 * Called by do_cmdline() when it's called from do_source(). 2533 * 2534 * Return a pointer to the line in allocated memory. 2535 * Return NULL for end-of-file or some error. 2536 */ 2537 /* ARGSUSED */ 2538 char_u * 2539 getsourceline(c, cookie, indent) 2540 int c; /* not used */ 2541 void *cookie; 2542 int indent; /* not used */ 2543 { 2544 struct source_cookie *sp = (struct source_cookie *)cookie; 2545 char_u *line; 2546 char_u *p, *s; 2547 2548 #ifdef FEAT_EVAL 2549 /* If breakpoints have been added/deleted need to check for it. */ 2550 if (sp->dbg_tick < debug_tick) 2551 { 2552 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum); 2553 sp->dbg_tick = debug_tick; 2554 } 2555 #endif 2556 /* 2557 * Get current line. If there is a read-ahead line, use it, otherwise get 2558 * one now. 2559 */ 2560 if (sp->finished) 2561 line = NULL; 2562 else if (sp->nextline == NULL) 2563 line = get_one_sourceline(sp); 2564 else 2565 { 2566 line = sp->nextline; 2567 sp->nextline = NULL; 2568 ++sourcing_lnum; 2569 } 2570 2571 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't 2572 * contain the 'C' flag. */ 2573 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL)) 2574 { 2575 /* compensate for the one line read-ahead */ 2576 --sourcing_lnum; 2577 for (;;) 2578 { 2579 sp->nextline = get_one_sourceline(sp); 2580 if (sp->nextline == NULL) 2581 break; 2582 p = skipwhite(sp->nextline); 2583 if (*p != '\\') 2584 break; 2585 s = alloc((int)(STRLEN(line) + STRLEN(p))); 2586 if (s == NULL) /* out of memory */ 2587 break; 2588 STRCPY(s, line); 2589 STRCAT(s, p + 1); 2590 vim_free(line); 2591 line = s; 2592 vim_free(sp->nextline); 2593 } 2594 } 2595 2596 #ifdef FEAT_MBYTE 2597 if (line != NULL && sp->conv.vc_type != CONV_NONE) 2598 { 2599 /* Convert the encoding of the script line. */ 2600 s = string_convert(&sp->conv, line, NULL); 2601 if (s != NULL) 2602 { 2603 vim_free(line); 2604 line = s; 2605 } 2606 } 2607 #endif 2608 2609 #ifdef FEAT_EVAL 2610 /* Did we encounter a breakpoint? */ 2611 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum) 2612 { 2613 dbg_breakpoint(sp->fname, sourcing_lnum); 2614 /* Find next breakpoint. */ 2615 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum); 2616 sp->dbg_tick = debug_tick; 2617 } 2618 #endif 2619 2620 return line; 2621 } 2622 2623 static char_u * 2624 get_one_sourceline(sp) 2625 struct source_cookie *sp; 2626 { 2627 garray_T ga; 2628 int len; 2629 int c; 2630 char_u *buf; 2631 #ifdef USE_CRNL 2632 int has_cr; /* CR-LF found */ 2633 #endif 2634 #ifdef USE_CR 2635 char_u *scan; 2636 #endif 2637 int have_read = FALSE; 2638 2639 /* use a growarray to store the sourced line */ 2640 ga_init2(&ga, 1, 200); 2641 2642 /* 2643 * Loop until there is a finished line (or end-of-file). 2644 */ 2645 sourcing_lnum++; 2646 for (;;) 2647 { 2648 /* make room to read at least 80 (more) characters */ 2649 if (ga_grow(&ga, 80) == FAIL) 2650 break; 2651 buf = (char_u *)ga.ga_data; 2652 2653 #ifdef USE_CR 2654 if (sp->fileformat == EOL_MAC) 2655 { 2656 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_room, sp->fp) == NULL) 2657 break; 2658 } 2659 else 2660 #endif 2661 if (fgets((char *)buf + ga.ga_len, ga.ga_room, sp->fp) == NULL) 2662 break; 2663 len = (int)STRLEN(buf); 2664 #ifdef USE_CRNL 2665 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the 2666 * CTRL-Z by its own, or after a NL. */ 2667 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n')) 2668 && sp->fileformat == EOL_DOS 2669 && buf[len - 1] == Ctrl_Z) 2670 { 2671 buf[len - 1] = NUL; 2672 break; 2673 } 2674 #endif 2675 2676 #ifdef USE_CR 2677 /* If the read doesn't stop on a new line, and there's 2678 * some CR then we assume a Mac format */ 2679 if (sp->fileformat == EOL_UNKNOWN) 2680 { 2681 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL) 2682 sp->fileformat = EOL_MAC; 2683 else 2684 sp->fileformat = EOL_UNIX; 2685 } 2686 2687 if (sp->fileformat == EOL_MAC) 2688 { 2689 scan = vim_strchr(buf, '\r'); 2690 2691 if (scan != NULL) 2692 { 2693 *scan = '\n'; 2694 if (*(scan + 1) != 0) 2695 { 2696 *(scan + 1) = 0; 2697 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR); 2698 } 2699 } 2700 len = STRLEN(buf); 2701 } 2702 #endif 2703 2704 have_read = TRUE; 2705 ga.ga_room -= len - ga.ga_len; 2706 ga.ga_len = len; 2707 2708 /* If the line was longer than the buffer, read more. */ 2709 if (ga.ga_room == 1 && buf[len - 1] != '\n') 2710 continue; 2711 2712 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */ 2713 { 2714 #ifdef USE_CRNL 2715 has_cr = (len >= 2 && buf[len - 2] == '\r'); 2716 if (sp->fileformat == EOL_UNKNOWN) 2717 { 2718 if (has_cr) 2719 sp->fileformat = EOL_DOS; 2720 else 2721 sp->fileformat = EOL_UNIX; 2722 } 2723 2724 if (sp->fileformat == EOL_DOS) 2725 { 2726 if (has_cr) /* replace trailing CR */ 2727 { 2728 buf[len - 2] = '\n'; 2729 --len; 2730 --ga.ga_len; 2731 ++ga.ga_room; 2732 } 2733 else /* lines like ":map xx yy^M" will have failed */ 2734 { 2735 if (!sp->error) 2736 { 2737 msg_source(hl_attr(HLF_W)); 2738 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing")); 2739 } 2740 sp->error = TRUE; 2741 sp->fileformat = EOL_UNIX; 2742 } 2743 } 2744 #endif 2745 /* The '\n' is escaped if there is an odd number of ^V's just 2746 * before it, first set "c" just before the 'V's and then check 2747 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */ 2748 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--) 2749 ; 2750 if ((len & 1) != (c & 1)) /* escaped NL, read more */ 2751 { 2752 sourcing_lnum++; 2753 continue; 2754 } 2755 2756 buf[len - 1] = NUL; /* remove the NL */ 2757 } 2758 2759 /* 2760 * Check for ^C here now and then, so recursive :so can be broken. 2761 */ 2762 line_breakcheck(); 2763 break; 2764 } 2765 2766 if (have_read) 2767 return (char_u *)ga.ga_data; 2768 2769 vim_free(ga.ga_data); 2770 return NULL; 2771 } 2772 2773 /* 2774 * ":scriptencoding": Set encoding conversion for a sourced script. 2775 * Without the multi-byte feature it's simply ignored. 2776 */ 2777 /*ARGSUSED*/ 2778 void 2779 ex_scriptencoding(eap) 2780 exarg_T *eap; 2781 { 2782 #ifdef FEAT_MBYTE 2783 struct source_cookie *sp; 2784 char_u *name; 2785 2786 if (!getline_equal(eap->getline, eap->cookie, getsourceline)) 2787 { 2788 EMSG(_("E167: :scriptencoding used outside of a sourced file")); 2789 return; 2790 } 2791 2792 if (*eap->arg != NUL) 2793 { 2794 name = enc_canonize(eap->arg); 2795 if (name == NULL) /* out of memory */ 2796 return; 2797 } 2798 else 2799 name = eap->arg; 2800 2801 /* Setup for conversion from the specified encoding to 'encoding'. */ 2802 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie); 2803 convert_setup(&sp->conv, name, p_enc); 2804 2805 if (name != eap->arg) 2806 vim_free(name); 2807 #endif 2808 } 2809 2810 #if defined(FEAT_EVAL) || defined(PROTO) 2811 /* 2812 * ":finish": Mark a sourced file as finished. 2813 */ 2814 void 2815 ex_finish(eap) 2816 exarg_T *eap; 2817 { 2818 if (getline_equal(eap->getline, eap->cookie, getsourceline)) 2819 do_finish(eap, FALSE); 2820 else 2821 EMSG(_("E168: :finish used outside of a sourced file")); 2822 } 2823 2824 /* 2825 * Mark a sourced file as finished. Possibly makes the ":finish" pending. 2826 * Also called for a pending finish at the ":endtry" or after returning from 2827 * an extra do_cmdline(). "reanimate" is used in the latter case. 2828 */ 2829 void 2830 do_finish(eap, reanimate) 2831 exarg_T *eap; 2832 int reanimate; 2833 { 2834 int idx; 2835 2836 if (reanimate) 2837 ((struct source_cookie *)getline_cookie(eap->getline, 2838 eap->cookie))->finished = FALSE; 2839 2840 /* 2841 * Cleanup (and inactivate) conditionals, but stop when a try conditional 2842 * not in its finally clause (which then is to be executed next) is found. 2843 * In this case, make the ":finish" pending for execution at the ":endtry". 2844 * Otherwise, finish normally. 2845 */ 2846 idx = cleanup_conditionals(eap->cstack, 0, TRUE); 2847 if (idx >= 0) 2848 { 2849 eap->cstack->cs_pending[idx] = CSTP_FINISH; 2850 report_make_pending(CSTP_FINISH, NULL); 2851 } 2852 else 2853 ((struct source_cookie *)getline_cookie(eap->getline, 2854 eap->cookie))->finished = TRUE; 2855 } 2856 2857 2858 /* 2859 * Return TRUE when a sourced file had the ":finish" command: Don't give error 2860 * message for missing ":endif". 2861 * Return FALSE when not sourcing a file. 2862 */ 2863 int 2864 source_finished(getline, cookie) 2865 char_u *(*getline) __ARGS((int, void *, int)); 2866 void *cookie; 2867 { 2868 return (getline_equal(getline, cookie, getsourceline) 2869 && ((struct source_cookie *)getline_cookie( 2870 getline, cookie))->finished); 2871 } 2872 #endif 2873 2874 #if defined(FEAT_LISTCMDS) || defined(PROTO) 2875 /* 2876 * ":checktime [buffer]" 2877 */ 2878 void 2879 ex_checktime(eap) 2880 exarg_T *eap; 2881 { 2882 buf_T *buf; 2883 int save_no_check_timestamps = no_check_timestamps; 2884 2885 no_check_timestamps = 0; 2886 if (eap->addr_count == 0) /* default is all buffers */ 2887 check_timestamps(FALSE); 2888 else 2889 { 2890 buf = buflist_findnr((int)eap->line2); 2891 if (buf != NULL) /* cannot happen? */ 2892 (void)buf_check_timestamp(buf, FALSE); 2893 } 2894 no_check_timestamps = save_no_check_timestamps; 2895 } 2896 #endif 2897 2898 #if defined(FEAT_PRINTER) || defined(PROTO) 2899 /* 2900 * Printing code (Machine-independent.) 2901 * To implement printing on a platform, the following functions must be 2902 * defined: 2903 * 2904 * int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit) 2905 * Called once. Code should display printer dialogue (if appropriate) and 2906 * determine printer font and margin settings. Reset has_color if the printer 2907 * doesn't support colors at all. 2908 * Returns FAIL to abort. 2909 * 2910 * int mch_print_begin(prt_settings_T *settings) 2911 * Called to start the print job. 2912 * Return FALSE to abort. 2913 * 2914 * int mch_print_begin_page(char_u *msg) 2915 * Called at the start of each page. 2916 * "msg" indicates the progress of the print job, can be NULL. 2917 * Return FALSE to abort. 2918 * 2919 * int mch_print_end_page() 2920 * Called at the end of each page. 2921 * Return FALSE to abort. 2922 * 2923 * int mch_print_blank_page() 2924 * Called to generate a blank page for collated, duplex, multiple copy 2925 * document. Return FALSE to abort. 2926 * 2927 * void mch_print_end(prt_settings_T *psettings) 2928 * Called at normal end of print job. 2929 * 2930 * void mch_print_cleanup() 2931 * Called if print job ends normally or is abandoned. Free any memory, close 2932 * devices and handles. Also called when mch_print_begin() fails, but not 2933 * when mch_print_init() fails. 2934 * 2935 * void mch_print_set_font(int Bold, int Italic, int Underline); 2936 * Called whenever the font style changes. 2937 * 2938 * void mch_print_set_bg(long bgcol); 2939 * Called to set the background color for the following text. Parameter is an 2940 * RGB value. 2941 * 2942 * void mch_print_set_fg(long fgcol); 2943 * Called to set the foreground color for the following text. Parameter is an 2944 * RGB value. 2945 * 2946 * mch_print_start_line(int margin, int page_line) 2947 * Sets the current position at the start of line "page_line". 2948 * If margin is TRUE start in the left margin (for header and line number). 2949 * 2950 * int mch_print_text_out(char_u *p, int len); 2951 * Output one character of text p[len] at the current position. 2952 * Return TRUE if there is no room for another character in the same line. 2953 * 2954 * Note that the generic code has no idea of margins. The machine code should 2955 * simply make the page look smaller! The header and the line numbers are 2956 * printed in the margin. 2957 */ 2958 2959 #ifdef FEAT_SYN_HL 2960 static const long_u cterm_color_8[8] = 2961 { 2962 (long_u)0x000000L, (long_u)0xff0000L, (long_u)0x00ff00L, (long_u)0xffff00L, 2963 (long_u)0x0000ffL, (long_u)0xff00ffL, (long_u)0x00ffffL, (long_u)0xffffffL 2964 }; 2965 2966 static const long_u cterm_color_16[16] = 2967 { 2968 (long_u)0x000000L, (long_u)0x0000c0L, (long_u)0x008000L, (long_u)0x004080L, 2969 (long_u)0xc00000L, (long_u)0xc000c0L, (long_u)0x808000L, (long_u)0xc0c0c0L, 2970 (long_u)0x808080L, (long_u)0x6060ffL, (long_u)0x00ff00L, (long_u)0x00ffffL, 2971 (long_u)0xff8080L, (long_u)0xff40ffL, (long_u)0xffff00L, (long_u)0xffffffL 2972 }; 2973 2974 static int current_syn_id; 2975 #endif 2976 2977 #define PRCOLOR_BLACK (long_u)0 2978 #define PRCOLOR_WHITE (long_u)0xFFFFFFL 2979 2980 static int curr_italic; 2981 static int curr_bold; 2982 static int curr_underline; 2983 static long_u curr_bg; 2984 static long_u curr_fg; 2985 static int page_count; 2986 2987 /* 2988 * These values determine the print position on a page. 2989 */ 2990 typedef struct 2991 { 2992 int lead_spaces; /* remaining spaces for a TAB */ 2993 int print_pos; /* virtual column for computing TABs */ 2994 colnr_T column; /* byte column */ 2995 linenr_T file_line; /* line nr in the buffer */ 2996 long_u bytes_printed; /* bytes printed so far */ 2997 int ff; /* seen form feed character */ 2998 } prt_pos_T; 2999 3000 #ifdef FEAT_SYN_HL 3001 static long_u darken_rgb __ARGS((long_u rgb)); 3002 static long_u prt_get_term_color __ARGS((int colorindex)); 3003 #endif 3004 static void prt_set_fg __ARGS((long_u fg)); 3005 static void prt_set_bg __ARGS((long_u bg)); 3006 static void prt_set_font __ARGS((int bold, int italic, int underline)); 3007 static void prt_line_number __ARGS((prt_settings_T *psettings, int page_line, linenr_T lnum)); 3008 static void prt_header __ARGS((prt_settings_T *psettings, int pagenum, linenr_T lnum)); 3009 static void prt_message __ARGS((char_u *s)); 3010 static colnr_T hardcopy_line __ARGS((prt_settings_T *psettings, int page_line, prt_pos_T *ppos)); 3011 static void prt_get_attr __ARGS((int hl_id, prt_text_attr_T* pattr, int modec)); 3012 3013 #ifdef FEAT_SYN_HL 3014 /* 3015 * If using a dark background, the colors will probably be too bright to show 3016 * up well on white paper, so reduce their brightness. 3017 */ 3018 static long_u 3019 darken_rgb(rgb) 3020 long_u rgb; 3021 { 3022 return ((rgb >> 17) << 16) 3023 + (((rgb & 0xff00) >> 9) << 8) 3024 + ((rgb & 0xff) >> 1); 3025 } 3026 3027 static long_u 3028 prt_get_term_color(colorindex) 3029 int colorindex; 3030 { 3031 /* TODO: Should check for xterm with 88 or 256 colors. */ 3032 if (t_colors > 8) 3033 return cterm_color_16[colorindex % 16]; 3034 return cterm_color_8[colorindex % 8]; 3035 } 3036 3037 static void 3038 prt_get_attr(hl_id, pattr, modec) 3039 int hl_id; 3040 prt_text_attr_T* pattr; 3041 int modec; 3042 { 3043 int colorindex; 3044 long_u fg_color; 3045 long_u bg_color; 3046 char *color; 3047 3048 pattr->bold = (highlight_has_attr(hl_id, HL_BOLD, modec) != NULL); 3049 pattr->italic = (highlight_has_attr(hl_id, HL_ITALIC, modec) != NULL); 3050 pattr->underline = (highlight_has_attr(hl_id, HL_UNDERLINE, modec) != NULL); 3051 3052 # ifdef FEAT_GUI 3053 if (gui.in_use) 3054 { 3055 bg_color = highlight_gui_color_rgb(hl_id, FALSE); 3056 if (bg_color == PRCOLOR_BLACK) 3057 bg_color = PRCOLOR_WHITE; 3058 3059 fg_color = highlight_gui_color_rgb(hl_id, TRUE); 3060 } 3061 else 3062 # endif 3063 { 3064 bg_color = PRCOLOR_WHITE; 3065 3066 color = (char *)highlight_color(hl_id, (char_u *)"fg", modec); 3067 if (color == NULL) 3068 colorindex = 0; 3069 else 3070 colorindex = atoi(color); 3071 3072 if (colorindex >= 0 && colorindex < t_colors) 3073 fg_color = prt_get_term_color(colorindex); 3074 else 3075 fg_color = PRCOLOR_BLACK; 3076 } 3077 3078 if (fg_color == PRCOLOR_WHITE) 3079 fg_color = PRCOLOR_BLACK; 3080 else if (*p_bg == 'd') 3081 fg_color = darken_rgb(fg_color); 3082 3083 pattr->fg_color = fg_color; 3084 pattr->bg_color = bg_color; 3085 } 3086 #endif /* FEAT_SYN_HL */ 3087 3088 static void 3089 prt_set_fg(fg) 3090 long_u fg; 3091 { 3092 if (fg != curr_fg) 3093 { 3094 curr_fg = fg; 3095 mch_print_set_fg(fg); 3096 } 3097 } 3098 3099 static void 3100 prt_set_bg(bg) 3101 long_u bg; 3102 { 3103 if (bg != curr_bg) 3104 { 3105 curr_bg = bg; 3106 mch_print_set_bg(bg); 3107 } 3108 } 3109 3110 static void 3111 prt_set_font(bold, italic, underline) 3112 int bold; 3113 int italic; 3114 int underline; 3115 { 3116 if (curr_bold != bold 3117 || curr_italic != italic 3118 || curr_underline != underline) 3119 { 3120 curr_underline = underline; 3121 curr_italic = italic; 3122 curr_bold = bold; 3123 mch_print_set_font(bold, italic, underline); 3124 } 3125 } 3126 3127 /* 3128 * Print the line number in the left margin. 3129 */ 3130 static void 3131 prt_line_number(psettings, page_line, lnum) 3132 prt_settings_T *psettings; 3133 int page_line; 3134 linenr_T lnum; 3135 { 3136 int i; 3137 char_u tbuf[20]; 3138 3139 prt_set_fg(psettings->number.fg_color); 3140 prt_set_bg(psettings->number.bg_color); 3141 prt_set_font(psettings->number.bold, psettings->number.italic, psettings->number.underline); 3142 mch_print_start_line(TRUE, page_line); 3143 3144 /* Leave two spaces between the number and the text; depends on 3145 * PRINT_NUMBER_WIDTH. */ 3146 sprintf((char *)tbuf, "%6ld", (long)lnum); 3147 for (i = 0; i < 6; i++) 3148 (void)mch_print_text_out(&tbuf[i], 1); 3149 3150 #ifdef FEAT_SYN_HL 3151 if (psettings->do_syntax) 3152 /* Set colors for next character. */ 3153 current_syn_id = -1; 3154 else 3155 #endif 3156 { 3157 /* Set colors and font back to normal. */ 3158 prt_set_fg(PRCOLOR_BLACK); 3159 prt_set_bg(PRCOLOR_WHITE); 3160 prt_set_font(FALSE, FALSE, FALSE); 3161 } 3162 } 3163 3164 static linenr_T printer_page_num; 3165 3166 int 3167 get_printer_page_num() 3168 { 3169 return printer_page_num; 3170 } 3171 3172 /* 3173 * Get the currently effective header height. 3174 */ 3175 int 3176 prt_header_height() 3177 { 3178 if (printer_opts[OPT_PRINT_HEADERHEIGHT].present) 3179 return printer_opts[OPT_PRINT_HEADERHEIGHT].number; 3180 return 2; 3181 } 3182 3183 /* 3184 * Return TRUE if using a line number for printing. 3185 */ 3186 int 3187 prt_use_number() 3188 { 3189 return (printer_opts[OPT_PRINT_NUMBER].present 3190 && TOLOWER_ASC(printer_opts[OPT_PRINT_NUMBER].string[0]) == 'y'); 3191 } 3192 3193 /* 3194 * Return the unit used in a margin item in 'printoptions'. 3195 * Returns PRT_UNIT_NONE if not recognized. 3196 */ 3197 int 3198 prt_get_unit(idx) 3199 int idx; 3200 { 3201 int u = PRT_UNIT_NONE; 3202 int i; 3203 static char *(units[4]) = PRT_UNIT_NAMES; 3204 3205 if (printer_opts[idx].present) 3206 for (i = 0; i < 4; ++i) 3207 if (STRNICMP(printer_opts[idx].string, units[i], 2) == 0) 3208 { 3209 u = i; 3210 break; 3211 } 3212 return u; 3213 } 3214 3215 /* 3216 * Print the page header. 3217 */ 3218 /*ARGSUSED*/ 3219 static void 3220 prt_header(psettings, pagenum, lnum) 3221 prt_settings_T *psettings; 3222 int pagenum; 3223 linenr_T lnum; 3224 { 3225 int width = psettings->chars_per_line; 3226 int page_line; 3227 char_u *tbuf; 3228 char_u *p; 3229 #ifdef FEAT_MBYTE 3230 int l; 3231 #endif 3232 3233 /* Also use the space for the line number. */ 3234 if (prt_use_number()) 3235 width += PRINT_NUMBER_WIDTH; 3236 3237 tbuf = alloc(width + IOSIZE); 3238 if (tbuf == NULL) 3239 return; 3240 3241 #ifdef FEAT_STL_OPT 3242 if (*p_header != NUL) 3243 { 3244 linenr_T tmp_lnum, tmp_topline, tmp_botline; 3245 3246 /* 3247 * Need to (temporarily) set current line number and first/last line 3248 * number on the 'window'. Since we don't know how long the page is, 3249 * set the first and current line number to the top line, and guess 3250 * that the page length is 64. 3251 */ 3252 tmp_lnum = curwin->w_cursor.lnum; 3253 tmp_topline = curwin->w_topline; 3254 tmp_botline = curwin->w_botline; 3255 curwin->w_cursor.lnum = lnum; 3256 curwin->w_topline = lnum; 3257 curwin->w_botline = lnum + 63; 3258 printer_page_num = pagenum; 3259 3260 build_stl_str_hl(curwin, tbuf, (size_t)(width + IOSIZE), 3261 p_header, ' ', width, NULL); 3262 3263 /* Reset line numbers */ 3264 curwin->w_cursor.lnum = tmp_lnum; 3265 curwin->w_topline = tmp_topline; 3266 curwin->w_botline = tmp_botline; 3267 } 3268 else 3269 #endif 3270 sprintf((char *)tbuf, _("Page %d"), pagenum); 3271 3272 prt_set_fg(PRCOLOR_BLACK); 3273 prt_set_bg(PRCOLOR_WHITE); 3274 prt_set_font(TRUE, FALSE, FALSE); 3275 3276 /* Use a negative line number to indicate printing in the top margin. */ 3277 page_line = 0 - prt_header_height(); 3278 mch_print_start_line(TRUE, page_line); 3279 for (p = tbuf; *p != NUL; ) 3280 { 3281 if (mch_print_text_out(p, 3282 #ifdef FEAT_MBYTE 3283 (l = (*mb_ptr2len_check)(p)) 3284 #else 3285 1 3286 #endif 3287 )) 3288 { 3289 ++page_line; 3290 if (page_line >= 0) /* out of room in header */ 3291 break; 3292 mch_print_start_line(TRUE, page_line); 3293 } 3294 #ifdef FEAT_MBYTE 3295 p += l; 3296 #else 3297 p++; 3298 #endif 3299 } 3300 3301 vim_free(tbuf); 3302 3303 #ifdef FEAT_SYN_HL 3304 if (psettings->do_syntax) 3305 /* Set colors for next character. */ 3306 current_syn_id = -1; 3307 else 3308 #endif 3309 { 3310 /* Set colors and font back to normal. */ 3311 prt_set_fg(PRCOLOR_BLACK); 3312 prt_set_bg(PRCOLOR_WHITE); 3313 prt_set_font(FALSE, FALSE, FALSE); 3314 } 3315 } 3316 3317 /* 3318 * Display a print status message. 3319 */ 3320 static void 3321 prt_message(s) 3322 char_u *s; 3323 { 3324 screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0); 3325 screen_puts(s, (int)Rows - 1, 0, hl_attr(HLF_R)); 3326 out_flush(); 3327 } 3328 3329 void 3330 ex_hardcopy(eap) 3331 exarg_T *eap; 3332 { 3333 linenr_T lnum; 3334 int collated_copies, uncollated_copies; 3335 prt_settings_T settings; 3336 long_u bytes_to_print = 0; 3337 int page_line; 3338 int jobsplit; 3339 int id; 3340 3341 memset(&settings, 0, sizeof(prt_settings_T)); 3342 settings.has_color = TRUE; 3343 3344 # ifdef FEAT_POSTSCRIPT 3345 if (*eap->arg == '>') 3346 { 3347 char_u *errormsg = NULL; 3348 3349 /* Expand things like "%.ps". */ 3350 if (expand_filename(eap, eap->cmdlinep, &errormsg) == FAIL) 3351 { 3352 if (errormsg != NULL) 3353 EMSG(errormsg); 3354 return; 3355 } 3356 settings.outfile = skipwhite(eap->arg + 1); 3357 } 3358 else if (*eap->arg != NUL) 3359 settings.arguments = eap->arg; 3360 # endif 3361 3362 /* 3363 * Initialise for printing. Ask the user for settings, unless forceit is 3364 * set. 3365 * The mch_print_init() code should set up margins if applicable. (It may 3366 * not be a real printer - for example the engine might generate HTML or 3367 * PS.) 3368 */ 3369 if (mch_print_init(&settings, 3370 curbuf->b_fname == NULL 3371 ? (char_u *)buf_spname(curbuf) 3372 : curbuf->b_sfname == NULL 3373 ? curbuf->b_fname 3374 : curbuf->b_sfname, 3375 eap->forceit) == FAIL) 3376 return; 3377 3378 #ifdef FEAT_SYN_HL 3379 # ifdef FEAT_GUI 3380 if (gui.in_use) 3381 settings.modec = 'g'; 3382 else 3383 # endif 3384 if (t_colors > 1) 3385 settings.modec = 'c'; 3386 else 3387 settings.modec = 't'; 3388 3389 if (!syntax_present(curbuf)) 3390 settings.do_syntax = FALSE; 3391 else if (printer_opts[OPT_PRINT_SYNTAX].present 3392 && TOLOWER_ASC(printer_opts[OPT_PRINT_SYNTAX].string[0]) != 'a') 3393 settings.do_syntax = 3394 (TOLOWER_ASC(printer_opts[OPT_PRINT_SYNTAX].string[0]) == 'y'); 3395 else 3396 settings.do_syntax = settings.has_color; 3397 #endif 3398 3399 /* Set up printing attributes for line numbers */ 3400 settings.number.fg_color = PRCOLOR_BLACK; 3401 settings.number.bg_color = PRCOLOR_WHITE; 3402 settings.number.bold = FALSE; 3403 settings.number.italic = TRUE; 3404 settings.number.underline = FALSE; 3405 #ifdef FEAT_SYN_HL 3406 /* 3407 * Syntax highlighting of line numbers. 3408 */ 3409 if (prt_use_number() && settings.do_syntax) 3410 { 3411 id = syn_name2id((char_u *)"LineNr"); 3412 if (id > 0) 3413 id = syn_get_final_id(id); 3414 3415 prt_get_attr(id, &settings.number, settings.modec); 3416 } 3417 #endif /* FEAT_SYN_HL */ 3418 3419 /* 3420 * Estimate the total lines to be printed 3421 */ 3422 for (lnum = eap->line1; lnum <= eap->line2; lnum++) 3423 bytes_to_print += (long_u)STRLEN(skipwhite(ml_get(lnum))); 3424 if (bytes_to_print == 0) 3425 { 3426 MSG(_("No text to be printed")); 3427 goto print_fail_no_begin; 3428 } 3429 3430 /* Set colors and font to normal. */ 3431 curr_bg = (long_u)0xffffffffL; 3432 curr_fg = (long_u)0xffffffffL; 3433 curr_italic = MAYBE; 3434 curr_bold = MAYBE; 3435 curr_underline = MAYBE; 3436 3437 prt_set_fg(PRCOLOR_BLACK); 3438 prt_set_bg(PRCOLOR_WHITE); 3439 prt_set_font(FALSE, FALSE, FALSE); 3440 #ifdef FEAT_SYN_HL 3441 current_syn_id = -1; 3442 #endif 3443 3444 jobsplit = (printer_opts[OPT_PRINT_JOBSPLIT].present 3445 && TOLOWER_ASC(printer_opts[OPT_PRINT_JOBSPLIT].string[0]) == 'y'); 3446 3447 if (!mch_print_begin(&settings)) 3448 goto print_fail_no_begin; 3449 3450 /* 3451 * Loop over collated copies: 1 2 3, 1 2 3, ... 3452 */ 3453 page_count = 0; 3454 for (collated_copies = 0; 3455 collated_copies < settings.n_collated_copies; 3456 collated_copies++) 3457 { 3458 prt_pos_T prtpos; /* current print position */ 3459 prt_pos_T page_prtpos; /* print position at page start */ 3460 int side; 3461 3462 memset(&page_prtpos, 0, sizeof(prt_pos_T)); 3463 page_prtpos.file_line = eap->line1; 3464 prtpos = page_prtpos; 3465 3466 if (jobsplit && collated_copies > 0) 3467 { 3468 /* Splitting jobs: Stop a previous job and start a new one. */ 3469 mch_print_end(&settings); 3470 if (!mch_print_begin(&settings)) 3471 goto print_fail_no_begin; 3472 } 3473 3474 /* 3475 * Loop over all pages in the print job: 1 2 3 ... 3476 */ 3477 for (page_count = 0; prtpos.file_line <= eap->line2; ++page_count) 3478 { 3479 /* 3480 * Loop over uncollated copies: 1 1 1, 2 2 2, 3 3 3, ... 3481 * For duplex: 12 12 12 34 34 34, ... 3482 */ 3483 for (uncollated_copies = 0; 3484 uncollated_copies < settings.n_uncollated_copies; 3485 uncollated_copies++) 3486 { 3487 /* Set the print position to the start of this page. */ 3488 prtpos = page_prtpos; 3489 3490 /* 3491 * Do front and rear side of a page. 3492 */ 3493 for (side = 0; side <= settings.duplex; ++side) 3494 { 3495 /* 3496 * Print one page. 3497 */ 3498 3499 /* Check for interrupt character every page. */ 3500 ui_breakcheck(); 3501 if (got_int || settings.user_abort) 3502 goto print_fail; 3503 3504 sprintf((char *)IObuff, _("Printing page %d (%d%%)"), 3505 page_count + 1 + side, 3506 prtpos.bytes_printed > 1000000 3507 ? (int)(prtpos.bytes_printed / 3508 (bytes_to_print / 100)) 3509 : (int)((prtpos.bytes_printed * 100) 3510 / bytes_to_print)); 3511 if (!mch_print_begin_page(IObuff)) 3512 goto print_fail; 3513 3514 if (settings.n_collated_copies > 1) 3515 sprintf((char *)IObuff + STRLEN(IObuff), 3516 _(" Copy %d of %d"), 3517 collated_copies + 1, 3518 settings.n_collated_copies); 3519 prt_message(IObuff); 3520 3521 /* 3522 * Output header if required 3523 */ 3524 if (prt_header_height() > 0) 3525 prt_header(&settings, page_count + 1 + side, 3526 prtpos.file_line); 3527 3528 for (page_line = 0; page_line < settings.lines_per_page; 3529 ++page_line) 3530 { 3531 prtpos.column = hardcopy_line(&settings, 3532 page_line, &prtpos); 3533 if (prtpos.column == 0) 3534 { 3535 /* finished a file line */ 3536 prtpos.bytes_printed += 3537 STRLEN(skipwhite(ml_get(prtpos.file_line))); 3538 if (++prtpos.file_line > eap->line2) 3539 break; /* reached the end */ 3540 } 3541 else if (prtpos.ff) 3542 { 3543 /* Line had a formfeed in it - start new page but 3544 * stay on the current line */ 3545 break; 3546 } 3547 } 3548 3549 if (!mch_print_end_page()) 3550 goto print_fail; 3551 if (prtpos.file_line > eap->line2) 3552 break; /* reached the end */ 3553 } 3554 3555 /* 3556 * Extra blank page for duplexing with odd number of pages and 3557 * more copies to come. 3558 */ 3559 if (prtpos.file_line > eap->line2 && settings.duplex 3560 && side == 0 3561 && uncollated_copies + 1 < settings.n_uncollated_copies) 3562 { 3563 if (!mch_print_blank_page()) 3564 goto print_fail; 3565 } 3566 } 3567 if (settings.duplex && prtpos.file_line <= eap->line2) 3568 ++page_count; 3569 3570 /* Remember the position where the next page starts. */ 3571 page_prtpos = prtpos; 3572 } 3573 3574 sprintf((char *)IObuff, _("Printed: %s"), settings.jobname); 3575 prt_message(IObuff); 3576 } 3577 3578 print_fail: 3579 if (got_int || settings.user_abort) 3580 { 3581 sprintf((char *)IObuff, _("Printing aborted")); 3582 prt_message(IObuff); 3583 } 3584 mch_print_end(&settings); 3585 3586 print_fail_no_begin: 3587 mch_print_cleanup(); 3588 } 3589 3590 /* 3591 * Print one page line. 3592 * Return the next column to print, or zero if the line is finished. 3593 */ 3594 static colnr_T 3595 hardcopy_line(psettings, page_line, ppos) 3596 prt_settings_T *psettings; 3597 int page_line; 3598 prt_pos_T *ppos; 3599 { 3600 colnr_T col; 3601 char_u *line; 3602 int need_break = FALSE; 3603 int outputlen; 3604 int tab_spaces; 3605 long_u print_pos; 3606 #ifdef FEAT_SYN_HL 3607 prt_text_attr_T attr; 3608 int id; 3609 #endif 3610 3611 if (ppos->column == 0 || ppos->ff) 3612 { 3613 print_pos = 0; 3614 tab_spaces = 0; 3615 if (!ppos->ff && prt_use_number()) 3616 prt_line_number(psettings, page_line, ppos->file_line); 3617 ppos->ff = FALSE; 3618 } 3619 else 3620 { 3621 /* left over from wrap halfway a tab */ 3622 print_pos = ppos->print_pos; 3623 tab_spaces = ppos->lead_spaces; 3624 } 3625 3626 mch_print_start_line(0, page_line); 3627 line = ml_get(ppos->file_line); 3628 3629 /* 3630 * Loop over the columns until the end of the file line or right margin. 3631 */ 3632 for (col = ppos->column; line[col] != NUL && !need_break; col += outputlen) 3633 { 3634 outputlen = 1; 3635 #ifdef FEAT_MBYTE 3636 if (has_mbyte && (outputlen = (*mb_ptr2len_check)(line + col)) < 1) 3637 outputlen = 1; 3638 #endif 3639 #ifdef FEAT_SYN_HL 3640 /* 3641 * syntax highlighting stuff. 3642 */ 3643 if (psettings->do_syntax) 3644 { 3645 id = syn_get_id(ppos->file_line, (long)col, 1); 3646 if (id > 0) 3647 id = syn_get_final_id(id); 3648 else 3649 id = 0; 3650 /* Get the line again, a multi-line regexp may invalidate it. */ 3651 line = ml_get(ppos->file_line); 3652 3653 if (id != current_syn_id) 3654 { 3655 current_syn_id = id; 3656 prt_get_attr(id, &attr, psettings->modec); 3657 prt_set_font(attr.bold, attr.italic, attr.underline); 3658 prt_set_fg(attr.fg_color); 3659 prt_set_bg(attr.bg_color); 3660 } 3661 } 3662 #endif /* FEAT_SYN_HL */ 3663 3664 /* 3665 * Appropriately expand any tabs to spaces. 3666 */ 3667 if (line[col] == TAB || tab_spaces != 0) 3668 { 3669 if (tab_spaces == 0) 3670 tab_spaces = curbuf->b_p_ts - (print_pos % curbuf->b_p_ts); 3671 3672 while (tab_spaces > 0) 3673 { 3674 need_break = mch_print_text_out((char_u *)" ", 1); 3675 print_pos++; 3676 tab_spaces--; 3677 if (need_break) 3678 break; 3679 } 3680 /* Keep the TAB if we didn't finish it. */ 3681 if (need_break && tab_spaces > 0) 3682 break; 3683 } 3684 else if (line[col] == FF 3685 && printer_opts[OPT_PRINT_FORMFEED].present 3686 && TOLOWER_ASC(printer_opts[OPT_PRINT_FORMFEED].string[0]) 3687 == 'y') 3688 { 3689 ppos->ff = TRUE; 3690 need_break = 1; 3691 } 3692 else 3693 { 3694 need_break = mch_print_text_out(line + col, outputlen); 3695 #ifdef FEAT_MBYTE 3696 if (has_mbyte) 3697 print_pos += (*mb_ptr2cells)(line + col); 3698 else 3699 #endif 3700 print_pos++; 3701 } 3702 } 3703 3704 ppos->lead_spaces = tab_spaces; 3705 ppos->print_pos = print_pos; 3706 3707 /* 3708 * Start next line of file if we clip lines, or have reached end of the 3709 * line, unless we are doing a formfeed. 3710 */ 3711 if (!ppos->ff 3712 && (line[col] == NUL 3713 || (printer_opts[OPT_PRINT_WRAP].present 3714 && TOLOWER_ASC(printer_opts[OPT_PRINT_WRAP].string[0]) 3715 == 'n'))) 3716 return 0; 3717 return col; 3718 } 3719 3720 # if defined(FEAT_POSTSCRIPT) || defined(PROTO) 3721 3722 /* 3723 * PS printer stuff. 3724 * 3725 * Sources of information to help maintain the PS printing code: 3726 * 3727 * 1. PostScript Language Reference, 3rd Edition, 3728 * Addison-Wesley, 1999, ISBN 0-201-37922-8 3729 * 2. PostScript Language Program Design, 3730 * Addison-Wesley, 1988, ISBN 0-201-14396-8 3731 * 3. PostScript Tutorial and Cookbook, 3732 * Addison Wesley, 1985, ISBN 0-201-10179-3 3733 * 4. PostScript Language Document Structuring Conventions Specification, 3734 * version 3.0, 3735 * Adobe Technote 5001, 25th September 1992 3736 * 5. PostScript Printer Description File Format Specification, Version 4.3, 3737 * Adobe technote 5003, 9th February 1996 3738 * 6. Adobe Font Metrics File Format Specification, Version 4.1, 3739 * Adobe Technote 5007, 7th October 1998 3740 * 7. Adobe CMap and CIDFont Files Specification, Version 1.0, 3741 * Adobe Technote 5014, 8th October 1996 3742 * 8. Adobe CJKV Character Collections and CMaps for CID-Keyed Fonts, 3743 * Adoboe Technote 5094, 8th September, 2001 3744 * 9. CJKV Information Processing, 2nd Edition, 3745 * O'Reilly, 2002, ISBN 1-56592-224-7 3746 * 3747 * Some of these documents can be found in PDF form on Adobe's web site - 3748 * http://www.adobe.com 3749 */ 3750 3751 #define NUM_ELEMENTS(arr) (sizeof(arr)/sizeof((arr)[0])) 3752 3753 #define PRT_PS_DEFAULT_DPI (72) /* Default user space resolution */ 3754 #define PRT_PS_DEFAULT_FONTSIZE (10) 3755 #define PRT_PS_DEFAULT_BUFFER_SIZE (80) 3756 3757 struct prt_mediasize_S 3758 { 3759 char *name; 3760 float width; /* width and height in points for portrait */ 3761 float height; 3762 }; 3763 3764 #define PRT_MEDIASIZE_LEN (sizeof(prt_mediasize) / sizeof(struct prt_mediasize_S)) 3765 3766 static struct prt_mediasize_S prt_mediasize[] = 3767 { 3768 {"A4", 595.0, 842.0}, 3769 {"letter", 612.0, 792.0}, 3770 {"10x14", 720.0, 1008.0}, 3771 {"A3", 842.0, 1191.0}, 3772 {"A5", 420.0, 595.0}, 3773 {"B4", 729.0, 1032.0}, 3774 {"B5", 516.0, 729.0}, 3775 {"executive", 522.0, 756.0}, 3776 {"folio", 595.0, 935.0}, 3777 {"ledger", 1224.0, 792.0}, /* Yes, it is wider than taller! */ 3778 {"legal", 612.0, 1008.0}, 3779 {"quarto", 610.0, 780.0}, 3780 {"statement", 396.0, 612.0}, 3781 {"tabloid", 792.0, 1224.0} 3782 }; 3783 3784 /* PS font names, must be in Roman, Bold, Italic, Bold-Italic order */ 3785 struct prt_ps_font_S 3786 { 3787 int wx; 3788 int uline_offset; 3789 int uline_width; 3790 int bbox_min_y; 3791 int bbox_max_y; 3792 char *(ps_fontname[4]); 3793 }; 3794 3795 #define PRT_PS_FONT_ROMAN (0) 3796 #define PRT_PS_FONT_BOLD (1) 3797 #define PRT_PS_FONT_OBLIQUE (2) 3798 #define PRT_PS_FONT_BOLDOBLIQUE (3) 3799 3800 /* Standard font metrics for Courier family */ 3801 static struct prt_ps_font_S prt_ps_courier_font = 3802 { 3803 600, 3804 -100, 50, 3805 -250, 805, 3806 {"Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique"} 3807 }; 3808 3809 /* Generic font metrics for multi-byte fonts */ 3810 static struct prt_ps_font_S prt_ps_mb_font = 3811 { 3812 1000, 3813 -100, 50, 3814 -250, 805, 3815 {NULL, NULL, NULL, NULL} 3816 }; 3817 3818 /* Pointer to current font set being used */ 3819 static struct prt_ps_font_S* prt_ps_font; 3820 3821 /* Structures to map user named encoding and mapping to PS equivalents for 3822 * building CID font name */ 3823 struct prt_ps_encoding_S 3824 { 3825 char_u *encoding; 3826 char_u *cmap_encoding; 3827 int needs_charset; 3828 }; 3829 3830 struct prt_ps_charset_S 3831 { 3832 char *charset; 3833 char *cmap_charset; 3834 int has_charset; 3835 }; 3836 3837 #define CS_JIS_C_1978 (0x01) 3838 #define CS_JIS_X_1983 (0x02) 3839 #define CS_JIS_X_1990 (0x04) 3840 #define CS_NEC (0x08) 3841 #define CS_MSWINDOWS (0x10) 3842 #define CS_CP932 (0x20) 3843 #define CS_KANJITALK6 (0x40) 3844 #define CS_KANJITALK7 (0x80) 3845 3846 /* Japanese encodings and charsets */ 3847 static struct prt_ps_encoding_S j_encodings[] = 3848 { 3849 {"iso-2022-jp", NULL, (CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_1990| 3850 CS_NEC)}, 3851 {"euc-jp", "EUC", (CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_1990)}, 3852 {"sjis", "RKSJ", (CS_JIS_C_1978|CS_JIS_X_1983|CS_MSWINDOWS| 3853 CS_KANJITALK6|CS_KANJITALK7)}, 3854 {"cp932", "RKSJ", CS_JIS_X_1983}, 3855 {"ucs-2", "UCS2", CS_JIS_X_1990}, 3856 {"utf-8", "UTF8" , CS_JIS_X_1990} 3857 }; 3858 static struct prt_ps_charset_S j_charsets[] = 3859 { 3860 {"JIS_C_1978", "78", CS_JIS_C_1978}, 3861 {"JIS_X_1983", NULL, CS_JIS_X_1983}, 3862 {"JIS_X_1990", "Hojo", CS_JIS_X_1990}, 3863 {"NEC", "Ext", CS_NEC}, 3864 {"MSWINDOWS", "90ms", CS_MSWINDOWS}, 3865 {"CP932", "90ms", CS_JIS_X_1983}, 3866 {"KANJITALK6", "83pv", CS_KANJITALK6}, 3867 {"KANJITALK7", "90pv", CS_KANJITALK7} 3868 }; 3869 3870 #define CS_GB_2312_80 (0x01) 3871 #define CS_GBT_12345_90 (0x02) 3872 #define CS_GBK2K (0x04) 3873 #define CS_SC_MAC (0x08) 3874 #define CS_GBT_90_MAC (0x10) 3875 #define CS_GBK (0x20) 3876 #define CS_SC_ISO10646 (0x40) 3877 3878 /* Simplified Chinese encodings and charsets */ 3879 static struct prt_ps_encoding_S sc_encodings[] = 3880 { 3881 {"iso-2022", NULL, (CS_GB_2312_80|CS_GBT_12345_90)}, 3882 {"gb18030", NULL, CS_GBK2K}, 3883 {"euc-cn", "EUC", (CS_GB_2312_80|CS_GBT_12345_90|CS_SC_MAC| 3884 CS_GBT_90_MAC)}, 3885 {"gbk", "EUC", CS_GBK}, 3886 {"ucs-2", "UCS2", CS_SC_ISO10646}, 3887 {"utf-8", "UTF8", CS_SC_ISO10646} 3888 }; 3889 static struct prt_ps_charset_S sc_charsets[] = 3890 { 3891 {"GB_2312-80", "GB", CS_GB_2312_80}, 3892 {"GBT_12345-90","GBT", CS_GBT_12345_90}, 3893 {"MAC", "GBpc", CS_SC_MAC}, 3894 {"GBT-90_MAC", "GBTpc", CS_GBT_90_MAC}, 3895 {"GBK", "GBK", CS_GBK}, 3896 {"GB18030", "GBK2K", CS_GBK2K}, 3897 {"ISO10646", "UniGB", CS_SC_ISO10646} 3898 }; 3899 3900 #define CS_CNS_PLANE_1 (0x01) 3901 #define CS_CNS_PLANE_2 (0x02) 3902 #define CS_CNS_PLANE_1_2 (0x04) 3903 #define CS_B5 (0x08) 3904 #define CS_ETEN (0x10) 3905 #define CS_HK_GCCS (0x20) 3906 #define CS_HK_SCS (0x40) 3907 #define CS_HK_SCS_ETEN (0x80) 3908 #define CS_MTHKL (0x100) 3909 #define CS_MTHKS (0x200) 3910 #define CS_DLHKL (0x400) 3911 #define CS_DLHKS (0x800) 3912 #define CS_TC_ISO10646 (0x1000) 3913 3914 /* Traditional Chinese encodings and charsets */ 3915 static struct prt_ps_encoding_S tc_encodings[] = 3916 { 3917 {"iso-2022", NULL, (CS_CNS_PLANE_1|CS_CNS_PLANE_2)}, 3918 {"euc-tw", "EUC", CS_CNS_PLANE_1_2}, 3919 {"big5", "B5", (CS_B5|CS_ETEN|CS_HK_GCCS|CS_HK_SCS| 3920 CS_HK_SCS_ETEN|CS_MTHKL|CS_MTHKS|CS_DLHKL| 3921 CS_DLHKS)}, 3922 {"cp950", "B5", CS_B5}, 3923 {"ucs-2", "UCS2", CS_TC_ISO10646}, 3924 {"utf-8", "UTF8", CS_TC_ISO10646}, 3925 {"utf-16", "UTF16", CS_TC_ISO10646}, 3926 {"utf-32", "UTF32", CS_TC_ISO10646} 3927 }; 3928 static struct prt_ps_charset_S tc_charsets[] = 3929 { 3930 {"CNS_1992_1", "CNS1", CS_CNS_PLANE_1}, 3931 {"CNS_1992_2", "CNS2", CS_CNS_PLANE_2}, 3932 {"CNS_1993", "CNS", CS_CNS_PLANE_1_2}, 3933 {"BIG5", NULL, CS_B5}, 3934 {"CP950", NULL, CS_B5}, 3935 {"ETEN", "ETen", CS_ETEN}, 3936 {"HK_GCCS", "HKgccs", CS_HK_GCCS}, 3937 {"SCS", "HKscs", CS_HK_SCS}, 3938 {"SCS_ETEN", "ETHK", CS_HK_SCS_ETEN}, 3939 {"MTHKL", "HKm471", CS_MTHKL}, 3940 {"MTHKS", "HKm314", CS_MTHKS}, 3941 {"DLHKL", "HKdla", CS_DLHKL}, 3942 {"DLHKS", "HKdlb", CS_DLHKS}, 3943 {"ISO10646", "UniCNS", CS_TC_ISO10646} 3944 }; 3945 3946 #define CS_KR_X_1992 (0x01) 3947 #define CS_KR_MAC (0x02) 3948 #define CS_KR_X_1992_MS (0x04) 3949 #define CS_KR_ISO10646 (0x08) 3950 3951 /* Korean encodings and charsets */ 3952 static struct prt_ps_encoding_S k_encodings[] = 3953 { 3954 {"iso-2022-kr", NULL, CS_KR_X_1992}, 3955 {"euc-kr", "EUC", (CS_KR_X_1992|CS_KR_MAC)}, 3956 {"johab", "Johab", CS_KR_X_1992}, 3957 {"cp1361", "Johab", CS_KR_X_1992}, 3958 {"uhc", "UHC", CS_KR_X_1992_MS}, 3959 {"cp949", "UHC", CS_KR_X_1992_MS}, 3960 {"ucs-2", "UCS2", CS_KR_ISO10646}, 3961 {"utf-8", "UTF8", CS_KR_ISO10646} 3962 }; 3963 static struct prt_ps_charset_S k_charsets[] = 3964 { 3965 {"KS_X_1992", "KSC", CS_KR_X_1992}, 3966 {"CP1361", "KSC", CS_KR_X_1992}, 3967 {"MAC", "KSCpc", CS_KR_MAC}, 3968 {"MSWINDOWS", "KSCms", CS_KR_X_1992_MS}, 3969 {"CP949", "KSCms", CS_KR_X_1992_MS}, 3970 {"WANSUNG", "KSCms", CS_KR_X_1992_MS}, 3971 {"ISO10646", "UniKS", CS_KR_ISO10646} 3972 }; 3973 3974 /* Collections of encodings and charsets for multi-byte printing */ 3975 struct prt_ps_mbfont_S 3976 { 3977 int num_encodings; 3978 struct prt_ps_encoding_S *encodings; 3979 int num_charsets; 3980 struct prt_ps_charset_S *charsets; 3981 char *ascii_enc; 3982 char *defcs; 3983 }; 3984 3985 static struct prt_ps_mbfont_S prt_ps_mbfonts[] = 3986 { 3987 { 3988 NUM_ELEMENTS(j_encodings), 3989 j_encodings, 3990 NUM_ELEMENTS(j_charsets), 3991 j_charsets, 3992 "jis_roman", 3993 "JIS_X_1983" 3994 }, 3995 { 3996 NUM_ELEMENTS(sc_encodings), 3997 sc_encodings, 3998 NUM_ELEMENTS(sc_charsets), 3999 sc_charsets, 4000 "gb_roman", 4001 "GB_2312-80" 4002 }, 4003 { 4004 NUM_ELEMENTS(tc_encodings), 4005 tc_encodings, 4006 NUM_ELEMENTS(tc_charsets), 4007 tc_charsets, 4008 "cns_roman", 4009 "BIG5" 4010 }, 4011 { 4012 NUM_ELEMENTS(k_encodings), 4013 k_encodings, 4014 NUM_ELEMENTS(k_charsets), 4015 k_charsets, 4016 "ks_roman", 4017 "KS_X_1992" 4018 } 4019 }; 4020 4021 struct prt_ps_resource_S 4022 { 4023 char_u name[64]; 4024 char_u filename[MAXPATHL + 1]; 4025 int type; 4026 char_u title[256]; 4027 char_u version[256]; 4028 }; 4029 4030 /* Types of PS resource file currently used */ 4031 #define PRT_RESOURCE_TYPE_PROCSET (0) 4032 #define PRT_RESOURCE_TYPE_ENCODING (1) 4033 #define PRT_RESOURCE_TYPE_CMAP (2) 4034 4035 /* The PS prolog file version number has to match - if the prolog file is 4036 * updated, increment the number in the file and here. Version checking was 4037 * added as of VIM 6.2. 4038 * The CID prolog file version number behaves as per PS prolog. 4039 * Table of VIM and prolog versions: 4040 * 4041 * VIM Prolog CIDProlog 4042 * 6.2 1.3 4043 * 7.0 1.4 1.0 4044 */ 4045 #define PRT_PROLOG_VERSION ((char_u *)"1.4") 4046 #define PRT_CID_PROLOG_VERSION ((char_u *)"1.0") 4047 4048 /* String versions of PS resource types - indexed by constants above so don't 4049 * re-order! 4050 */ 4051 static char *prt_resource_types[] = 4052 { 4053 "procset", 4054 "encoding", 4055 "cmap" 4056 }; 4057 4058 /* Strings to look for in a PS resource file */ 4059 #define PRT_RESOURCE_HEADER "%!PS-Adobe-" 4060 #define PRT_RESOURCE_RESOURCE "Resource-" 4061 #define PRT_RESOURCE_PROCSET "ProcSet" 4062 #define PRT_RESOURCE_ENCODING "Encoding" 4063 #define PRT_RESOURCE_CMAP "CMap" 4064 4065 4066 /* Data for table based DSC comment recognition, easy to extend if VIM needs to 4067 * read more comments. */ 4068 #define PRT_DSC_MISC_TYPE (-1) 4069 #define PRT_DSC_TITLE_TYPE (1) 4070 #define PRT_DSC_VERSION_TYPE (2) 4071 #define PRT_DSC_ENDCOMMENTS_TYPE (3) 4072 4073 #define PRT_DSC_TITLE "%%Title:" 4074 #define PRT_DSC_VERSION "%%Version:" 4075 #define PRT_DSC_ENDCOMMENTS "%%EndComments:" 4076 4077 struct prt_dsc_comment_S 4078 { 4079 char_u *string; 4080 int len; 4081 int type; 4082 }; 4083 4084 struct prt_dsc_line_S 4085 { 4086 int type; 4087 char_u *string; 4088 int len; 4089 }; 4090 4091 4092 #define SIZEOF_CSTR(s) (sizeof(s) - 1) 4093 struct prt_dsc_comment_S prt_dsc_table[] = 4094 { 4095 {PRT_DSC_TITLE, SIZEOF_CSTR(PRT_DSC_TITLE), PRT_DSC_TITLE_TYPE}, 4096 {PRT_DSC_VERSION, SIZEOF_CSTR(PRT_DSC_VERSION), 4097 PRT_DSC_VERSION_TYPE}, 4098 {PRT_DSC_ENDCOMMENTS, SIZEOF_CSTR(PRT_DSC_ENDCOMMENTS), 4099 PRT_DSC_ENDCOMMENTS_TYPE} 4100 }; 4101 4102 static void prt_write_file_raw_len __ARGS((char_u *buffer, int bytes)); 4103 static void prt_write_file __ARGS((char_u *buffer)); 4104 static void prt_write_file_len __ARGS((char_u *buffer, int bytes)); 4105 static void prt_write_string __ARGS((char *s)); 4106 static void prt_write_int __ARGS((int i)); 4107 static void prt_write_boolean __ARGS((int b)); 4108 static void prt_def_font __ARGS((char *new_name, char *encoding, int height, char *font)); 4109 static void prt_real_bits __ARGS((double real, int precision, int *pinteger, int *pfraction)); 4110 static void prt_write_real __ARGS((double val, int prec)); 4111 static void prt_def_var __ARGS((char *name, double value, int prec)); 4112 static void prt_flush_buffer __ARGS((void)); 4113 static void prt_resource_name __ARGS((char_u *filename)); 4114 static int prt_find_resource __ARGS((char *name, struct prt_ps_resource_S *resource)); 4115 static int prt_open_resource __ARGS((struct prt_ps_resource_S *resource)); 4116 static int prt_check_resource __ARGS((struct prt_ps_resource_S *resource, char_u *version)); 4117 static void prt_dsc_start __ARGS((void)); 4118 static void prt_dsc_noarg __ARGS((char *comment)); 4119 static void prt_dsc_textline __ARGS((char *comment, char *text)); 4120 static void prt_dsc_text __ARGS((char *comment, char *text)); 4121 static void prt_dsc_ints __ARGS((char *comment, int count, int *ints)); 4122 static void prt_dsc_requirements __ARGS((int duplex, int tumble, int collate, int color, int num_copies)); 4123 static void prt_dsc_docmedia __ARGS((char *paper_name, double width, double height, double weight, char *colour, char *type)); 4124 static void prt_dsc_resources __ARGS((char *comment, char *type, char *strings)); 4125 static void prt_dsc_font_resource __ARGS((char *resource, struct prt_ps_font_S *ps_font)); 4126 static float to_device_units __ARGS((int idx, double physsize, int def_number)); 4127 static void prt_page_margins __ARGS((double width, double height, double *left, double *right, double *top, double *bottom)); 4128 static void prt_font_metrics __ARGS((int font_scale)); 4129 static int prt_get_cpl __ARGS((void)); 4130 static int prt_get_lpp __ARGS((void)); 4131 static int prt_add_resource __ARGS((struct prt_ps_resource_S *resource)); 4132 static int prt_resfile_next_line __ARGS((void)); 4133 static int prt_resfile_strncmp __ARGS((int offset, char *string, int len)); 4134 static int prt_resfile_skip_nonws __ARGS((int offset)); 4135 static int prt_resfile_skip_ws __ARGS((int offset)); 4136 static int prt_next_dsc __ARGS((struct prt_dsc_line_S *p_dsc_line)); 4137 #ifdef FEAT_MBYTE 4138 static void prt_def_cidfont __ARGS((char *new_name, int height, char *cidfont)); 4139 static int prt_match_encoding __ARGS((char *p_encoding, struct prt_ps_mbfont_S *p_cmap, struct prt_ps_encoding_S **pp_mbenc)); 4140 static int prt_match_charset __ARGS((char *p_charset, struct prt_ps_mbfont_S *p_cmap, struct prt_ps_charset_S **pp_mbchar)); 4141 #endif 4142 4143 /* 4144 * Variables for the output PostScript file. 4145 */ 4146 static FILE *prt_ps_fd; 4147 static int prt_file_error; 4148 static char_u *prt_ps_file_name = NULL; 4149 4150 /* 4151 * Various offsets and dimensions in default PostScript user space (points). 4152 * Used for text positioning calculations 4153 */ 4154 static float prt_page_width; 4155 static float prt_page_height; 4156 static float prt_left_margin; 4157 static float prt_right_margin; 4158 static float prt_top_margin; 4159 static float prt_bottom_margin; 4160 static float prt_line_height; 4161 static float prt_first_line_height; 4162 static float prt_char_width; 4163 static float prt_number_width; 4164 static float prt_bgcol_offset; 4165 static float prt_pos_x_moveto = 0.0; 4166 static float prt_pos_y_moveto = 0.0; 4167 4168 /* 4169 * Various control variables used to decide when and how to change the 4170 * PostScript graphics state. 4171 */ 4172 static int prt_need_moveto; 4173 static int prt_do_moveto; 4174 static int prt_need_font; 4175 static int prt_font; 4176 static int prt_need_underline; 4177 static int prt_underline; 4178 static int prt_do_underline; 4179 static int prt_need_fgcol; 4180 static int prt_fgcol; 4181 static int prt_need_bgcol; 4182 static int prt_do_bgcol; 4183 static int prt_bgcol; 4184 static int prt_new_bgcol; 4185 static int prt_attribute_change; 4186 static float prt_text_run; 4187 static int prt_page_num; 4188 static int prt_bufsiz; 4189 4190 /* 4191 * Variables controlling physical printing. 4192 */ 4193 static int prt_media; 4194 static int prt_portrait; 4195 static int prt_num_copies; 4196 static int prt_duplex; 4197 static int prt_tumble; 4198 static int prt_collate; 4199 4200 /* 4201 * Buffers used when generating PostScript output 4202 */ 4203 static char_u prt_line_buffer[257]; 4204 static garray_T prt_ps_buffer; 4205 4206 # ifdef FEAT_MBYTE 4207 static int prt_do_conv; 4208 static vimconv_T prt_conv; 4209 4210 static int prt_out_mbyte; 4211 static int prt_custom_cmap; 4212 static char prt_cmap[80]; 4213 static int prt_use_courier; 4214 static int prt_in_ascii; 4215 static int prt_half_width; 4216 static char *prt_ascii_encoding; 4217 static char_u prt_hexchar[] = "0123456789abcdef"; 4218 # endif 4219 4220 static void 4221 prt_write_file_raw_len(buffer, bytes) 4222 char_u *buffer; 4223 int bytes; 4224 { 4225 if (!prt_file_error 4226 && fwrite(buffer, sizeof(char_u), bytes, prt_ps_fd) 4227 != (size_t)bytes) 4228 { 4229 EMSG(_("E455: Error writing to PostScript output file")); 4230 prt_file_error = TRUE; 4231 } 4232 } 4233 4234 static void 4235 prt_write_file(buffer) 4236 char_u *buffer; 4237 { 4238 prt_write_file_len(buffer, STRLEN(buffer)); 4239 } 4240 4241 static void 4242 prt_write_file_len(buffer, bytes) 4243 char_u *buffer; 4244 int bytes; 4245 { 4246 #ifdef EBCDIC 4247 ebcdic2ascii(buffer, bytes); 4248 #endif 4249 prt_write_file_raw_len(buffer, bytes); 4250 } 4251 4252 /* 4253 * Write a string. 4254 */ 4255 static void 4256 prt_write_string(s) 4257 char *s; 4258 { 4259 sprintf((char *)prt_line_buffer, "%s", s); 4260 prt_write_file(prt_line_buffer); 4261 } 4262 4263 /* 4264 * Write an int and a space. 4265 */ 4266 static void 4267 prt_write_int(i) 4268 int i; 4269 { 4270 sprintf((char *)prt_line_buffer, "%d ", i); 4271 prt_write_file(prt_line_buffer); 4272 } 4273 4274 /* 4275 * Write a boolean and a space. 4276 */ 4277 static void 4278 prt_write_boolean(b) 4279 int b; 4280 { 4281 sprintf((char *)prt_line_buffer, "%s ", (b ? "T" : "F")); 4282 prt_write_file(prt_line_buffer); 4283 } 4284 4285 /* 4286 * Write PostScript to re-encode and define the font. 4287 */ 4288 static void 4289 prt_def_font(new_name, encoding, height, font) 4290 char *new_name; 4291 char *encoding; 4292 int height; 4293 char *font; 4294 { 4295 sprintf((char *)prt_line_buffer, "/_%s /VIM-%s /%s ref\n", 4296 new_name, encoding, font); 4297 prt_write_file(prt_line_buffer); 4298 #ifdef FEAT_MBYTE 4299 if (prt_out_mbyte) 4300 sprintf((char *)prt_line_buffer, "/%s %d %f /_%s sffs\n", 4301 new_name, height, 500./prt_ps_courier_font.wx, new_name); 4302 else 4303 #endif 4304 sprintf((char *)prt_line_buffer, "/%s %d /_%s ffs\n", 4305 new_name, height, new_name); 4306 prt_write_file(prt_line_buffer); 4307 } 4308 4309 #ifdef FEAT_MBYTE 4310 /* 4311 * Write a line to define the CID font. 4312 */ 4313 static void 4314 prt_def_cidfont(new_name, height, cidfont) 4315 char *new_name; 4316 int height; 4317 char *cidfont; 4318 { 4319 sprintf((char *)prt_line_buffer, "/_%s /%s[/%s] vim_composefont\n", 4320 new_name, prt_cmap, cidfont); 4321 prt_write_file(prt_line_buffer); 4322 sprintf((char *)prt_line_buffer, "/%s %d /_%s ffs\n", new_name, height, 4323 new_name); 4324 prt_write_file(prt_line_buffer); 4325 } 4326 4327 /* 4328 * Write a line to define a duplicate of a CID font 4329 */ 4330 static void 4331 prt_dup_cidfont(original_name, new_name) 4332 char *original_name; 4333 char *new_name; 4334 { 4335 sprintf((char *)prt_line_buffer, "/%s %s d\n", new_name, original_name); 4336 prt_write_file(prt_line_buffer); 4337 } 4338 #endif 4339 4340 /* 4341 * Convert a real value into an integer and fractional part as integers, with 4342 * the fractional part being in the range [0,10^precision). The fractional part 4343 * is also rounded based on the precision + 1'th fractional digit. 4344 */ 4345 static void 4346 prt_real_bits(real, precision, pinteger, pfraction) 4347 double real; 4348 int precision; 4349 int *pinteger; 4350 int *pfraction; 4351 { 4352 int i; 4353 int integer; 4354 float fraction; 4355 4356 integer = (int)real; 4357 fraction = (float)(real - integer); 4358 if (real < (double)integer) 4359 fraction = -fraction; 4360 for (i = 0; i < precision; i++) 4361 fraction *= 10.0; 4362 4363 *pinteger = integer; 4364 *pfraction = (int)(fraction + 0.5); 4365 } 4366 4367 /* 4368 * Write a real and a space. Save bytes if real value has no fractional part! 4369 * We use prt_real_bits() as %f in sprintf uses the locale setting to decide 4370 * what decimal point character to use, but PS always requires a '.'. 4371 */ 4372 static void 4373 prt_write_real(val, prec) 4374 double val; 4375 int prec; 4376 { 4377 int integer; 4378 int fraction; 4379 4380 prt_real_bits(val, prec, &integer, &fraction); 4381 /* Emit integer part */ 4382 sprintf((char *)prt_line_buffer, "%d", integer); 4383 prt_write_file(prt_line_buffer); 4384 /* Only emit fraction if necessary */ 4385 if (fraction != 0) 4386 { 4387 /* Remove any trailing zeros */ 4388 while ((fraction % 10) == 0) 4389 { 4390 prec--; 4391 fraction /= 10; 4392 } 4393 /* Emit fraction left padded with zeros */ 4394 sprintf((char *)prt_line_buffer, ".%0*d", prec, fraction); 4395 prt_write_file(prt_line_buffer); 4396 } 4397 sprintf((char *)prt_line_buffer, " "); 4398 prt_write_file(prt_line_buffer); 4399 } 4400 4401 /* 4402 * Write a line to define a numeric variable. 4403 */ 4404 static void 4405 prt_def_var(name, value, prec) 4406 char *name; 4407 double value; 4408 int prec; 4409 { 4410 sprintf((char *)prt_line_buffer, "/%s ", name); 4411 prt_write_file(prt_line_buffer); 4412 prt_write_real(value, prec); 4413 sprintf((char *)prt_line_buffer, "d\n"); 4414 prt_write_file(prt_line_buffer); 4415 } 4416 4417 /* Convert size from font space to user space at current font scale */ 4418 #define PRT_PS_FONT_TO_USER(scale, size) ((size) * ((scale)/1000.0)) 4419 4420 static void 4421 prt_flush_buffer() 4422 { 4423 if (prt_ps_buffer.ga_len > 0) 4424 { 4425 /* Any background color must be drawn first */ 4426 if (prt_do_bgcol && (prt_new_bgcol != PRCOLOR_WHITE)) 4427 { 4428 int r, g, b; 4429 4430 if (prt_do_moveto) 4431 { 4432 prt_write_real(prt_pos_x_moveto, 2); 4433 prt_write_real(prt_pos_y_moveto, 2); 4434 prt_write_string("m\n"); 4435 prt_do_moveto = FALSE; 4436 } 4437 4438 /* Size of rect of background color on which text is printed */ 4439 prt_write_real(prt_text_run, 2); 4440 prt_write_real(prt_line_height, 2); 4441 4442 /* Lastly add the color of the background */ 4443 r = ((unsigned)prt_new_bgcol & 0xff0000) >> 16; 4444 g = ((unsigned)prt_new_bgcol & 0xff00) >> 8; 4445 b = prt_new_bgcol & 0xff; 4446 prt_write_real(r / 255.0, 3); 4447 prt_write_real(g / 255.0, 3); 4448 prt_write_real(b / 255.0, 3); 4449 prt_write_string("bg\n"); 4450 } 4451 /* Draw underlines before the text as it makes it slightly easier to 4452 * find the starting point. 4453 */ 4454 if (prt_do_underline) 4455 { 4456 if (prt_do_moveto) 4457 { 4458 prt_write_real(prt_pos_x_moveto, 2); 4459 prt_write_real(prt_pos_y_moveto, 2); 4460 prt_write_string("m\n"); 4461 prt_do_moveto = FALSE; 4462 } 4463 4464 /* Underline length of text run */ 4465 prt_write_real(prt_text_run, 2); 4466 prt_write_string("ul\n"); 4467 } 4468 /* Draw the text 4469 * Note: we write text out raw - EBCDIC conversion is handled in the 4470 * PostScript world via the font encoding vector. */ 4471 #ifdef FEAT_MBYTE 4472 if (prt_out_mbyte) 4473 prt_write_string("<"); 4474 else 4475 #endif 4476 prt_write_string("("); 4477 prt_write_file_raw_len(prt_ps_buffer.ga_data, prt_ps_buffer.ga_len); 4478 #ifdef FEAT_MBYTE 4479 if (prt_out_mbyte) 4480 prt_write_string(">"); 4481 else 4482 #endif 4483 prt_write_string(")"); 4484 /* Add a moveto if need be and use the appropriate show procedure */ 4485 if (prt_do_moveto) 4486 { 4487 prt_write_real(prt_pos_x_moveto, 2); 4488 prt_write_real(prt_pos_y_moveto, 2); 4489 /* moveto and a show */ 4490 prt_write_string("ms\n"); 4491 prt_do_moveto = FALSE; 4492 } 4493 else /* Simple show */ 4494 prt_write_string("s\n"); 4495 4496 ga_clear(&prt_ps_buffer); 4497 ga_init2(&prt_ps_buffer, (int)sizeof(char), prt_bufsiz); 4498 } 4499 } 4500 4501 static char_u *resource_filename; 4502 4503 static void 4504 prt_resource_name(filename) 4505 char_u *filename; 4506 { 4507 if (STRLEN(filename) >= MAXPATHL) 4508 *resource_filename = NUL; 4509 else 4510 STRCPY(resource_filename, filename); 4511 } 4512 4513 static int 4514 prt_find_resource(name, resource) 4515 char *name; 4516 struct prt_ps_resource_S *resource; 4517 { 4518 char_u buffer[MAXPATHL + 1]; 4519 4520 STRCPY(resource->name, name); 4521 /* Look for named resource file in runtimepath */ 4522 STRCPY(buffer, "print"); 4523 add_pathsep(buffer); 4524 STRCAT(buffer, name); 4525 STRCAT(buffer, ".ps"); 4526 resource_filename = resource->filename; 4527 *resource_filename = NUL; 4528 return (do_in_runtimepath(buffer, FALSE, prt_resource_name) 4529 && resource->filename[0] != NUL); 4530 } 4531 4532 /* PS CR and LF characters have platform independent values */ 4533 #define PSLF (0x0a) 4534 #define PSCR (0x0d) 4535 4536 /* Static buffer to read initial comments in a resource file, some can have a 4537 * couple of KB of comments! */ 4538 #define PRT_FILE_BUFFER_LEN (2048) 4539 struct prt_resfile_buffer_S 4540 { 4541 char_u buffer[PRT_FILE_BUFFER_LEN]; 4542 int len; 4543 int line_start; 4544 int line_end; 4545 }; 4546 4547 static struct prt_resfile_buffer_S prt_resfile; 4548 4549 static int 4550 prt_resfile_next_line() 4551 { 4552 int index; 4553 4554 /* Move to start of next line and then find end of line */ 4555 index = prt_resfile.line_end + 1; 4556 while (index < prt_resfile.len) 4557 { 4558 if (prt_resfile.buffer[index] != PSLF && prt_resfile.buffer[index] 4559 != PSCR) 4560 break; 4561 index++; 4562 } 4563 prt_resfile.line_start = index; 4564 4565 while (index < prt_resfile.len) 4566 { 4567 if (prt_resfile.buffer[index] == PSLF || prt_resfile.buffer[index] 4568 == PSCR) 4569 break; 4570 index++; 4571 } 4572 prt_resfile.line_end = index; 4573 4574 return (index < prt_resfile.len); 4575 } 4576 4577 static int 4578 prt_resfile_strncmp(offset, string, len) 4579 int offset; 4580 char *string; 4581 int len; 4582 { 4583 /* Force not equal if string is longer than remainder of line */ 4584 if (len > (prt_resfile.line_end - (prt_resfile.line_start + offset))) 4585 return 1; 4586 4587 return STRNCMP(&prt_resfile.buffer[prt_resfile.line_start + offset], 4588 string, len); 4589 } 4590 4591 static int 4592 prt_resfile_skip_nonws(offset) 4593 int offset; 4594 { 4595 int index; 4596 4597 index = prt_resfile.line_start + offset; 4598 while (index < prt_resfile.line_end) 4599 { 4600 if (isspace(prt_resfile.buffer[index])) 4601 return index - prt_resfile.line_start; 4602 index++; 4603 } 4604 return -1; 4605 } 4606 4607 static int 4608 prt_resfile_skip_ws(offset) 4609 int offset; 4610 { 4611 int index; 4612 4613 index = prt_resfile.line_start + offset; 4614 while (index < prt_resfile.line_end) 4615 { 4616 if (!isspace(prt_resfile.buffer[index])) 4617 return index - prt_resfile.line_start; 4618 index++; 4619 } 4620 return -1; 4621 } 4622 4623 /* prt_next_dsc() - returns detail on next DSC comment line found. Returns true 4624 * if a DSC comment is found, else false */ 4625 static int 4626 prt_next_dsc(p_dsc_line) 4627 struct prt_dsc_line_S *p_dsc_line; 4628 { 4629 int comment; 4630 int offset; 4631 4632 /* Move to start of next line */ 4633 if (!prt_resfile_next_line()) 4634 return FALSE; 4635 4636 /* DSC comments always start %% */ 4637 if (prt_resfile_strncmp(0, "%%", 2) != 0) 4638 return FALSE; 4639 4640 /* Find type of DSC comment */ 4641 for (comment = 0; comment < NUM_ELEMENTS(prt_dsc_table); comment++) 4642 if (prt_resfile_strncmp(0, prt_dsc_table[comment].string, 4643 prt_dsc_table[comment].len) == 0) 4644 break; 4645 4646 if (comment != NUM_ELEMENTS(prt_dsc_table)) 4647 { 4648 /* Return type of comment */ 4649 p_dsc_line->type = prt_dsc_table[comment].type; 4650 offset = prt_dsc_table[comment].len; 4651 } 4652 else 4653 { 4654 /* Unrecognised DSC comment, skip to ws after comment leader */ 4655 p_dsc_line->type = PRT_DSC_MISC_TYPE; 4656 offset = prt_resfile_skip_nonws(0); 4657 if (offset == -1) 4658 return FALSE; 4659 } 4660 4661 /* Skip ws to comment value */ 4662 offset = prt_resfile_skip_ws(offset); 4663 if (offset == -1) 4664 return FALSE; 4665 4666 p_dsc_line->string = &prt_resfile.buffer[prt_resfile.line_start + offset]; 4667 p_dsc_line->len = prt_resfile.line_end - (prt_resfile.line_start + offset); 4668 4669 return TRUE; 4670 } 4671 4672 /* Improved hand crafted parser to get the type, title, and version number of a 4673 * PS resource file so the file details can be added to the DSC header comments. 4674 */ 4675 static int 4676 prt_open_resource(resource) 4677 struct prt_ps_resource_S *resource; 4678 { 4679 int offset; 4680 int seen_all; 4681 int seen_title; 4682 int seen_version; 4683 FILE *fd_resource; 4684 struct prt_dsc_line_S dsc_line; 4685 4686 fd_resource = mch_fopen((char *)resource->filename, READBIN); 4687 if (fd_resource == NULL) 4688 { 4689 EMSG2(_("E624: Can't open file \"%s\""), resource->filename); 4690 return FALSE; 4691 } 4692 vim_memset(prt_resfile.buffer, NUL, PRT_FILE_BUFFER_LEN); 4693 4694 /* Parse first line to ensure valid resource file */ 4695 prt_resfile.len = fread((char *)prt_resfile.buffer, sizeof(char_u), 4696 PRT_FILE_BUFFER_LEN, fd_resource); 4697 if (ferror(fd_resource)) 4698 { 4699 EMSG2(_("E457: Can't read PostScript resource file \"%s\""), 4700 resource->filename); 4701 fclose(fd_resource); 4702 return FALSE; 4703 } 4704 4705 prt_resfile.line_end = -1; 4706 prt_resfile.line_start = 0; 4707 if (!prt_resfile_next_line()) 4708 return FALSE; 4709 4710 offset = 0; 4711 4712 if (prt_resfile_strncmp(offset, PRT_RESOURCE_HEADER, 4713 STRLEN(PRT_RESOURCE_HEADER)) != 0) 4714 { 4715 EMSG2(_("E618: file \"%s\" is not a PostScript resource file"), 4716 resource->filename); 4717 fclose(fd_resource); 4718 return FALSE; 4719 } 4720 4721 /* Skip over any version numbers and following ws */ 4722 offset += STRLEN(PRT_RESOURCE_HEADER); 4723 offset = prt_resfile_skip_nonws(offset); 4724 if (offset == -1) 4725 return FALSE; 4726 offset = prt_resfile_skip_ws(offset); 4727 if (offset == -1) 4728 return FALSE; 4729 4730 if (prt_resfile_strncmp(offset, PRT_RESOURCE_RESOURCE, 4731 STRLEN(PRT_RESOURCE_RESOURCE)) != 0) 4732 { 4733 EMSG2(_("E619: file \"%s\" is not a supported PostScript resource file"), 4734 resource->filename); 4735 fclose(fd_resource); 4736 return FALSE; 4737 } 4738 offset += STRLEN(PRT_RESOURCE_RESOURCE); 4739 4740 /* Decide type of resource in the file */ 4741 if (prt_resfile_strncmp(offset, PRT_RESOURCE_PROCSET, 4742 STRLEN(PRT_RESOURCE_PROCSET)) == 0) 4743 resource->type = PRT_RESOURCE_TYPE_PROCSET; 4744 else if (prt_resfile_strncmp(offset, PRT_RESOURCE_ENCODING, 4745 STRLEN(PRT_RESOURCE_ENCODING)) == 0) 4746 resource->type = PRT_RESOURCE_TYPE_ENCODING; 4747 else if (prt_resfile_strncmp(offset, PRT_RESOURCE_CMAP, 4748 STRLEN(PRT_RESOURCE_CMAP)) == 0) 4749 resource->type = PRT_RESOURCE_TYPE_CMAP; 4750 else 4751 { 4752 EMSG2(_("E619: file \"%s\" is not a supported PostScript resource file"), 4753 resource->filename); 4754 fclose(fd_resource); 4755 return FALSE; 4756 } 4757 4758 /* Look for title and version of resource */ 4759 resource->title[0] = '\0'; 4760 resource->version[0] = '\0'; 4761 seen_title = FALSE; 4762 seen_version = FALSE; 4763 seen_all = FALSE; 4764 while (!seen_all && prt_next_dsc(&dsc_line)) 4765 { 4766 switch (dsc_line.type) 4767 { 4768 case PRT_DSC_TITLE_TYPE: 4769 STRNCPY(resource->title, dsc_line.string, dsc_line.len); 4770 resource->title[dsc_line.len] = '\0'; 4771 seen_title = TRUE; 4772 if (seen_version) 4773 seen_all = TRUE; 4774 break; 4775 4776 case PRT_DSC_VERSION_TYPE: 4777 STRNCPY(resource->version, dsc_line.string, dsc_line.len); 4778 resource->version[dsc_line.len] = '\0'; 4779 seen_version = TRUE; 4780 if (seen_title) 4781 seen_all = TRUE; 4782 break; 4783 4784 case PRT_DSC_ENDCOMMENTS_TYPE: 4785 /* Wont find title or resource after this comment, stop searching */ 4786 seen_all = TRUE; 4787 break; 4788 4789 case PRT_DSC_MISC_TYPE: 4790 /* Not interested in whatever comment this line had */ 4791 break; 4792 } 4793 } 4794 4795 if (!seen_title || !seen_version) 4796 { 4797 EMSG2(_("E619: file \"%s\" is not a supported PostScript resource file"), 4798 resource->filename); 4799 fclose(fd_resource); 4800 return FALSE; 4801 } 4802 4803 fclose(fd_resource); 4804 4805 return TRUE; 4806 } 4807 4808 static int 4809 prt_check_resource(resource, version) 4810 struct prt_ps_resource_S *resource; 4811 char_u *version; 4812 { 4813 /* Version number m.n should match, the revision number does not matter */ 4814 if (STRNCMP(resource->version, version, STRLEN(version))) 4815 { 4816 EMSG2(_("E621: \"%s\" resource file has wrong version"), 4817 resource->name); 4818 return FALSE; 4819 } 4820 4821 /* Other checks to be added as needed */ 4822 return TRUE; 4823 } 4824 4825 static void 4826 prt_dsc_start() 4827 { 4828 prt_write_string("%!PS-Adobe-3.0\n"); 4829 } 4830 4831 static void 4832 prt_dsc_noarg(comment) 4833 char *comment; 4834 { 4835 sprintf((char *)prt_line_buffer, "%%%%%s\n", comment); 4836 prt_write_file(prt_line_buffer); 4837 } 4838 4839 static void 4840 prt_dsc_textline(comment, text) 4841 char *comment; 4842 char *text; 4843 { 4844 sprintf((char *)prt_line_buffer, "%%%%%s: %s\n", comment, text); 4845 prt_write_file(prt_line_buffer); 4846 } 4847 4848 static void 4849 prt_dsc_text(comment, text) 4850 char *comment; 4851 char *text; 4852 { 4853 /* TODO - should scan 'text' for any chars needing escaping! */ 4854 sprintf((char *)prt_line_buffer, "%%%%%s: (%s)\n", comment, text); 4855 prt_write_file(prt_line_buffer); 4856 } 4857 4858 #define prt_dsc_atend(c) prt_dsc_text((c), "atend") 4859 4860 static void 4861 prt_dsc_ints(comment, count, ints) 4862 char *comment; 4863 int count; 4864 int *ints; 4865 { 4866 int i; 4867 4868 sprintf((char *)prt_line_buffer, "%%%%%s:", comment); 4869 prt_write_file(prt_line_buffer); 4870 4871 for (i = 0; i < count; i++) 4872 { 4873 sprintf((char *)prt_line_buffer, " %d", ints[i]); 4874 prt_write_file(prt_line_buffer); 4875 } 4876 4877 prt_write_string("\n"); 4878 } 4879 4880 static void 4881 prt_dsc_resources(comment, type, string) 4882 char *comment; /* if NULL add to previous */ 4883 char *type; 4884 char *string; 4885 { 4886 if (comment != NULL) 4887 sprintf((char *)prt_line_buffer, "%%%%%s: %s", comment, type); 4888 else 4889 sprintf((char *)prt_line_buffer, "%%%%+ %s", type); 4890 prt_write_file(prt_line_buffer); 4891 4892 sprintf((char *)prt_line_buffer, " %s\n", string); 4893 prt_write_file(prt_line_buffer); 4894 } 4895 4896 static void 4897 prt_dsc_font_resource(resource, ps_font) 4898 char *resource; 4899 struct prt_ps_font_S *ps_font; 4900 { 4901 int i; 4902 4903 prt_dsc_resources(resource, "font", 4904 ps_font->ps_fontname[PRT_PS_FONT_ROMAN]); 4905 for (i = PRT_PS_FONT_BOLD ; i <= PRT_PS_FONT_BOLDOBLIQUE ; i++) 4906 if (ps_font->ps_fontname[i] != NULL) 4907 prt_dsc_resources(NULL, "font", ps_font->ps_fontname[i]); 4908 } 4909 4910 static void 4911 prt_dsc_requirements(duplex, tumble, collate, color, num_copies) 4912 int duplex; 4913 int tumble; 4914 int collate; 4915 int color; 4916 int num_copies; 4917 { 4918 /* Only output the comment if we need to. 4919 * Note: tumble is ignored if we are not duplexing 4920 */ 4921 if (!(duplex || collate || color || (num_copies > 1))) 4922 return; 4923 4924 sprintf((char *)prt_line_buffer, "%%%%Requirements:"); 4925 prt_write_file(prt_line_buffer); 4926 4927 if (duplex) 4928 { 4929 prt_write_string(" duplex"); 4930 if (tumble) 4931 prt_write_string("(tumble)"); 4932 } 4933 if (collate) 4934 prt_write_string(" collate"); 4935 if (color) 4936 prt_write_string(" color"); 4937 if (num_copies > 1) 4938 { 4939 prt_write_string(" numcopies("); 4940 /* Note: no space wanted so dont use prt_write_int() */ 4941 sprintf((char *)prt_line_buffer, "%d", num_copies); 4942 prt_write_file(prt_line_buffer); 4943 prt_write_string(")"); 4944 } 4945 prt_write_string("\n"); 4946 } 4947 4948 static void 4949 prt_dsc_docmedia(paper_name, width, height, weight, colour, type) 4950 char *paper_name; 4951 double width; 4952 double height; 4953 double weight; 4954 char *colour; 4955 char *type; 4956 { 4957 sprintf((char *)prt_line_buffer, "%%%%DocumentMedia: %s ", paper_name); 4958 prt_write_file(prt_line_buffer); 4959 prt_write_real(width, 2); 4960 prt_write_real(height, 2); 4961 prt_write_real(weight, 2); 4962 if (colour == NULL) 4963 prt_write_string("()"); 4964 else 4965 prt_write_string(colour); 4966 prt_write_string(" "); 4967 if (type == NULL) 4968 prt_write_string("()"); 4969 else 4970 prt_write_string(type); 4971 prt_write_string("\n"); 4972 } 4973 4974 void 4975 mch_print_cleanup() 4976 { 4977 #ifdef FEAT_MBYTE 4978 if (prt_out_mbyte) 4979 { 4980 int i; 4981 4982 /* Free off all CID font names created, but first clear duplicate 4983 * pointers to the same string (when the same font is used for more than 4984 * one style). 4985 */ 4986 for (i = PRT_PS_FONT_ROMAN; i <= PRT_PS_FONT_BOLDOBLIQUE; i++) 4987 { 4988 if (prt_ps_mb_font.ps_fontname[i] != NULL) 4989 vim_free(prt_ps_mb_font.ps_fontname[i]); 4990 prt_ps_mb_font.ps_fontname[i] = NULL; 4991 } 4992 } 4993 4994 if (prt_do_conv) 4995 { 4996 convert_setup(&prt_conv, NULL, NULL); 4997 prt_do_conv = FALSE; 4998 } 4999 #endif 5000 if (prt_ps_fd != NULL) 5001 { 5002 fclose(prt_ps_fd); 5003 prt_ps_fd = NULL; 5004 prt_file_error = FALSE; 5005 } 5006 if (prt_ps_file_name != NULL) 5007 { 5008 vim_free(prt_ps_file_name); 5009 prt_ps_file_name = NULL; 5010 } 5011 } 5012 5013 static float 5014 to_device_units(idx, physsize, def_number) 5015 int idx; 5016 double physsize; 5017 int def_number; 5018 { 5019 float ret; 5020 int u; 5021 int nr; 5022 5023 u = prt_get_unit(idx); 5024 if (u == PRT_UNIT_NONE) 5025 { 5026 u = PRT_UNIT_PERC; 5027 nr = def_number; 5028 } 5029 else 5030 nr = printer_opts[idx].number; 5031 5032 switch (u) 5033 { 5034 case PRT_UNIT_INCH: 5035 ret = (float)(nr * PRT_PS_DEFAULT_DPI); 5036 break; 5037 case PRT_UNIT_MM: 5038 ret = (float)(nr * PRT_PS_DEFAULT_DPI) / (float)25.4; 5039 break; 5040 case PRT_UNIT_POINT: 5041 ret = (float)nr; 5042 break; 5043 case PRT_UNIT_PERC: 5044 default: 5045 ret = (float)(physsize * nr) / 100; 5046 break; 5047 } 5048 5049 return ret; 5050 } 5051 5052 /* 5053 * Calculate margins for given width and height from printoptions settings. 5054 */ 5055 static void 5056 prt_page_margins(width, height, left, right, top, bottom) 5057 double width; 5058 double height; 5059 double *left; 5060 double *right; 5061 double *top; 5062 double *bottom; 5063 { 5064 *left = to_device_units(OPT_PRINT_LEFT, width, 10); 5065 *right = width - to_device_units(OPT_PRINT_RIGHT, width, 5); 5066 *top = height - to_device_units(OPT_PRINT_TOP, height, 5); 5067 *bottom = to_device_units(OPT_PRINT_BOT, height, 5); 5068 } 5069 5070 static void 5071 prt_font_metrics(font_scale) 5072 int font_scale; 5073 { 5074 prt_line_height = (float)font_scale; 5075 prt_char_width = (float)PRT_PS_FONT_TO_USER(font_scale, prt_ps_font->wx); 5076 } 5077 5078 5079 static int 5080 prt_get_cpl() 5081 { 5082 if (prt_use_number()) 5083 { 5084 prt_number_width = PRINT_NUMBER_WIDTH * prt_char_width; 5085 #ifdef FEAT_MBYTE 5086 /* If we are outputting multi-byte characters then line numbers will be 5087 * printed with half width characters 5088 */ 5089 if (prt_out_mbyte) 5090 prt_number_width /= 2; 5091 #endif 5092 prt_left_margin += prt_number_width; 5093 } 5094 else 5095 prt_number_width = 0.0; 5096 5097 return (int)((prt_right_margin - prt_left_margin) / prt_char_width); 5098 } 5099 5100 static int 5101 prt_build_cid_fontname(font, name, name_len) 5102 int font; 5103 char *name; 5104 int name_len; 5105 { 5106 char *fontname; 5107 5108 fontname = alloc(name_len + 1); 5109 if (fontname == NULL) 5110 return FALSE; 5111 STRNCPY(fontname, name, name_len); 5112 fontname[name_len] = '\0'; 5113 prt_ps_mb_font.ps_fontname[font] = fontname; 5114 5115 return TRUE; 5116 } 5117 5118 /* 5119 * Get number of lines of text that fit on a page (excluding the header). 5120 */ 5121 static int 5122 prt_get_lpp() 5123 { 5124 int lpp; 5125 5126 /* 5127 * Calculate offset to lower left corner of background rect based on actual 5128 * font height (based on its bounding box) and the line height, handling the 5129 * case where the font height can exceed the line height. 5130 */ 5131 prt_bgcol_offset = (float)PRT_PS_FONT_TO_USER(prt_line_height, 5132 prt_ps_font->bbox_min_y); 5133 if ((prt_ps_font->bbox_max_y - prt_ps_font->bbox_min_y) < 1000.0) 5134 { 5135 prt_bgcol_offset -= (float)PRT_PS_FONT_TO_USER(prt_line_height, 5136 (1000.0 - (prt_ps_font->bbox_max_y - 5137 prt_ps_font->bbox_min_y)) / 2); 5138 } 5139 5140 /* Get height for topmost line based on background rect offset. */ 5141 prt_first_line_height = prt_line_height + prt_bgcol_offset; 5142 5143 /* Calculate lpp */ 5144 lpp = (int)((prt_top_margin - prt_bottom_margin) / prt_line_height); 5145 5146 /* Adjust top margin if there is a header */ 5147 prt_top_margin -= prt_line_height * prt_header_height(); 5148 5149 return lpp - prt_header_height(); 5150 } 5151 5152 #ifdef FEAT_MBYTE 5153 static int 5154 prt_match_encoding(p_encoding, p_cmap, pp_mbenc) 5155 char *p_encoding; 5156 struct prt_ps_mbfont_S *p_cmap; 5157 struct prt_ps_encoding_S **pp_mbenc; 5158 { 5159 int mbenc; 5160 int enc_len; 5161 struct prt_ps_encoding_S *p_mbenc; 5162 5163 *pp_mbenc = NULL; 5164 /* Look for recognised encoding */ 5165 enc_len = STRLEN(p_encoding); 5166 p_mbenc = p_cmap->encodings; 5167 for (mbenc = 0; mbenc < p_cmap->num_encodings; mbenc++) 5168 { 5169 if (STRNICMP(p_mbenc->encoding, p_encoding, enc_len) == 0) 5170 { 5171 *pp_mbenc = p_mbenc; 5172 return TRUE; 5173 } 5174 p_mbenc++; 5175 } 5176 return FALSE; 5177 } 5178 5179 static int 5180 prt_match_charset(p_charset, p_cmap, pp_mbchar) 5181 char *p_charset; 5182 struct prt_ps_mbfont_S *p_cmap; 5183 struct prt_ps_charset_S **pp_mbchar; 5184 { 5185 int mbchar; 5186 int char_len; 5187 struct prt_ps_charset_S *p_mbchar; 5188 5189 /* Look for recognised character set, using default if one is not given */ 5190 if (*p_charset == NUL) 5191 p_charset = p_cmap->defcs; 5192 char_len = STRLEN(p_charset); 5193 p_mbchar = p_cmap->charsets; 5194 for (mbchar = 0; mbchar < p_cmap->num_charsets; mbchar++) 5195 { 5196 if (STRNICMP(p_mbchar->charset, p_charset, char_len) == 0) 5197 { 5198 *pp_mbchar = p_mbchar; 5199 return TRUE; 5200 } 5201 p_mbchar++; 5202 } 5203 return FALSE; 5204 } 5205 #endif 5206 5207 /*ARGSUSED*/ 5208 int 5209 mch_print_init(psettings, jobname, forceit) 5210 prt_settings_T *psettings; 5211 char_u *jobname; 5212 int forceit; 5213 { 5214 int i; 5215 char *paper_name; 5216 int paper_strlen; 5217 int fontsize; 5218 char_u *p; 5219 double left; 5220 double right; 5221 double top; 5222 double bottom; 5223 #ifdef FEAT_MBYTE 5224 int cmap; 5225 int pmcs_len; 5226 char_u *p_encoding; 5227 struct prt_ps_encoding_S *p_mbenc; 5228 struct prt_ps_encoding_S *p_mbenc_first; 5229 struct prt_ps_charset_S *p_mbchar; 5230 #endif 5231 5232 #if 0 5233 /* 5234 * TODO: 5235 * If "forceit" is false: pop up a dialog to select: 5236 * - printer name 5237 * - copies 5238 * - collated/uncollated 5239 * - duplex off/long side/short side 5240 * - paper size 5241 * - portrait/landscape 5242 * - font size 5243 * 5244 * If "forceit" is true: use the default printer and settings 5245 */ 5246 if (forceit) 5247 s_pd.Flags |= PD_RETURNDEFAULT; 5248 #endif 5249 5250 /* 5251 * Set up font and encoding. 5252 */ 5253 #ifdef FEAT_MBYTE 5254 p_encoding = enc_skip(p_penc); 5255 if (*p_encoding == NUL) 5256 p_encoding = enc_skip(p_enc); 5257 5258 /* Look for recognised multi-byte coding, and if the charset is recognised. 5259 * This is to cope with the fact that various unicode encodings are 5260 * supported in more than one of CJK. */ 5261 p_mbenc = NULL; 5262 p_mbenc_first = NULL; 5263 p_mbchar = NULL; 5264 for (cmap = 0; cmap < NUM_ELEMENTS(prt_ps_mbfonts); cmap++) 5265 if (prt_match_encoding(p_encoding, &prt_ps_mbfonts[cmap], &p_mbenc)) 5266 { 5267 if (p_mbenc_first == NULL) 5268 p_mbenc_first = p_mbenc; 5269 if (prt_match_charset(p_pmcs, &prt_ps_mbfonts[cmap], &p_mbchar)) 5270 break; 5271 } 5272 5273 /* Use first encoding matched if no charset matched */ 5274 if (p_mbchar == NULL && p_mbenc_first != NULL) 5275 p_mbenc = p_mbenc_first; 5276 5277 prt_out_mbyte = (p_mbenc != NULL); 5278 if (prt_out_mbyte) 5279 { 5280 /* Build CMap name - will be same for all multi-byte fonts used */ 5281 prt_cmap[0] = '\0'; 5282 5283 prt_custom_cmap = prt_out_mbyte && p_mbchar == NULL; 5284 5285 if (!prt_custom_cmap) 5286 { 5287 /* Check encoding and character set are compatible */ 5288 if ((p_mbenc->needs_charset&p_mbchar->has_charset) == 0) 5289 { 5290 EMSG(_("E673: Incompatible multi-byte encoding and character set.")); 5291 return FALSE; 5292 } 5293 5294 /* Add charset name if not empty */ 5295 if (p_mbchar->cmap_charset != NULL) 5296 { 5297 STRCAT(prt_cmap, p_mbchar->cmap_charset); 5298 STRCAT(prt_cmap, "-"); 5299 } 5300 } 5301 else 5302 { 5303 /* Add custom CMap character set name */ 5304 pmcs_len = STRLEN(p_pmcs); 5305 if (pmcs_len == 0) 5306 { 5307 EMSG(_("E674: printmbcharset cannot be empty with multi-byte encoding.")); 5308 return FALSE; 5309 } 5310 STRNCPY(prt_cmap, p_pmcs, STRLEN(p_pmcs)); 5311 prt_cmap[pmcs_len] = '\0'; 5312 STRCAT(prt_cmap, "-"); 5313 } 5314 5315 /* CMap name ends with (optional) encoding name and -H for horizontal */ 5316 if (p_mbenc->cmap_encoding != NULL) 5317 { 5318 STRCAT(prt_cmap, p_mbenc->cmap_encoding); 5319 STRCAT(prt_cmap, "-"); 5320 } 5321 STRCAT(prt_cmap, "H"); 5322 5323 if (!mbfont_opts[OPT_MBFONT_REGULAR].present) 5324 { 5325 EMSG(_("E675: No default font specfifed for multi-byte printing.")); 5326 return FALSE; 5327 } 5328 5329 /* Derive CID font names with fallbacks if not defined */ 5330 if (!prt_build_cid_fontname(PRT_PS_FONT_ROMAN, 5331 mbfont_opts[OPT_MBFONT_REGULAR].string, 5332 mbfont_opts[OPT_MBFONT_REGULAR].strlen)) 5333 return FALSE; 5334 if (mbfont_opts[OPT_MBFONT_BOLD].present) 5335 if (!prt_build_cid_fontname(PRT_PS_FONT_BOLD, 5336 mbfont_opts[OPT_MBFONT_BOLD].string, 5337 mbfont_opts[OPT_MBFONT_BOLD].strlen)) 5338 return FALSE; 5339 if (mbfont_opts[OPT_MBFONT_OBLIQUE].present) 5340 if (!prt_build_cid_fontname(PRT_PS_FONT_OBLIQUE, 5341 mbfont_opts[OPT_MBFONT_OBLIQUE].string, 5342 mbfont_opts[OPT_MBFONT_OBLIQUE].strlen)) 5343 return FALSE; 5344 if (mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].present) 5345 if (!prt_build_cid_fontname(PRT_PS_FONT_BOLDOBLIQUE, 5346 mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].string, 5347 mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].strlen)) 5348 return FALSE; 5349 5350 /* Check if need to use Courier for ASCII code range, and if so pick up 5351 * the encoding to use */ 5352 prt_use_courier = mbfont_opts[OPT_MBFONT_USECOURIER].present && 5353 (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_USECOURIER].string[0]) == 'y'); 5354 if (prt_use_courier) 5355 { 5356 /* Use national ASCII variant unless ASCII wanted */ 5357 if (mbfont_opts[OPT_MBFONT_ASCII].present && 5358 (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_ASCII].string[0]) == 'y')) 5359 prt_ascii_encoding = "ascii"; 5360 else 5361 prt_ascii_encoding = prt_ps_mbfonts[cmap].ascii_enc; 5362 } 5363 5364 prt_ps_font = &prt_ps_mb_font; 5365 } 5366 else 5367 #endif 5368 { 5369 #ifdef FEAT_MBYTE 5370 prt_use_courier = FALSE; 5371 #endif 5372 prt_ps_font = &prt_ps_courier_font; 5373 } 5374 5375 /* 5376 * Find the size of the paper and set the margins. 5377 */ 5378 prt_portrait = (!printer_opts[OPT_PRINT_PORTRAIT].present 5379 || TOLOWER_ASC(printer_opts[OPT_PRINT_PORTRAIT].string[0]) == 'y'); 5380 if (printer_opts[OPT_PRINT_PAPER].present) 5381 { 5382 paper_name = (char *)printer_opts[OPT_PRINT_PAPER].string; 5383 paper_strlen = printer_opts[OPT_PRINT_PAPER].strlen; 5384 } 5385 else 5386 { 5387 paper_name = "A4"; 5388 paper_strlen = 2; 5389 } 5390 for (i = 0; i < PRT_MEDIASIZE_LEN; ++i) 5391 if (STRLEN(prt_mediasize[i].name) == (unsigned)paper_strlen 5392 && STRNICMP(prt_mediasize[i].name, paper_name, 5393 paper_strlen) == 0) 5394 break; 5395 if (i == PRT_MEDIASIZE_LEN) 5396 i = 0; 5397 prt_media = i; 5398 5399 /* 5400 * Set PS pagesize based on media dimensions and print orientation. 5401 * Note: Media and page sizes have defined meanings in PostScript and should 5402 * be kept distinct. Media is the paper (or transparency, or ...) that is 5403 * printed on, whereas the page size is the area that the PostScript 5404 * interpreter renders into. 5405 */ 5406 if (prt_portrait) 5407 { 5408 prt_page_width = prt_mediasize[i].width; 5409 prt_page_height = prt_mediasize[i].height; 5410 } 5411 else 5412 { 5413 prt_page_width = prt_mediasize[i].height; 5414 prt_page_height = prt_mediasize[i].width; 5415 } 5416 5417 /* 5418 * Set PS page margins based on the PS pagesize, not the mediasize - this 5419 * needs to be done before the cpl and lpp are calculated. 5420 */ 5421 prt_page_margins(prt_page_width, prt_page_height, &left, &right, &top, 5422 &bottom); 5423 prt_left_margin = (float)left; 5424 prt_right_margin = (float)right; 5425 prt_top_margin = (float)top; 5426 prt_bottom_margin = (float)bottom; 5427 5428 /* 5429 * Set up the font size. 5430 */ 5431 fontsize = PRT_PS_DEFAULT_FONTSIZE; 5432 for (p = p_pfn; (p = vim_strchr(p, ':')) != NULL; ++p) 5433 if (p[1] == 'h' && VIM_ISDIGIT(p[2])) 5434 fontsize = atoi((char *)p + 2); 5435 prt_font_metrics(fontsize); 5436 5437 /* 5438 * Return the number of characters per line, and lines per page for the 5439 * generic print code. 5440 */ 5441 psettings->chars_per_line = prt_get_cpl(); 5442 psettings->lines_per_page = prt_get_lpp(); 5443 5444 /* Catch margin settings that leave no space for output! */ 5445 if (psettings->chars_per_line <= 0 || psettings->lines_per_page <= 0) 5446 return FAIL; 5447 5448 /* 5449 * Sort out the number of copies to be printed. PS by default will do 5450 * uncollated copies for you, so once we know how many uncollated copies are 5451 * wanted cache it away and lie to the generic code that we only want one 5452 * uncollated copy. 5453 */ 5454 psettings->n_collated_copies = 1; 5455 psettings->n_uncollated_copies = 1; 5456 prt_num_copies = 1; 5457 prt_collate = (!printer_opts[OPT_PRINT_COLLATE].present 5458 || TOLOWER_ASC(printer_opts[OPT_PRINT_COLLATE].string[0]) == 'y'); 5459 if (prt_collate) 5460 { 5461 /* TODO: Get number of collated copies wanted. */ 5462 psettings->n_collated_copies = 1; 5463 } 5464 else 5465 { 5466 /* TODO: Get number of uncollated copies wanted and update the cached 5467 * count. 5468 */ 5469 prt_num_copies = 1; 5470 } 5471 5472 psettings->jobname = jobname; 5473 5474 /* 5475 * Set up printer duplex and tumble based on Duplex option setting - default 5476 * is long sided duplex printing (i.e. no tumble). 5477 */ 5478 prt_duplex = TRUE; 5479 prt_tumble = FALSE; 5480 psettings->duplex = 1; 5481 if (printer_opts[OPT_PRINT_DUPLEX].present) 5482 { 5483 if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "off", 3) == 0) 5484 { 5485 prt_duplex = FALSE; 5486 psettings->duplex = 0; 5487 } 5488 else if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "short", 5) 5489 == 0) 5490 prt_tumble = TRUE; 5491 } 5492 5493 /* For now user abort not supported */ 5494 psettings->user_abort = 0; 5495 5496 /* If the user didn't specify a file name, use a temp file. */ 5497 if (psettings->outfile == NULL) 5498 { 5499 prt_ps_file_name = vim_tempname('p'); 5500 if (prt_ps_file_name == NULL) 5501 { 5502 EMSG(_(e_notmp)); 5503 return FAIL; 5504 } 5505 prt_ps_fd = mch_fopen((char *)prt_ps_file_name, WRITEBIN); 5506 } 5507 else 5508 { 5509 p = expand_env_save(psettings->outfile); 5510 if (p != NULL) 5511 { 5512 prt_ps_fd = mch_fopen((char *)p, WRITEBIN); 5513 vim_free(p); 5514 } 5515 } 5516 if (prt_ps_fd == NULL) 5517 { 5518 EMSG(_("E324: Can't open PostScript output file")); 5519 mch_print_cleanup(); 5520 return FAIL; 5521 } 5522 5523 prt_bufsiz = psettings->chars_per_line; 5524 #ifdef FEAT_MBYTE 5525 if (prt_out_mbyte) 5526 prt_bufsiz *= 2; 5527 #endif 5528 ga_init2(&prt_ps_buffer, (int)sizeof(char), prt_bufsiz); 5529 5530 prt_page_num = 0; 5531 5532 prt_attribute_change = FALSE; 5533 prt_need_moveto = FALSE; 5534 prt_need_font = FALSE; 5535 prt_need_fgcol = FALSE; 5536 prt_need_bgcol = FALSE; 5537 prt_need_underline = FALSE; 5538 5539 prt_file_error = FALSE; 5540 5541 return OK; 5542 } 5543 5544 static int 5545 prt_add_resource(resource) 5546 struct prt_ps_resource_S *resource; 5547 { 5548 FILE* fd_resource; 5549 char_u resource_buffer[512]; 5550 size_t bytes_read; 5551 5552 fd_resource = mch_fopen((char *)resource->filename, READBIN); 5553 if (fd_resource == NULL) 5554 { 5555 EMSG2(_("E456: Can't open file \"%s\""), resource->filename); 5556 return FALSE; 5557 } 5558 prt_dsc_resources("BeginResource", 5559 prt_resource_types[resource->type], resource->title); 5560 5561 prt_dsc_textline("BeginDocument", (char *)resource->filename); 5562 5563 for (;;) 5564 { 5565 bytes_read = fread((char *)resource_buffer, sizeof(char_u), 5566 sizeof(resource_buffer), fd_resource); 5567 if (ferror(fd_resource)) 5568 { 5569 EMSG2(_("E457: Can't read PostScript resource file \"%s\""), 5570 resource->filename); 5571 fclose(fd_resource); 5572 return FALSE; 5573 } 5574 if (bytes_read == 0) 5575 break; 5576 prt_write_file_raw_len(resource_buffer, bytes_read); 5577 if (prt_file_error) 5578 { 5579 fclose(fd_resource); 5580 return FALSE; 5581 } 5582 } 5583 fclose(fd_resource); 5584 5585 prt_dsc_noarg("EndDocument"); 5586 5587 prt_dsc_noarg("EndResource"); 5588 5589 return TRUE; 5590 } 5591 5592 int 5593 mch_print_begin(psettings) 5594 prt_settings_T *psettings; 5595 { 5596 time_t now; 5597 int bbox[4]; 5598 char *p_time; 5599 double left; 5600 double right; 5601 double top; 5602 double bottom; 5603 struct prt_ps_resource_S res_prolog; 5604 struct prt_ps_resource_S res_encoding; 5605 char_u buffer[256]; 5606 char_u *p_encoding; 5607 #ifdef FEAT_MBYTE 5608 struct prt_ps_resource_S res_cidfont; 5609 struct prt_ps_resource_S res_cmap; 5610 #endif 5611 5612 /* 5613 * PS DSC Header comments - no PS code! 5614 */ 5615 prt_dsc_start(); 5616 prt_dsc_textline("Title", (char *)psettings->jobname); 5617 if (!get_user_name(buffer, 256)) 5618 STRCPY(buffer, "Unknown"); 5619 prt_dsc_textline("For", buffer); 5620 prt_dsc_textline("Creator", VIM_VERSION_LONG); 5621 /* Note: to ensure Clean8bit I don't think we can use LC_TIME */ 5622 now = time(NULL); 5623 p_time = ctime(&now); 5624 /* Note: ctime() adds a \n so we have to remove it :-( */ 5625 *(vim_strchr((char_u *)p_time, '\n')) = '\0'; 5626 prt_dsc_textline("CreationDate", p_time); 5627 prt_dsc_textline("DocumentData", "Clean8Bit"); 5628 prt_dsc_textline("Orientation", "Portrait"); 5629 prt_dsc_atend("Pages"); 5630 prt_dsc_textline("PageOrder", "Ascend"); 5631 /* The bbox does not change with orientation - it is always in the default 5632 * user coordinate system! We have to recalculate right and bottom 5633 * coordinates based on the font metrics for the bbox to be accurate. */ 5634 prt_page_margins(prt_mediasize[prt_media].width, 5635 prt_mediasize[prt_media].height, 5636 &left, &right, &top, &bottom); 5637 bbox[0] = (int)left; 5638 if (prt_portrait) 5639 { 5640 /* In portrait printing the fixed point is the top left corner so we 5641 * derive the bbox from that point. We have the expected cpl chars 5642 * across the media and lpp lines down the media. 5643 */ 5644 bbox[1] = (int)(top - (psettings->lines_per_page + prt_header_height()) 5645 * prt_line_height); 5646 bbox[2] = (int)(left + psettings->chars_per_line * prt_char_width 5647 + 0.5); 5648 bbox[3] = (int)(top + 0.5); 5649 } 5650 else 5651 { 5652 /* In landscape printing the fixed point is the bottom left corner so we 5653 * derive the bbox from that point. We have lpp chars across the media 5654 * and cpl lines up the media. 5655 */ 5656 bbox[1] = (int)bottom; 5657 bbox[2] = (int)(left + ((psettings->lines_per_page 5658 + prt_header_height()) * prt_line_height) + 0.5); 5659 bbox[3] = (int)(bottom + psettings->chars_per_line * prt_char_width 5660 + 0.5); 5661 } 5662 prt_dsc_ints("BoundingBox", 4, bbox); 5663 /* The media width and height does not change with landscape printing! */ 5664 prt_dsc_docmedia(prt_mediasize[prt_media].name, 5665 prt_mediasize[prt_media].width, 5666 prt_mediasize[prt_media].height, 5667 (double)0, NULL, NULL); 5668 /* Define fonts needed */ 5669 #ifdef FEAT_MBYTE 5670 if (!prt_out_mbyte || prt_use_courier) 5671 #endif 5672 prt_dsc_font_resource("DocumentNeededResources", &prt_ps_courier_font); 5673 #ifdef FEAT_MBYTE 5674 if (prt_out_mbyte) 5675 { 5676 prt_dsc_font_resource((prt_use_courier ? NULL 5677 : "DocumentNeededResources"), &prt_ps_mb_font); 5678 if (!prt_custom_cmap) 5679 prt_dsc_resources(NULL, "cmap", prt_cmap); 5680 } 5681 #endif 5682 5683 /* Search for external resources VIM supplies */ 5684 if (!prt_find_resource("prolog", &res_prolog)) 5685 { 5686 EMSG(_("E456: Can't find PostScript resource file \"prolog.ps\"")); 5687 return FALSE; 5688 } 5689 if (!prt_open_resource(&res_prolog)) 5690 return FALSE; 5691 if (!prt_check_resource(&res_prolog, PRT_PROLOG_VERSION)) 5692 return FALSE; 5693 #ifdef FEAT_MBYTE 5694 if (prt_out_mbyte) 5695 { 5696 /* Look for required version of multi-byte printing procset */ 5697 if (!prt_find_resource("cidfont", &res_cidfont)) 5698 { 5699 EMSG(_("E456: Can't find PostScript resource file \"cidfont.ps\"")); 5700 return FALSE; 5701 } 5702 if (!prt_open_resource(&res_cidfont)) 5703 return FALSE; 5704 if (!prt_check_resource(&res_cidfont, PRT_CID_PROLOG_VERSION)) 5705 return FALSE; 5706 } 5707 #endif 5708 5709 /* Find an encoding to use for printing. 5710 * Check 'printencoding'. If not set or not found, then use 'encoding'. If 5711 * that cannot be found then default to "latin1". 5712 * Note: VIM specific encoding header is always skipped. 5713 */ 5714 #ifdef FEAT_MBYTE 5715 if (!prt_out_mbyte) 5716 { 5717 #endif 5718 p_encoding = enc_skip(p_penc); 5719 if (*p_encoding == NUL 5720 || !prt_find_resource((char *)p_encoding, &res_encoding)) 5721 { 5722 /* 'printencoding' not set or not supported - find alternate */ 5723 #ifdef FEAT_MBYTE 5724 int props; 5725 5726 p_encoding = enc_skip(p_enc); 5727 props = enc_canon_props(p_encoding); 5728 if (!(props & ENC_8BIT) 5729 || !prt_find_resource((char *)p_encoding, &res_encoding)) 5730 /* 8-bit 'encoding' is not supported */ 5731 #endif 5732 { 5733 /* Use latin1 as default printing encoding */ 5734 p_encoding = (char_u *)"latin1"; 5735 if (!prt_find_resource((char *)p_encoding, &res_encoding)) 5736 { 5737 EMSG2(_("E456: Can't find PostScript resource file \"%s.ps\""), 5738 p_encoding); 5739 return FALSE; 5740 } 5741 } 5742 } 5743 if (!prt_open_resource(&res_encoding)) 5744 return FALSE; 5745 /* For the moment there are no checks on encoding resource files to 5746 * perform */ 5747 #ifdef FEAT_MBYTE 5748 } 5749 else 5750 { 5751 p_encoding = enc_skip(p_penc); 5752 if (*p_encoding == NUL) 5753 p_encoding = enc_skip(p_enc); 5754 if (prt_use_courier) 5755 { 5756 /* Include ASCII range encoding vector */ 5757 if (!prt_find_resource(prt_ascii_encoding, &res_encoding)) 5758 { 5759 EMSG2(_("E456: Can't find PostScript resource file \"%s.ps\""), 5760 prt_ascii_encoding); 5761 return FALSE; 5762 } 5763 if (!prt_open_resource(&res_encoding)) 5764 return FALSE; 5765 /* For the moment there are no checks on encoding resource files to 5766 * perform */ 5767 } 5768 } 5769 5770 prt_conv.vc_type = CONV_NONE; 5771 if (!(enc_canon_props(p_enc) & enc_canon_props(p_encoding) & ENC_8BIT)) { 5772 /* Set up encoding conversion if required */ 5773 if (FAIL == convert_setup(&prt_conv, p_enc, p_encoding)) 5774 { 5775 EMSG2(_("E620: Unable to convert to print encoding \"%s\""), 5776 p_encoding); 5777 return FALSE; 5778 } 5779 prt_do_conv = TRUE; 5780 } 5781 prt_do_conv = prt_conv.vc_type != CONV_NONE; 5782 5783 if (prt_out_mbyte && prt_custom_cmap) 5784 { 5785 /* Find user supplied CMap */ 5786 if (!prt_find_resource(prt_cmap, &res_cmap)) 5787 { 5788 EMSG2(_("E456: Can't find PostScript resource file \"%s.ps\""), 5789 prt_cmap); 5790 return FALSE; 5791 } 5792 if (!prt_open_resource(&res_cmap)) 5793 return FALSE; 5794 } 5795 #endif 5796 5797 /* List resources supplied */ 5798 STRCPY(buffer, res_prolog.title); 5799 STRCAT(buffer, " "); 5800 STRCAT(buffer, res_prolog.version); 5801 prt_dsc_resources("DocumentSuppliedResources", "procset", buffer); 5802 #ifdef FEAT_MBYTE 5803 if (prt_out_mbyte) 5804 { 5805 STRCPY(buffer, res_cidfont.title); 5806 STRCAT(buffer, " "); 5807 STRCAT(buffer, res_cidfont.version); 5808 prt_dsc_resources(NULL, "procset", buffer); 5809 5810 if (prt_custom_cmap) 5811 { 5812 STRCPY(buffer, res_cmap.title); 5813 STRCAT(buffer, " "); 5814 STRCAT(buffer, res_cmap.version); 5815 prt_dsc_resources(NULL, "cmap", buffer); 5816 } 5817 } 5818 if (!prt_out_mbyte || prt_use_courier) 5819 #endif 5820 { 5821 STRCPY(buffer, res_encoding.title); 5822 STRCAT(buffer, " "); 5823 STRCAT(buffer, res_encoding.version); 5824 prt_dsc_resources(NULL, "encoding", buffer); 5825 } 5826 prt_dsc_requirements(prt_duplex, prt_tumble, prt_collate, 5827 #ifdef FEAT_SYN_HL 5828 psettings->do_syntax 5829 #else 5830 0 5831 #endif 5832 , prt_num_copies); 5833 prt_dsc_noarg("EndComments"); 5834 5835 /* 5836 * PS Document page defaults 5837 */ 5838 prt_dsc_noarg("BeginDefaults"); 5839 5840 /* List font resources most likely common to all pages */ 5841 #ifdef FEAT_MBYTE 5842 if (!prt_out_mbyte || prt_use_courier) 5843 #endif 5844 prt_dsc_font_resource("PageResources", &prt_ps_courier_font); 5845 #ifdef FEAT_MBYTE 5846 if (prt_out_mbyte) 5847 { 5848 prt_dsc_font_resource((prt_use_courier ? NULL : "PageResources"), 5849 &prt_ps_mb_font); 5850 if (!prt_custom_cmap) 5851 prt_dsc_resources(NULL, "cmap", prt_cmap); 5852 } 5853 #endif 5854 5855 /* Paper will be used for all pages */ 5856 prt_dsc_textline("PageMedia", prt_mediasize[prt_media].name); 5857 5858 prt_dsc_noarg("EndDefaults"); 5859 5860 /* 5861 * PS Document prolog inclusion - all required procsets. 5862 */ 5863 prt_dsc_noarg("BeginProlog"); 5864 5865 /* Add required procsets - NOTE: order is important! */ 5866 if (!prt_add_resource(&res_prolog)) 5867 return FALSE; 5868 #ifdef FEAT_MBYTE 5869 if (prt_out_mbyte) 5870 { 5871 /* Add CID font procset, and any user supplied CMap */ 5872 if (!prt_add_resource(&res_cidfont)) 5873 return FALSE; 5874 if (prt_custom_cmap && !prt_add_resource(&res_cmap)) 5875 return FALSE; 5876 } 5877 #endif 5878 5879 #ifdef FEAT_MBYTE 5880 if (!prt_out_mbyte || prt_use_courier) 5881 #endif 5882 /* There will be only one Roman font encoding to be included in the PS 5883 * file. */ 5884 if (!prt_add_resource(&res_encoding)) 5885 return FALSE; 5886 5887 prt_dsc_noarg("EndProlog"); 5888 5889 /* 5890 * PS Document setup - must appear after the prolog 5891 */ 5892 prt_dsc_noarg("BeginSetup"); 5893 5894 /* Device setup - page size and number of uncollated copies */ 5895 prt_write_int((int)prt_mediasize[prt_media].width); 5896 prt_write_int((int)prt_mediasize[prt_media].height); 5897 prt_write_int(0); 5898 prt_write_string("sps\n"); 5899 prt_write_int(prt_num_copies); 5900 prt_write_string("nc\n"); 5901 prt_write_boolean(prt_duplex); 5902 prt_write_boolean(prt_tumble); 5903 prt_write_string("dt\n"); 5904 prt_write_boolean(prt_collate); 5905 prt_write_string("c\n"); 5906 5907 /* Font resource inclusion and definition */ 5908 #ifdef FEAT_MBYTE 5909 if (!prt_out_mbyte || prt_use_courier) 5910 { 5911 /* When using Courier for ASCII range when printing multi-byte, need to 5912 * pick up ASCII encoding to use with it. */ 5913 if (prt_use_courier) 5914 p_encoding = prt_ascii_encoding; 5915 #endif 5916 prt_dsc_resources("IncludeResource", "font", 5917 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]); 5918 prt_def_font("F0", (char *)p_encoding, (int)prt_line_height, 5919 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]); 5920 prt_dsc_resources("IncludeResource", "font", 5921 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]); 5922 prt_def_font("F1", (char *)p_encoding, (int)prt_line_height, 5923 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]); 5924 prt_dsc_resources("IncludeResource", "font", 5925 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]); 5926 prt_def_font("F2", (char *)p_encoding, (int)prt_line_height, 5927 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]); 5928 prt_dsc_resources("IncludeResource", "font", 5929 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]); 5930 prt_def_font("F3", (char *)p_encoding, (int)prt_line_height, 5931 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]); 5932 #ifdef FEAT_MBYTE 5933 } 5934 if (prt_out_mbyte) 5935 { 5936 /* Define the CID fonts to be used in the job. Typically CJKV fonts do 5937 * not have an italic form being a western style, so where no font is 5938 * defined for these faces VIM falls back to an existing face. 5939 * Note: if using Courier for the ASCII range then the printout will 5940 * have bold/italic/bolditalic regardless of the setting of printmbfont. 5941 */ 5942 prt_dsc_resources("IncludeResource", "font", 5943 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_ROMAN]); 5944 if (!prt_custom_cmap) 5945 prt_dsc_resources("IncludeResource", "cmap", prt_cmap); 5946 prt_def_cidfont("CF0", (int)prt_line_height, 5947 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_ROMAN]); 5948 5949 if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD] != NULL) 5950 { 5951 prt_dsc_resources("IncludeResource", "font", 5952 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]); 5953 if (!prt_custom_cmap) 5954 prt_dsc_resources("IncludeResource", "cmap", prt_cmap); 5955 prt_def_cidfont("CF1", (int)prt_line_height, 5956 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]); 5957 } 5958 else 5959 /* Use ROMAN for BOLD */ 5960 prt_dup_cidfont("CF0", "CF1"); 5961 5962 if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE] != NULL) 5963 { 5964 prt_dsc_resources("IncludeResource", "font", 5965 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]); 5966 if (!prt_custom_cmap) 5967 prt_dsc_resources("IncludeResource", "cmap", prt_cmap); 5968 prt_def_cidfont("CF2", (int)prt_line_height, 5969 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]); 5970 } 5971 else 5972 /* Use ROMAN for OBLIQUE */ 5973 prt_dup_cidfont("CF0", "CF2"); 5974 5975 if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE] != NULL) 5976 { 5977 prt_dsc_resources("IncludeResource", "font", 5978 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]); 5979 if (!prt_custom_cmap) 5980 prt_dsc_resources("IncludeResource", "cmap", prt_cmap); 5981 prt_def_cidfont("CF3", (int)prt_line_height, 5982 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]); 5983 } 5984 else 5985 /* Use BOLD for BOLDOBLIQUE */ 5986 prt_dup_cidfont("CF1", "CF3"); 5987 } 5988 #endif 5989 5990 /* Misc constant vars used for underlining and background rects */ 5991 prt_def_var("UO", PRT_PS_FONT_TO_USER(prt_line_height, 5992 prt_ps_font->uline_offset), 2); 5993 prt_def_var("UW", PRT_PS_FONT_TO_USER(prt_line_height, 5994 prt_ps_font->uline_width), 2); 5995 prt_def_var("BO", prt_bgcol_offset, 2); 5996 5997 prt_dsc_noarg("EndSetup"); 5998 5999 /* Fail if any problems writing out to the PS file */ 6000 return !prt_file_error; 6001 } 6002 6003 void 6004 mch_print_end(psettings) 6005 prt_settings_T *psettings; 6006 { 6007 prt_dsc_noarg("Trailer"); 6008 6009 /* 6010 * Output any info we don't know in toto until we finish 6011 */ 6012 prt_dsc_ints("Pages", 1, &prt_page_num); 6013 6014 prt_dsc_noarg("EOF"); 6015 6016 /* Write CTRL-D to close serial communication link if used. 6017 * NOTHING MUST BE WRITTEN AFTER THIS! */ 6018 prt_write_file(IF_EB("\004", "\067")); 6019 6020 if (!prt_file_error && psettings->outfile == NULL 6021 && !got_int && !psettings->user_abort) 6022 { 6023 /* Close the file first. */ 6024 if (prt_ps_fd != NULL) 6025 { 6026 fclose(prt_ps_fd); 6027 prt_ps_fd = NULL; 6028 } 6029 prt_message((char_u *)_("Sending to printer...")); 6030 6031 /* Not printing to a file: use 'printexpr' to print the file. */ 6032 if (eval_printexpr(prt_ps_file_name, psettings->arguments) == FAIL) 6033 EMSG(_("E365: Failed to print PostScript file")); 6034 else 6035 prt_message((char_u *)_("Print job sent.")); 6036 } 6037 6038 mch_print_cleanup(); 6039 } 6040 6041 int 6042 mch_print_end_page() 6043 { 6044 prt_flush_buffer(); 6045 6046 prt_write_string("re sp\n"); 6047 6048 prt_dsc_noarg("PageTrailer"); 6049 6050 return !prt_file_error; 6051 } 6052 6053 /*ARGSUSED*/ 6054 int 6055 mch_print_begin_page(str) 6056 char_u *str; 6057 { 6058 int page_num[2]; 6059 6060 prt_page_num++; 6061 6062 page_num[0] = page_num[1] = prt_page_num; 6063 prt_dsc_ints("Page", 2, page_num); 6064 6065 prt_dsc_noarg("BeginPageSetup"); 6066 6067 prt_write_string("sv\n0 g\n"); 6068 #ifdef FEAT_MBYTE 6069 prt_in_ascii = !prt_out_mbyte; 6070 if (prt_out_mbyte) 6071 prt_write_string("CF0 sf\n"); 6072 else 6073 #endif 6074 prt_write_string("F0 sf\n"); 6075 prt_fgcol = PRCOLOR_BLACK; 6076 prt_bgcol = PRCOLOR_WHITE; 6077 prt_font = PRT_PS_FONT_ROMAN; 6078 6079 /* Set up page transformation for landscape printing. */ 6080 if (!prt_portrait) 6081 { 6082 prt_write_int(-((int)prt_mediasize[prt_media].width)); 6083 prt_write_string("sl\n"); 6084 } 6085 6086 prt_dsc_noarg("EndPageSetup"); 6087 6088 /* We have reset the font attributes, force setting them again. */ 6089 curr_bg = (long_u)0xffffffff; 6090 curr_fg = (long_u)0xffffffff; 6091 curr_bold = MAYBE; 6092 6093 return !prt_file_error; 6094 } 6095 6096 int 6097 mch_print_blank_page() 6098 { 6099 return (mch_print_begin_page(NULL) ? (mch_print_end_page()) : FALSE); 6100 } 6101 6102 static float prt_pos_x = 0; 6103 static float prt_pos_y = 0; 6104 6105 void 6106 mch_print_start_line(margin, page_line) 6107 int margin; 6108 int page_line; 6109 { 6110 prt_pos_x = prt_left_margin; 6111 if (margin) 6112 prt_pos_x -= prt_number_width; 6113 6114 prt_pos_y = prt_top_margin - prt_first_line_height - 6115 page_line * prt_line_height; 6116 6117 prt_attribute_change = TRUE; 6118 prt_need_moveto = TRUE; 6119 #ifdef FEAT_MBYTE 6120 prt_half_width = FALSE; 6121 #endif 6122 } 6123 6124 /*ARGSUSED*/ 6125 int 6126 mch_print_text_out(p, len) 6127 char_u *p; 6128 int len; 6129 { 6130 int need_break; 6131 char_u ch; 6132 char_u ch_buff[8]; 6133 float char_width; 6134 float next_pos; 6135 #ifdef FEAT_MBYTE 6136 int in_ascii; 6137 int half_width; 6138 #endif 6139 6140 char_width = prt_char_width; 6141 6142 #ifdef FEAT_MBYTE 6143 /* Ideally VIM would create a rearranged CID font to combine a Roman and 6144 * CJKV font to do what VIM is doing here - use a Roman font for characters 6145 * in the ASCII range, and the origingal CID font for everything else. 6146 * The problem is that GhostScript still (as of 8.13) does not support 6147 * rearranged fonts even though they have been documented by Adobe for 7 6148 * years! If they ever do, a lot of this code will disappear. 6149 */ 6150 if (prt_use_courier) 6151 { 6152 in_ascii = (len == 1 && *p < 0x80); 6153 if (prt_in_ascii) 6154 { 6155 if (!in_ascii) 6156 { 6157 /* No longer in ASCII range - need to switch font */ 6158 prt_in_ascii = FALSE; 6159 prt_need_font = TRUE; 6160 prt_attribute_change = TRUE; 6161 } 6162 } 6163 else if (in_ascii) 6164 { 6165 /* Now in ASCII range - need to switch font */ 6166 prt_in_ascii = TRUE; 6167 prt_need_font = TRUE; 6168 prt_attribute_change = TRUE; 6169 } 6170 } 6171 if (prt_out_mbyte) 6172 { 6173 half_width = ((*mb_ptr2cells)(p) == 1); 6174 if (half_width) 6175 char_width /= 2; 6176 if (prt_half_width) 6177 { 6178 if (!half_width) 6179 { 6180 prt_half_width = FALSE; 6181 prt_pos_x += prt_char_width/4; 6182 prt_need_moveto = TRUE; 6183 prt_attribute_change = TRUE; 6184 } 6185 } 6186 else if (half_width) 6187 { 6188 prt_half_width = TRUE; 6189 prt_pos_x += prt_char_width/4; 6190 prt_need_moveto = TRUE; 6191 prt_attribute_change = TRUE; 6192 } 6193 } 6194 #endif 6195 6196 /* Output any required changes to the graphics state, after flushing any 6197 * text buffered so far. 6198 */ 6199 if (prt_attribute_change) 6200 { 6201 prt_flush_buffer(); 6202 /* Reset count of number of chars that will be printed */ 6203 prt_text_run = 0; 6204 6205 if (prt_need_moveto) 6206 { 6207 prt_pos_x_moveto = prt_pos_x; 6208 prt_pos_y_moveto = prt_pos_y; 6209 prt_do_moveto = TRUE; 6210 6211 prt_need_moveto = FALSE; 6212 } 6213 if (prt_need_font) 6214 { 6215 #ifdef FEAT_MBYTE 6216 if (!prt_in_ascii) 6217 prt_write_string("CF"); 6218 else 6219 #endif 6220 prt_write_string("F"); 6221 prt_write_int(prt_font); 6222 prt_write_string("sf\n"); 6223 prt_need_font = FALSE; 6224 } 6225 if (prt_need_fgcol) 6226 { 6227 int r, g, b; 6228 r = ((unsigned)prt_fgcol & 0xff0000) >> 16; 6229 g = ((unsigned)prt_fgcol & 0xff00) >> 8; 6230 b = prt_fgcol & 0xff; 6231 6232 prt_write_real(r / 255.0, 3); 6233 if (r == g && g == b) 6234 prt_write_string("g\n"); 6235 else 6236 { 6237 prt_write_real(g / 255.0, 3); 6238 prt_write_real(b / 255.0, 3); 6239 prt_write_string("r\n"); 6240 } 6241 prt_need_fgcol = FALSE; 6242 } 6243 6244 if (prt_bgcol != PRCOLOR_WHITE) 6245 { 6246 prt_new_bgcol = prt_bgcol; 6247 if (prt_need_bgcol) 6248 prt_do_bgcol = TRUE; 6249 } 6250 else 6251 prt_do_bgcol = FALSE; 6252 prt_need_bgcol = FALSE; 6253 6254 if (prt_need_underline) 6255 prt_do_underline = prt_underline; 6256 prt_need_underline = FALSE; 6257 6258 prt_attribute_change = FALSE; 6259 } 6260 6261 #ifdef FEAT_MBYTE 6262 if (prt_do_conv) 6263 { 6264 /* Convert from multi-byte to 8-bit encoding */ 6265 p = string_convert(&prt_conv, p, &len); 6266 if (p == NULL) 6267 p = (char_u *)""; 6268 } 6269 6270 if (prt_out_mbyte) 6271 { 6272 /* Multi-byte character strings are represented more efficiently as hex 6273 * strings when outputting clean 8 bit PS. 6274 */ 6275 do 6276 { 6277 ch = prt_hexchar[(*p) >> 4]; 6278 ga_append(&prt_ps_buffer, ch); 6279 ch = prt_hexchar[(*p) & 0xf]; 6280 ga_append(&prt_ps_buffer, ch); 6281 p++; 6282 } 6283 while (--len); 6284 } 6285 else 6286 #endif 6287 { 6288 /* Add next character to buffer of characters to output. 6289 * Note: One printed character may require several PS characters to 6290 * represent it, but we only count them as one printed character. 6291 */ 6292 ch = *p; 6293 if (ch < 32 || ch == '(' || ch == ')' || ch == '\\') 6294 { 6295 /* Convert non-printing characters to either their escape or octal 6296 * sequence, ensures PS sent over a serial line does not interfere 6297 * with the comms protocol. Note: For EBCDIC we need to write out 6298 * the escape sequences as ASCII codes! 6299 * Note 2: Char codes < 32 are identical in EBCDIC and ASCII AFAIK! 6300 */ 6301 ga_append(&prt_ps_buffer, IF_EB('\\', 0134)); 6302 switch (ch) 6303 { 6304 case BS: ga_append(&prt_ps_buffer, IF_EB('b', 0142)); break; 6305 case TAB: ga_append(&prt_ps_buffer, IF_EB('t', 0164)); break; 6306 case NL: ga_append(&prt_ps_buffer, IF_EB('n', 0156)); break; 6307 case FF: ga_append(&prt_ps_buffer, IF_EB('f', 0146)); break; 6308 case CAR: ga_append(&prt_ps_buffer, IF_EB('r', 0162)); break; 6309 case '(': ga_append(&prt_ps_buffer, IF_EB('(', 0050)); break; 6310 case ')': ga_append(&prt_ps_buffer, IF_EB(')', 0051)); break; 6311 case '\\': ga_append(&prt_ps_buffer, IF_EB('\\', 0134)); break; 6312 6313 default: 6314 sprintf((char *)ch_buff, "%03o", (unsigned int)ch); 6315 #ifdef EBCDIC 6316 ebcdic2ascii(ch_buff, 3); 6317 #endif 6318 ga_append(&prt_ps_buffer, ch_buff[0]); 6319 ga_append(&prt_ps_buffer, ch_buff[1]); 6320 ga_append(&prt_ps_buffer, ch_buff[2]); 6321 break; 6322 } 6323 } 6324 else 6325 ga_append(&prt_ps_buffer, ch); 6326 } 6327 6328 #ifdef FEAT_MBYTE 6329 /* Need to free any translated characters */ 6330 if (prt_do_conv && (*p != NUL)) 6331 vim_free(p); 6332 #endif 6333 6334 prt_text_run += char_width; 6335 prt_pos_x += char_width; 6336 6337 /* The downside of fp - use relative error on right margin check */ 6338 next_pos = prt_pos_x + prt_char_width; 6339 need_break = (next_pos > prt_right_margin) && 6340 ((next_pos - prt_right_margin) > (prt_right_margin*1e-5)); 6341 6342 if (need_break) 6343 prt_flush_buffer(); 6344 6345 return need_break; 6346 } 6347 6348 void 6349 mch_print_set_font(iBold, iItalic, iUnderline) 6350 int iBold; 6351 int iItalic; 6352 int iUnderline; 6353 { 6354 int font = 0; 6355 6356 if (iBold) 6357 font |= 0x01; 6358 if (iItalic) 6359 font |= 0x02; 6360 6361 if (font != prt_font) 6362 { 6363 prt_font = font; 6364 prt_attribute_change = TRUE; 6365 prt_need_font = TRUE; 6366 } 6367 if (prt_underline != iUnderline) 6368 { 6369 prt_underline = iUnderline; 6370 prt_attribute_change = TRUE; 6371 prt_need_underline = TRUE; 6372 } 6373 } 6374 6375 void 6376 mch_print_set_bg(bgcol) 6377 long_u bgcol; 6378 { 6379 prt_bgcol = bgcol; 6380 prt_attribute_change = TRUE; 6381 prt_need_bgcol = TRUE; 6382 } 6383 6384 void 6385 mch_print_set_fg(fgcol) 6386 long_u fgcol; 6387 { 6388 if (fgcol != (long_u)prt_fgcol) 6389 { 6390 prt_fgcol = fgcol; 6391 prt_attribute_change = TRUE; 6392 prt_need_fgcol = TRUE; 6393 } 6394 } 6395 6396 # endif /*FEAT_POSTSCRIPT*/ 6397 #endif /*FEAT_PRINTER*/ 6398 6399 #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \ 6400 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG)) 6401 static char *get_locale_val __ARGS((int what)); 6402 6403 static char * 6404 get_locale_val(what) 6405 int what; 6406 { 6407 char *loc; 6408 6409 /* Obtain the locale value from the libraries. For DJGPP this is 6410 * redefined and it doesn't use the arguments. */ 6411 loc = setlocale(what, NULL); 6412 6413 # if defined(__BORLANDC__) 6414 if (loc != NULL) 6415 { 6416 char_u *p; 6417 6418 /* Borland returns something like "LC_CTYPE=<name>\n" 6419 * Let's try to fix that bug here... */ 6420 p = vim_strchr(loc, '='); 6421 if (p != NULL) 6422 { 6423 loc = ++p; 6424 while (*p != NUL) /* remove trailing newline */ 6425 { 6426 if (*p < ' ') 6427 { 6428 *p = NUL; 6429 break; 6430 } 6431 ++p; 6432 } 6433 } 6434 } 6435 # endif 6436 6437 return loc; 6438 } 6439 #endif 6440 6441 6442 #ifdef WIN32 6443 /* 6444 * On MS-Windows locale names are strings like "German_Germany.1252", but 6445 * gettext expects "de". Try to translate one into another here for a few 6446 * supported languages. 6447 */ 6448 static char_u * 6449 gettext_lang(char_u *name) 6450 { 6451 int i; 6452 static char *(mtable[]) = { 6453 "afrikaans", "af", 6454 "czech", "cs", 6455 "dutch", "nl", 6456 "german", "de", 6457 "english_united kingdom", "en_GB", 6458 "spanish", "es", 6459 "french", "fr", 6460 "italian", "it", 6461 "japanese", "ja", 6462 "korean", "ko", 6463 "norwegian", "no", 6464 "polish", "pl", 6465 "russian", "ru", 6466 "slovak", "sk", 6467 "swedish", "sv", 6468 "ukrainian", "uk", 6469 "chinese_china", "zh_CN", 6470 "chinese_taiwan", "zh_TW", 6471 NULL}; 6472 6473 for (i = 0; mtable[i] != NULL; i += 2) 6474 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0) 6475 return mtable[i + 1]; 6476 return name; 6477 } 6478 #endif 6479 6480 #if defined(FEAT_MULTI_LANG) || defined(PROTO) 6481 /* 6482 * Obtain the current messages language. Used to set the default for 6483 * 'helplang'. May return NULL or an empty string. 6484 */ 6485 char_u * 6486 get_mess_lang() 6487 { 6488 char_u *p; 6489 6490 # if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) 6491 # if defined(LC_MESSAGES) 6492 p = (char_u *)get_locale_val(LC_MESSAGES); 6493 # else 6494 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG 6495 * may be set to the LCID number. */ 6496 p = (char_u *)get_locale_val(LC_ALL); 6497 # endif 6498 # else 6499 p = mch_getenv((char_u *)"LC_ALL"); 6500 if (p == NULL || *p == NUL) 6501 { 6502 p = mch_getenv((char_u *)"LC_MESSAGES"); 6503 if (p == NULL || *p == NUL) 6504 p = mch_getenv((char_u *)"LANG"); 6505 } 6506 # endif 6507 # ifdef WIN32 6508 p = gettext_lang(p); 6509 # endif 6510 return p; 6511 } 6512 #endif 6513 6514 #if !defined(LC_MESSAGES) \ 6515 && (((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \ 6516 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))) \ 6517 || defined(FEAT_EVAL)) 6518 static char_u *get_mess_env __ARGS((void)); 6519 6520 /* 6521 * Get the language used for messages from the environment. 6522 */ 6523 static char_u * 6524 get_mess_env() 6525 { 6526 char_u *p; 6527 6528 p = mch_getenv((char_u *)"LC_ALL"); 6529 if (p == NULL || *p == NUL) 6530 { 6531 p = mch_getenv((char_u *)"LC_MESSAGES"); 6532 if (p == NULL || *p == NUL) 6533 { 6534 p = mch_getenv((char_u *)"LANG"); 6535 if (p != NULL && VIM_ISDIGIT(*p)) 6536 p = NULL; /* ignore something like "1043" */ 6537 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE) 6538 if (p == NULL || *p == NUL) 6539 p = (char_u *)get_locale_val(LC_CTYPE); 6540 # endif 6541 } 6542 } 6543 return p; 6544 } 6545 #endif 6546 6547 #if defined(FEAT_EVAL) || defined(PROTO) 6548 6549 /* 6550 * Set the "v:lang" variable according to the current locale setting. 6551 * Also do "v:lc_time"and "v:ctype". 6552 */ 6553 void 6554 set_lang_var() 6555 { 6556 char_u *loc; 6557 6558 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE) 6559 loc = (char_u *)get_locale_val(LC_CTYPE); 6560 # else 6561 /* setlocale() not supported: use the default value */ 6562 loc = (char_u *)"C"; 6563 # endif 6564 set_vim_var_string(VV_CTYPE, loc, -1); 6565 6566 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall 6567 * back to LC_CTYPE if it's empty. */ 6568 # if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) && defined(LC_MESSAGES) 6569 loc = (char_u *)get_locale_val(LC_MESSAGES); 6570 # else 6571 loc = get_mess_env(); 6572 # endif 6573 set_vim_var_string(VV_LANG, loc, -1); 6574 6575 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE) 6576 loc = (char_u *)get_locale_val(LC_TIME); 6577 # endif 6578 set_vim_var_string(VV_LC_TIME, loc, -1); 6579 } 6580 #endif 6581 6582 #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \ 6583 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) 6584 /* 6585 * ":language": Set the language (locale). 6586 */ 6587 void 6588 ex_language(eap) 6589 exarg_T *eap; 6590 { 6591 char *loc; 6592 char_u *p; 6593 char_u *name; 6594 int what = LC_ALL; 6595 char *whatstr = ""; 6596 #ifdef LC_MESSAGES 6597 # define VIM_LC_MESSAGES LC_MESSAGES 6598 #else 6599 # define VIM_LC_MESSAGES 6789 6600 #endif 6601 6602 name = eap->arg; 6603 6604 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument. 6605 * Allow abbreviation, but require at least 3 characters to avoid 6606 * confusion with a two letter language name "me" or "ct". */ 6607 p = skiptowhite(eap->arg); 6608 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3) 6609 { 6610 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0) 6611 { 6612 what = VIM_LC_MESSAGES; 6613 name = skipwhite(p); 6614 whatstr = "messages "; 6615 } 6616 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0) 6617 { 6618 what = LC_CTYPE; 6619 name = skipwhite(p); 6620 whatstr = "ctype "; 6621 } 6622 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0) 6623 { 6624 what = LC_TIME; 6625 name = skipwhite(p); 6626 whatstr = "time "; 6627 } 6628 } 6629 6630 if (*name == NUL) 6631 { 6632 #ifndef LC_MESSAGES 6633 if (what == VIM_LC_MESSAGES) 6634 p = get_mess_env(); 6635 else 6636 #endif 6637 p = (char_u *)setlocale(what, NULL); 6638 if (p == NULL || *p == NUL) 6639 p = (char_u *)"Unknown"; 6640 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p); 6641 } 6642 else 6643 { 6644 #ifndef LC_MESSAGES 6645 if (what == VIM_LC_MESSAGES) 6646 loc = ""; 6647 else 6648 #endif 6649 loc = setlocale(what, (char *)name); 6650 if (loc == NULL) 6651 EMSG2(_("E197: Cannot set language to \"%s\""), name); 6652 else 6653 { 6654 #ifdef HAVE_NL_MSG_CAT_CNTR 6655 /* Need to do this for GNU gettext, otherwise cached translations 6656 * will be used again. */ 6657 extern int _nl_msg_cat_cntr; 6658 6659 ++_nl_msg_cat_cntr; 6660 #endif 6661 /* Reset $LC_ALL, otherwise it would overrule everyting. */ 6662 vim_setenv((char_u *)"LC_ALL", (char_u *)""); 6663 6664 if (what != LC_TIME) 6665 { 6666 /* Tell gettext() what to translate to. It apparently doesn't 6667 * use the currently effective locale. Also do this when 6668 * FEAT_GETTEXT isn't defined, so that shell commands use this 6669 * value. */ 6670 if (what == LC_ALL) 6671 vim_setenv((char_u *)"LANG", name); 6672 if (what != LC_CTYPE) 6673 { 6674 char_u *mname; 6675 #ifdef WIN32 6676 mname = gettext_lang(name); 6677 #else 6678 mname = name; 6679 #endif 6680 vim_setenv((char_u *)"LC_MESSAGES", mname); 6681 #ifdef FEAT_MULTI_LANG 6682 set_helplang_default(mname); 6683 #endif 6684 } 6685 6686 /* Set $LC_CTYPE, because it overrules $LANG, and 6687 * gtk_set_locale() calls setlocale() again. gnome_init() 6688 * sets $LC_CTYPE to "en_US" (that's a bug!). */ 6689 if (what != VIM_LC_MESSAGES) 6690 vim_setenv((char_u *)"LC_CTYPE", name); 6691 # ifdef FEAT_GUI_GTK 6692 /* Let GTK know what locale we're using. Not sure this is 6693 * really needed... */ 6694 if (gui.in_use) 6695 (void)gtk_set_locale(); 6696 # endif 6697 } 6698 6699 # ifdef FEAT_EVAL 6700 /* Set v:lang, v:lc_time and v:ctype to the final result. */ 6701 set_lang_var(); 6702 # endif 6703 } 6704 } 6705 } 6706 6707 # if defined(FEAT_CMDL_COMPL) || defined(PROTO) 6708 /* 6709 * Function given to ExpandGeneric() to obtain the possible arguments of the 6710 * ":language" command. 6711 */ 6712 /*ARGSUSED*/ 6713 char_u * 6714 get_lang_arg(xp, idx) 6715 expand_T *xp; 6716 int idx; 6717 { 6718 if (idx == 0) 6719 return (char_u *)"messages"; 6720 if (idx == 1) 6721 return (char_u *)"ctype"; 6722 if (idx == 2) 6723 return (char_u *)"time"; 6724 return NULL; 6725 } 6726 # endif 6727 6728 #endif 6729