/* * v_quit -- * Quit command. */ static int v_quit(SCR *sp, VICMD *vp) { EXCMD cmd; ex_cinit(sp, &cmd, C_QUIT, 0, OOBLNO, OOBLNO, 0); return (v_exec_ex(sp, vp, &cmd)); }
/* * v_edit -- * Edit command. */ static int v_edit(SCR *sp, VICMD *vp) { EXCMD cmd; ex_cinit(sp, &cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0); argv_exp0(sp, &cmd, vp->ev.e_csp, vp->ev.e_len); return (v_exec_ex(sp, vp, &cmd)); }
/* * api_edit * Create a new screen and return its id * or edit a new file in the current screen. * * PUBLIC: int api_edit __P((SCR *, char *, SCR **, int)); */ int api_edit(SCR *sp, char *file, SCR **spp, int newscreen) { EXCMD cmd; size_t wlen; const CHAR_T *wp; if (file) { ex_cinit(sp, &cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0); CHAR2INT(sp, file, strlen(file) + 1, wp, wlen); argv_exp0(sp, &cmd, wp, wlen - 1 /* terminating 0 */); } else ex_cinit(sp, &cmd, C_EDIT, 0, OOBLNO, OOBLNO, 0); if (newscreen) cmd.flags |= E_NEWSCREEN; /* XXX */ if (cmd.cmd->fn(sp, &cmd)) return (1); *spp = sp->nextdisp; return (0); }
/* * ex_run_file -- * Set up a file of ex commands to run. */ static int ex_run_file(SCR *sp, char *name) { EXCMD cmd; CHAR_T *wp; size_t wlen; ex_cinit(sp, &cmd, C_SOURCE, 0, OOBLNO, OOBLNO, 0); CHAR2INT(sp, name, strlen(name)+1, wp, wlen); argv_exp0(sp, &cmd, wp, wlen - 1); return (ex_source(sp, &cmd)); }
/* * v_write -- * Write command. */ static int v_write(SCR *sp, VICMD *vp) { EXCMD cmd; ex_cinit(sp, &cmd, C_WRITE, 0, OOBLNO, OOBLNO, 0); cmd.addr1.lno = 1; if (db_last(sp, &cmd.addr2.lno)) return (1); return (v_exec_ex(sp, vp, &cmd)); }
/* * v_tag -- * Tag command. */ static int v_tag(SCR *sp, VICMD *vp) { EXCMD cmd; if (v_curword(sp)) return (1); ex_cinit(sp, &cmd, C_TAG, 0, OOBLNO, OOBLNO, 0); argv_exp0(sp, &cmd, VIP(sp)->keyw, STRLEN(VIP(sp)->keyw)); return (v_exec_ex(sp, vp, &cmd)); }
/* * api_escreen * End a screen. * * PUBLIC: int api_escreen __P((SCR *)); */ int api_escreen(SCR *sp) { EXCMD cmd; /* * XXX * If the interpreter exits anything other than the current * screen, vi isn't going to update everything correctly. */ ex_cinit(sp, &cmd, C_QUIT, 0, OOBLNO, OOBLNO, 0); return (cmd.cmd->fn(sp, &cmd)); }
/* * ex_tag_first -- * The tag code can be entered from main, e.g., "vi -t tag". * * PUBLIC: int ex_tag_first __P((SCR *, CHAR_T *)); */ int ex_tag_first(SCR *sp, const CHAR_T *tagarg) { EXCMD cmd; /* Build an argument for the ex :tag command. */ ex_cinit(sp, &cmd, C_TAG, 0, OOBLNO, OOBLNO, 0); argv_exp0(sp, &cmd, tagarg, STRLEN(tagarg)); /* * XXX * Historic vi went ahead and created a temporary file when it failed * to find the tag. We match historic practice, but don't distinguish * between real error and failure to find the tag. */ if (ex_tag_push(sp, &cmd)) return (0); /* Display tags in the center of the screen. */ F_CLR(sp, SC_SCR_TOP); F_SET(sp, SC_SCR_CENTER); return (0); }
/* * file_backup -- * Backup the about-to-be-written file. * * XXX * We do the backup by copying the entire file. It would be nice to do * a rename instead, but: (1) both files may not fit and we want to fail * before doing the rename; (2) the backup file may not be on the same * disk partition as the file being written; (3) there may be optional * file information (MACs, DACs, whatever) that we won't get right if we * recreate the file. So, let's not risk it. */ static int file_backup(SCR *sp, char *name, char *bname) { struct dirent *dp; struct stat sb; DIR *dirp; EXCMD cmd; off_t off; size_t blen; int flags, maxnum, nr, num, nw, rfd, wfd, version; char *bp, *estr, *p, *pct, *slash, *t, *wfname, buf[8192]; CHAR_T *wp; size_t wlen; size_t nlen; char *d = NULL; rfd = wfd = -1; bp = estr = wfname = NULL; /* * Open the current file for reading. Do this first, so that * we don't exec a shell before the most likely failure point. * If it doesn't exist, it's okay, there's just nothing to back * up. */ errno = 0; if ((rfd = open(name, O_RDONLY, 0)) < 0) { if (errno == ENOENT) return (0); estr = name; goto err; } /* * If the name starts with an 'N' character, add a version number * to the name. Strip the leading N from the string passed to the * expansion routines, for no particular reason. It would be nice * to permit users to put the version number anywhere in the backup * name, but there isn't a special character that we can use in the * name, and giving a new character a special meaning leads to ugly * hacks both here and in the supporting ex routines. * * Shell and file name expand the option's value. */ ex_cinit(sp, &cmd, 0, 0, 0, 0, 0); if (bname[0] == 'N') { version = 1; ++bname; } else version = 0; CHAR2INT(sp, bname, strlen(bname) + 1, wp, wlen); if (argv_exp2(sp, &cmd, wp, wlen - 1)) return (1); /* * 0 args: impossible. * 1 args: use it. * >1 args: object, too many args. */ if (cmd.argc != 1) { msgq_str(sp, M_ERR, bname, "258|%s expanded into too many file names"); (void)close(rfd); return (1); } /* * If appending a version number, read through the directory, looking * for file names that match the name followed by a number. Make all * of the other % characters in name literal, so the user doesn't get * surprised and sscanf doesn't drop core indirecting through pointers * that don't exist. If any such files are found, increment its number * by one. */ if (version) { GET_SPACE_GOTOC(sp, bp, blen, cmd.argv[0]->len * 2 + 50); INT2SYS(sp, cmd.argv[0]->bp, cmd.argv[0]->len + 1, p, nlen); d = strdup(p); p = d; for (t = bp, slash = NULL; p[0] != '\0'; *t++ = *p++) if (p[0] == '%') { if (p[1] != '%') *t++ = '%'; } else if (p[0] == '/') slash = t; pct = t; *t++ = '%'; *t++ = 'd'; *t = '\0'; if (slash == NULL) { dirp = opendir("."); p = bp; } else { *slash = '\0'; dirp = opendir(bp); *slash = '/'; p = slash + 1; } if (dirp == NULL) { INT2SYS(sp, cmd.argv[0]->bp, cmd.argv[0]->len + 1, estr, nlen); goto err; } for (maxnum = 0; (dp = readdir(dirp)) != NULL;) if (sscanf(dp->d_name, p, &num) == 1 && num > maxnum) maxnum = num; (void)closedir(dirp); /* Format the backup file name. */ (void)snprintf(pct, blen - (pct - bp), "%d", maxnum + 1); wfname = bp; } else { bp = NULL; INT2SYS(sp, cmd.argv[0]->bp, cmd.argv[0]->len + 1, wfname, nlen); } /* Open the backup file, avoiding lurkers. */ if (stat(wfname, &sb) == 0) { if (!S_ISREG(sb.st_mode)) { msgq_str(sp, M_ERR, bname, "259|%s: not a regular file"); goto err; } if (sb.st_uid != getuid()) { msgq_str(sp, M_ERR, bname, "260|%s: not owned by you"); goto err; } if (sb.st_mode & (S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) { msgq_str(sp, M_ERR, bname, "261|%s: accessible by a user other than the owner"); goto err; } flags = O_TRUNC; } else flags = O_CREAT | O_EXCL; if ((wfd = open(wfname, flags | O_WRONLY, S_IRUSR | S_IWUSR)) < 0) { estr = bname; goto err; } /* Copy the file's current contents to its backup value. */ while ((nr = read(rfd, buf, sizeof(buf))) > 0) for (off = 0; nr != 0; nr -= nw, off += nw) if ((nw = write(wfd, buf + off, nr)) < 0) { estr = wfname; goto err; } if (nr < 0) { estr = name; goto err; } if (close(rfd)) { estr = name; goto err; } if (close(wfd)) { estr = wfname; goto err; } if (bp != NULL) FREE_SPACE(sp, bp, blen); return (0); alloc_err: err: if (rfd != -1) (void)close(rfd); if (wfd != -1) { (void)unlink(wfname); (void)close(wfd); } if (estr) msgq_str(sp, M_SYSERR, estr, "%s"); if (d != NULL) free(d); if (bp != NULL) FREE_SPACE(sp, bp, blen); return (1); }