|
发表于 2006-4-28 14:23:41
|
显示全部楼层
#if defined(MSDOS) || defined(WIN32) || defined(_WIN64)
# include <io.h> /* for close() and dup() */
#endif
#define EXTERN
#include "vim.h"
#ifdef SPAWNO
# include <spawno.h> /* special MSDOS swapping library */
#endif
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
#ifdef __CYGWIN__
# ifndef WIN32
# include <sys/cygwin.h> /* for cygwin_conv_to_posix_path() */
# endif
# include <limits.h>
#endif
#if defined(UNIX) || defined(VMS)
static int file_owned __ARGS((char *fname));
#endif
static void mainerr __ARGS((int, char_u *));
static void main_msg __ARGS((char *s));
static void usage __ARGS((void));
static int get_number_arg __ARGS((char_u *p, int *idx, int def));
static void main_start_gui __ARGS((void));
#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
static void check_swap_exists_action __ARGS((void));
#endif
#ifdef FEAT_CLIENTSERVER
static void cmdsrv_main __ARGS((int *argc, char **argv, char_u *serverName_arg, char_u **serverStr));
static char_u *serverMakeName __ARGS((char_u *arg, char *cmd));
#endif
#ifdef STARTUPTIME
static FILE *time_fd = NULL;
#endif
#define FEAT_PRECOMMANDS
/*
* Different types of error messages.
*/
static char *(main_errors[]) =
{
N_("Unknown option"),
#define ME_UNKNOWN_OPTION 0
N_("Too many edit arguments"),
#define ME_TOO_MANY_ARGS 1
N_("Argument missing after"),
#define ME_ARG_MISSING 2
N_("Garbage after option"),
#define ME_GARBAGE 3
N_("Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"),
#define ME_EXTRA_CMD 4
N_("Invalid argument for"),
#define ME_INVALID_ARG 5
};
/* Maximum number of commands from + or -c options */
#define MAX_ARG_CMDS 10
#ifndef PROTO /* don't want a prototype for main() */
int
# ifdef VIMDLL
_export
# endif
# ifdef FEAT_GUI_MSWIN
# ifdef __BORLANDC__
_cdecl
# endif
VimMain
# else
main
# endif
(argc, argv)
int argc;
char **argv;
{
char_u *initstr; /* init string from environment */
char_u *term = NULL; /* specified terminal name */
char_u *fname = NULL; /* file name from command line */
char_u *tagname = NULL; /* tag from -t option */
char_u *use_vimrc = NULL; /* vimrc from -u option */
#ifdef FEAT_QUICKFIX
char_u *use_ef = NULL; /* 'errorfile' from -q option */
#endif
#ifdef FEAT_CRYPT
int ask_for_key = FALSE; /* -x argument */
#endif
int n_commands = 0; /* no. of commands from + or -c */
char_u *commands[MAX_ARG_CMDS]; /* commands from + or -c option */
#ifdef FEAT_PRECOMMANDS
int p_commands = 0; /* no. of commands from --cmd */
char_u *pre_commands[MAX_ARG_CMDS]; /* commands from --cmd option */
#endif
int no_swap_file = FALSE; /* "-n" option used */
int c;
int i;
char_u *p = NULL;
int bin_mode = FALSE; /* -b option used */
#ifdef FEAT_EVAL
int use_debug_break_level = -1;
#endif
#ifdef FEAT_WINDOWS
int window_count = -1; /* number of windows to use */
int arg_idx; /* index in argument list */
int vert_windows = MAYBE; /* "-O" used instead of "-o" */
#endif
int had_minmin = FALSE; /* found "--" option */
int argv_idx; /* index in argv[n][] */
int want_full_screen = TRUE;
int want_argument; /* option with argument */
#define EDIT_NONE 0 /* no edit type yet */
#define EDIT_FILE 1 /* file name argument[s] given, use argument list */
#define EDIT_STDIN 2 /* read file from stdin */
#define EDIT_TAG 3 /* tag name argument given, use tagname */
#define EDIT_QF 4 /* start in quickfix mode */
int edit_type = EDIT_NONE; /* type of editing to do */
#ifdef FEAT_DIFF
int diff_mode = FALSE; /* start with 'diff' set */
#endif
int evim_mode = FALSE; /* started as "evim" */
int stdout_isatty; /* is stdout a terminal? */
int input_isatty; /* is active input a terminal? */
#ifdef MSWIN
int full_path = FALSE;
#endif
#ifdef FEAT_CLIENTSERVER
char_u *serverStr = NULL;
char_u *serverName_arg = NULL; /* cmdline arg for server name */
int serverArg = FALSE; /* TRUE when argument for a server */
char_u *servername = NULL; /* allocated name for our server */
#endif
#if (!defined(UNIX) && !defined(__EMX__)) || defined(ARCHIE)
int literal = FALSE; /* don't expand file names */
#endif
/*
* Do any system-specific initialisations. These can NOT use IObuff or
* NameBuff. Thus emsg2() cannot be called!
*/
mch_early_init();
#ifdef FEAT_TCL
vim_tcl_init(argv[0]);
#endif
#ifdef MEM_PROFILE
atexit(vim_mem_profile_dump);
#endif
#ifdef STARTUPTIME
time_fd = fopen(STARTUPTIME, "a");
TIME_MSG("--- VIM STARTING ---");
#endif
#ifdef __EMX__
_wildcard(&argc, &argv);
#endif
#ifdef FEAT_MBYTE
(void)mb_init(); /* init mb_bytelen_tab[] to ones */
#endif
#ifdef __QNXNTO__
qnx_init(); /* PhAttach() for clipboard, (and gui) */
#endif
#ifdef MAC_OS_CLASSIC
/* Macintosh needs this before any memory is allocated. */
gui_prepare(&argc, argv); /* Prepare for possibly starting GUI sometime */
TIME_MSG("GUI prepared");
#endif
/* Init the table of Normal mode commands. */
init_normal_cmds();
#if defined(HAVE_DATE_TIME) && defined(VMS) && defined(VAXC)
make_version();
#endif
/*
* Allocate space for the generic buffers (needed for set_init_1() and
* EMSG2()).
*/
if ((IObuff = alloc(IOSIZE)) == NULL
|| (NameBuff = alloc(MAXPATHL)) == NULL)
mch_exit(0);
TIME_MSG("Allocated generic buffers");
#ifdef NBDEBUG
/* Wait a moment for debugging NetBeans. Must be after allocating
* NameBuff. */
nbdebug_log_init("SPRO_GVIM_DEBUG", "SPRO_GVIM_DLEVEL");
nbdebug_wait(WT_ENV | WT_WAIT | WT_STOP, "SPRO_GVIM_WAIT", 20);
#endif
#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
/*
* Setup to use the current locale (for ctype() and many other things).
* NOTE: Translated messages with encodings other than latin1 will not
* work until set_init_1() has been called!
*/
setlocale(LC_ALL, "");
# ifdef FEAT_GETTEXT
{
int mustfree = FALSE;
# ifdef DYNAMIC_GETTEXT
/* Initialize the gettext library */
dyn_libintl_init(NULL);
# endif
/* expand_env() doesn't work yet, because chartab[] is not initialized
* yet, call vim_getenv() directly */
p = vim_getenv((char_u *)"VIMRUNTIME", &mustfree);
if (p != NULL && *p != NUL)
{
STRCPY(NameBuff, p);
STRCAT(NameBuff, "/lang");
bindtextdomain(VIMPACKAGE, (char *)NameBuff);
}
if (mustfree)
vim_free(p);
textdomain(VIMPACKAGE);
}
# endif
TIME_MSG("locale set");
#endif
#ifdef FEAT_GUI
gui.dofork = TRUE; /* default is to use fork() */
#endif
#if defined(FEAT_XCLIPBOARD) || defined(FEAT_CLIENTSERVER)
/*
* Get the name of the display, before gui_prepare() removes it from
* argv[]. Used for the xterm-clipboard display.
*
* Also find the --server... arguments
*/
for (i = 1; i < argc; i++)
{
if (STRCMP(argv[i], "--") == 0)
break;
# ifdef FEAT_XCLIPBOARD
else if (STRICMP(argv[i], "-display") == 0
# ifdef FEAT_GUI_GTK
|| STRICMP(argv[i], "--display") == 0
# endif
)
{
if (i == argc - 1)
mainerr_arg_missing((char_u *)argv[i]);
xterm_display = argv[++i];
}
# endif
# ifdef FEAT_CLIENTSERVER
else if (STRICMP(argv[i], "--servername") == 0)
{
if (i == argc - 1)
mainerr_arg_missing((char_u *)argv[i]);
serverName_arg = (char_u *)argv[++i];
}
else if (STRICMP(argv[i], "--serverlist") == 0
|| STRICMP(argv[i], "--remote-send") == 0
|| STRICMP(argv[i], "--remote-expr") == 0
|| STRICMP(argv[i], "--remote") == 0
|| STRICMP(argv[i], "--remote-silent") == 0)
serverArg = TRUE;
else if (STRICMP(argv[i], "--remote-wait") == 0
|| STRICMP(argv[i], "--remote-wait-silent") == 0)
{
serverArg = TRUE;
#ifdef FEAT_GUI
/* don't fork() when starting the GUI to edit the files ourself */
gui.dofork = FALSE;
#endif
}
# endif
# ifdef FEAT_GUI_GTK
else if (STRICMP(argv[i], "--socketid") == 0)
{
unsigned int socket_id;
int count;
if (i == argc - 1)
mainerr_arg_missing((char_u *)argv[i]);
if (STRNICMP(argv[i+1], "0x", 2) == 0)
count = sscanf(&(argv[i + 1][2]), "%x", &socket_id);
else
count = sscanf(argv[i+1], "%u", &socket_id);
if (count != 1)
mainerr(ME_INVALID_ARG, (char_u *)argv[i]);
else
gtk_socket_id = socket_id;
i++;
}
else if (STRICMP(argv[i], "--echo-wid") == 0)
echo_wid_arg = TRUE;
# endif
}
#endif
#ifdef FEAT_SUN_WORKSHOP
findYourself(argv[0]);
#endif
#if defined(FEAT_GUI) && !defined(MAC_OS_CLASSIC)
gui_prepare(&argc, argv); /* Prepare for possibly starting GUI sometime */
TIME_MSG("GUI prepared");
#endif
#ifdef FEAT_CLIPBOARD
clip_init(FALSE); /* Initialise clipboard stuff */
TIME_MSG("clipboard setup");
#endif
/*
* Check if we have an interactive window.
* On the Amiga: If there is no window, we open one with a newcli command
* (needed for :! to * work). mch_check_win() will also handle the -d or
* -dev argument.
*/
stdout_isatty = (mch_check_win(argc, argv) != FAIL);
TIME_MSG("window checked");
/*
* Allocate the first window and buffer. Can't do much without it.
*/
win_alloc_first();
init_yank(); /* init yank buffers */
/* Init the argument list to empty. */
alist_init(&global_alist);
/*
* Set the default values for the options.
* NOTE: Non-latin1 translated messages are working only after this,
* because this is where "has_mbyte" will be set, which is used by
* msg_outtrans_len_attr().
* First find out the home directory, needed to expand "~" in options.
*/
init_homedir(); /* find real value of $HOME */
set_init_1();
TIME_MSG("inits 1");
#ifdef FEAT_EVAL
set_lang_var(); /* set v:lang and v:ctype */
#endif
#ifdef FEAT_CLIENTSERVER
/*
* Do the client-server stuff, unless "--servername ''" was used.
*/
if (serverName_arg == NULL || *serverName_arg != NUL)
{
# ifdef WIN32
/* Initialise the client/server messaging infrastructure. */
serverInitMessaging();
# endif
/*
* When a command server argument was found, execute it. This may
* exit Vim when it was successful.
*/
if (serverArg)
cmdsrv_main(&argc, argv, serverName_arg, &serverStr);
/* If we're still running, get the name to register ourselves.
* On Win32 can register right now, for X11 need to setup the
* clipboard first, it's further down. */
servername = serverMakeName(serverName_arg, argv[0]);
# ifdef WIN32
if (servername != NULL)
{
serverSetName(servername);
vim_free(servername);
}
# endif
}
#endif
/*
* Check for: [r][e][g][vi|vim|view][diff][ex[im]]
* If the executable name starts with "r" we disable shell commands.
* If the next character is "e" we run in Easy mode.
* If the next character is "g" we run the GUI version.
* If the next characters are "view" we start in readonly mode.
* If the next characters are "diff" or "vimdiff" we start in diff mode.
* If the next characters are "ex" we start in Ex mode. If it's followed
* by "im" use improved Ex mode.
*/
initstr = gettail((char_u *)argv[0]);
#ifdef MACOS_X_UNIX
/* An issue has been seen when launching Vim in such a way that
* $PWD/$ARGV[0] or $ARGV[0] is not the absolute path to the
* executable or a symbolic link of it. Until this issue is resolved
* we prohibit the GUI from being used.
*/
if (STRCMP(initstr, argv[0]) == 0)
disallow_gui = TRUE;
#endif
#ifdef FEAT_EVAL
set_vim_var_string(VV_PROGNAME, initstr, -1);
#endif
/* TODO: On MacOS X default to gui if argv[0] ends in:
* /vim.app/Contents/MacOS/Vim */
if (TOLOWER_ASC(initstr[0]) == 'r')
{
restricted = TRUE;
++initstr;
}
/* Avoid using evim mode for "editor". */
if (TOLOWER_ASC(initstr[0]) == 'e'
&& (TOLOWER_ASC(initstr[1]) == 'v'
|| TOLOWER_ASC(initstr[1]) == 'g'))
{
#ifdef FEAT_GUI
gui.starting = TRUE;
#endif
evim_mode = TRUE;
++initstr;
}
if (TOLOWER_ASC(initstr[0]) == 'g')
{
main_start_gui();
#ifdef FEAT_GUI
++initstr;
#endif
}
if (STRNICMP(initstr, "view", 4) == 0)
{
readonlymode = TRUE;
curbuf->b_p_ro = TRUE;
p_uc = 10000; /* don't update very often */
initstr += 4;
}
else if (STRNICMP(initstr, "vim", 3) == 0)
initstr += 3;
/* Catch "[r][g]vimdiff" and "[r][g]viewdiff". */
if (STRICMP(initstr, "diff") == 0)
{
#ifdef FEAT_DIFF
diff_mode = TRUE;
#else
mch_errmsg(_("This Vim was not compiled with the diff feature."));
mch_errmsg("\n");
mch_exit(2);
#endif
}
if (STRNICMP(initstr, "ex", 2) == 0)
{
if (STRNICMP(initstr + 2, "im", 2) == 0)
exmode_active = EXMODE_VIM;
else
exmode_active = EXMODE_NORMAL;
change_compatible(TRUE); /* set 'compatible' */
}
initstr = gettail((char_u *)argv[0]);
++argv;
--argc;
/*
* Process the command line arguments.
*/
argv_idx = 1; /* active option letter is argv[0][argv_idx] */
while (argc > 0)
{
/*
* "+" or "+{number}" or "+/{pat}" or "+{command}" argument.
*/
if (argv[0][0] == '+' && !had_minmin)
{
if (n_commands >= MAX_ARG_CMDS)
mainerr(ME_EXTRA_CMD, NULL);
argv_idx = -1; /* skip to next argument */
if (argv[0][1] == NUL)
commands[n_commands++] = (char_u *)"$";
else
commands[n_commands++] = (char_u *)&(argv[0][1]);
}
/*
* Optional argument.
*/
else if (argv[0][0] == '-' && !had_minmin)
{
want_argument = FALSE;
c = argv[0][argv_idx++];
#ifdef VMS
/*
* VMS only uses upper case command lines. Interpret "-X" as "-x"
* and "-/X" as "-X".
*/
if (c == '/')
{
c = argv[0][argv_idx++];
c = TOUPPER_ASC(c);
}
else
c = TOLOWER_ASC(c);
#endif
switch (c)
{
case NUL: /* "vim -" read from stdin */
/* "ex -" silent mode */
if (exmode_active)
silent_mode = TRUE;
else
{
if (edit_type != EDIT_NONE)
mainerr(ME_TOO_MANY_ARGS, (char_u *)argv[0]);
edit_type = EDIT_STDIN;
read_cmd_fd = 2; /* read from stderr instead of stdin */
}
argv_idx = -1; /* skip to next argument */
break;
case '-': /* "--" don't take any more options */
/* "--help" give help message */
/* "--version" give version message */
/* "--literal" take files literally */
/* "--nofork" don't fork */
/* "--noplugin[s]" skip plugins */
/* "--cmd <cmd>" execute cmd before vimrc */
if (STRICMP(argv[0] + argv_idx, "help") == 0)
usage();
else if (STRICMP(argv[0] + argv_idx, "version") == 0)
{
Columns = 80; /* need to init Columns */
info_message = TRUE; /* use mch_msg(), not mch_errmsg() */
list_version();
msg_putchar('\n');
msg_didout = FALSE;
mch_exit(0);
}
else if (STRNICMP(argv[0] + argv_idx, "literal", 7) == 0)
{
#if (!defined(UNIX) && !defined(__EMX__)) || defined(ARCHIE)
literal = TRUE;
#endif
}
else if (STRNICMP(argv[0] + argv_idx, "nofork", 6) == 0)
{
#ifdef FEAT_GUI
gui.dofork = FALSE; /* don't fork() when starting GUI */
#endif
}
else if (STRNICMP(argv[0] + argv_idx, "noplugin", 8) == 0)
p_lpl = FALSE;
#ifdef FEAT_PRECOMMANDS
else if (STRNICMP(argv[0] + argv_idx, "cmd", 3) == 0)
{
want_argument = TRUE;
argv_idx += 3;
}
#endif
#ifdef FEAT_CLIENTSERVER
else if (STRNICMP(argv[0] + argv_idx, "serverlist", 10) == 0)
; /* already processed -- no arg */
else if (STRNICMP(argv[0] + argv_idx, "servername", 10) == 0
|| STRNICMP(argv[0] + argv_idx, "serversend", 10) == 0)
{
/* already processed -- snatch the following arg */
if (argc > 1)
{
--argc;
++argv;
}
}
#endif
#ifdef FEAT_GUI_GTK
else if (STRNICMP(argv[0] + argv_idx, "socketid", 8) == 0)
{
/* already processed -- snatch the following arg */
if (argc > 1)
{
--argc;
++argv;
}
}
else if (STRNICMP(argv[0] + argv_idx, "echo-wid", 8) == 0)
{
/* already processed, skip */
}
#endif
else
{
if (argv[0][argv_idx])
mainerr(ME_UNKNOWN_OPTION, (char_u *)argv[0]);
had_minmin = TRUE;
}
if (!want_argument)
argv_idx = -1; /* skip to next argument */
break;
case 'A': /* "-A" start in Arabic mode */
#ifdef FEAT_ARABIC
set_option_value((char_u *)"arabic", 1L, NULL, 0);
#else
mch_errmsg(_(e_noarabic));
mch_exit(2);
#endif
break;
case 'b': /* "-b" binary mode */
bin_mode = TRUE; /* postpone to after reading .exrc files */
break;
case 'C': /* "-C" Compatible */
change_compatible(TRUE);
break;
case 'e': /* "-e" Ex mode */
exmode_active = EXMODE_NORMAL;
break;
case 'E': /* "-E" Improved Ex mode */
exmode_active = EXMODE_VIM;
break;
case 'f': /* "-f" GUI: run in foreground. Amiga: open
window directly, not with newcli */
#ifdef FEAT_GUI
gui.dofork = FALSE; /* don't fork() when starting GUI */
#endif
break;
case 'g': /* "-g" start GUI */
main_start_gui();
break;
case 'F': /* "-F" start in Farsi mode: rl + fkmap set */
#ifdef FEAT_FKMAP
curwin->w_p_rl = p_fkmap = TRUE;
#else
mch_errmsg(_(e_nofarsi));
mch_exit(2);
#endif
break;
case 'h': /* "-h" give help message */
#ifdef FEAT_GUI_GNOME
/* Tell usage() to exit for "gvim". */
gui.starting = FALSE;
#endif
usage();
break;
case 'H': /* "-H" start in Hebrew mode: rl + hkmap set */
#ifdef FEAT_RIGHTLEFT
curwin->w_p_rl = p_hkmap = TRUE;
#else
mch_errmsg(_(e_nohebrew));
mch_exit(2);
#endif
break;
case 'l': /* "-l" lisp mode, 'lisp' and 'showmatch' on */
#ifdef FEAT_LISP
set_option_value((char_u *)"lisp", 1L, NULL, 0);
p_sm = TRUE;
#endif
break;
#ifdef TARGET_API_MAC_OSX
/* For some reason on MacOS X, an argument like:
-psn_0_10223617 is passed in when invoke from Finder
or with the 'open' command */
case 'p':
argv_idx = -1; /* bypass full -psn */
main_start_gui();
break;
#endif
case 'M': /* "-M" no changes or writing of files */
reset_modifiable();
/* FALLTRHOUGH */
case 'm': /* "-m" no writing of files */
p_write = FALSE;
break;
case 'y': /* "-y" easy mode */
#ifdef FEAT_GUI
gui.starting = TRUE; /* start GUI a bit later */
#endif
evim_mode = TRUE;
break;
case 'N': /* "-N" Nocompatible */
change_compatible(FALSE);
break;
case 'n': /* "-n" no swap file */
no_swap_file = TRUE;
break;
case 'o': /* "-o[N]" open N horizontal split windows */
#ifdef FEAT_WINDOWS
/* default is 0: open window for each file */
window_count = get_number_arg((char_u *)argv[0], &argv_idx, 0);
vert_windows = FALSE;
#endif
break;
case 'O': /* "-O[N]" open N vertical split windows */
#if defined(FEAT_VERTSPLIT) && defined(FEAT_WINDOWS)
/* default is 0: open window for each file */
window_count = get_number_arg((char_u *)argv[0], &argv_idx, 0);
vert_windows = TRUE;
#endif
break; |
|