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 #ifdef FEAT_MBYTE 3810 /* Generic font metrics for multi-byte fonts */ 3811 static struct prt_ps_font_S prt_ps_mb_font = 3812 { 3813 1000, 3814 -100, 50, 3815 -250, 805, 3816 {NULL, NULL, NULL, NULL} 3817 }; 3818 #endif 3819 3820 /* Pointer to current font set being used */ 3821 static struct prt_ps_font_S* prt_ps_font; 3822 3823 /* Structures to map user named encoding and mapping to PS equivalents for 3824 * building CID font name */ 3825 struct prt_ps_encoding_S 3826 { 3827 char *encoding; 3828 char *cmap_encoding; 3829 int needs_charset; 3830 }; 3831 3832 struct prt_ps_charset_S 3833 { 3834 char *charset; 3835 char *cmap_charset; 3836 int has_charset; 3837 }; 3838 3839 #ifdef FEAT_MBYTE 3840 3841 #define CS_JIS_C_1978 (0x01) 3842 #define CS_JIS_X_1983 (0x02) 3843 #define CS_JIS_X_1990 (0x04) 3844 #define CS_NEC (0x08) 3845 #define CS_MSWINDOWS (0x10) 3846 #define CS_CP932 (0x20) 3847 #define CS_KANJITALK6 (0x40) 3848 #define CS_KANJITALK7 (0x80) 3849 3850 /* Japanese encodings and charsets */ 3851 static struct prt_ps_encoding_S j_encodings[] = 3852 { 3853 {"iso-2022-jp", NULL, (CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_1990| 3854 CS_NEC)}, 3855 {"euc-jp", "EUC", (CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_1990)}, 3856 {"sjis", "RKSJ", (CS_JIS_C_1978|CS_JIS_X_1983|CS_MSWINDOWS| 3857 CS_KANJITALK6|CS_KANJITALK7)}, 3858 {"cp932", "RKSJ", CS_JIS_X_1983}, 3859 {"ucs-2", "UCS2", CS_JIS_X_1990}, 3860 {"utf-8", "UTF8" , CS_JIS_X_1990} 3861 }; 3862 static struct prt_ps_charset_S j_charsets[] = 3863 { 3864 {"JIS_C_1978", "78", CS_JIS_C_1978}, 3865 {"JIS_X_1983", NULL, CS_JIS_X_1983}, 3866 {"JIS_X_1990", "Hojo", CS_JIS_X_1990}, 3867 {"NEC", "Ext", CS_NEC}, 3868 {"MSWINDOWS", "90ms", CS_MSWINDOWS}, 3869 {"CP932", "90ms", CS_JIS_X_1983}, 3870 {"KANJITALK6", "83pv", CS_KANJITALK6}, 3871 {"KANJITALK7", "90pv", CS_KANJITALK7} 3872 }; 3873 3874 #define CS_GB_2312_80 (0x01) 3875 #define CS_GBT_12345_90 (0x02) 3876 #define CS_GBK2K (0x04) 3877 #define CS_SC_MAC (0x08) 3878 #define CS_GBT_90_MAC (0x10) 3879 #define CS_GBK (0x20) 3880 #define CS_SC_ISO10646 (0x40) 3881 3882 /* Simplified Chinese encodings and charsets */ 3883 static struct prt_ps_encoding_S sc_encodings[] = 3884 { 3885 {"iso-2022", NULL, (CS_GB_2312_80|CS_GBT_12345_90)}, 3886 {"gb18030", NULL, CS_GBK2K}, 3887 {"euc-cn", "EUC", (CS_GB_2312_80|CS_GBT_12345_90|CS_SC_MAC| 3888 CS_GBT_90_MAC)}, 3889 {"gbk", "EUC", CS_GBK}, 3890 {"ucs-2", "UCS2", CS_SC_ISO10646}, 3891 {"utf-8", "UTF8", CS_SC_ISO10646} 3892 }; 3893 static struct prt_ps_charset_S sc_charsets[] = 3894 { 3895 {"GB_2312-80", "GB", CS_GB_2312_80}, 3896 {"GBT_12345-90","GBT", CS_GBT_12345_90}, 3897 {"MAC", "GBpc", CS_SC_MAC}, 3898 {"GBT-90_MAC", "GBTpc", CS_GBT_90_MAC}, 3899 {"GBK", "GBK", CS_GBK}, 3900 {"GB18030", "GBK2K", CS_GBK2K}, 3901 {"ISO10646", "UniGB", CS_SC_ISO10646} 3902 }; 3903 3904 #define CS_CNS_PLANE_1 (0x01) 3905 #define CS_CNS_PLANE_2 (0x02) 3906 #define CS_CNS_PLANE_1_2 (0x04) 3907 #define CS_B5 (0x08) 3908 #define CS_ETEN (0x10) 3909 #define CS_HK_GCCS (0x20) 3910 #define CS_HK_SCS (0x40) 3911 #define CS_HK_SCS_ETEN (0x80) 3912 #define CS_MTHKL (0x100) 3913 #define CS_MTHKS (0x200) 3914 #define CS_DLHKL (0x400) 3915 #define CS_DLHKS (0x800) 3916 #define CS_TC_ISO10646 (0x1000) 3917 3918 /* Traditional Chinese encodings and charsets */ 3919 static struct prt_ps_encoding_S tc_encodings[] = 3920 { 3921 {"iso-2022", NULL, (CS_CNS_PLANE_1|CS_CNS_PLANE_2)}, 3922 {"euc-tw", "EUC", CS_CNS_PLANE_1_2}, 3923 {"big5", "B5", (CS_B5|CS_ETEN|CS_HK_GCCS|CS_HK_SCS| 3924 CS_HK_SCS_ETEN|CS_MTHKL|CS_MTHKS|CS_DLHKL| 3925 CS_DLHKS)}, 3926 {"cp950", "B5", CS_B5}, 3927 {"ucs-2", "UCS2", CS_TC_ISO10646}, 3928 {"utf-8", "UTF8", CS_TC_ISO10646}, 3929 {"utf-16", "UTF16", CS_TC_ISO10646}, 3930 {"utf-32", "UTF32", CS_TC_ISO10646} 3931 }; 3932 static struct prt_ps_charset_S tc_charsets[] = 3933 { 3934 {"CNS_1992_1", "CNS1", CS_CNS_PLANE_1}, 3935 {"CNS_1992_2", "CNS2", CS_CNS_PLANE_2}, 3936 {"CNS_1993", "CNS", CS_CNS_PLANE_1_2}, 3937 {"BIG5", NULL, CS_B5}, 3938 {"CP950", NULL, CS_B5}, 3939 {"ETEN", "ETen", CS_ETEN}, 3940 {"HK_GCCS", "HKgccs", CS_HK_GCCS}, 3941 {"SCS", "HKscs", CS_HK_SCS}, 3942 {"SCS_ETEN", "ETHK", CS_HK_SCS_ETEN}, 3943 {"MTHKL", "HKm471", CS_MTHKL}, 3944 {"MTHKS", "HKm314", CS_MTHKS}, 3945 {"DLHKL", "HKdla", CS_DLHKL}, 3946 {"DLHKS", "HKdlb", CS_DLHKS}, 3947 {"ISO10646", "UniCNS", CS_TC_ISO10646} 3948 }; 3949 3950 #define CS_KR_X_1992 (0x01) 3951 #define CS_KR_MAC (0x02) 3952 #define CS_KR_X_1992_MS (0x04) 3953 #define CS_KR_ISO10646 (0x08) 3954 3955 /* Korean encodings and charsets */ 3956 static struct prt_ps_encoding_S k_encodings[] = 3957 { 3958 {"iso-2022-kr", NULL, CS_KR_X_1992}, 3959 {"euc-kr", "EUC", (CS_KR_X_1992|CS_KR_MAC)}, 3960 {"johab", "Johab", CS_KR_X_1992}, 3961 {"cp1361", "Johab", CS_KR_X_1992}, 3962 {"uhc", "UHC", CS_KR_X_1992_MS}, 3963 {"cp949", "UHC", CS_KR_X_1992_MS}, 3964 {"ucs-2", "UCS2", CS_KR_ISO10646}, 3965 {"utf-8", "UTF8", CS_KR_ISO10646} 3966 }; 3967 static struct prt_ps_charset_S k_charsets[] = 3968 { 3969 {"KS_X_1992", "KSC", CS_KR_X_1992}, 3970 {"CP1361", "KSC", CS_KR_X_1992}, 3971 {"MAC", "KSCpc", CS_KR_MAC}, 3972 {"MSWINDOWS", "KSCms", CS_KR_X_1992_MS}, 3973 {"CP949", "KSCms", CS_KR_X_1992_MS}, 3974 {"WANSUNG", "KSCms", CS_KR_X_1992_MS}, 3975 {"ISO10646", "UniKS", CS_KR_ISO10646} 3976 }; 3977 3978 /* Collections of encodings and charsets for multi-byte printing */ 3979 struct prt_ps_mbfont_S 3980 { 3981 int num_encodings; 3982 struct prt_ps_encoding_S *encodings; 3983 int num_charsets; 3984 struct prt_ps_charset_S *charsets; 3985 char *ascii_enc; 3986 char *defcs; 3987 }; 3988 3989 static struct prt_ps_mbfont_S prt_ps_mbfonts[] = 3990 { 3991 { 3992 NUM_ELEMENTS(j_encodings), 3993 j_encodings, 3994 NUM_ELEMENTS(j_charsets), 3995 j_charsets, 3996 "jis_roman", 3997 "JIS_X_1983" 3998 }, 3999 { 4000 NUM_ELEMENTS(sc_encodings), 4001 sc_encodings, 4002 NUM_ELEMENTS(sc_charsets), 4003 sc_charsets, 4004 "gb_roman", 4005 "GB_2312-80" 4006 }, 4007 { 4008 NUM_ELEMENTS(tc_encodings), 4009 tc_encodings, 4010 NUM_ELEMENTS(tc_charsets), 4011 tc_charsets, 4012 "cns_roman", 4013 "BIG5" 4014 }, 4015 { 4016 NUM_ELEMENTS(k_encodings), 4017 k_encodings, 4018 NUM_ELEMENTS(k_charsets), 4019 k_charsets, 4020 "ks_roman", 4021 "KS_X_1992" 4022 } 4023 }; 4024 #endif /* FEAT_MBYTE */ 4025 4026 struct prt_ps_resource_S 4027 { 4028 char_u name[64]; 4029 char_u filename[MAXPATHL + 1]; 4030 int type; 4031 char_u title[256]; 4032 char_u version[256]; 4033 }; 4034 4035 /* Types of PS resource file currently used */ 4036 #define PRT_RESOURCE_TYPE_PROCSET (0) 4037 #define PRT_RESOURCE_TYPE_ENCODING (1) 4038 #define PRT_RESOURCE_TYPE_CMAP (2) 4039 4040 /* The PS prolog file version number has to match - if the prolog file is 4041 * updated, increment the number in the file and here. Version checking was 4042 * added as of VIM 6.2. 4043 * The CID prolog file version number behaves as per PS prolog. 4044 * Table of VIM and prolog versions: 4045 * 4046 * VIM Prolog CIDProlog 4047 * 6.2 1.3 4048 * 7.0 1.4 1.0 4049 */ 4050 #define PRT_PROLOG_VERSION ((char_u *)"1.4") 4051 #define PRT_CID_PROLOG_VERSION ((char_u *)"1.0") 4052 4053 /* String versions of PS resource types - indexed by constants above so don't 4054 * re-order! 4055 */ 4056 static char *prt_resource_types[] = 4057 { 4058 "procset", 4059 "encoding", 4060 "cmap" 4061 }; 4062 4063 /* Strings to look for in a PS resource file */ 4064 #define PRT_RESOURCE_HEADER "%!PS-Adobe-" 4065 #define PRT_RESOURCE_RESOURCE "Resource-" 4066 #define PRT_RESOURCE_PROCSET "ProcSet" 4067 #define PRT_RESOURCE_ENCODING "Encoding" 4068 #define PRT_RESOURCE_CMAP "CMap" 4069 4070 4071 /* Data for table based DSC comment recognition, easy to extend if VIM needs to 4072 * read more comments. */ 4073 #define PRT_DSC_MISC_TYPE (-1) 4074 #define PRT_DSC_TITLE_TYPE (1) 4075 #define PRT_DSC_VERSION_TYPE (2) 4076 #define PRT_DSC_ENDCOMMENTS_TYPE (3) 4077 4078 #define PRT_DSC_TITLE "%%Title:" 4079 #define PRT_DSC_VERSION "%%Version:" 4080 #define PRT_DSC_ENDCOMMENTS "%%EndComments:" 4081 4082 struct prt_dsc_comment_S 4083 { 4084 char *string; 4085 int len; 4086 int type; 4087 }; 4088 4089 struct prt_dsc_line_S 4090 { 4091 int type; 4092 char_u *string; 4093 int len; 4094 }; 4095 4096 4097 #define SIZEOF_CSTR(s) (sizeof(s) - 1) 4098 struct prt_dsc_comment_S prt_dsc_table[] = 4099 { 4100 {PRT_DSC_TITLE, SIZEOF_CSTR(PRT_DSC_TITLE), PRT_DSC_TITLE_TYPE}, 4101 {PRT_DSC_VERSION, SIZEOF_CSTR(PRT_DSC_VERSION), 4102 PRT_DSC_VERSION_TYPE}, 4103 {PRT_DSC_ENDCOMMENTS, SIZEOF_CSTR(PRT_DSC_ENDCOMMENTS), 4104 PRT_DSC_ENDCOMMENTS_TYPE} 4105 }; 4106 4107 static void prt_write_file_raw_len __ARGS((char_u *buffer, int bytes)); 4108 static void prt_write_file __ARGS((char_u *buffer)); 4109 static void prt_write_file_len __ARGS((char_u *buffer, int bytes)); 4110 static void prt_write_string __ARGS((char *s)); 4111 static void prt_write_int __ARGS((int i)); 4112 static void prt_write_boolean __ARGS((int b)); 4113 static void prt_def_font __ARGS((char *new_name, char *encoding, int height, char *font)); 4114 static void prt_real_bits __ARGS((double real, int precision, int *pinteger, int *pfraction)); 4115 static void prt_write_real __ARGS((double val, int prec)); 4116 static void prt_def_var __ARGS((char *name, double value, int prec)); 4117 static void prt_flush_buffer __ARGS((void)); 4118 static void prt_resource_name __ARGS((char_u *filename)); 4119 static int prt_find_resource __ARGS((char *name, struct prt_ps_resource_S *resource)); 4120 static int prt_open_resource __ARGS((struct prt_ps_resource_S *resource)); 4121 static int prt_check_resource __ARGS((struct prt_ps_resource_S *resource, char_u *version)); 4122 static void prt_dsc_start __ARGS((void)); 4123 static void prt_dsc_noarg __ARGS((char *comment)); 4124 static void prt_dsc_textline __ARGS((char *comment, char *text)); 4125 static void prt_dsc_text __ARGS((char *comment, char *text)); 4126 static void prt_dsc_ints __ARGS((char *comment, int count, int *ints)); 4127 static void prt_dsc_requirements __ARGS((int duplex, int tumble, int collate, int color, int num_copies)); 4128 static void prt_dsc_docmedia __ARGS((char *paper_name, double width, double height, double weight, char *colour, char *type)); 4129 static void prt_dsc_resources __ARGS((char *comment, char *type, char *strings)); 4130 static void prt_dsc_font_resource __ARGS((char *resource, struct prt_ps_font_S *ps_font)); 4131 static float to_device_units __ARGS((int idx, double physsize, int def_number)); 4132 static void prt_page_margins __ARGS((double width, double height, double *left, double *right, double *top, double *bottom)); 4133 static void prt_font_metrics __ARGS((int font_scale)); 4134 static int prt_get_cpl __ARGS((void)); 4135 static int prt_get_lpp __ARGS((void)); 4136 static int prt_add_resource __ARGS((struct prt_ps_resource_S *resource)); 4137 static int prt_resfile_next_line __ARGS((void)); 4138 static int prt_resfile_strncmp __ARGS((int offset, char *string, int len)); 4139 static int prt_resfile_skip_nonws __ARGS((int offset)); 4140 static int prt_resfile_skip_ws __ARGS((int offset)); 4141 static int prt_next_dsc __ARGS((struct prt_dsc_line_S *p_dsc_line)); 4142 #ifdef FEAT_MBYTE 4143 static int prt_build_cid_fontname __ARGS((int font, char_u *name, int name_len)); 4144 static void prt_def_cidfont __ARGS((char *new_name, int height, char *cidfont)); 4145 static int prt_match_encoding __ARGS((char *p_encoding, struct prt_ps_mbfont_S *p_cmap, struct prt_ps_encoding_S **pp_mbenc)); 4146 static int prt_match_charset __ARGS((char *p_charset, struct prt_ps_mbfont_S *p_cmap, struct prt_ps_charset_S **pp_mbchar)); 4147 #endif 4148 4149 /* 4150 * Variables for the output PostScript file. 4151 */ 4152 static FILE *prt_ps_fd; 4153 static int prt_file_error; 4154 static char_u *prt_ps_file_name = NULL; 4155 4156 /* 4157 * Various offsets and dimensions in default PostScript user space (points). 4158 * Used for text positioning calculations 4159 */ 4160 static float prt_page_width; 4161 static float prt_page_height; 4162 static float prt_left_margin; 4163 static float prt_right_margin; 4164 static float prt_top_margin; 4165 static float prt_bottom_margin; 4166 static float prt_line_height; 4167 static float prt_first_line_height; 4168 static float prt_char_width; 4169 static float prt_number_width; 4170 static float prt_bgcol_offset; 4171 static float prt_pos_x_moveto = 0.0; 4172 static float prt_pos_y_moveto = 0.0; 4173 4174 /* 4175 * Various control variables used to decide when and how to change the 4176 * PostScript graphics state. 4177 */ 4178 static int prt_need_moveto; 4179 static int prt_do_moveto; 4180 static int prt_need_font; 4181 static int prt_font; 4182 static int prt_need_underline; 4183 static int prt_underline; 4184 static int prt_do_underline; 4185 static int prt_need_fgcol; 4186 static int prt_fgcol; 4187 static int prt_need_bgcol; 4188 static int prt_do_bgcol; 4189 static int prt_bgcol; 4190 static int prt_new_bgcol; 4191 static int prt_attribute_change; 4192 static float prt_text_run; 4193 static int prt_page_num; 4194 static int prt_bufsiz; 4195 4196 /* 4197 * Variables controlling physical printing. 4198 */ 4199 static int prt_media; 4200 static int prt_portrait; 4201 static int prt_num_copies; 4202 static int prt_duplex; 4203 static int prt_tumble; 4204 static int prt_collate; 4205 4206 /* 4207 * Buffers used when generating PostScript output 4208 */ 4209 static char_u prt_line_buffer[257]; 4210 static garray_T prt_ps_buffer; 4211 4212 # ifdef FEAT_MBYTE 4213 static int prt_do_conv; 4214 static vimconv_T prt_conv; 4215 4216 static int prt_out_mbyte; 4217 static int prt_custom_cmap; 4218 static char prt_cmap[80]; 4219 static int prt_use_courier; 4220 static int prt_in_ascii; 4221 static int prt_half_width; 4222 static char *prt_ascii_encoding; 4223 static char_u prt_hexchar[] = "0123456789abcdef"; 4224 # endif 4225 4226 static void 4227 prt_write_file_raw_len(buffer, bytes) 4228 char_u *buffer; 4229 int bytes; 4230 { 4231 if (!prt_file_error 4232 && fwrite(buffer, sizeof(char_u), bytes, prt_ps_fd) 4233 != (size_t)bytes) 4234 { 4235 EMSG(_("E455: Error writing to PostScript output file")); 4236 prt_file_error = TRUE; 4237 } 4238 } 4239 4240 static void 4241 prt_write_file(buffer) 4242 char_u *buffer; 4243 { 4244 prt_write_file_len(buffer, STRLEN(buffer)); 4245 } 4246 4247 static void 4248 prt_write_file_len(buffer, bytes) 4249 char_u *buffer; 4250 int bytes; 4251 { 4252 #ifdef EBCDIC 4253 ebcdic2ascii(buffer, bytes); 4254 #endif 4255 prt_write_file_raw_len(buffer, bytes); 4256 } 4257 4258 /* 4259 * Write a string. 4260 */ 4261 static void 4262 prt_write_string(s) 4263 char *s; 4264 { 4265 sprintf((char *)prt_line_buffer, "%s", s); 4266 prt_write_file(prt_line_buffer); 4267 } 4268 4269 /* 4270 * Write an int and a space. 4271 */ 4272 static void 4273 prt_write_int(i) 4274 int i; 4275 { 4276 sprintf((char *)prt_line_buffer, "%d ", i); 4277 prt_write_file(prt_line_buffer); 4278 } 4279 4280 /* 4281 * Write a boolean and a space. 4282 */ 4283 static void 4284 prt_write_boolean(b) 4285 int b; 4286 { 4287 sprintf((char *)prt_line_buffer, "%s ", (b ? "T" : "F")); 4288 prt_write_file(prt_line_buffer); 4289 } 4290 4291 /* 4292 * Write PostScript to re-encode and define the font. 4293 */ 4294 static void 4295 prt_def_font(new_name, encoding, height, font) 4296 char *new_name; 4297 char *encoding; 4298 int height; 4299 char *font; 4300 { 4301 sprintf((char *)prt_line_buffer, "/_%s /VIM-%s /%s ref\n", 4302 new_name, encoding, font); 4303 prt_write_file(prt_line_buffer); 4304 #ifdef FEAT_MBYTE 4305 if (prt_out_mbyte) 4306 sprintf((char *)prt_line_buffer, "/%s %d %f /_%s sffs\n", 4307 new_name, height, 500./prt_ps_courier_font.wx, new_name); 4308 else 4309 #endif 4310 sprintf((char *)prt_line_buffer, "/%s %d /_%s ffs\n", 4311 new_name, height, new_name); 4312 prt_write_file(prt_line_buffer); 4313 } 4314 4315 #ifdef FEAT_MBYTE 4316 /* 4317 * Write a line to define the CID font. 4318 */ 4319 static void 4320 prt_def_cidfont(new_name, height, cidfont) 4321 char *new_name; 4322 int height; 4323 char *cidfont; 4324 { 4325 sprintf((char *)prt_line_buffer, "/_%s /%s[/%s] vim_composefont\n", 4326 new_name, prt_cmap, cidfont); 4327 prt_write_file(prt_line_buffer); 4328 sprintf((char *)prt_line_buffer, "/%s %d /_%s ffs\n", new_name, height, 4329 new_name); 4330 prt_write_file(prt_line_buffer); 4331 } 4332 4333 /* 4334 * Write a line to define a duplicate of a CID font 4335 */ 4336 static void 4337 prt_dup_cidfont(original_name, new_name) 4338 char *original_name; 4339 char *new_name; 4340 { 4341 sprintf((char *)prt_line_buffer, "/%s %s d\n", new_name, original_name); 4342 prt_write_file(prt_line_buffer); 4343 } 4344 #endif 4345 4346 /* 4347 * Convert a real value into an integer and fractional part as integers, with 4348 * the fractional part being in the range [0,10^precision). The fractional part 4349 * is also rounded based on the precision + 1'th fractional digit. 4350 */ 4351 static void 4352 prt_real_bits(real, precision, pinteger, pfraction) 4353 double real; 4354 int precision; 4355 int *pinteger; 4356 int *pfraction; 4357 { 4358 int i; 4359 int integer; 4360 float fraction; 4361 4362 integer = (int)real; 4363 fraction = (float)(real - integer); 4364 if (real < (double)integer) 4365 fraction = -fraction; 4366 for (i = 0; i < precision; i++) 4367 fraction *= 10.0; 4368 4369 *pinteger = integer; 4370 *pfraction = (int)(fraction + 0.5); 4371 } 4372 4373 /* 4374 * Write a real and a space. Save bytes if real value has no fractional part! 4375 * We use prt_real_bits() as %f in sprintf uses the locale setting to decide 4376 * what decimal point character to use, but PS always requires a '.'. 4377 */ 4378 static void 4379 prt_write_real(val, prec) 4380 double val; 4381 int prec; 4382 { 4383 int integer; 4384 int fraction; 4385 4386 prt_real_bits(val, prec, &integer, &fraction); 4387 /* Emit integer part */ 4388 sprintf((char *)prt_line_buffer, "%d", integer); 4389 prt_write_file(prt_line_buffer); 4390 /* Only emit fraction if necessary */ 4391 if (fraction != 0) 4392 { 4393 /* Remove any trailing zeros */ 4394 while ((fraction % 10) == 0) 4395 { 4396 prec--; 4397 fraction /= 10; 4398 } 4399 /* Emit fraction left padded with zeros */ 4400 sprintf((char *)prt_line_buffer, ".%0*d", prec, fraction); 4401 prt_write_file(prt_line_buffer); 4402 } 4403 sprintf((char *)prt_line_buffer, " "); 4404 prt_write_file(prt_line_buffer); 4405 } 4406 4407 /* 4408 * Write a line to define a numeric variable. 4409 */ 4410 static void 4411 prt_def_var(name, value, prec) 4412 char *name; 4413 double value; 4414 int prec; 4415 { 4416 sprintf((char *)prt_line_buffer, "/%s ", name); 4417 prt_write_file(prt_line_buffer); 4418 prt_write_real(value, prec); 4419 sprintf((char *)prt_line_buffer, "d\n"); 4420 prt_write_file(prt_line_buffer); 4421 } 4422 4423 /* Convert size from font space to user space at current font scale */ 4424 #define PRT_PS_FONT_TO_USER(scale, size) ((size) * ((scale)/1000.0)) 4425 4426 static void 4427 prt_flush_buffer() 4428 { 4429 if (prt_ps_buffer.ga_len > 0) 4430 { 4431 /* Any background color must be drawn first */ 4432 if (prt_do_bgcol && (prt_new_bgcol != PRCOLOR_WHITE)) 4433 { 4434 int r, g, b; 4435 4436 if (prt_do_moveto) 4437 { 4438 prt_write_real(prt_pos_x_moveto, 2); 4439 prt_write_real(prt_pos_y_moveto, 2); 4440 prt_write_string("m\n"); 4441 prt_do_moveto = FALSE; 4442 } 4443 4444 /* Size of rect of background color on which text is printed */ 4445 prt_write_real(prt_text_run, 2); 4446 prt_write_real(prt_line_height, 2); 4447 4448 /* Lastly add the color of the background */ 4449 r = ((unsigned)prt_new_bgcol & 0xff0000) >> 16; 4450 g = ((unsigned)prt_new_bgcol & 0xff00) >> 8; 4451 b = prt_new_bgcol & 0xff; 4452 prt_write_real(r / 255.0, 3); 4453 prt_write_real(g / 255.0, 3); 4454 prt_write_real(b / 255.0, 3); 4455 prt_write_string("bg\n"); 4456 } 4457 /* Draw underlines before the text as it makes it slightly easier to 4458 * find the starting point. 4459 */ 4460 if (prt_do_underline) 4461 { 4462 if (prt_do_moveto) 4463 { 4464 prt_write_real(prt_pos_x_moveto, 2); 4465 prt_write_real(prt_pos_y_moveto, 2); 4466 prt_write_string("m\n"); 4467 prt_do_moveto = FALSE; 4468 } 4469 4470 /* Underline length of text run */ 4471 prt_write_real(prt_text_run, 2); 4472 prt_write_string("ul\n"); 4473 } 4474 /* Draw the text 4475 * Note: we write text out raw - EBCDIC conversion is handled in the 4476 * PostScript world via the font encoding vector. */ 4477 #ifdef FEAT_MBYTE 4478 if (prt_out_mbyte) 4479 prt_write_string("<"); 4480 else 4481 #endif 4482 prt_write_string("("); 4483 prt_write_file_raw_len(prt_ps_buffer.ga_data, prt_ps_buffer.ga_len); 4484 #ifdef FEAT_MBYTE 4485 if (prt_out_mbyte) 4486 prt_write_string(">"); 4487 else 4488 #endif 4489 prt_write_string(")"); 4490 /* Add a moveto if need be and use the appropriate show procedure */ 4491 if (prt_do_moveto) 4492 { 4493 prt_write_real(prt_pos_x_moveto, 2); 4494 prt_write_real(prt_pos_y_moveto, 2); 4495 /* moveto and a show */ 4496 prt_write_string("ms\n"); 4497 prt_do_moveto = FALSE; 4498 } 4499 else /* Simple show */ 4500 prt_write_string("s\n"); 4501 4502 ga_clear(&prt_ps_buffer); 4503 ga_init2(&prt_ps_buffer, (int)sizeof(char), prt_bufsiz); 4504 } 4505 } 4506 4507 static char_u *resource_filename; 4508 4509 static void 4510 prt_resource_name(filename) 4511 char_u *filename; 4512 { 4513 if (STRLEN(filename) >= MAXPATHL) 4514 *resource_filename = NUL; 4515 else 4516 STRCPY(resource_filename, filename); 4517 } 4518 4519 static int 4520 prt_find_resource(name, resource) 4521 char *name; 4522 struct prt_ps_resource_S *resource; 4523 { 4524 char_u buffer[MAXPATHL + 1]; 4525 4526 STRCPY(resource->name, name); 4527 /* Look for named resource file in runtimepath */ 4528 STRCPY(buffer, "print"); 4529 add_pathsep(buffer); 4530 STRCAT(buffer, name); 4531 STRCAT(buffer, ".ps"); 4532 resource_filename = resource->filename; 4533 *resource_filename = NUL; 4534 return (do_in_runtimepath(buffer, FALSE, prt_resource_name) 4535 && resource->filename[0] != NUL); 4536 } 4537 4538 /* PS CR and LF characters have platform independent values */ 4539 #define PSLF (0x0a) 4540 #define PSCR (0x0d) 4541 4542 /* Static buffer to read initial comments in a resource file, some can have a 4543 * couple of KB of comments! */ 4544 #define PRT_FILE_BUFFER_LEN (2048) 4545 struct prt_resfile_buffer_S 4546 { 4547 char_u buffer[PRT_FILE_BUFFER_LEN]; 4548 int len; 4549 int line_start; 4550 int line_end; 4551 }; 4552 4553 static struct prt_resfile_buffer_S prt_resfile; 4554 4555 static int 4556 prt_resfile_next_line() 4557 { 4558 int index; 4559 4560 /* Move to start of next line and then find end of line */ 4561 index = prt_resfile.line_end + 1; 4562 while (index < prt_resfile.len) 4563 { 4564 if (prt_resfile.buffer[index] != PSLF && prt_resfile.buffer[index] 4565 != PSCR) 4566 break; 4567 index++; 4568 } 4569 prt_resfile.line_start = index; 4570 4571 while (index < prt_resfile.len) 4572 { 4573 if (prt_resfile.buffer[index] == PSLF || prt_resfile.buffer[index] 4574 == PSCR) 4575 break; 4576 index++; 4577 } 4578 prt_resfile.line_end = index; 4579 4580 return (index < prt_resfile.len); 4581 } 4582 4583 static int 4584 prt_resfile_strncmp(offset, string, len) 4585 int offset; 4586 char *string; 4587 int len; 4588 { 4589 /* Force not equal if string is longer than remainder of line */ 4590 if (len > (prt_resfile.line_end - (prt_resfile.line_start + offset))) 4591 return 1; 4592 4593 return STRNCMP(&prt_resfile.buffer[prt_resfile.line_start + offset], 4594 string, len); 4595 } 4596 4597 static int 4598 prt_resfile_skip_nonws(offset) 4599 int offset; 4600 { 4601 int index; 4602 4603 index = prt_resfile.line_start + offset; 4604 while (index < prt_resfile.line_end) 4605 { 4606 if (isspace(prt_resfile.buffer[index])) 4607 return index - prt_resfile.line_start; 4608 index++; 4609 } 4610 return -1; 4611 } 4612 4613 static int 4614 prt_resfile_skip_ws(offset) 4615 int offset; 4616 { 4617 int index; 4618 4619 index = prt_resfile.line_start + offset; 4620 while (index < prt_resfile.line_end) 4621 { 4622 if (!isspace(prt_resfile.buffer[index])) 4623 return index - prt_resfile.line_start; 4624 index++; 4625 } 4626 return -1; 4627 } 4628 4629 /* prt_next_dsc() - returns detail on next DSC comment line found. Returns true 4630 * if a DSC comment is found, else false */ 4631 static int 4632 prt_next_dsc(p_dsc_line) 4633 struct prt_dsc_line_S *p_dsc_line; 4634 { 4635 int comment; 4636 int offset; 4637 4638 /* Move to start of next line */ 4639 if (!prt_resfile_next_line()) 4640 return FALSE; 4641 4642 /* DSC comments always start %% */ 4643 if (prt_resfile_strncmp(0, "%%", 2) != 0) 4644 return FALSE; 4645 4646 /* Find type of DSC comment */ 4647 for (comment = 0; comment < NUM_ELEMENTS(prt_dsc_table); comment++) 4648 if (prt_resfile_strncmp(0, prt_dsc_table[comment].string, 4649 prt_dsc_table[comment].len) == 0) 4650 break; 4651 4652 if (comment != NUM_ELEMENTS(prt_dsc_table)) 4653 { 4654 /* Return type of comment */ 4655 p_dsc_line->type = prt_dsc_table[comment].type; 4656 offset = prt_dsc_table[comment].len; 4657 } 4658 else 4659 { 4660 /* Unrecognised DSC comment, skip to ws after comment leader */ 4661 p_dsc_line->type = PRT_DSC_MISC_TYPE; 4662 offset = prt_resfile_skip_nonws(0); 4663 if (offset == -1) 4664 return FALSE; 4665 } 4666 4667 /* Skip ws to comment value */ 4668 offset = prt_resfile_skip_ws(offset); 4669 if (offset == -1) 4670 return FALSE; 4671 4672 p_dsc_line->string = &prt_resfile.buffer[prt_resfile.line_start + offset]; 4673 p_dsc_line->len = prt_resfile.line_end - (prt_resfile.line_start + offset); 4674 4675 return TRUE; 4676 } 4677 4678 /* Improved hand crafted parser to get the type, title, and version number of a 4679 * PS resource file so the file details can be added to the DSC header comments. 4680 */ 4681 static int 4682 prt_open_resource(resource) 4683 struct prt_ps_resource_S *resource; 4684 { 4685 int offset; 4686 int seen_all; 4687 int seen_title; 4688 int seen_version; 4689 FILE *fd_resource; 4690 struct prt_dsc_line_S dsc_line; 4691 4692 fd_resource = mch_fopen((char *)resource->filename, READBIN); 4693 if (fd_resource == NULL) 4694 { 4695 EMSG2(_("E624: Can't open file \"%s\""), resource->filename); 4696 return FALSE; 4697 } 4698 vim_memset(prt_resfile.buffer, NUL, PRT_FILE_BUFFER_LEN); 4699 4700 /* Parse first line to ensure valid resource file */ 4701 prt_resfile.len = fread((char *)prt_resfile.buffer, sizeof(char_u), 4702 PRT_FILE_BUFFER_LEN, fd_resource); 4703 if (ferror(fd_resource)) 4704 { 4705 EMSG2(_("E457: Can't read PostScript resource file \"%s\""), 4706 resource->filename); 4707 fclose(fd_resource); 4708 return FALSE; 4709 } 4710 4711 prt_resfile.line_end = -1; 4712 prt_resfile.line_start = 0; 4713 if (!prt_resfile_next_line()) 4714 return FALSE; 4715 4716 offset = 0; 4717 4718 if (prt_resfile_strncmp(offset, PRT_RESOURCE_HEADER, 4719 STRLEN(PRT_RESOURCE_HEADER)) != 0) 4720 { 4721 EMSG2(_("E618: file \"%s\" is not a PostScript resource file"), 4722 resource->filename); 4723 fclose(fd_resource); 4724 return FALSE; 4725 } 4726 4727 /* Skip over any version numbers and following ws */ 4728 offset += STRLEN(PRT_RESOURCE_HEADER); 4729 offset = prt_resfile_skip_nonws(offset); 4730 if (offset == -1) 4731 return FALSE; 4732 offset = prt_resfile_skip_ws(offset); 4733 if (offset == -1) 4734 return FALSE; 4735 4736 if (prt_resfile_strncmp(offset, PRT_RESOURCE_RESOURCE, 4737 STRLEN(PRT_RESOURCE_RESOURCE)) != 0) 4738 { 4739 EMSG2(_("E619: file \"%s\" is not a supported PostScript resource file"), 4740 resource->filename); 4741 fclose(fd_resource); 4742 return FALSE; 4743 } 4744 offset += STRLEN(PRT_RESOURCE_RESOURCE); 4745 4746 /* Decide type of resource in the file */ 4747 if (prt_resfile_strncmp(offset, PRT_RESOURCE_PROCSET, 4748 STRLEN(PRT_RESOURCE_PROCSET)) == 0) 4749 resource->type = PRT_RESOURCE_TYPE_PROCSET; 4750 else if (prt_resfile_strncmp(offset, PRT_RESOURCE_ENCODING, 4751 STRLEN(PRT_RESOURCE_ENCODING)) == 0) 4752 resource->type = PRT_RESOURCE_TYPE_ENCODING; 4753 else if (prt_resfile_strncmp(offset, PRT_RESOURCE_CMAP, 4754 STRLEN(PRT_RESOURCE_CMAP)) == 0) 4755 resource->type = PRT_RESOURCE_TYPE_CMAP; 4756 else 4757 { 4758 EMSG2(_("E619: file \"%s\" is not a supported PostScript resource file"), 4759 resource->filename); 4760 fclose(fd_resource); 4761 return FALSE; 4762 } 4763 4764 /* Look for title and version of resource */ 4765 resource->title[0] = '\0'; 4766 resource->version[0] = '\0'; 4767 seen_title = FALSE; 4768 seen_version = FALSE; 4769 seen_all = FALSE; 4770 while (!seen_all && prt_next_dsc(&dsc_line)) 4771 { 4772 switch (dsc_line.type) 4773 { 4774 case PRT_DSC_TITLE_TYPE: 4775 STRNCPY(resource->title, dsc_line.string, dsc_line.len); 4776 resource->title[dsc_line.len] = '\0'; 4777 seen_title = TRUE; 4778 if (seen_version) 4779 seen_all = TRUE; 4780 break; 4781 4782 case PRT_DSC_VERSION_TYPE: 4783 STRNCPY(resource->version, dsc_line.string, dsc_line.len); 4784 resource->version[dsc_line.len] = '\0'; 4785 seen_version = TRUE; 4786 if (seen_title) 4787 seen_all = TRUE; 4788 break; 4789 4790 case PRT_DSC_ENDCOMMENTS_TYPE: 4791 /* Wont find title or resource after this comment, stop searching */ 4792 seen_all = TRUE; 4793 break; 4794 4795 case PRT_DSC_MISC_TYPE: 4796 /* Not interested in whatever comment this line had */ 4797 break; 4798 } 4799 } 4800 4801 if (!seen_title || !seen_version) 4802 { 4803 EMSG2(_("E619: file \"%s\" is not a supported PostScript resource file"), 4804 resource->filename); 4805 fclose(fd_resource); 4806 return FALSE; 4807 } 4808 4809 fclose(fd_resource); 4810 4811 return TRUE; 4812 } 4813 4814 static int 4815 prt_check_resource(resource, version) 4816 struct prt_ps_resource_S *resource; 4817 char_u *version; 4818 { 4819 /* Version number m.n should match, the revision number does not matter */ 4820 if (STRNCMP(resource->version, version, STRLEN(version))) 4821 { 4822 EMSG2(_("E621: \"%s\" resource file has wrong version"), 4823 resource->name); 4824 return FALSE; 4825 } 4826 4827 /* Other checks to be added as needed */ 4828 return TRUE; 4829 } 4830 4831 static void 4832 prt_dsc_start() 4833 { 4834 prt_write_string("%!PS-Adobe-3.0\n"); 4835 } 4836 4837 static void 4838 prt_dsc_noarg(comment) 4839 char *comment; 4840 { 4841 sprintf((char *)prt_line_buffer, "%%%%%s\n", comment); 4842 prt_write_file(prt_line_buffer); 4843 } 4844 4845 static void 4846 prt_dsc_textline(comment, text) 4847 char *comment; 4848 char *text; 4849 { 4850 sprintf((char *)prt_line_buffer, "%%%%%s: %s\n", comment, text); 4851 prt_write_file(prt_line_buffer); 4852 } 4853 4854 static void 4855 prt_dsc_text(comment, text) 4856 char *comment; 4857 char *text; 4858 { 4859 /* TODO - should scan 'text' for any chars needing escaping! */ 4860 sprintf((char *)prt_line_buffer, "%%%%%s: (%s)\n", comment, text); 4861 prt_write_file(prt_line_buffer); 4862 } 4863 4864 #define prt_dsc_atend(c) prt_dsc_text((c), "atend") 4865 4866 static void 4867 prt_dsc_ints(comment, count, ints) 4868 char *comment; 4869 int count; 4870 int *ints; 4871 { 4872 int i; 4873 4874 sprintf((char *)prt_line_buffer, "%%%%%s:", comment); 4875 prt_write_file(prt_line_buffer); 4876 4877 for (i = 0; i < count; i++) 4878 { 4879 sprintf((char *)prt_line_buffer, " %d", ints[i]); 4880 prt_write_file(prt_line_buffer); 4881 } 4882 4883 prt_write_string("\n"); 4884 } 4885 4886 static void 4887 prt_dsc_resources(comment, type, string) 4888 char *comment; /* if NULL add to previous */ 4889 char *type; 4890 char *string; 4891 { 4892 if (comment != NULL) 4893 sprintf((char *)prt_line_buffer, "%%%%%s: %s", comment, type); 4894 else 4895 sprintf((char *)prt_line_buffer, "%%%%+ %s", type); 4896 prt_write_file(prt_line_buffer); 4897 4898 sprintf((char *)prt_line_buffer, " %s\n", string); 4899 prt_write_file(prt_line_buffer); 4900 } 4901 4902 static void 4903 prt_dsc_font_resource(resource, ps_font) 4904 char *resource; 4905 struct prt_ps_font_S *ps_font; 4906 { 4907 int i; 4908 4909 prt_dsc_resources(resource, "font", 4910 ps_font->ps_fontname[PRT_PS_FONT_ROMAN]); 4911 for (i = PRT_PS_FONT_BOLD ; i <= PRT_PS_FONT_BOLDOBLIQUE ; i++) 4912 if (ps_font->ps_fontname[i] != NULL) 4913 prt_dsc_resources(NULL, "font", ps_font->ps_fontname[i]); 4914 } 4915 4916 static void 4917 prt_dsc_requirements(duplex, tumble, collate, color, num_copies) 4918 int duplex; 4919 int tumble; 4920 int collate; 4921 int color; 4922 int num_copies; 4923 { 4924 /* Only output the comment if we need to. 4925 * Note: tumble is ignored if we are not duplexing 4926 */ 4927 if (!(duplex || collate || color || (num_copies > 1))) 4928 return; 4929 4930 sprintf((char *)prt_line_buffer, "%%%%Requirements:"); 4931 prt_write_file(prt_line_buffer); 4932 4933 if (duplex) 4934 { 4935 prt_write_string(" duplex"); 4936 if (tumble) 4937 prt_write_string("(tumble)"); 4938 } 4939 if (collate) 4940 prt_write_string(" collate"); 4941 if (color) 4942 prt_write_string(" color"); 4943 if (num_copies > 1) 4944 { 4945 prt_write_string(" numcopies("); 4946 /* Note: no space wanted so dont use prt_write_int() */ 4947 sprintf((char *)prt_line_buffer, "%d", num_copies); 4948 prt_write_file(prt_line_buffer); 4949 prt_write_string(")"); 4950 } 4951 prt_write_string("\n"); 4952 } 4953 4954 static void 4955 prt_dsc_docmedia(paper_name, width, height, weight, colour, type) 4956 char *paper_name; 4957 double width; 4958 double height; 4959 double weight; 4960 char *colour; 4961 char *type; 4962 { 4963 sprintf((char *)prt_line_buffer, "%%%%DocumentMedia: %s ", paper_name); 4964 prt_write_file(prt_line_buffer); 4965 prt_write_real(width, 2); 4966 prt_write_real(height, 2); 4967 prt_write_real(weight, 2); 4968 if (colour == NULL) 4969 prt_write_string("()"); 4970 else 4971 prt_write_string(colour); 4972 prt_write_string(" "); 4973 if (type == NULL) 4974 prt_write_string("()"); 4975 else 4976 prt_write_string(type); 4977 prt_write_string("\n"); 4978 } 4979 4980 void 4981 mch_print_cleanup() 4982 { 4983 #ifdef FEAT_MBYTE 4984 if (prt_out_mbyte) 4985 { 4986 int i; 4987 4988 /* Free off all CID font names created, but first clear duplicate 4989 * pointers to the same string (when the same font is used for more than 4990 * one style). 4991 */ 4992 for (i = PRT_PS_FONT_ROMAN; i <= PRT_PS_FONT_BOLDOBLIQUE; i++) 4993 { 4994 if (prt_ps_mb_font.ps_fontname[i] != NULL) 4995 vim_free(prt_ps_mb_font.ps_fontname[i]); 4996 prt_ps_mb_font.ps_fontname[i] = NULL; 4997 } 4998 } 4999 5000 if (prt_do_conv) 5001 { 5002 convert_setup(&prt_conv, NULL, NULL); 5003 prt_do_conv = FALSE; 5004 } 5005 #endif 5006 if (prt_ps_fd != NULL) 5007 { 5008 fclose(prt_ps_fd); 5009 prt_ps_fd = NULL; 5010 prt_file_error = FALSE; 5011 } 5012 if (prt_ps_file_name != NULL) 5013 { 5014 vim_free(prt_ps_file_name); 5015 prt_ps_file_name = NULL; 5016 } 5017 } 5018 5019 static float 5020 to_device_units(idx, physsize, def_number) 5021 int idx; 5022 double physsize; 5023 int def_number; 5024 { 5025 float ret; 5026 int u; 5027 int nr; 5028 5029 u = prt_get_unit(idx); 5030 if (u == PRT_UNIT_NONE) 5031 { 5032 u = PRT_UNIT_PERC; 5033 nr = def_number; 5034 } 5035 else 5036 nr = printer_opts[idx].number; 5037 5038 switch (u) 5039 { 5040 case PRT_UNIT_INCH: 5041 ret = (float)(nr * PRT_PS_DEFAULT_DPI); 5042 break; 5043 case PRT_UNIT_MM: 5044 ret = (float)(nr * PRT_PS_DEFAULT_DPI) / (float)25.4; 5045 break; 5046 case PRT_UNIT_POINT: 5047 ret = (float)nr; 5048 break; 5049 case PRT_UNIT_PERC: 5050 default: 5051 ret = (float)(physsize * nr) / 100; 5052 break; 5053 } 5054 5055 return ret; 5056 } 5057 5058 /* 5059 * Calculate margins for given width and height from printoptions settings. 5060 */ 5061 static void 5062 prt_page_margins(width, height, left, right, top, bottom) 5063 double width; 5064 double height; 5065 double *left; 5066 double *right; 5067 double *top; 5068 double *bottom; 5069 { 5070 *left = to_device_units(OPT_PRINT_LEFT, width, 10); 5071 *right = width - to_device_units(OPT_PRINT_RIGHT, width, 5); 5072 *top = height - to_device_units(OPT_PRINT_TOP, height, 5); 5073 *bottom = to_device_units(OPT_PRINT_BOT, height, 5); 5074 } 5075 5076 static void 5077 prt_font_metrics(font_scale) 5078 int font_scale; 5079 { 5080 prt_line_height = (float)font_scale; 5081 prt_char_width = (float)PRT_PS_FONT_TO_USER(font_scale, prt_ps_font->wx); 5082 } 5083 5084 5085 static int 5086 prt_get_cpl() 5087 { 5088 if (prt_use_number()) 5089 { 5090 prt_number_width = PRINT_NUMBER_WIDTH * prt_char_width; 5091 #ifdef FEAT_MBYTE 5092 /* If we are outputting multi-byte characters then line numbers will be 5093 * printed with half width characters 5094 */ 5095 if (prt_out_mbyte) 5096 prt_number_width /= 2; 5097 #endif 5098 prt_left_margin += prt_number_width; 5099 } 5100 else 5101 prt_number_width = 0.0; 5102 5103 return (int)((prt_right_margin - prt_left_margin) / prt_char_width); 5104 } 5105 5106 #ifdef FEAT_MBYTE 5107 static int 5108 prt_build_cid_fontname(font, name, name_len) 5109 int font; 5110 char_u *name; 5111 int name_len; 5112 { 5113 char *fontname; 5114 5115 fontname = (char *)alloc(name_len + 1); 5116 if (fontname == NULL) 5117 return FALSE; 5118 STRNCPY(fontname, name, name_len); 5119 fontname[name_len] = '\0'; 5120 prt_ps_mb_font.ps_fontname[font] = fontname; 5121 5122 return TRUE; 5123 } 5124 #endif 5125 5126 /* 5127 * Get number of lines of text that fit on a page (excluding the header). 5128 */ 5129 static int 5130 prt_get_lpp() 5131 { 5132 int lpp; 5133 5134 /* 5135 * Calculate offset to lower left corner of background rect based on actual 5136 * font height (based on its bounding box) and the line height, handling the 5137 * case where the font height can exceed the line height. 5138 */ 5139 prt_bgcol_offset = (float)PRT_PS_FONT_TO_USER(prt_line_height, 5140 prt_ps_font->bbox_min_y); 5141 if ((prt_ps_font->bbox_max_y - prt_ps_font->bbox_min_y) < 1000.0) 5142 { 5143 prt_bgcol_offset -= (float)PRT_PS_FONT_TO_USER(prt_line_height, 5144 (1000.0 - (prt_ps_font->bbox_max_y - 5145 prt_ps_font->bbox_min_y)) / 2); 5146 } 5147 5148 /* Get height for topmost line based on background rect offset. */ 5149 prt_first_line_height = prt_line_height + prt_bgcol_offset; 5150 5151 /* Calculate lpp */ 5152 lpp = (int)((prt_top_margin - prt_bottom_margin) / prt_line_height); 5153 5154 /* Adjust top margin if there is a header */ 5155 prt_top_margin -= prt_line_height * prt_header_height(); 5156 5157 return lpp - prt_header_height(); 5158 } 5159 5160 #ifdef FEAT_MBYTE 5161 static int 5162 prt_match_encoding(p_encoding, p_cmap, pp_mbenc) 5163 char *p_encoding; 5164 struct prt_ps_mbfont_S *p_cmap; 5165 struct prt_ps_encoding_S **pp_mbenc; 5166 { 5167 int mbenc; 5168 int enc_len; 5169 struct prt_ps_encoding_S *p_mbenc; 5170 5171 *pp_mbenc = NULL; 5172 /* Look for recognised encoding */ 5173 enc_len = STRLEN(p_encoding); 5174 p_mbenc = p_cmap->encodings; 5175 for (mbenc = 0; mbenc < p_cmap->num_encodings; mbenc++) 5176 { 5177 if (STRNICMP(p_mbenc->encoding, p_encoding, enc_len) == 0) 5178 { 5179 *pp_mbenc = p_mbenc; 5180 return TRUE; 5181 } 5182 p_mbenc++; 5183 } 5184 return FALSE; 5185 } 5186 5187 static int 5188 prt_match_charset(p_charset, p_cmap, pp_mbchar) 5189 char *p_charset; 5190 struct prt_ps_mbfont_S *p_cmap; 5191 struct prt_ps_charset_S **pp_mbchar; 5192 { 5193 int mbchar; 5194 int char_len; 5195 struct prt_ps_charset_S *p_mbchar; 5196 5197 /* Look for recognised character set, using default if one is not given */ 5198 if (*p_charset == NUL) 5199 p_charset = p_cmap->defcs; 5200 char_len = STRLEN(p_charset); 5201 p_mbchar = p_cmap->charsets; 5202 for (mbchar = 0; mbchar < p_cmap->num_charsets; mbchar++) 5203 { 5204 if (STRNICMP(p_mbchar->charset, p_charset, char_len) == 0) 5205 { 5206 *pp_mbchar = p_mbchar; 5207 return TRUE; 5208 } 5209 p_mbchar++; 5210 } 5211 return FALSE; 5212 } 5213 #endif 5214 5215 /*ARGSUSED*/ 5216 int 5217 mch_print_init(psettings, jobname, forceit) 5218 prt_settings_T *psettings; 5219 char_u *jobname; 5220 int forceit; 5221 { 5222 int i; 5223 char *paper_name; 5224 int paper_strlen; 5225 int fontsize; 5226 char_u *p; 5227 double left; 5228 double right; 5229 double top; 5230 double bottom; 5231 #ifdef FEAT_MBYTE 5232 int cmap; 5233 int pmcs_len; 5234 char_u *p_encoding; 5235 struct prt_ps_encoding_S *p_mbenc; 5236 struct prt_ps_encoding_S *p_mbenc_first; 5237 struct prt_ps_charset_S *p_mbchar; 5238 #endif 5239 5240 #if 0 5241 /* 5242 * TODO: 5243 * If "forceit" is false: pop up a dialog to select: 5244 * - printer name 5245 * - copies 5246 * - collated/uncollated 5247 * - duplex off/long side/short side 5248 * - paper size 5249 * - portrait/landscape 5250 * - font size 5251 * 5252 * If "forceit" is true: use the default printer and settings 5253 */ 5254 if (forceit) 5255 s_pd.Flags |= PD_RETURNDEFAULT; 5256 #endif 5257 5258 /* 5259 * Set up font and encoding. 5260 */ 5261 #ifdef FEAT_MBYTE 5262 p_encoding = enc_skip(p_penc); 5263 if (*p_encoding == NUL) 5264 p_encoding = enc_skip(p_enc); 5265 5266 /* Look for recognised multi-byte coding, and if the charset is recognised. 5267 * This is to cope with the fact that various unicode encodings are 5268 * supported in more than one of CJK. */ 5269 p_mbenc = NULL; 5270 p_mbenc_first = NULL; 5271 p_mbchar = NULL; 5272 for (cmap = 0; cmap < NUM_ELEMENTS(prt_ps_mbfonts); cmap++) 5273 if (prt_match_encoding((char *)p_encoding, &prt_ps_mbfonts[cmap], 5274 &p_mbenc)) 5275 { 5276 if (p_mbenc_first == NULL) 5277 p_mbenc_first = p_mbenc; 5278 if (prt_match_charset((char *)p_pmcs, &prt_ps_mbfonts[cmap], 5279 &p_mbchar)) 5280 break; 5281 } 5282 5283 /* Use first encoding matched if no charset matched */ 5284 if (p_mbchar == NULL && p_mbenc_first != NULL) 5285 p_mbenc = p_mbenc_first; 5286 5287 prt_out_mbyte = (p_mbenc != NULL); 5288 if (prt_out_mbyte) 5289 { 5290 /* Build CMap name - will be same for all multi-byte fonts used */ 5291 prt_cmap[0] = '\0'; 5292 5293 prt_custom_cmap = prt_out_mbyte && p_mbchar == NULL; 5294 5295 if (!prt_custom_cmap) 5296 { 5297 /* Check encoding and character set are compatible */ 5298 if ((p_mbenc->needs_charset&p_mbchar->has_charset) == 0) 5299 { 5300 EMSG(_("E673: Incompatible multi-byte encoding and character set.")); 5301 return FALSE; 5302 } 5303 5304 /* Add charset name if not empty */ 5305 if (p_mbchar->cmap_charset != NULL) 5306 { 5307 STRCAT(prt_cmap, p_mbchar->cmap_charset); 5308 STRCAT(prt_cmap, "-"); 5309 } 5310 } 5311 else 5312 { 5313 /* Add custom CMap character set name */ 5314 pmcs_len = STRLEN(p_pmcs); 5315 if (pmcs_len == 0) 5316 { 5317 EMSG(_("E674: printmbcharset cannot be empty with multi-byte encoding.")); 5318 return FALSE; 5319 } 5320 STRNCPY(prt_cmap, p_pmcs, STRLEN(p_pmcs)); 5321 prt_cmap[pmcs_len] = '\0'; 5322 STRCAT(prt_cmap, "-"); 5323 } 5324 5325 /* CMap name ends with (optional) encoding name and -H for horizontal */ 5326 if (p_mbenc->cmap_encoding != NULL) 5327 { 5328 STRCAT(prt_cmap, p_mbenc->cmap_encoding); 5329 STRCAT(prt_cmap, "-"); 5330 } 5331 STRCAT(prt_cmap, "H"); 5332 5333 if (!mbfont_opts[OPT_MBFONT_REGULAR].present) 5334 { 5335 EMSG(_("E675: No default font specfifed for multi-byte printing.")); 5336 return FALSE; 5337 } 5338 5339 /* Derive CID font names with fallbacks if not defined */ 5340 if (!prt_build_cid_fontname(PRT_PS_FONT_ROMAN, 5341 mbfont_opts[OPT_MBFONT_REGULAR].string, 5342 mbfont_opts[OPT_MBFONT_REGULAR].strlen)) 5343 return FALSE; 5344 if (mbfont_opts[OPT_MBFONT_BOLD].present) 5345 if (!prt_build_cid_fontname(PRT_PS_FONT_BOLD, 5346 mbfont_opts[OPT_MBFONT_BOLD].string, 5347 mbfont_opts[OPT_MBFONT_BOLD].strlen)) 5348 return FALSE; 5349 if (mbfont_opts[OPT_MBFONT_OBLIQUE].present) 5350 if (!prt_build_cid_fontname(PRT_PS_FONT_OBLIQUE, 5351 mbfont_opts[OPT_MBFONT_OBLIQUE].string, 5352 mbfont_opts[OPT_MBFONT_OBLIQUE].strlen)) 5353 return FALSE; 5354 if (mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].present) 5355 if (!prt_build_cid_fontname(PRT_PS_FONT_BOLDOBLIQUE, 5356 mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].string, 5357 mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].strlen)) 5358 return FALSE; 5359 5360 /* Check if need to use Courier for ASCII code range, and if so pick up 5361 * the encoding to use */ 5362 prt_use_courier = mbfont_opts[OPT_MBFONT_USECOURIER].present && 5363 (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_USECOURIER].string[0]) == 'y'); 5364 if (prt_use_courier) 5365 { 5366 /* Use national ASCII variant unless ASCII wanted */ 5367 if (mbfont_opts[OPT_MBFONT_ASCII].present && 5368 (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_ASCII].string[0]) == 'y')) 5369 prt_ascii_encoding = "ascii"; 5370 else 5371 prt_ascii_encoding = prt_ps_mbfonts[cmap].ascii_enc; 5372 } 5373 5374 prt_ps_font = &prt_ps_mb_font; 5375 } 5376 else 5377 #endif 5378 { 5379 #ifdef FEAT_MBYTE 5380 prt_use_courier = FALSE; 5381 #endif 5382 prt_ps_font = &prt_ps_courier_font; 5383 } 5384 5385 /* 5386 * Find the size of the paper and set the margins. 5387 */ 5388 prt_portrait = (!printer_opts[OPT_PRINT_PORTRAIT].present 5389 || TOLOWER_ASC(printer_opts[OPT_PRINT_PORTRAIT].string[0]) == 'y'); 5390 if (printer_opts[OPT_PRINT_PAPER].present) 5391 { 5392 paper_name = (char *)printer_opts[OPT_PRINT_PAPER].string; 5393 paper_strlen = printer_opts[OPT_PRINT_PAPER].strlen; 5394 } 5395 else 5396 { 5397 paper_name = "A4"; 5398 paper_strlen = 2; 5399 } 5400 for (i = 0; i < PRT_MEDIASIZE_LEN; ++i) 5401 if (STRLEN(prt_mediasize[i].name) == (unsigned)paper_strlen 5402 && STRNICMP(prt_mediasize[i].name, paper_name, 5403 paper_strlen) == 0) 5404 break; 5405 if (i == PRT_MEDIASIZE_LEN) 5406 i = 0; 5407 prt_media = i; 5408 5409 /* 5410 * Set PS pagesize based on media dimensions and print orientation. 5411 * Note: Media and page sizes have defined meanings in PostScript and should 5412 * be kept distinct. Media is the paper (or transparency, or ...) that is 5413 * printed on, whereas the page size is the area that the PostScript 5414 * interpreter renders into. 5415 */ 5416 if (prt_portrait) 5417 { 5418 prt_page_width = prt_mediasize[i].width; 5419 prt_page_height = prt_mediasize[i].height; 5420 } 5421 else 5422 { 5423 prt_page_width = prt_mediasize[i].height; 5424 prt_page_height = prt_mediasize[i].width; 5425 } 5426 5427 /* 5428 * Set PS page margins based on the PS pagesize, not the mediasize - this 5429 * needs to be done before the cpl and lpp are calculated. 5430 */ 5431 prt_page_margins(prt_page_width, prt_page_height, &left, &right, &top, 5432 &bottom); 5433 prt_left_margin = (float)left; 5434 prt_right_margin = (float)right; 5435 prt_top_margin = (float)top; 5436 prt_bottom_margin = (float)bottom; 5437 5438 /* 5439 * Set up the font size. 5440 */ 5441 fontsize = PRT_PS_DEFAULT_FONTSIZE; 5442 for (p = p_pfn; (p = vim_strchr(p, ':')) != NULL; ++p) 5443 if (p[1] == 'h' && VIM_ISDIGIT(p[2])) 5444 fontsize = atoi((char *)p + 2); 5445 prt_font_metrics(fontsize); 5446 5447 /* 5448 * Return the number of characters per line, and lines per page for the 5449 * generic print code. 5450 */ 5451 psettings->chars_per_line = prt_get_cpl(); 5452 psettings->lines_per_page = prt_get_lpp(); 5453 5454 /* Catch margin settings that leave no space for output! */ 5455 if (psettings->chars_per_line <= 0 || psettings->lines_per_page <= 0) 5456 return FAIL; 5457 5458 /* 5459 * Sort out the number of copies to be printed. PS by default will do 5460 * uncollated copies for you, so once we know how many uncollated copies are 5461 * wanted cache it away and lie to the generic code that we only want one 5462 * uncollated copy. 5463 */ 5464 psettings->n_collated_copies = 1; 5465 psettings->n_uncollated_copies = 1; 5466 prt_num_copies = 1; 5467 prt_collate = (!printer_opts[OPT_PRINT_COLLATE].present 5468 || TOLOWER_ASC(printer_opts[OPT_PRINT_COLLATE].string[0]) == 'y'); 5469 if (prt_collate) 5470 { 5471 /* TODO: Get number of collated copies wanted. */ 5472 psettings->n_collated_copies = 1; 5473 } 5474 else 5475 { 5476 /* TODO: Get number of uncollated copies wanted and update the cached 5477 * count. 5478 */ 5479 prt_num_copies = 1; 5480 } 5481 5482 psettings->jobname = jobname; 5483 5484 /* 5485 * Set up printer duplex and tumble based on Duplex option setting - default 5486 * is long sided duplex printing (i.e. no tumble). 5487 */ 5488 prt_duplex = TRUE; 5489 prt_tumble = FALSE; 5490 psettings->duplex = 1; 5491 if (printer_opts[OPT_PRINT_DUPLEX].present) 5492 { 5493 if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "off", 3) == 0) 5494 { 5495 prt_duplex = FALSE; 5496 psettings->duplex = 0; 5497 } 5498 else if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "short", 5) 5499 == 0) 5500 prt_tumble = TRUE; 5501 } 5502 5503 /* For now user abort not supported */ 5504 psettings->user_abort = 0; 5505 5506 /* If the user didn't specify a file name, use a temp file. */ 5507 if (psettings->outfile == NULL) 5508 { 5509 prt_ps_file_name = vim_tempname('p'); 5510 if (prt_ps_file_name == NULL) 5511 { 5512 EMSG(_(e_notmp)); 5513 return FAIL; 5514 } 5515 prt_ps_fd = mch_fopen((char *)prt_ps_file_name, WRITEBIN); 5516 } 5517 else 5518 { 5519 p = expand_env_save(psettings->outfile); 5520 if (p != NULL) 5521 { 5522 prt_ps_fd = mch_fopen((char *)p, WRITEBIN); 5523 vim_free(p); 5524 } 5525 } 5526 if (prt_ps_fd == NULL) 5527 { 5528 EMSG(_("E324: Can't open PostScript output file")); 5529 mch_print_cleanup(); 5530 return FAIL; 5531 } 5532 5533 prt_bufsiz = psettings->chars_per_line; 5534 #ifdef FEAT_MBYTE 5535 if (prt_out_mbyte) 5536 prt_bufsiz *= 2; 5537 #endif 5538 ga_init2(&prt_ps_buffer, (int)sizeof(char), prt_bufsiz); 5539 5540 prt_page_num = 0; 5541 5542 prt_attribute_change = FALSE; 5543 prt_need_moveto = FALSE; 5544 prt_need_font = FALSE; 5545 prt_need_fgcol = FALSE; 5546 prt_need_bgcol = FALSE; 5547 prt_need_underline = FALSE; 5548 5549 prt_file_error = FALSE; 5550 5551 return OK; 5552 } 5553 5554 static int 5555 prt_add_resource(resource) 5556 struct prt_ps_resource_S *resource; 5557 { 5558 FILE* fd_resource; 5559 char_u resource_buffer[512]; 5560 size_t bytes_read; 5561 5562 fd_resource = mch_fopen((char *)resource->filename, READBIN); 5563 if (fd_resource == NULL) 5564 { 5565 EMSG2(_("E456: Can't open file \"%s\""), resource->filename); 5566 return FALSE; 5567 } 5568 prt_dsc_resources("BeginResource", prt_resource_types[resource->type], 5569 (char *)resource->title); 5570 5571 prt_dsc_textline("BeginDocument", (char *)resource->filename); 5572 5573 for (;;) 5574 { 5575 bytes_read = fread((char *)resource_buffer, sizeof(char_u), 5576 sizeof(resource_buffer), fd_resource); 5577 if (ferror(fd_resource)) 5578 { 5579 EMSG2(_("E457: Can't read PostScript resource file \"%s\""), 5580 resource->filename); 5581 fclose(fd_resource); 5582 return FALSE; 5583 } 5584 if (bytes_read == 0) 5585 break; 5586 prt_write_file_raw_len(resource_buffer, bytes_read); 5587 if (prt_file_error) 5588 { 5589 fclose(fd_resource); 5590 return FALSE; 5591 } 5592 } 5593 fclose(fd_resource); 5594 5595 prt_dsc_noarg("EndDocument"); 5596 5597 prt_dsc_noarg("EndResource"); 5598 5599 return TRUE; 5600 } 5601 5602 int 5603 mch_print_begin(psettings) 5604 prt_settings_T *psettings; 5605 { 5606 time_t now; 5607 int bbox[4]; 5608 char *p_time; 5609 double left; 5610 double right; 5611 double top; 5612 double bottom; 5613 struct prt_ps_resource_S res_prolog; 5614 struct prt_ps_resource_S res_encoding; 5615 char buffer[256]; 5616 char_u *p_encoding; 5617 #ifdef FEAT_MBYTE 5618 struct prt_ps_resource_S res_cidfont; 5619 struct prt_ps_resource_S res_cmap; 5620 #endif 5621 5622 /* 5623 * PS DSC Header comments - no PS code! 5624 */ 5625 prt_dsc_start(); 5626 prt_dsc_textline("Title", (char *)psettings->jobname); 5627 if (!get_user_name((char_u *)buffer, 256)) 5628 STRCPY(buffer, "Unknown"); 5629 prt_dsc_textline("For", buffer); 5630 prt_dsc_textline("Creator", VIM_VERSION_LONG); 5631 /* Note: to ensure Clean8bit I don't think we can use LC_TIME */ 5632 now = time(NULL); 5633 p_time = ctime(&now); 5634 /* Note: ctime() adds a \n so we have to remove it :-( */ 5635 *(vim_strchr((char_u *)p_time, '\n')) = '\0'; 5636 prt_dsc_textline("CreationDate", p_time); 5637 prt_dsc_textline("DocumentData", "Clean8Bit"); 5638 prt_dsc_textline("Orientation", "Portrait"); 5639 prt_dsc_atend("Pages"); 5640 prt_dsc_textline("PageOrder", "Ascend"); 5641 /* The bbox does not change with orientation - it is always in the default 5642 * user coordinate system! We have to recalculate right and bottom 5643 * coordinates based on the font metrics for the bbox to be accurate. */ 5644 prt_page_margins(prt_mediasize[prt_media].width, 5645 prt_mediasize[prt_media].height, 5646 &left, &right, &top, &bottom); 5647 bbox[0] = (int)left; 5648 if (prt_portrait) 5649 { 5650 /* In portrait printing the fixed point is the top left corner so we 5651 * derive the bbox from that point. We have the expected cpl chars 5652 * across the media and lpp lines down the media. 5653 */ 5654 bbox[1] = (int)(top - (psettings->lines_per_page + prt_header_height()) 5655 * prt_line_height); 5656 bbox[2] = (int)(left + psettings->chars_per_line * prt_char_width 5657 + 0.5); 5658 bbox[3] = (int)(top + 0.5); 5659 } 5660 else 5661 { 5662 /* In landscape printing the fixed point is the bottom left corner so we 5663 * derive the bbox from that point. We have lpp chars across the media 5664 * and cpl lines up the media. 5665 */ 5666 bbox[1] = (int)bottom; 5667 bbox[2] = (int)(left + ((psettings->lines_per_page 5668 + prt_header_height()) * prt_line_height) + 0.5); 5669 bbox[3] = (int)(bottom + psettings->chars_per_line * prt_char_width 5670 + 0.5); 5671 } 5672 prt_dsc_ints("BoundingBox", 4, bbox); 5673 /* The media width and height does not change with landscape printing! */ 5674 prt_dsc_docmedia(prt_mediasize[prt_media].name, 5675 prt_mediasize[prt_media].width, 5676 prt_mediasize[prt_media].height, 5677 (double)0, NULL, NULL); 5678 /* Define fonts needed */ 5679 #ifdef FEAT_MBYTE 5680 if (!prt_out_mbyte || prt_use_courier) 5681 #endif 5682 prt_dsc_font_resource("DocumentNeededResources", &prt_ps_courier_font); 5683 #ifdef FEAT_MBYTE 5684 if (prt_out_mbyte) 5685 { 5686 prt_dsc_font_resource((prt_use_courier ? NULL 5687 : "DocumentNeededResources"), &prt_ps_mb_font); 5688 if (!prt_custom_cmap) 5689 prt_dsc_resources(NULL, "cmap", prt_cmap); 5690 } 5691 #endif 5692 5693 /* Search for external resources VIM supplies */ 5694 if (!prt_find_resource("prolog", &res_prolog)) 5695 { 5696 EMSG(_("E456: Can't find PostScript resource file \"prolog.ps\"")); 5697 return FALSE; 5698 } 5699 if (!prt_open_resource(&res_prolog)) 5700 return FALSE; 5701 if (!prt_check_resource(&res_prolog, PRT_PROLOG_VERSION)) 5702 return FALSE; 5703 #ifdef FEAT_MBYTE 5704 if (prt_out_mbyte) 5705 { 5706 /* Look for required version of multi-byte printing procset */ 5707 if (!prt_find_resource("cidfont", &res_cidfont)) 5708 { 5709 EMSG(_("E456: Can't find PostScript resource file \"cidfont.ps\"")); 5710 return FALSE; 5711 } 5712 if (!prt_open_resource(&res_cidfont)) 5713 return FALSE; 5714 if (!prt_check_resource(&res_cidfont, PRT_CID_PROLOG_VERSION)) 5715 return FALSE; 5716 } 5717 #endif 5718 5719 /* Find an encoding to use for printing. 5720 * Check 'printencoding'. If not set or not found, then use 'encoding'. If 5721 * that cannot be found then default to "latin1". 5722 * Note: VIM specific encoding header is always skipped. 5723 */ 5724 #ifdef FEAT_MBYTE 5725 if (!prt_out_mbyte) 5726 { 5727 #endif 5728 p_encoding = enc_skip(p_penc); 5729 if (*p_encoding == NUL 5730 || !prt_find_resource((char *)p_encoding, &res_encoding)) 5731 { 5732 /* 'printencoding' not set or not supported - find alternate */ 5733 #ifdef FEAT_MBYTE 5734 int props; 5735 5736 p_encoding = enc_skip(p_enc); 5737 props = enc_canon_props(p_encoding); 5738 if (!(props & ENC_8BIT) 5739 || !prt_find_resource((char *)p_encoding, &res_encoding)) 5740 /* 8-bit 'encoding' is not supported */ 5741 #endif 5742 { 5743 /* Use latin1 as default printing encoding */ 5744 p_encoding = (char_u *)"latin1"; 5745 if (!prt_find_resource((char *)p_encoding, &res_encoding)) 5746 { 5747 EMSG2(_("E456: Can't find PostScript resource file \"%s.ps\""), 5748 p_encoding); 5749 return FALSE; 5750 } 5751 } 5752 } 5753 if (!prt_open_resource(&res_encoding)) 5754 return FALSE; 5755 /* For the moment there are no checks on encoding resource files to 5756 * perform */ 5757 #ifdef FEAT_MBYTE 5758 } 5759 else 5760 { 5761 p_encoding = enc_skip(p_penc); 5762 if (*p_encoding == NUL) 5763 p_encoding = enc_skip(p_enc); 5764 if (prt_use_courier) 5765 { 5766 /* Include ASCII range encoding vector */ 5767 if (!prt_find_resource(prt_ascii_encoding, &res_encoding)) 5768 { 5769 EMSG2(_("E456: Can't find PostScript resource file \"%s.ps\""), 5770 prt_ascii_encoding); 5771 return FALSE; 5772 } 5773 if (!prt_open_resource(&res_encoding)) 5774 return FALSE; 5775 /* For the moment there are no checks on encoding resource files to 5776 * perform */ 5777 } 5778 } 5779 5780 prt_conv.vc_type = CONV_NONE; 5781 if (!(enc_canon_props(p_enc) & enc_canon_props(p_encoding) & ENC_8BIT)) { 5782 /* Set up encoding conversion if required */ 5783 if (FAIL == convert_setup(&prt_conv, p_enc, p_encoding)) 5784 { 5785 EMSG2(_("E620: Unable to convert to print encoding \"%s\""), 5786 p_encoding); 5787 return FALSE; 5788 } 5789 prt_do_conv = TRUE; 5790 } 5791 prt_do_conv = prt_conv.vc_type != CONV_NONE; 5792 5793 if (prt_out_mbyte && prt_custom_cmap) 5794 { 5795 /* Find user supplied CMap */ 5796 if (!prt_find_resource(prt_cmap, &res_cmap)) 5797 { 5798 EMSG2(_("E456: Can't find PostScript resource file \"%s.ps\""), 5799 prt_cmap); 5800 return FALSE; 5801 } 5802 if (!prt_open_resource(&res_cmap)) 5803 return FALSE; 5804 } 5805 #endif 5806 5807 /* List resources supplied */ 5808 STRCPY(buffer, res_prolog.title); 5809 STRCAT(buffer, " "); 5810 STRCAT(buffer, res_prolog.version); 5811 prt_dsc_resources("DocumentSuppliedResources", "procset", buffer); 5812 #ifdef FEAT_MBYTE 5813 if (prt_out_mbyte) 5814 { 5815 STRCPY(buffer, res_cidfont.title); 5816 STRCAT(buffer, " "); 5817 STRCAT(buffer, res_cidfont.version); 5818 prt_dsc_resources(NULL, "procset", buffer); 5819 5820 if (prt_custom_cmap) 5821 { 5822 STRCPY(buffer, res_cmap.title); 5823 STRCAT(buffer, " "); 5824 STRCAT(buffer, res_cmap.version); 5825 prt_dsc_resources(NULL, "cmap", buffer); 5826 } 5827 } 5828 if (!prt_out_mbyte || prt_use_courier) 5829 #endif 5830 { 5831 STRCPY(buffer, res_encoding.title); 5832 STRCAT(buffer, " "); 5833 STRCAT(buffer, res_encoding.version); 5834 prt_dsc_resources(NULL, "encoding", buffer); 5835 } 5836 prt_dsc_requirements(prt_duplex, prt_tumble, prt_collate, 5837 #ifdef FEAT_SYN_HL 5838 psettings->do_syntax 5839 #else 5840 0 5841 #endif 5842 , prt_num_copies); 5843 prt_dsc_noarg("EndComments"); 5844 5845 /* 5846 * PS Document page defaults 5847 */ 5848 prt_dsc_noarg("BeginDefaults"); 5849 5850 /* List font resources most likely common to all pages */ 5851 #ifdef FEAT_MBYTE 5852 if (!prt_out_mbyte || prt_use_courier) 5853 #endif 5854 prt_dsc_font_resource("PageResources", &prt_ps_courier_font); 5855 #ifdef FEAT_MBYTE 5856 if (prt_out_mbyte) 5857 { 5858 prt_dsc_font_resource((prt_use_courier ? NULL : "PageResources"), 5859 &prt_ps_mb_font); 5860 if (!prt_custom_cmap) 5861 prt_dsc_resources(NULL, "cmap", prt_cmap); 5862 } 5863 #endif 5864 5865 /* Paper will be used for all pages */ 5866 prt_dsc_textline("PageMedia", prt_mediasize[prt_media].name); 5867 5868 prt_dsc_noarg("EndDefaults"); 5869 5870 /* 5871 * PS Document prolog inclusion - all required procsets. 5872 */ 5873 prt_dsc_noarg("BeginProlog"); 5874 5875 /* Add required procsets - NOTE: order is important! */ 5876 if (!prt_add_resource(&res_prolog)) 5877 return FALSE; 5878 #ifdef FEAT_MBYTE 5879 if (prt_out_mbyte) 5880 { 5881 /* Add CID font procset, and any user supplied CMap */ 5882 if (!prt_add_resource(&res_cidfont)) 5883 return FALSE; 5884 if (prt_custom_cmap && !prt_add_resource(&res_cmap)) 5885 return FALSE; 5886 } 5887 #endif 5888 5889 #ifdef FEAT_MBYTE 5890 if (!prt_out_mbyte || prt_use_courier) 5891 #endif 5892 /* There will be only one Roman font encoding to be included in the PS 5893 * file. */ 5894 if (!prt_add_resource(&res_encoding)) 5895 return FALSE; 5896 5897 prt_dsc_noarg("EndProlog"); 5898 5899 /* 5900 * PS Document setup - must appear after the prolog 5901 */ 5902 prt_dsc_noarg("BeginSetup"); 5903 5904 /* Device setup - page size and number of uncollated copies */ 5905 prt_write_int((int)prt_mediasize[prt_media].width); 5906 prt_write_int((int)prt_mediasize[prt_media].height); 5907 prt_write_int(0); 5908 prt_write_string("sps\n"); 5909 prt_write_int(prt_num_copies); 5910 prt_write_string("nc\n"); 5911 prt_write_boolean(prt_duplex); 5912 prt_write_boolean(prt_tumble); 5913 prt_write_string("dt\n"); 5914 prt_write_boolean(prt_collate); 5915 prt_write_string("c\n"); 5916 5917 /* Font resource inclusion and definition */ 5918 #ifdef FEAT_MBYTE 5919 if (!prt_out_mbyte || prt_use_courier) 5920 { 5921 /* When using Courier for ASCII range when printing multi-byte, need to 5922 * pick up ASCII encoding to use with it. */ 5923 if (prt_use_courier) 5924 p_encoding = (char_u *)prt_ascii_encoding; 5925 #endif 5926 prt_dsc_resources("IncludeResource", "font", 5927 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]); 5928 prt_def_font("F0", (char *)p_encoding, (int)prt_line_height, 5929 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]); 5930 prt_dsc_resources("IncludeResource", "font", 5931 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]); 5932 prt_def_font("F1", (char *)p_encoding, (int)prt_line_height, 5933 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]); 5934 prt_dsc_resources("IncludeResource", "font", 5935 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]); 5936 prt_def_font("F2", (char *)p_encoding, (int)prt_line_height, 5937 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]); 5938 prt_dsc_resources("IncludeResource", "font", 5939 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]); 5940 prt_def_font("F3", (char *)p_encoding, (int)prt_line_height, 5941 prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]); 5942 #ifdef FEAT_MBYTE 5943 } 5944 if (prt_out_mbyte) 5945 { 5946 /* Define the CID fonts to be used in the job. Typically CJKV fonts do 5947 * not have an italic form being a western style, so where no font is 5948 * defined for these faces VIM falls back to an existing face. 5949 * Note: if using Courier for the ASCII range then the printout will 5950 * have bold/italic/bolditalic regardless of the setting of printmbfont. 5951 */ 5952 prt_dsc_resources("IncludeResource", "font", 5953 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_ROMAN]); 5954 if (!prt_custom_cmap) 5955 prt_dsc_resources("IncludeResource", "cmap", prt_cmap); 5956 prt_def_cidfont("CF0", (int)prt_line_height, 5957 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_ROMAN]); 5958 5959 if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD] != NULL) 5960 { 5961 prt_dsc_resources("IncludeResource", "font", 5962 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]); 5963 if (!prt_custom_cmap) 5964 prt_dsc_resources("IncludeResource", "cmap", prt_cmap); 5965 prt_def_cidfont("CF1", (int)prt_line_height, 5966 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]); 5967 } 5968 else 5969 /* Use ROMAN for BOLD */ 5970 prt_dup_cidfont("CF0", "CF1"); 5971 5972 if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE] != NULL) 5973 { 5974 prt_dsc_resources("IncludeResource", "font", 5975 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]); 5976 if (!prt_custom_cmap) 5977 prt_dsc_resources("IncludeResource", "cmap", prt_cmap); 5978 prt_def_cidfont("CF2", (int)prt_line_height, 5979 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]); 5980 } 5981 else 5982 /* Use ROMAN for OBLIQUE */ 5983 prt_dup_cidfont("CF0", "CF2"); 5984 5985 if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE] != NULL) 5986 { 5987 prt_dsc_resources("IncludeResource", "font", 5988 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]); 5989 if (!prt_custom_cmap) 5990 prt_dsc_resources("IncludeResource", "cmap", prt_cmap); 5991 prt_def_cidfont("CF3", (int)prt_line_height, 5992 prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]); 5993 } 5994 else 5995 /* Use BOLD for BOLDOBLIQUE */ 5996 prt_dup_cidfont("CF1", "CF3"); 5997 } 5998 #endif 5999 6000 /* Misc constant vars used for underlining and background rects */ 6001 prt_def_var("UO", PRT_PS_FONT_TO_USER(prt_line_height, 6002 prt_ps_font->uline_offset), 2); 6003 prt_def_var("UW", PRT_PS_FONT_TO_USER(prt_line_height, 6004 prt_ps_font->uline_width), 2); 6005 prt_def_var("BO", prt_bgcol_offset, 2); 6006 6007 prt_dsc_noarg("EndSetup"); 6008 6009 /* Fail if any problems writing out to the PS file */ 6010 return !prt_file_error; 6011 } 6012 6013 void 6014 mch_print_end(psettings) 6015 prt_settings_T *psettings; 6016 { 6017 prt_dsc_noarg("Trailer"); 6018 6019 /* 6020 * Output any info we don't know in toto until we finish 6021 */ 6022 prt_dsc_ints("Pages", 1, &prt_page_num); 6023 6024 prt_dsc_noarg("EOF"); 6025 6026 /* Write CTRL-D to close serial communication link if used. 6027 * NOTHING MUST BE WRITTEN AFTER THIS! */ 6028 prt_write_file((char_u *)IF_EB("\004", "\067")); 6029 6030 if (!prt_file_error && psettings->outfile == NULL 6031 && !got_int && !psettings->user_abort) 6032 { 6033 /* Close the file first. */ 6034 if (prt_ps_fd != NULL) 6035 { 6036 fclose(prt_ps_fd); 6037 prt_ps_fd = NULL; 6038 } 6039 prt_message((char_u *)_("Sending to printer...")); 6040 6041 /* Not printing to a file: use 'printexpr' to print the file. */ 6042 if (eval_printexpr(prt_ps_file_name, psettings->arguments) == FAIL) 6043 EMSG(_("E365: Failed to print PostScript file")); 6044 else 6045 prt_message((char_u *)_("Print job sent.")); 6046 } 6047 6048 mch_print_cleanup(); 6049 } 6050 6051 int 6052 mch_print_end_page() 6053 { 6054 prt_flush_buffer(); 6055 6056 prt_write_string("re sp\n"); 6057 6058 prt_dsc_noarg("PageTrailer"); 6059 6060 return !prt_file_error; 6061 } 6062 6063 /*ARGSUSED*/ 6064 int 6065 mch_print_begin_page(str) 6066 char_u *str; 6067 { 6068 int page_num[2]; 6069 6070 prt_page_num++; 6071 6072 page_num[0] = page_num[1] = prt_page_num; 6073 prt_dsc_ints("Page", 2, page_num); 6074 6075 prt_dsc_noarg("BeginPageSetup"); 6076 6077 prt_write_string("sv\n0 g\n"); 6078 #ifdef FEAT_MBYTE 6079 prt_in_ascii = !prt_out_mbyte; 6080 if (prt_out_mbyte) 6081 prt_write_string("CF0 sf\n"); 6082 else 6083 #endif 6084 prt_write_string("F0 sf\n"); 6085 prt_fgcol = PRCOLOR_BLACK; 6086 prt_bgcol = PRCOLOR_WHITE; 6087 prt_font = PRT_PS_FONT_ROMAN; 6088 6089 /* Set up page transformation for landscape printing. */ 6090 if (!prt_portrait) 6091 { 6092 prt_write_int(-((int)prt_mediasize[prt_media].width)); 6093 prt_write_string("sl\n"); 6094 } 6095 6096 prt_dsc_noarg("EndPageSetup"); 6097 6098 /* We have reset the font attributes, force setting them again. */ 6099 curr_bg = (long_u)0xffffffff; 6100 curr_fg = (long_u)0xffffffff; 6101 curr_bold = MAYBE; 6102 6103 return !prt_file_error; 6104 } 6105 6106 int 6107 mch_print_blank_page() 6108 { 6109 return (mch_print_begin_page(NULL) ? (mch_print_end_page()) : FALSE); 6110 } 6111 6112 static float prt_pos_x = 0; 6113 static float prt_pos_y = 0; 6114 6115 void 6116 mch_print_start_line(margin, page_line) 6117 int margin; 6118 int page_line; 6119 { 6120 prt_pos_x = prt_left_margin; 6121 if (margin) 6122 prt_pos_x -= prt_number_width; 6123 6124 prt_pos_y = prt_top_margin - prt_first_line_height - 6125 page_line * prt_line_height; 6126 6127 prt_attribute_change = TRUE; 6128 prt_need_moveto = TRUE; 6129 #ifdef FEAT_MBYTE 6130 prt_half_width = FALSE; 6131 #endif 6132 } 6133 6134 /*ARGSUSED*/ 6135 int 6136 mch_print_text_out(p, len) 6137 char_u *p; 6138 int len; 6139 { 6140 int need_break; 6141 char_u ch; 6142 char_u ch_buff[8]; 6143 float char_width; 6144 float next_pos; 6145 #ifdef FEAT_MBYTE 6146 int in_ascii; 6147 int half_width; 6148 #endif 6149 6150 char_width = prt_char_width; 6151 6152 #ifdef FEAT_MBYTE 6153 /* Ideally VIM would create a rearranged CID font to combine a Roman and 6154 * CJKV font to do what VIM is doing here - use a Roman font for characters 6155 * in the ASCII range, and the origingal CID font for everything else. 6156 * The problem is that GhostScript still (as of 8.13) does not support 6157 * rearranged fonts even though they have been documented by Adobe for 7 6158 * years! If they ever do, a lot of this code will disappear. 6159 */ 6160 if (prt_use_courier) 6161 { 6162 in_ascii = (len == 1 && *p < 0x80); 6163 if (prt_in_ascii) 6164 { 6165 if (!in_ascii) 6166 { 6167 /* No longer in ASCII range - need to switch font */ 6168 prt_in_ascii = FALSE; 6169 prt_need_font = TRUE; 6170 prt_attribute_change = TRUE; 6171 } 6172 } 6173 else if (in_ascii) 6174 { 6175 /* Now in ASCII range - need to switch font */ 6176 prt_in_ascii = TRUE; 6177 prt_need_font = TRUE; 6178 prt_attribute_change = TRUE; 6179 } 6180 } 6181 if (prt_out_mbyte) 6182 { 6183 half_width = ((*mb_ptr2cells)(p) == 1); 6184 if (half_width) 6185 char_width /= 2; 6186 if (prt_half_width) 6187 { 6188 if (!half_width) 6189 { 6190 prt_half_width = FALSE; 6191 prt_pos_x += prt_char_width/4; 6192 prt_need_moveto = TRUE; 6193 prt_attribute_change = TRUE; 6194 } 6195 } 6196 else if (half_width) 6197 { 6198 prt_half_width = TRUE; 6199 prt_pos_x += prt_char_width/4; 6200 prt_need_moveto = TRUE; 6201 prt_attribute_change = TRUE; 6202 } 6203 } 6204 #endif 6205 6206 /* Output any required changes to the graphics state, after flushing any 6207 * text buffered so far. 6208 */ 6209 if (prt_attribute_change) 6210 { 6211 prt_flush_buffer(); 6212 /* Reset count of number of chars that will be printed */ 6213 prt_text_run = 0; 6214 6215 if (prt_need_moveto) 6216 { 6217 prt_pos_x_moveto = prt_pos_x; 6218 prt_pos_y_moveto = prt_pos_y; 6219 prt_do_moveto = TRUE; 6220 6221 prt_need_moveto = FALSE; 6222 } 6223 if (prt_need_font) 6224 { 6225 #ifdef FEAT_MBYTE 6226 if (!prt_in_ascii) 6227 prt_write_string("CF"); 6228 else 6229 #endif 6230 prt_write_string("F"); 6231 prt_write_int(prt_font); 6232 prt_write_string("sf\n"); 6233 prt_need_font = FALSE; 6234 } 6235 if (prt_need_fgcol) 6236 { 6237 int r, g, b; 6238 r = ((unsigned)prt_fgcol & 0xff0000) >> 16; 6239 g = ((unsigned)prt_fgcol & 0xff00) >> 8; 6240 b = prt_fgcol & 0xff; 6241 6242 prt_write_real(r / 255.0, 3); 6243 if (r == g && g == b) 6244 prt_write_string("g\n"); 6245 else 6246 { 6247 prt_write_real(g / 255.0, 3); 6248 prt_write_real(b / 255.0, 3); 6249 prt_write_string("r\n"); 6250 } 6251 prt_need_fgcol = FALSE; 6252 } 6253 6254 if (prt_bgcol != PRCOLOR_WHITE) 6255 { 6256 prt_new_bgcol = prt_bgcol; 6257 if (prt_need_bgcol) 6258 prt_do_bgcol = TRUE; 6259 } 6260 else 6261 prt_do_bgcol = FALSE; 6262 prt_need_bgcol = FALSE; 6263 6264 if (prt_need_underline) 6265 prt_do_underline = prt_underline; 6266 prt_need_underline = FALSE; 6267 6268 prt_attribute_change = FALSE; 6269 } 6270 6271 #ifdef FEAT_MBYTE 6272 if (prt_do_conv) 6273 { 6274 /* Convert from multi-byte to 8-bit encoding */ 6275 p = string_convert(&prt_conv, p, &len); 6276 if (p == NULL) 6277 p = (char_u *)""; 6278 } 6279 6280 if (prt_out_mbyte) 6281 { 6282 /* Multi-byte character strings are represented more efficiently as hex 6283 * strings when outputting clean 8 bit PS. 6284 */ 6285 do 6286 { 6287 ch = prt_hexchar[(unsigned)(*p) >> 4]; 6288 ga_append(&prt_ps_buffer, ch); 6289 ch = prt_hexchar[(*p) & 0xf]; 6290 ga_append(&prt_ps_buffer, ch); 6291 p++; 6292 } 6293 while (--len); 6294 } 6295 else 6296 #endif 6297 { 6298 /* Add next character to buffer of characters to output. 6299 * Note: One printed character may require several PS characters to 6300 * represent it, but we only count them as one printed character. 6301 */ 6302 ch = *p; 6303 if (ch < 32 || ch == '(' || ch == ')' || ch == '\\') 6304 { 6305 /* Convert non-printing characters to either their escape or octal 6306 * sequence, ensures PS sent over a serial line does not interfere 6307 * with the comms protocol. Note: For EBCDIC we need to write out 6308 * the escape sequences as ASCII codes! 6309 * Note 2: Char codes < 32 are identical in EBCDIC and ASCII AFAIK! 6310 */ 6311 ga_append(&prt_ps_buffer, IF_EB('\\', 0134)); 6312 switch (ch) 6313 { 6314 case BS: ga_append(&prt_ps_buffer, IF_EB('b', 0142)); break; 6315 case TAB: ga_append(&prt_ps_buffer, IF_EB('t', 0164)); break; 6316 case NL: ga_append(&prt_ps_buffer, IF_EB('n', 0156)); break; 6317 case FF: ga_append(&prt_ps_buffer, IF_EB('f', 0146)); break; 6318 case CAR: ga_append(&prt_ps_buffer, IF_EB('r', 0162)); break; 6319 case '(': ga_append(&prt_ps_buffer, IF_EB('(', 0050)); break; 6320 case ')': ga_append(&prt_ps_buffer, IF_EB(')', 0051)); break; 6321 case '\\': ga_append(&prt_ps_buffer, IF_EB('\\', 0134)); break; 6322 6323 default: 6324 sprintf((char *)ch_buff, "%03o", (unsigned int)ch); 6325 #ifdef EBCDIC 6326 ebcdic2ascii(ch_buff, 3); 6327 #endif 6328 ga_append(&prt_ps_buffer, ch_buff[0]); 6329 ga_append(&prt_ps_buffer, ch_buff[1]); 6330 ga_append(&prt_ps_buffer, ch_buff[2]); 6331 break; 6332 } 6333 } 6334 else 6335 ga_append(&prt_ps_buffer, ch); 6336 } 6337 6338 #ifdef FEAT_MBYTE 6339 /* Need to free any translated characters */ 6340 if (prt_do_conv && (*p != NUL)) 6341 vim_free(p); 6342 #endif 6343 6344 prt_text_run += char_width; 6345 prt_pos_x += char_width; 6346 6347 /* The downside of fp - use relative error on right margin check */ 6348 next_pos = prt_pos_x + prt_char_width; 6349 need_break = (next_pos > prt_right_margin) && 6350 ((next_pos - prt_right_margin) > (prt_right_margin*1e-5)); 6351 6352 if (need_break) 6353 prt_flush_buffer(); 6354 6355 return need_break; 6356 } 6357 6358 void 6359 mch_print_set_font(iBold, iItalic, iUnderline) 6360 int iBold; 6361 int iItalic; 6362 int iUnderline; 6363 { 6364 int font = 0; 6365 6366 if (iBold) 6367 font |= 0x01; 6368 if (iItalic) 6369 font |= 0x02; 6370 6371 if (font != prt_font) 6372 { 6373 prt_font = font; 6374 prt_attribute_change = TRUE; 6375 prt_need_font = TRUE; 6376 } 6377 if (prt_underline != iUnderline) 6378 { 6379 prt_underline = iUnderline; 6380 prt_attribute_change = TRUE; 6381 prt_need_underline = TRUE; 6382 } 6383 } 6384 6385 void 6386 mch_print_set_bg(bgcol) 6387 long_u bgcol; 6388 { 6389 prt_bgcol = bgcol; 6390 prt_attribute_change = TRUE; 6391 prt_need_bgcol = TRUE; 6392 } 6393 6394 void 6395 mch_print_set_fg(fgcol) 6396 long_u fgcol; 6397 { 6398 if (fgcol != (long_u)prt_fgcol) 6399 { 6400 prt_fgcol = fgcol; 6401 prt_attribute_change = TRUE; 6402 prt_need_fgcol = TRUE; 6403 } 6404 } 6405 6406 # endif /*FEAT_POSTSCRIPT*/ 6407 #endif /*FEAT_PRINTER*/ 6408 6409 #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \ 6410 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG)) 6411 static char *get_locale_val __ARGS((int what)); 6412 6413 static char * 6414 get_locale_val(what) 6415 int what; 6416 { 6417 char *loc; 6418 6419 /* Obtain the locale value from the libraries. For DJGPP this is 6420 * redefined and it doesn't use the arguments. */ 6421 loc = setlocale(what, NULL); 6422 6423 # if defined(__BORLANDC__) 6424 if (loc != NULL) 6425 { 6426 char_u *p; 6427 6428 /* Borland returns something like "LC_CTYPE=<name>\n" 6429 * Let's try to fix that bug here... */ 6430 p = vim_strchr(loc, '='); 6431 if (p != NULL) 6432 { 6433 loc = ++p; 6434 while (*p != NUL) /* remove trailing newline */ 6435 { 6436 if (*p < ' ') 6437 { 6438 *p = NUL; 6439 break; 6440 } 6441 ++p; 6442 } 6443 } 6444 } 6445 # endif 6446 6447 return loc; 6448 } 6449 #endif 6450 6451 6452 #ifdef WIN32 6453 /* 6454 * On MS-Windows locale names are strings like "German_Germany.1252", but 6455 * gettext expects "de". Try to translate one into another here for a few 6456 * supported languages. 6457 */ 6458 static char_u * 6459 gettext_lang(char_u *name) 6460 { 6461 int i; 6462 static char *(mtable[]) = { 6463 "afrikaans", "af", 6464 "czech", "cs", 6465 "dutch", "nl", 6466 "german", "de", 6467 "english_united kingdom", "en_GB", 6468 "spanish", "es", 6469 "french", "fr", 6470 "italian", "it", 6471 "japanese", "ja", 6472 "korean", "ko", 6473 "norwegian", "no", 6474 "polish", "pl", 6475 "russian", "ru", 6476 "slovak", "sk", 6477 "swedish", "sv", 6478 "ukrainian", "uk", 6479 "chinese_china", "zh_CN", 6480 "chinese_taiwan", "zh_TW", 6481 NULL}; 6482 6483 for (i = 0; mtable[i] != NULL; i += 2) 6484 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0) 6485 return mtable[i + 1]; 6486 return name; 6487 } 6488 #endif 6489 6490 #if defined(FEAT_MULTI_LANG) || defined(PROTO) 6491 /* 6492 * Obtain the current messages language. Used to set the default for 6493 * 'helplang'. May return NULL or an empty string. 6494 */ 6495 char_u * 6496 get_mess_lang() 6497 { 6498 char_u *p; 6499 6500 # if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) 6501 # if defined(LC_MESSAGES) 6502 p = (char_u *)get_locale_val(LC_MESSAGES); 6503 # else 6504 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG 6505 * may be set to the LCID number. */ 6506 p = (char_u *)get_locale_val(LC_ALL); 6507 # endif 6508 # else 6509 p = mch_getenv((char_u *)"LC_ALL"); 6510 if (p == NULL || *p == NUL) 6511 { 6512 p = mch_getenv((char_u *)"LC_MESSAGES"); 6513 if (p == NULL || *p == NUL) 6514 p = mch_getenv((char_u *)"LANG"); 6515 } 6516 # endif 6517 # ifdef WIN32 6518 p = gettext_lang(p); 6519 # endif 6520 return p; 6521 } 6522 #endif 6523 6524 #if !defined(LC_MESSAGES) \ 6525 && (((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \ 6526 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))) \ 6527 || defined(FEAT_EVAL)) 6528 static char_u *get_mess_env __ARGS((void)); 6529 6530 /* 6531 * Get the language used for messages from the environment. 6532 */ 6533 static char_u * 6534 get_mess_env() 6535 { 6536 char_u *p; 6537 6538 p = mch_getenv((char_u *)"LC_ALL"); 6539 if (p == NULL || *p == NUL) 6540 { 6541 p = mch_getenv((char_u *)"LC_MESSAGES"); 6542 if (p == NULL || *p == NUL) 6543 { 6544 p = mch_getenv((char_u *)"LANG"); 6545 if (p != NULL && VIM_ISDIGIT(*p)) 6546 p = NULL; /* ignore something like "1043" */ 6547 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE) 6548 if (p == NULL || *p == NUL) 6549 p = (char_u *)get_locale_val(LC_CTYPE); 6550 # endif 6551 } 6552 } 6553 return p; 6554 } 6555 #endif 6556 6557 #if defined(FEAT_EVAL) || defined(PROTO) 6558 6559 /* 6560 * Set the "v:lang" variable according to the current locale setting. 6561 * Also do "v:lc_time"and "v:ctype". 6562 */ 6563 void 6564 set_lang_var() 6565 { 6566 char_u *loc; 6567 6568 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE) 6569 loc = (char_u *)get_locale_val(LC_CTYPE); 6570 # else 6571 /* setlocale() not supported: use the default value */ 6572 loc = (char_u *)"C"; 6573 # endif 6574 set_vim_var_string(VV_CTYPE, loc, -1); 6575 6576 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall 6577 * back to LC_CTYPE if it's empty. */ 6578 # if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) && defined(LC_MESSAGES) 6579 loc = (char_u *)get_locale_val(LC_MESSAGES); 6580 # else 6581 loc = get_mess_env(); 6582 # endif 6583 set_vim_var_string(VV_LANG, loc, -1); 6584 6585 # if defined(HAVE_LOCALE_H) || defined(X_LOCALE) 6586 loc = (char_u *)get_locale_val(LC_TIME); 6587 # endif 6588 set_vim_var_string(VV_LC_TIME, loc, -1); 6589 } 6590 #endif 6591 6592 #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \ 6593 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) 6594 /* 6595 * ":language": Set the language (locale). 6596 */ 6597 void 6598 ex_language(eap) 6599 exarg_T *eap; 6600 { 6601 char *loc; 6602 char_u *p; 6603 char_u *name; 6604 int what = LC_ALL; 6605 char *whatstr = ""; 6606 #ifdef LC_MESSAGES 6607 # define VIM_LC_MESSAGES LC_MESSAGES 6608 #else 6609 # define VIM_LC_MESSAGES 6789 6610 #endif 6611 6612 name = eap->arg; 6613 6614 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument. 6615 * Allow abbreviation, but require at least 3 characters to avoid 6616 * confusion with a two letter language name "me" or "ct". */ 6617 p = skiptowhite(eap->arg); 6618 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3) 6619 { 6620 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0) 6621 { 6622 what = VIM_LC_MESSAGES; 6623 name = skipwhite(p); 6624 whatstr = "messages "; 6625 } 6626 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0) 6627 { 6628 what = LC_CTYPE; 6629 name = skipwhite(p); 6630 whatstr = "ctype "; 6631 } 6632 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0) 6633 { 6634 what = LC_TIME; 6635 name = skipwhite(p); 6636 whatstr = "time "; 6637 } 6638 } 6639 6640 if (*name == NUL) 6641 { 6642 #ifndef LC_MESSAGES 6643 if (what == VIM_LC_MESSAGES) 6644 p = get_mess_env(); 6645 else 6646 #endif 6647 p = (char_u *)setlocale(what, NULL); 6648 if (p == NULL || *p == NUL) 6649 p = (char_u *)"Unknown"; 6650 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p); 6651 } 6652 else 6653 { 6654 #ifndef LC_MESSAGES 6655 if (what == VIM_LC_MESSAGES) 6656 loc = ""; 6657 else 6658 #endif 6659 loc = setlocale(what, (char *)name); 6660 if (loc == NULL) 6661 EMSG2(_("E197: Cannot set language to \"%s\""), name); 6662 else 6663 { 6664 #ifdef HAVE_NL_MSG_CAT_CNTR 6665 /* Need to do this for GNU gettext, otherwise cached translations 6666 * will be used again. */ 6667 extern int _nl_msg_cat_cntr; 6668 6669 ++_nl_msg_cat_cntr; 6670 #endif 6671 /* Reset $LC_ALL, otherwise it would overrule everyting. */ 6672 vim_setenv((char_u *)"LC_ALL", (char_u *)""); 6673 6674 if (what != LC_TIME) 6675 { 6676 /* Tell gettext() what to translate to. It apparently doesn't 6677 * use the currently effective locale. Also do this when 6678 * FEAT_GETTEXT isn't defined, so that shell commands use this 6679 * value. */ 6680 if (what == LC_ALL) 6681 vim_setenv((char_u *)"LANG", name); 6682 if (what != LC_CTYPE) 6683 { 6684 char_u *mname; 6685 #ifdef WIN32 6686 mname = gettext_lang(name); 6687 #else 6688 mname = name; 6689 #endif 6690 vim_setenv((char_u *)"LC_MESSAGES", mname); 6691 #ifdef FEAT_MULTI_LANG 6692 set_helplang_default(mname); 6693 #endif 6694 } 6695 6696 /* Set $LC_CTYPE, because it overrules $LANG, and 6697 * gtk_set_locale() calls setlocale() again. gnome_init() 6698 * sets $LC_CTYPE to "en_US" (that's a bug!). */ 6699 if (what != VIM_LC_MESSAGES) 6700 vim_setenv((char_u *)"LC_CTYPE", name); 6701 # ifdef FEAT_GUI_GTK 6702 /* Let GTK know what locale we're using. Not sure this is 6703 * really needed... */ 6704 if (gui.in_use) 6705 (void)gtk_set_locale(); 6706 # endif 6707 } 6708 6709 # ifdef FEAT_EVAL 6710 /* Set v:lang, v:lc_time and v:ctype to the final result. */ 6711 set_lang_var(); 6712 # endif 6713 } 6714 } 6715 } 6716 6717 # if defined(FEAT_CMDL_COMPL) || defined(PROTO) 6718 /* 6719 * Function given to ExpandGeneric() to obtain the possible arguments of the 6720 * ":language" command. 6721 */ 6722 /*ARGSUSED*/ 6723 char_u * 6724 get_lang_arg(xp, idx) 6725 expand_T *xp; 6726 int idx; 6727 { 6728 if (idx == 0) 6729 return (char_u *)"messages"; 6730 if (idx == 1) 6731 return (char_u *)"ctype"; 6732 if (idx == 2) 6733 return (char_u *)"time"; 6734 return NULL; 6735 } 6736 # endif 6737 6738 #endif 6739