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