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