1*0a6a1f1dSLionel Sambuc /* $NetBSD: ex_read.c,v 1.3 2014/01/26 21:43:45 christos Exp $ */
284d9c625SLionel Sambuc /*-
384d9c625SLionel Sambuc * Copyright (c) 1992, 1993, 1994
484d9c625SLionel Sambuc * The Regents of the University of California. All rights reserved.
584d9c625SLionel Sambuc * Copyright (c) 1992, 1993, 1994, 1995, 1996
684d9c625SLionel Sambuc * Keith Bostic. All rights reserved.
784d9c625SLionel Sambuc *
884d9c625SLionel Sambuc * See the LICENSE file for redistribution information.
984d9c625SLionel Sambuc */
1084d9c625SLionel Sambuc
1184d9c625SLionel Sambuc #include "config.h"
1284d9c625SLionel Sambuc
13*0a6a1f1dSLionel Sambuc #include <sys/cdefs.h>
14*0a6a1f1dSLionel Sambuc #if 0
1584d9c625SLionel Sambuc #ifndef lint
1684d9c625SLionel Sambuc static const char sccsid[] = "Id: ex_read.c,v 10.44 2001/06/25 15:19:19 skimo Exp (Berkeley) Date: 2001/06/25 15:19:19 ";
1784d9c625SLionel Sambuc #endif /* not lint */
18*0a6a1f1dSLionel Sambuc #else
19*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: ex_read.c,v 1.3 2014/01/26 21:43:45 christos Exp $");
20*0a6a1f1dSLionel Sambuc #endif
2184d9c625SLionel Sambuc
2284d9c625SLionel Sambuc #include <sys/types.h>
2384d9c625SLionel Sambuc #include <sys/queue.h>
2484d9c625SLionel Sambuc #include <sys/stat.h>
2584d9c625SLionel Sambuc #include <sys/time.h>
2684d9c625SLionel Sambuc
2784d9c625SLionel Sambuc #include <bitstring.h>
2884d9c625SLionel Sambuc #include <ctype.h>
2984d9c625SLionel Sambuc #include <errno.h>
3084d9c625SLionel Sambuc #include <limits.h>
3184d9c625SLionel Sambuc #include <stdio.h>
3284d9c625SLionel Sambuc #include <stdlib.h>
3384d9c625SLionel Sambuc #include <string.h>
3484d9c625SLionel Sambuc
3584d9c625SLionel Sambuc #include "../common/common.h"
3684d9c625SLionel Sambuc #include "../vi/vi.h"
3784d9c625SLionel Sambuc
3884d9c625SLionel Sambuc /*
3984d9c625SLionel Sambuc * ex_read -- :read [file]
4084d9c625SLionel Sambuc * :read [!cmd]
4184d9c625SLionel Sambuc * Read from a file or utility.
4284d9c625SLionel Sambuc *
4384d9c625SLionel Sambuc * !!!
4484d9c625SLionel Sambuc * Historical vi wouldn't undo a filter read, for no apparent reason.
4584d9c625SLionel Sambuc *
4684d9c625SLionel Sambuc * PUBLIC: int ex_read __P((SCR *, EXCMD *));
4784d9c625SLionel Sambuc */
4884d9c625SLionel Sambuc int
ex_read(SCR * sp,EXCMD * cmdp)4984d9c625SLionel Sambuc ex_read(SCR *sp, EXCMD *cmdp)
5084d9c625SLionel Sambuc {
5184d9c625SLionel Sambuc enum { R_ARG, R_EXPANDARG, R_FILTER } which;
5284d9c625SLionel Sambuc struct stat sb;
5384d9c625SLionel Sambuc CHAR_T *arg = NULL;
5484d9c625SLionel Sambuc const char *name;
5584d9c625SLionel Sambuc size_t nlen;
5684d9c625SLionel Sambuc EX_PRIVATE *exp;
5784d9c625SLionel Sambuc FILE *fp;
5884d9c625SLionel Sambuc FREF *frp;
5984d9c625SLionel Sambuc GS *gp;
6084d9c625SLionel Sambuc MARK rm;
6184d9c625SLionel Sambuc db_recno_t nlines;
6284d9c625SLionel Sambuc size_t arglen = 0;
6384d9c625SLionel Sambuc int argc, rval;
6484d9c625SLionel Sambuc char *p;
6584d9c625SLionel Sambuc
6661df9b64SLionel Sambuc #if defined(__minix)
6761df9b64SLionel Sambuc /* Prevent complains from GCC at -O3 optimisation level. */
6861df9b64SLionel Sambuc nlines = 0;
6961df9b64SLionel Sambuc #endif /* defined(__minix) */
7084d9c625SLionel Sambuc gp = sp->gp;
7184d9c625SLionel Sambuc
7284d9c625SLionel Sambuc /*
7384d9c625SLionel Sambuc * 0 args: read the current pathname.
7484d9c625SLionel Sambuc * 1 args: check for "read !arg".
7584d9c625SLionel Sambuc */
7684d9c625SLionel Sambuc switch (cmdp->argc) {
7784d9c625SLionel Sambuc case 0:
7884d9c625SLionel Sambuc which = R_ARG;
7984d9c625SLionel Sambuc break;
8084d9c625SLionel Sambuc case 1:
8184d9c625SLionel Sambuc arg = cmdp->argv[0]->bp;
8284d9c625SLionel Sambuc arglen = cmdp->argv[0]->len;
8384d9c625SLionel Sambuc if (*arg == '!') {
8484d9c625SLionel Sambuc ++arg;
8584d9c625SLionel Sambuc --arglen;
8684d9c625SLionel Sambuc which = R_FILTER;
8784d9c625SLionel Sambuc
8884d9c625SLionel Sambuc /* Secure means no shell access. */
8984d9c625SLionel Sambuc if (O_ISSET(sp, O_SECURE)) {
9084d9c625SLionel Sambuc ex_wemsg(sp, cmdp->cmd->name, EXM_SECURE_F);
9184d9c625SLionel Sambuc return (1);
9284d9c625SLionel Sambuc }
9384d9c625SLionel Sambuc } else
9484d9c625SLionel Sambuc which = R_EXPANDARG;
9584d9c625SLionel Sambuc break;
9684d9c625SLionel Sambuc default:
9784d9c625SLionel Sambuc abort();
9884d9c625SLionel Sambuc /* NOTREACHED */
9984d9c625SLionel Sambuc }
10084d9c625SLionel Sambuc
10184d9c625SLionel Sambuc /* Load a temporary file if no file being edited. */
10284d9c625SLionel Sambuc if (sp->ep == NULL) {
10384d9c625SLionel Sambuc if ((frp = file_add(sp, NULL)) == NULL)
10484d9c625SLionel Sambuc return (1);
10584d9c625SLionel Sambuc if (file_init(sp, frp, NULL, 0))
10684d9c625SLionel Sambuc return (1);
10784d9c625SLionel Sambuc }
10884d9c625SLionel Sambuc
10984d9c625SLionel Sambuc switch (which) {
11084d9c625SLionel Sambuc case R_FILTER:
11184d9c625SLionel Sambuc /*
11284d9c625SLionel Sambuc * File name and bang expand the user's argument. If
11384d9c625SLionel Sambuc * we don't get an additional argument, it's illegal.
11484d9c625SLionel Sambuc */
11584d9c625SLionel Sambuc argc = cmdp->argc;
11684d9c625SLionel Sambuc if (argv_exp1(sp, cmdp, arg, arglen, 1))
11784d9c625SLionel Sambuc return (1);
11884d9c625SLionel Sambuc if (argc == cmdp->argc) {
11984d9c625SLionel Sambuc ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
12084d9c625SLionel Sambuc return (1);
12184d9c625SLionel Sambuc }
12284d9c625SLionel Sambuc argc = cmdp->argc - 1;
12384d9c625SLionel Sambuc
12484d9c625SLionel Sambuc /* Set the last bang command. */
12584d9c625SLionel Sambuc exp = EXP(sp);
12684d9c625SLionel Sambuc if (exp->lastbcomm != NULL)
12784d9c625SLionel Sambuc free(exp->lastbcomm);
12884d9c625SLionel Sambuc if ((exp->lastbcomm =
12984d9c625SLionel Sambuc v_wstrdup(sp, cmdp->argv[argc]->bp,
13084d9c625SLionel Sambuc cmdp->argv[argc]->len)) == NULL) {
13184d9c625SLionel Sambuc msgq(sp, M_SYSERR, NULL);
13284d9c625SLionel Sambuc return (1);
13384d9c625SLionel Sambuc }
13484d9c625SLionel Sambuc
13584d9c625SLionel Sambuc /*
13684d9c625SLionel Sambuc * Vi redisplayed the user's argument if it changed, ex
13784d9c625SLionel Sambuc * always displayed a !, plus the user's argument if it
13884d9c625SLionel Sambuc * changed.
13984d9c625SLionel Sambuc */
14084d9c625SLionel Sambuc if (F_ISSET(sp, SC_VI)) {
14184d9c625SLionel Sambuc if (F_ISSET(cmdp, E_MODIFY))
14284d9c625SLionel Sambuc (void)vs_update(sp, "!", cmdp->argv[argc]->bp);
14384d9c625SLionel Sambuc } else {
14484d9c625SLionel Sambuc if (F_ISSET(cmdp, E_MODIFY)) {
14584d9c625SLionel Sambuc INT2CHAR(sp, cmdp->argv[argc]->bp,
14684d9c625SLionel Sambuc cmdp->argv[argc]->len + 1, name, nlen);
14784d9c625SLionel Sambuc (void)ex_printf(sp,
14884d9c625SLionel Sambuc "!%s\n", name);
14984d9c625SLionel Sambuc } else
15084d9c625SLionel Sambuc (void)ex_puts(sp, "!\n");
15184d9c625SLionel Sambuc (void)ex_fflush(sp);
15284d9c625SLionel Sambuc }
15384d9c625SLionel Sambuc
15484d9c625SLionel Sambuc /*
15584d9c625SLionel Sambuc * Historically, filter reads as the first ex command didn't
15684d9c625SLionel Sambuc * wait for the user. If SC_SCR_EXWROTE not already set, set
15784d9c625SLionel Sambuc * the don't-wait flag.
15884d9c625SLionel Sambuc */
15984d9c625SLionel Sambuc if (!F_ISSET(sp, SC_SCR_EXWROTE))
16084d9c625SLionel Sambuc F_SET(sp, SC_EX_WAIT_NO);
16184d9c625SLionel Sambuc
16284d9c625SLionel Sambuc /*
16384d9c625SLionel Sambuc * Switch into ex canonical mode. The reason to restore the
16484d9c625SLionel Sambuc * original terminal modes for read filters is so that users
16584d9c625SLionel Sambuc * can do things like ":r! cat /dev/tty".
16684d9c625SLionel Sambuc *
16784d9c625SLionel Sambuc * !!!
16884d9c625SLionel Sambuc * We do not output an extra <newline>, so that we don't touch
16984d9c625SLionel Sambuc * the screen on a normal read.
17084d9c625SLionel Sambuc */
17184d9c625SLionel Sambuc if (F_ISSET(sp, SC_VI)) {
17284d9c625SLionel Sambuc if (gp->scr_screen(sp, SC_EX)) {
17384d9c625SLionel Sambuc ex_wemsg(sp, cmdp->cmd->name, EXM_NOCANON_F);
17484d9c625SLionel Sambuc return (1);
17584d9c625SLionel Sambuc }
17684d9c625SLionel Sambuc /*
17784d9c625SLionel Sambuc * !!!
17884d9c625SLionel Sambuc * Historically, the read command doesn't switch to
17984d9c625SLionel Sambuc * the alternate X11 xterm screen, if doing a filter
18084d9c625SLionel Sambuc * read -- don't set SA_ALTERNATE.
18184d9c625SLionel Sambuc */
18284d9c625SLionel Sambuc F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE);
18384d9c625SLionel Sambuc }
18484d9c625SLionel Sambuc
18584d9c625SLionel Sambuc if (ex_filter(sp, cmdp, &cmdp->addr1,
18684d9c625SLionel Sambuc NULL, &rm, cmdp->argv[argc]->bp, FILTER_READ))
18784d9c625SLionel Sambuc return (1);
18884d9c625SLionel Sambuc
18984d9c625SLionel Sambuc /* The filter version of read set the autoprint flag. */
19084d9c625SLionel Sambuc F_SET(cmdp, E_AUTOPRINT);
19184d9c625SLionel Sambuc
19284d9c625SLionel Sambuc /*
19384d9c625SLionel Sambuc * If in vi mode, move to the first nonblank. Might have
19484d9c625SLionel Sambuc * switched into ex mode, so saved the original SC_VI value.
19584d9c625SLionel Sambuc */
19684d9c625SLionel Sambuc sp->lno = rm.lno;
19784d9c625SLionel Sambuc if (F_ISSET(sp, SC_VI)) {
19884d9c625SLionel Sambuc sp->cno = 0;
19984d9c625SLionel Sambuc (void)nonblank(sp, sp->lno, &sp->cno);
20084d9c625SLionel Sambuc }
20184d9c625SLionel Sambuc return (0);
20284d9c625SLionel Sambuc case R_ARG:
20384d9c625SLionel Sambuc name = sp->frp->name;
20484d9c625SLionel Sambuc break;
20584d9c625SLionel Sambuc case R_EXPANDARG:
20684d9c625SLionel Sambuc if (argv_exp2(sp, cmdp, arg, arglen))
20784d9c625SLionel Sambuc return (1);
20884d9c625SLionel Sambuc /*
20984d9c625SLionel Sambuc * 0 args: impossible.
21084d9c625SLionel Sambuc * 1 args: impossible (I hope).
21184d9c625SLionel Sambuc * 2 args: read it.
21284d9c625SLionel Sambuc * >2 args: object, too many args.
21384d9c625SLionel Sambuc *
21484d9c625SLionel Sambuc * The 1 args case depends on the argv_sexp() function refusing
21584d9c625SLionel Sambuc * to return success without at least one non-blank character.
21684d9c625SLionel Sambuc */
21784d9c625SLionel Sambuc switch (cmdp->argc) {
21884d9c625SLionel Sambuc case 0:
21984d9c625SLionel Sambuc case 1:
22084d9c625SLionel Sambuc abort();
22184d9c625SLionel Sambuc /* NOTREACHED */
22284d9c625SLionel Sambuc case 2:
22384d9c625SLionel Sambuc INT2CHAR(sp, cmdp->argv[1]->bp, cmdp->argv[1]->len + 1,
22484d9c625SLionel Sambuc name, nlen);
22584d9c625SLionel Sambuc /*
22684d9c625SLionel Sambuc * !!!
22784d9c625SLionel Sambuc * Historically, the read and write commands renamed
22884d9c625SLionel Sambuc * "unnamed" files, or, if the file had a name, set
22984d9c625SLionel Sambuc * the alternate file name.
23084d9c625SLionel Sambuc */
23184d9c625SLionel Sambuc if (F_ISSET(sp->frp, FR_TMPFILE) &&
23284d9c625SLionel Sambuc !F_ISSET(sp->frp, FR_EXNAMED)) {
23384d9c625SLionel Sambuc if ((p = strdup(name)) != NULL) {
23484d9c625SLionel Sambuc free(sp->frp->name);
23584d9c625SLionel Sambuc sp->frp->name = p;
23684d9c625SLionel Sambuc }
23784d9c625SLionel Sambuc /*
23884d9c625SLionel Sambuc * The file has a real name, it's no longer a
23984d9c625SLionel Sambuc * temporary, clear the temporary file flags.
24084d9c625SLionel Sambuc */
24184d9c625SLionel Sambuc F_CLR(sp->frp, FR_TMPEXIT | FR_TMPFILE);
24284d9c625SLionel Sambuc F_SET(sp->frp, FR_NAMECHANGE | FR_EXNAMED);
24384d9c625SLionel Sambuc
24484d9c625SLionel Sambuc /* Notify the screen. */
24584d9c625SLionel Sambuc (void)sp->gp->scr_rename(sp, sp->frp->name, 1);
24684d9c625SLionel Sambuc name = sp->frp->name;
24784d9c625SLionel Sambuc } else {
24884d9c625SLionel Sambuc set_alt_name(sp, name);
24984d9c625SLionel Sambuc name = sp->alt_name;
25084d9c625SLionel Sambuc }
25184d9c625SLionel Sambuc break;
25284d9c625SLionel Sambuc default:
25384d9c625SLionel Sambuc ex_wemsg(sp, cmdp->argv[0]->bp, EXM_FILECOUNT);
25484d9c625SLionel Sambuc return (1);
25584d9c625SLionel Sambuc
25684d9c625SLionel Sambuc }
25784d9c625SLionel Sambuc break;
25884d9c625SLionel Sambuc }
25984d9c625SLionel Sambuc
26084d9c625SLionel Sambuc /*
26184d9c625SLionel Sambuc * !!!
26284d9c625SLionel Sambuc * Historically, vi did not permit reads from non-regular files, nor
26384d9c625SLionel Sambuc * did it distinguish between "read !" and "read!", so there was no
26484d9c625SLionel Sambuc * way to "force" it. We permit reading from named pipes too, since
26584d9c625SLionel Sambuc * they didn't exist when the original implementation of vi was done
26684d9c625SLionel Sambuc * and they seem a reasonable addition.
26784d9c625SLionel Sambuc */
26884d9c625SLionel Sambuc if ((fp = fopen(name, "r")) == NULL || fstat(fileno(fp), &sb)) {
26984d9c625SLionel Sambuc msgq_str(sp, M_SYSERR, name, "%s");
27084d9c625SLionel Sambuc return (1);
27184d9c625SLionel Sambuc }
27284d9c625SLionel Sambuc if (!S_ISFIFO(sb.st_mode) && !S_ISREG(sb.st_mode)) {
27384d9c625SLionel Sambuc (void)fclose(fp);
27484d9c625SLionel Sambuc msgq(sp, M_ERR,
27584d9c625SLionel Sambuc "145|Only regular files and named pipes may be read");
27684d9c625SLionel Sambuc return (1);
27784d9c625SLionel Sambuc }
27884d9c625SLionel Sambuc
27984d9c625SLionel Sambuc /* Try and get a lock. */
28084d9c625SLionel Sambuc if (file_lock(sp, NULL, NULL, fileno(fp), 0) == LOCK_UNAVAIL)
28184d9c625SLionel Sambuc msgq(sp, M_ERR, "146|%s: read lock was unavailable", name);
28284d9c625SLionel Sambuc
28384d9c625SLionel Sambuc rval = ex_readfp(sp, name, fp, &cmdp->addr1, &nlines, 0);
28484d9c625SLionel Sambuc
28584d9c625SLionel Sambuc /*
28684d9c625SLionel Sambuc * In vi, set the cursor to the first line read in, if anything read
28784d9c625SLionel Sambuc * in, otherwise, the address. (Historic vi set it to the line after
28884d9c625SLionel Sambuc * the address regardless, but since that line may not exist we don't
28984d9c625SLionel Sambuc * bother.)
29084d9c625SLionel Sambuc *
29184d9c625SLionel Sambuc * In ex, set the cursor to the last line read in, if anything read in,
29284d9c625SLionel Sambuc * otherwise, the address.
29384d9c625SLionel Sambuc */
29484d9c625SLionel Sambuc if (F_ISSET(sp, SC_VI)) {
29584d9c625SLionel Sambuc sp->lno = cmdp->addr1.lno;
29684d9c625SLionel Sambuc if (nlines)
29784d9c625SLionel Sambuc ++sp->lno;
29884d9c625SLionel Sambuc } else
29984d9c625SLionel Sambuc sp->lno = cmdp->addr1.lno + nlines;
30084d9c625SLionel Sambuc return (rval);
30184d9c625SLionel Sambuc }
30284d9c625SLionel Sambuc
30384d9c625SLionel Sambuc /*
30484d9c625SLionel Sambuc * ex_readfp --
30584d9c625SLionel Sambuc * Read lines into the file.
30684d9c625SLionel Sambuc *
30784d9c625SLionel Sambuc * PUBLIC: int ex_readfp __P((SCR *, const char *, FILE *, MARK *, db_recno_t *, int));
30884d9c625SLionel Sambuc */
30984d9c625SLionel Sambuc int
ex_readfp(SCR * sp,const char * name,FILE * fp,MARK * fm,db_recno_t * nlinesp,int silent)31084d9c625SLionel Sambuc ex_readfp(SCR *sp, const char *name, FILE *fp, MARK *fm, db_recno_t *nlinesp, int silent)
31184d9c625SLionel Sambuc {
31284d9c625SLionel Sambuc EX_PRIVATE *exp;
31384d9c625SLionel Sambuc GS *gp;
31484d9c625SLionel Sambuc db_recno_t lcnt, lno;
31584d9c625SLionel Sambuc size_t len;
31684d9c625SLionel Sambuc u_long ccnt; /* XXX: can't print off_t portably. */
31784d9c625SLionel Sambuc int nf, rval;
31884d9c625SLionel Sambuc const char *p;
31984d9c625SLionel Sambuc size_t wlen;
32084d9c625SLionel Sambuc const CHAR_T *wp;
32184d9c625SLionel Sambuc
32284d9c625SLionel Sambuc gp = sp->gp;
32384d9c625SLionel Sambuc exp = EXP(sp);
32484d9c625SLionel Sambuc
32584d9c625SLionel Sambuc /*
32684d9c625SLionel Sambuc * Add in the lines from the output. Insertion starts at the line
32784d9c625SLionel Sambuc * following the address.
32884d9c625SLionel Sambuc */
32984d9c625SLionel Sambuc ccnt = 0;
33084d9c625SLionel Sambuc lcnt = 0;
33184d9c625SLionel Sambuc p = "147|Reading...";
33284d9c625SLionel Sambuc for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno, ++lcnt) {
33384d9c625SLionel Sambuc if ((lcnt + 1) % INTERRUPT_CHECK == 0) {
33484d9c625SLionel Sambuc if (INTERRUPTED(sp))
33584d9c625SLionel Sambuc break;
33684d9c625SLionel Sambuc if (!silent) {
33784d9c625SLionel Sambuc gp->scr_busy(sp, p,
33884d9c625SLionel Sambuc p == NULL ? BUSY_UPDATE : BUSY_ON);
33984d9c625SLionel Sambuc p = NULL;
34084d9c625SLionel Sambuc }
34184d9c625SLionel Sambuc }
34284d9c625SLionel Sambuc FILE2INT5(sp, exp->ibcw, exp->ibp, len, wp, wlen);
34384d9c625SLionel Sambuc if (db_append(sp, 1, lno, wp, wlen))
34484d9c625SLionel Sambuc goto err;
34584d9c625SLionel Sambuc ccnt += len;
34684d9c625SLionel Sambuc }
34784d9c625SLionel Sambuc
34884d9c625SLionel Sambuc if (ferror(fp) || fclose(fp))
34984d9c625SLionel Sambuc goto err;
35084d9c625SLionel Sambuc
35184d9c625SLionel Sambuc /* Return the number of lines read in. */
35284d9c625SLionel Sambuc if (nlinesp != NULL)
35384d9c625SLionel Sambuc *nlinesp = lcnt;
35484d9c625SLionel Sambuc
35584d9c625SLionel Sambuc if (!silent) {
35684d9c625SLionel Sambuc char *q = msg_print(sp, name, &nf);
35784d9c625SLionel Sambuc msgq(sp, M_INFO,
35884d9c625SLionel Sambuc "148|%s: %lu lines, %lu characters", q, (unsigned long)lcnt,
35984d9c625SLionel Sambuc (unsigned long)ccnt);
36084d9c625SLionel Sambuc if (nf)
36184d9c625SLionel Sambuc FREE_SPACE(sp, q, 0);
36284d9c625SLionel Sambuc }
36384d9c625SLionel Sambuc
36484d9c625SLionel Sambuc rval = 0;
36584d9c625SLionel Sambuc if (0) {
36684d9c625SLionel Sambuc err: msgq_str(sp, M_SYSERR, name, "%s");
36784d9c625SLionel Sambuc (void)fclose(fp);
36884d9c625SLionel Sambuc rval = 1;
36984d9c625SLionel Sambuc }
37084d9c625SLionel Sambuc
37184d9c625SLionel Sambuc if (!silent)
37284d9c625SLionel Sambuc gp->scr_busy(sp, NULL, BUSY_OFF);
37384d9c625SLionel Sambuc return (rval);
37484d9c625SLionel Sambuc }
375