update to 1.01
[nvi.git] / ex / ex_read.c
blob7a4f43f43329d7df5cb3c1aeeea8ca4cfffc9842
1 /*-
2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
5 * %sccs.include.redist.c%
6 */
8 #ifndef lint
9 static char sccsid[] = "$Id: ex_read.c,v 8.20 1993/12/29 09:50:53 bostic Exp $ (Berkeley) $Date: 1993/12/29 09:50:53 $";
10 #endif /* not lint */
12 #include <sys/types.h>
13 #include <sys/stat.h>
15 #include <ctype.h>
16 #include <errno.h>
17 #include <stdlib.h>
18 #include <string.h>
20 #include "vi.h"
21 #include "excmd.h"
24 * ex_read -- :read [file]
25 * :read [! cmd]
26 * Read from a file or utility.
28 int
29 ex_read(sp, ep, cmdp)
30 SCR *sp;
31 EXF *ep;
32 EXCMDARG *cmdp;
34 struct stat sb;
35 FILE *fp;
36 MARK rm;
37 recno_t nlines;
38 size_t blen, len;
39 int rval;
40 char *bp, *name;
43 * If "read !", it's a pipe from a utility.
45 * !!!
46 * Historical vi wouldn't undo a filter read, for no apparent
47 * reason.
49 if (F_ISSET(cmdp, E_FORCE)) {
50 /* Expand the user's argument. */
51 if (argv_exp1(sp, ep,
52 cmdp, cmdp->argv[0]->bp, cmdp->argv[0]->len, 0))
53 return (1);
55 /* If argc still 1, there wasn't anything to expand. */
56 if (cmdp->argc == 1) {
57 msgq(sp, M_ERR, "Usage: %s.", cmdp->cmd->usage);
58 return (1);
61 /* Redisplay the user's argument if it's changed. */
62 if (F_ISSET(cmdp, E_MODIFY) && IN_VI_MODE(sp)) {
63 len = cmdp->argv[1]->len;
64 GET_SPACE_RET(sp, bp, blen, len + 2);
65 bp[0] = '!';
66 memmove(bp + 1, cmdp->argv[1], cmdp->argv[1]->len + 1);
67 (void)sp->s_busy(sp, bp);
68 FREE_SPACE(sp, bp, blen);
71 if (filtercmd(sp, ep,
72 &cmdp->addr1, NULL, &rm, cmdp->argv[1]->bp, FILTER_READ))
73 return (1);
74 sp->lno = rm.lno;
75 return (0);
78 /* Expand the user's argument. */
79 if (argv_exp2(sp, ep,
80 cmdp, cmdp->argv[0]->bp, cmdp->argv[0]->len, 0))
81 return (1);
83 switch (cmdp->argc) {
84 case 1:
85 /* Nothing to expand, read the current file. */
86 name = FILENAME(sp->frp);
87 if (sp->alt_name == NULL)
88 set_alt_name(sp, name);
89 break;
90 case 2:
91 /* One new argument, read it. */
92 name = cmdp->argv[1]->bp;
93 break;
94 default:
95 /* If expanded to more than one argument, object. */
96 msgq(sp, M_ERR, "%s expanded into too many file names",
97 cmdp->argv[0]->bp);
98 msgq(sp, M_ERR, "Usage: %s.", cmdp->cmd->usage);
99 return (1);
103 * !!!
104 * Historically, vi did not permit reads from non-regular files,
105 * nor did it distinguish between "read !" and "read!", so there
106 * was no way to "force" it.
108 if ((fp = fopen(name, "r")) == NULL || fstat(fileno(fp), &sb)) {
109 msgq(sp, M_SYSERR, name);
110 return (1);
112 if (!S_ISREG(sb.st_mode)) {
113 (void)fclose(fp);
114 msgq(sp, M_ERR, "Only regular files may be read.");
115 return (1);
118 rval = ex_readfp(sp, ep, name, fp, &cmdp->addr1, &nlines, 1);
121 * Set the cursor to the first line read in, if anything read
122 * in, otherwise, the address. (Historic vi set it to the
123 * line after the address regardless, but since that line may
124 * not exist we don't bother.)
126 sp->lno = cmdp->addr1.lno;
127 if (nlines)
128 ++sp->lno;
130 F_SET(EXP(sp), EX_AUTOPRINT);
131 return (rval);
135 * ex_readfp --
136 * Read lines into the file.
139 ex_readfp(sp, ep, name, fp, fm, nlinesp, success_msg)
140 SCR *sp;
141 EXF *ep;
142 char *name;
143 FILE *fp;
144 MARK *fm;
145 recno_t *nlinesp;
146 int success_msg;
148 EX_PRIVATE *exp;
149 u_long ccnt;
150 size_t len;
151 recno_t lno, nlines;
152 int rval;
155 * Add in the lines from the output. Insertion starts at the line
156 * following the address.
158 ccnt = 0;
159 rval = 0;
160 exp = EXP(sp);
161 for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno) {
162 if (file_aline(sp, ep, 1, lno, exp->ibp, len)) {
163 rval = 1;
164 break;
166 ccnt += len;
169 if (ferror(fp)) {
170 msgq(sp, M_SYSERR, name);
171 rval = 1;
174 if (fclose(fp)) {
175 msgq(sp, M_SYSERR, name);
176 return (1);
179 if (rval)
180 return (1);
182 /* Return the number of lines read in. */
183 nlines = lno - fm->lno;
184 if (nlinesp != NULL)
185 *nlinesp = nlines;
187 if (success_msg)
188 msgq(sp, M_INFO, "%s: %lu line%s, %lu characters.",
189 name, nlines, nlines == 1 ? "" : "s", ccnt);
191 return (0);