/// @file version.c /// /// Vim originated from Stevie version 3.6 (Fish disk 217) by GRWalter (Fred) /// It has been changed beyond recognition since then. /// /// Differences between version 6.x and 7.x can be found with ":help version7". /// Differences between version 5.x and 6.x can be found with ":help version6". /// Differences between version 4.x and 5.x can be found with ":help version5". /// Differences between version 3.0 and 4.x can be found with ":help version4". /// All the remarks about older versions have been removed, they are not very /// interesting. #include "vim.h" #include "version.h" #include "charset.h" #include "memline.h" #include "message.h" #include "misc2.h" #include "screen.h" #include "version_defs.h" char *Version = VIM_VERSION_SHORT; static char *mediumVersion = VIM_VERSION_MEDIUM; char *longVersion = VIM_VERSION_LONG_DATE __DATE__ " " __TIME__ ")"; static void list_features(void); static void version_msg(char *s); static char *(features[]) = { #ifdef HAVE_ACL "+acl", #else // ifdef HAVE_ACL "-acl", #endif // ifdef HAVE_ACL "+arabic", "+autocmd", "-browse", #ifdef NO_BUILTIN_TCAPS "-builtin_terms", #endif // ifdef NO_BUILTIN_TCAPS #ifdef SOME_BUILTIN_TCAPS "+builtin_terms", #endif // ifdef SOME_BUILTIN_TCAPS #ifdef ALL_BUILTIN_TCAPS "++builtin_terms", #endif // ifdef ALL_BUILTIN_TCAPS "+byte_offset", "+cindent", "-clipboard", "+cmdline_compl", "+cmdline_hist", "+cmdline_info", "+comments", "+conceal", "+cryptv", "+cscope", "+cursorbind", #ifdef CURSOR_SHAPE "+cursorshape", #else // ifdef CURSOR_SHAPE "-cursorshape", #endif // ifdef CURSOR_SHAPE "+dialog_con", "+diff", "+digraphs", "-dnd", "-ebcdic", "-emacs_tags", "+eval", "+ex_extra", "+extra_search", "+farsi", "+file_in_path", "+find_in_path", "+float", "+folding", "-footer", // only interesting on Unix systems #if defined(UNIX) "+fork()", #endif // if defined(UNIX) "+gettext", #if (defined(HAVE_ICONV_H) && defined(USE_ICONV)) || defined(DYNAMIC_ICONV) # ifdef DYNAMIC_ICONV "+iconv/dyn", # else // ifdef DYNAMIC_ICONV "+iconv", # endif // ifdef DYNAMIC_ICONV #else // if (defined(HAVE_ICONV_H) && defined(USE_ICONV)) // ||defined(DYNAMIC_ICONV) "-iconv", #endif // if (defined(HAVE_ICONV_H) && defined(USE_ICONV)) // || defined(DYNAMIC_ICONV) "+insert_expand", "+jumplist", "+keymap", "+langmap", #ifdef FEAT_LIBCALL "+libcall", #else // ifdef FEAT_LIBCALL "-libcall", #endif // ifdef FEAT_LIBCALL "+linebreak", "+lispindent", "+listcmds", "+localmap", "+menu", "+mksession", "+modify_fname", "+mouse", "-mouseshape", #if defined(UNIX) || defined(VMS) "+mouse_dec", "-mouse_gpm", # ifdef FEAT_MOUSE_JSB "+mouse_jsbterm", # else // ifdef FEAT_MOUSE_JSB "-mouse_jsbterm", # endif // ifdef FEAT_MOUSE_JSB "+mouse_netterm", #endif // if defined(UNIX) || defined(VMS) #if defined(UNIX) || defined(VMS) "+mouse_sgr", "-mouse_sysmouse", "+mouse_urxvt", "+mouse_xterm", #endif // if defined(UNIX) || defined(VMS) "+multi_byte", "+multi_lang", "+path_extra", "+persistent_undo", "+postscript", "+printer", "+profile", "+quickfix", "+reltime", "+rightleft", "+scrollbind", "+signs", "+smartindent", #ifdef STARTUPTIME "+startuptime", #else // ifdef STARTUPTIME "-startuptime", #endif // ifdef STARTUPTIME "+statusline", "+syntax", "+tag_binary", "+tag_old_static", #ifdef FEAT_TAG_ANYWHITE "+tag_any_white", #else // ifdef FEAT_TAG_ANYWHITE "-tag_any_white", #endif // ifdef FEAT_TAG_ANYWHITE #if defined(UNIX) || defined(__EMX__) // only Unix (or OS/2 with EMX!) can have terminfo instead of termcap # ifdef TERMINFO "+terminfo", # else // ifdef TERMINFO "-terminfo", # endif // ifdef TERMINFO #else // unix always includes termcap support # ifdef HAVE_TGETENT "+tgetent", # else // ifdef HAVE_TGETENT "-tgetent", # endif // ifdef HAVE_TGETENT #endif // if defined(UNIX) || defined(__EMX__) "+termresponse", "+textobjects", "+title", "-toolbar", "+user_commands", "+vertsplit", "+virtualedit", "+visual", "+visualextra", "+viminfo", "+vreplace", "+wildignore", "+wildmenu", "+windows", "+writebackup", #if defined(UNIX) || defined(VMS) "-X11", #endif // if defined(UNIX) || defined(VMS) "-xfontset", #if defined(UNIX) || defined(VMS) "-xsmp", "-xterm_clipboard", #endif // if defined(UNIX) || defined(VMS) NULL }; static int included_patches[] = { // Add new patch number below this line 172, 171, 170, 169, //168, //167, 166, //165, //164, //163, //162, //161, 160, 159, 158, 157, 156, 155, 154, 153, 152, 151, 150, 149, 148, 147, 146, 145, 144, 143, 142, 141, 140, 139, 138, 137, 136, 135, 134, 133, 132, 131, 130, 129, 128, 127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; /// Place to put a short description when adding a feature with a patch. /// Keep it short, e.g.,: "relative numbers", "persistent undo". /// Also add a comment marker to separate the lines. /// See the official Vim patches for the diff format: It must use a context of /// one line only. Create it by hand or use "diff -C2" and edit the patch. static char *(extra_patches[]) = { // Add your patch description below this line NULL }; int highest_patch(void) { int i; int h = 0; for (i = 0; included_patches[i] != 0; ++i) { if (included_patches[i] > h) { h = included_patches[i]; } } return h; } /// Checks whether patch `n` has been included. /// /// @param n The patch number. /// /// @return TRUE if patch "n" has been included. int has_patch(int n) { int i; for (i = 0; included_patches[i] != 0; ++i) { if (included_patches[i] == n) { return TRUE; } } return FALSE; } void ex_version(exarg_T *eap) { // Ignore a ":version 9.99" command. if (*eap->arg == NUL) { msg_putchar('\n'); list_version(); } } /// List all features aligned in columns, dictionary style. static void list_features(void) { int nfeat = 0; int width = 0; // Find the length of the longest feature name, use that + 1 as the column // width int i; for (i = 0; features[i] != NULL; ++i) { int l = (int)STRLEN(features[i]); if (l > width) { width = l; } nfeat++; } width += 1; if (Columns < width) { // Not enough screen columns - show one per line for (i = 0; features[i] != NULL; ++i) { version_msg(features[i]); if (msg_col > 0) { msg_putchar('\n'); } } return; } // The rightmost column doesn't need a separator. // Sacrifice it to fit in one more column if possible. int ncol = (int)(Columns + 1) / width; int nrow = nfeat / ncol + (nfeat % ncol ? 1 : 0); // i counts columns then rows. idx counts rows then columns. for (i = 0; !got_int && i < nrow * ncol; ++i) { int idx = (i / ncol) + (i % ncol) * nrow; if (idx < nfeat) { int last_col = (i + 1) % ncol == 0; msg_puts((char_u *)features[idx]); if (last_col) { if (msg_col > 0) { msg_putchar('\n'); } } else { while (msg_col % width) { msg_putchar(' '); } } } else { if (msg_col > 0) { msg_putchar('\n'); } } } } void list_version(void) { int i; int first; char *s = ""; // When adding features here, don't forget to update the list of // internal variables in eval.c! MSG(longVersion); // Print the list of patch numbers if there is at least one. // Print a range when patches are consecutive: "1-10, 12, 15-40, 42-45" if (included_patches[0] != 0) { MSG_PUTS(_("\nIncluded patches: ")); first = -1; // find last one for (i = 0; included_patches[i] != 0; ++i) {} while (--i >= 0) { if (first < 0) { first = included_patches[i]; } if ((i == 0) || (included_patches[i - 1] != included_patches[i] + 1)) { MSG_PUTS(s); s = ", "; msg_outnum((long)first); if (first != included_patches[i]) { MSG_PUTS("-"); msg_outnum((long)included_patches[i]); } first = -1; } } } // Print the list of extra patch descriptions if there is at least one. if (extra_patches[0] != NULL) { MSG_PUTS(_("\nExtra patches: ")); s = ""; for (i = 0; extra_patches[i] != NULL; ++i) { MSG_PUTS(s); s = ", "; MSG_PUTS(extra_patches[i]); } } #ifdef MODIFIED_BY MSG_PUTS("\n"); MSG_PUTS(_("Modified by ")); MSG_PUTS(MODIFIED_BY); #endif // ifdef MODIFIED_BY #ifdef HAVE_PATHDEF if ((*compiled_user != NUL) || (*compiled_sys != NUL)) { MSG_PUTS(_("\nCompiled ")); if (*compiled_user != NUL) { MSG_PUTS(_("by ")); MSG_PUTS(compiled_user); } if (*compiled_sys != NUL) { MSG_PUTS("@"); MSG_PUTS(compiled_sys); } } #endif // ifdef HAVE_PATHDEF MSG_PUTS(_("\nHuge version ")); MSG_PUTS(_("without GUI.")); version_msg(_(" Features included (+) or not (-):\n")); list_features(); #ifdef SYS_VIMRC_FILE version_msg(_(" system vimrc file: \"")); version_msg(SYS_VIMRC_FILE); version_msg("\"\n"); #endif // ifdef SYS_VIMRC_FILE #ifdef USR_VIMRC_FILE version_msg(_(" user vimrc file: \"")); version_msg(USR_VIMRC_FILE); version_msg("\"\n"); #endif // ifdef USR_VIMRC_FILE #ifdef USR_VIMRC_FILE2 version_msg(_(" 2nd user vimrc file: \"")); version_msg(USR_VIMRC_FILE2); version_msg("\"\n"); #endif // ifdef USR_VIMRC_FILE2 #ifdef USR_VIMRC_FILE3 version_msg(_(" 3rd user vimrc file: \"")); version_msg(USR_VIMRC_FILE3); version_msg("\"\n"); #endif // ifdef USR_VIMRC_FILE3 #ifdef USR_EXRC_FILE version_msg(_(" user exrc file: \"")); version_msg(USR_EXRC_FILE); version_msg("\"\n"); #endif // ifdef USR_EXRC_FILE #ifdef USR_EXRC_FILE2 version_msg(_(" 2nd user exrc file: \"")); version_msg(USR_EXRC_FILE2); version_msg("\"\n"); #endif // ifdef USR_EXRC_FILE2 #ifdef HAVE_PATHDEF if (*default_vim_dir != NUL) { version_msg(_(" fall-back for $VIM: \"")); version_msg((char *)default_vim_dir); version_msg("\"\n"); } if (*default_vimruntime_dir != NUL) { version_msg(_(" f-b for $VIMRUNTIME: \"")); version_msg((char *)default_vimruntime_dir); version_msg("\"\n"); } version_msg(_("Compilation: ")); version_msg((char *)all_cflags); version_msg("\n"); version_msg(_("Linking: ")); version_msg((char *)all_lflags); #endif // ifdef HAVE_PATHDEF #ifdef DEBUG version_msg("\n"); version_msg(_(" DEBUG BUILD")); #endif // ifdef DEBUG } /// Output a string for the version message. If it's going to wrap, output a /// newline, unless the message is too long to fit on the screen anyway. /// /// @param s static void version_msg(char *s) { int len = (int)STRLEN(s); if (!got_int && (len < (int)Columns) && (msg_col + len >= (int)Columns) && (*s != '\n')) { msg_putchar('\n'); } if (!got_int) { MSG_PUTS(s); } } static void do_intro_line(int row, char_u *mesg, int add_version, int attr); /// Show the intro message when not editing a file. void maybe_intro_message(void) { if (bufempty() && (curbuf->b_fname == NULL) && (firstwin->w_next == NULL) && (vim_strchr(p_shm, SHM_INTRO) == NULL)) { intro_message(FALSE); } } /// Give an introductory message about Vim. /// Only used when starting Vim on an empty file, without a file name. /// Or with the ":intro" command (for Sven :-). /// /// @param colon TRUE for ":intro" void intro_message(int colon) { int i; int row; int blanklines; int sponsor; char *p; static char *(lines[]) = { N_("VIM - Vi IMproved"), "", N_("version "), N_("by Bram Moolenaar et al."), #ifdef MODIFIED_BY " ", #endif // ifdef MODIFIED_BY N_("Vim is open source and freely distributable"), "", N_("Help poor children in Uganda!"), N_("type :help iccf for information "), "", N_("type :q to exit "), N_("type :help or for on-line help"), N_("type :help version7 for version info"), NULL, "", N_("Running in Vi compatible mode"), N_("type :set nocp for Vim defaults"), N_("type :help cp-default for info on this"), }; // blanklines = screen height - # message lines blanklines = (int)Rows - ((sizeof(lines) / sizeof(char *)) - 1); if (!p_cp) { // add 4 for not showing "Vi compatible" message blanklines += 4; } // Don't overwrite a statusline. Depends on 'cmdheight'. if (p_ls > 1) { blanklines -= Rows - topframe->fr_height; } if (blanklines < 0) { blanklines = 0; } // Show the sponsor and register message one out of four times, the Uganda // message two out of four times. sponsor = (int)time(NULL); sponsor = ((sponsor & 2) == 0) - ((sponsor & 4) == 0); // start displaying the message lines after half of the blank lines row = blanklines / 2; if (((row >= 2) && (Columns >= 50)) || colon) { for (i = 0; i < (int)(sizeof(lines) / sizeof(char *)); ++i) { p = lines[i]; if (p == NULL) { if (!p_cp) { break; } continue; } if (sponsor != 0) { if (strstr(p, "children") != NULL) { p = sponsor < 0 ? N_("Sponsor Vim development!") : N_("Become a registered Vim user!"); } else if (strstr(p, "iccf") != NULL) { p = sponsor < 0 ? N_("type :help sponsor for information ") : N_("type :help register for information "); } else if (strstr(p, "Orphans") != NULL) { p = N_("menu Help->Sponsor/Register for information "); } } if (*p != NUL) { do_intro_line(row, (char_u *)_(p), i == 2, 0); } row++; } } // Make the wait-return message appear just below the text. if (colon) { msg_row = row; } } static void do_intro_line(int row, char_u *mesg, int add_version, int attr) { char_u vers[20]; int col; char_u *p; int l; int clen; #ifdef MODIFIED_BY # define MODBY_LEN 150 char_u modby[MODBY_LEN]; if (*mesg == ' ') { vim_strncpy(modby, (char_u *)_("Modified by "), MODBY_LEN - 1); l = STRLEN(modby); vim_strncpy(modby + l, (char_u *)MODIFIED_BY, MODBY_LEN - l - 1); mesg = modby; } #endif // ifdef MODIFIED_BY // Center the message horizontally. col = vim_strsize(mesg); if (add_version) { STRCPY(vers, mediumVersion); if (highest_patch()) { // Check for 9.9x or 9.9xx, alpha/beta version if (isalpha((int)vers[3])) { int len = (isalpha((int)vers[4])) ? 5 : 4; sprintf((char *)vers + len, ".%d%s", highest_patch(), mediumVersion + len); } else { sprintf((char *)vers + 3, ".%d", highest_patch()); } } col += (int)STRLEN(vers); } col = (Columns - col) / 2; if (col < 0) { col = 0; } // Split up in parts to highlight <> items differently. for (p = mesg; *p != NUL; p += l) { clen = 0; for (l = 0; p[l] != NUL && (l == 0 || (p[l] != '<' && p[l - 1] != '>')); ++l) { if (has_mbyte) { clen += ptr2cells(p + l); l += (*mb_ptr2len)(p + l) - 1; } else { clen += byte2cells(p[l]); } } screen_puts_len(p, l, row, col, *p == '<' ? hl_attr(HLF_8) : attr); col += clen; } // Add the version number to the version line. if (add_version) { screen_puts(vers, row, col, 0); } } /// ":intro": clear screen, display intro screen and wait for return. /// /// @param eap void ex_intro(exarg_T *eap) { screenclear(); intro_message(TRUE); wait_return(TRUE); }