📄 main.c
字号:
goto err; } /* Set up the argument pointer. */ sp->a_frp = sp->frp; /* * If there's an initial command, push it on the command stack. * Historically, it was always an ex command, not vi in vi mode * or ex in ex mode. So, make it look like an ex command to vi. */ if (excmdarg != NULL) if (IN_EX_MODE(sp)) { if (term_push(sp, excmdarg, strlen(excmdarg), 0, 0)) goto err; } else if (IN_VI_MODE(sp)) { if (term_push(sp, "\n", 1, 0, 0)) goto err; if (term_push(sp, excmdarg, strlen(excmdarg), 0, 0)) goto err; if (term_push(sp, ":", 1, 0, 0)) goto err; } /* * Initialize the signals. Use sigaction(2), not signal(3), because * we don't want to always restart system calls on 4BSD systems. It * would be nice in some cases to restart system calls, but SA_RESTART * is a 4BSD extension so we can't use it. * * SIGALRM: * Walk structures and call handling routines. * SIGHUP, SIGTERM, SIGWINCH: * Catch and set a global bit. * SIGQUIT: * Always ignore. */ act.sa_handler = h_alrm; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (sigaction(SIGALRM, &act, NULL)) { msgq(sp, M_SYSERR, "timer: sigaction"); goto err; } act.sa_handler = h_hup; sigemptyset(&act.sa_mask); act.sa_flags = 0; (void)sigaction(SIGHUP, &act, NULL); act.sa_handler = h_term; sigemptyset(&act.sa_mask); act.sa_flags = 0; (void)sigaction(SIGTERM, &act, NULL); act.sa_handler = h_winch; sigemptyset(&act.sa_mask); act.sa_flags = 0; (void)sigaction(SIGWINCH, &act, NULL); act.sa_handler = SIG_IGN; sigemptyset(&act.sa_mask); act.sa_flags = 0; (void)sigaction(SIGQUIT, &act, NULL); for (;;) { if (sp->s_edit(sp, sp->ep)) goto err; /* * Edit the next screen on the display queue, or, move * a screen from the hidden queue to the display queue. */ if ((sp = __global_list->dq.cqh_first) == (void *)&__global_list->dq) if ((sp = __global_list->hq.cqh_first) != (void *)&__global_list->hq) { CIRCLEQ_REMOVE(&sp->gp->hq, sp, q); CIRCLEQ_INSERT_TAIL(&sp->gp->dq, sp, q); } else break; /* * The screen type may have changed -- reinitialize the * functions in case it has. */ switch (F_ISSET(sp, S_SCREENS)) { case S_EX: if (sex_screen_init(sp)) goto err; break; case S_VI_CURSES: if (svi_screen_init(sp)) goto err; break; case S_VI_XAW: if (xaw_screen_init(sp)) goto err; break; default: abort(); } } eval = 0; if (0)err: eval = 1; /* * NOTE: sp may be GONE when the screen returns, so only * the gp can be trusted. */ gs_end(gp); exit(eval);}/* * gs_init -- * Build and initialize the GS structure. */static GS *gs_init(){ GS *gp; int fd; CALLOC_NOMSG(NULL, gp, GS *, 1, sizeof(GS)); if (gp == NULL) err(1, NULL); CIRCLEQ_INIT(&gp->dq); CIRCLEQ_INIT(&gp->hq); LIST_INIT(&gp->msgq); /* Structures shared by screens so stored in the GS structure. */ CALLOC_NOMSG(NULL, gp->tty, IBUF *, 1, sizeof(IBUF)); if (gp->tty == NULL) err(1, NULL); LIST_INIT(&gp->cutq); LIST_INIT(&gp->seqq); /* Set a flag if we're reading from the tty. */ if (isatty(STDIN_FILENO)) F_SET(gp, G_STDIN_TTY); /* * Set the G_STDIN_TTY flag. It's purpose is to avoid setting and * resetting the tty if the input isn't from there. * * Set the G_TERMIOS_SET flag. It's purpose is to avoid using the * original_termios information (mostly special character values) * if it's not valid. We expect that if we've lost our controlling * terminal that the open() (but not the tcgetattr()) will fail. */ if (F_ISSET(gp, G_STDIN_TTY)) { if (tcgetattr(STDIN_FILENO, &gp->original_termios) == -1) err(1, "tcgetattr"); F_SET(gp, G_TERMIOS_SET); } else if ((fd = open(_PATH_TTY, O_RDONLY, 0)) != -1) { if (tcgetattr(fd, &gp->original_termios) == -1) err(1, "tcgetattr"); F_SET(gp, G_TERMIOS_SET); (void)close(fd); } return (gp);}/* * gs_end -- * End the GS structure. */static voidgs_end(gp) GS *gp;{ MSG *mp; SCR *sp; char *tty; /* Reset anything that needs resetting. */ if (gp->flags & G_SETMODE) /* O_MESG */ if ((tty = ttyname(STDERR_FILENO)) == NULL) warn("ttyname"); else if (chmod(tty, gp->origmode) < 0) warn("%s", tty); /* Ring the bell if scheduled. */ if (F_ISSET(gp, G_BELLSCHED)) (void)fprintf(stderr, "\07"); /* \a */ /* If there are any remaining screens, flush their messages. */ for (sp = __global_list->dq.cqh_first; sp != (void *)&__global_list->dq; sp = sp->q.cqe_next) for (mp = sp->msgq.lh_first; mp != NULL && !(F_ISSET(mp, M_EMPTY)); mp = mp->q.le_next) (void)fprintf(stderr, "%.*s\n", (int)mp->len, mp->mbuf); for (sp = __global_list->hq.cqh_first; sp != (void *)&__global_list->hq; sp = sp->q.cqe_next) for (mp = sp->msgq.lh_first; mp != NULL && !(F_ISSET(mp, M_EMPTY)); mp = mp->q.le_next) (void)fprintf(stderr, "%.*s\n", (int)mp->len, mp->mbuf); /* Flush messages on the global queue. */ for (mp = gp->msgq.lh_first; mp != NULL && !(F_ISSET(mp, M_EMPTY)); mp = mp->q.le_next) (void)fprintf(stderr, "%.*s\n", (int)mp->len, mp->mbuf); if (gp->special_key != NULL) FREE(gp->special_key, MAX_FAST_KEY); /* * DON'T FREE THE GLOBAL STRUCTURE -- WE DIDN'T TURN * OFF SIGNALS/TIMERS, SO IT MAY STILL BE REFERENCED. */}/* * h_hup -- * Handle SIGHUP. */static voidh_hup(signo) int signo;{ F_SET(__global_list, G_SIGHUP); /* * If we're asleep, just die. * * XXX * This isn't right if the windows are independent. */ if (F_ISSET(__global_list, G_SLEEPING)) rcv_hup();}/* * h_term -- * Handle SIGTERM. */static voidh_term(signo) int signo;{ F_SET(__global_list, G_SIGTERM); /* * If we're asleep, just die. * * XXX * This isn't right if the windows are independent. */ if (F_ISSET(__global_list, G_SLEEPING)) rcv_term();}/* * h_winch -- * Handle SIGWINCH. */static voidh_winch(signo) int signo;{ F_SET(__global_list, G_SIGWINCH);}/* * exrc_isok -- * Check a .exrc file for source-ability. * * !!! * Historically, vi read both $HOME and local .exrc file if they were owned * by the user's real ID, or the "sourceany" option was set, regardless of * any other considerations. We no longer support the sourceany option as * it's a security problem of mammoth proportions. We require that the file * be owned by root (for the system .exrc files) or the user's effective ID * (for any of the .exrc files), and require that it not be writeable by * anyone other than the owner. * * In O'Reilly ("Learning the VI Editor", Fifth Ed., May 1992, page 106), * it notes that System V release 3.2 and later has an option "[no]exrc". * The behavior is that local .exrc files are read only if the exrc option * is set. The default for the exrc option was off, so, by default, local * .exrc files were not read. The problem this was intended to solve was * that System V permitted users to give away files, so there's no possible * ownership/writeability test that the file is safe. * * POSIX 1003.2-1992 standardized exrc as an option. It required the exrc * option to be off by default, thus local .exrc files are not to be read * by default. The Rationale noted (incorrectly) that this was a change * to historic practice, but correctly noted that a default of off improves * system security. POSIX also required that vi check the effective user * ID instead of the real user ID, which is why we've switched from historic * practice. * * We initialize the exrc variable to off. If it's turned on by the system * or $HOME .exrc files, and the local .exrc file passes the ownership and * writeability tests, then we read it. This breaks historic 4BSD practice, * but it gives us a measure of security on systems where users can give away * files. */static enum rcexrc_isok(sp, sbp, path, rootok) SCR *sp; struct stat *sbp; char *path; int rootok;{ uid_t uid; char *emsg, buf[MAXPATHLEN]; /* Check for the file's existence. */ if (stat(path, sbp)) return (NOEXIST); /* Owned by the user or root. */ uid = geteuid(); if (rootok) { if (sbp->st_uid != uid && sbp->st_uid != 0) { emsg = "not owned by you or root"; goto denied; } } else if (sbp->st_uid != uid) { emsg = "not owned by you"; goto denied; } /* Not writeable by anyone but the owner. */ if (sbp->st_mode & (S_IWGRP | S_IWOTH)) { emsg = "writeable by a user other than the owner";denied: if (strchr(path, '/') == NULL && getcwd(buf, sizeof(buf)) != NULL) msgq(sp, M_ERR, "%s/%s: not sourced: %s.", buf, path, emsg); else msgq(sp, M_ERR, "%s: not sourced: %s.", path, emsg); return (NOPERM); } return (OK);}static voidobsolete(argv) char *argv[];{ size_t len; char *p; /* * Translate old style arguments into something getopt will like. * Make sure it's not text space memory, because ex changes the * strings. * Change "+" into "-c$". * Change "+<anything else>" into "-c<anything else>". * Change "-" into "-s" * Change "-r" into "-l" */ while (*++argv) if (argv[0][0] == '+') { if (argv[0][1] == '\0') { MALLOC_NOMSG(NULL, argv[0], char *, 4); if (argv[0] == NULL) err(1, NULL); (void)strcpy(argv[0], "-c$"); } else { p = argv[0]; len = strlen(argv[0]); MALLOC_NOMSG(NULL, argv[0], char *, len + 2); if (argv[0] == NULL) err(1, NULL); argv[0][0] = '-'; argv[0][1] = 'c'; (void)strcpy(argv[0] + 2, p + 1); } } else if (argv[0][0] == '-') { if (argv[0][1] == 'r') { if (argv[0][2] == '\0' && argv[1] == NULL) argv[0][1] = 'l'; } else if (argv[0][1] == '\0') { MALLOC_NOMSG(NULL, argv[0], char *, 3); if (argv[0] == NULL) err(1, NULL); (void)strcpy(argv[0], "-s"); } }}static voidusage(is_ex) int is_ex;{#define EX_USAGE \ "usage: ex [-eFlRsv] [-c command] [-r file] [-t tag] [-w size] [-x aw]"#define VI_USAGE \ "usage: vi [-eFlRv] [-c command] [-r file] [-t tag] [-w size] [-x aw]" (void)fprintf(stderr, "%s\n", is_ex ? EX_USAGE : VI_USAGE); exit(1);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -