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