wordsmithing
[nvi.git] / ex / ex_read.c
blobbbaef641100b52898acb82627092e12950625ebf
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.18 1993/12/19 12:59:19 bostic Exp $ (Berkeley) $Date: 1993/12/19 12:59:19 $";
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 /* Set autoprint. */
131 F_SET(sp, S_AUTOPRINT);
133 return (rval);
137 * ex_readfp --
138 * Read lines into the file.
141 ex_readfp(sp, ep, name, fp, fm, nlinesp, success_msg)
142 SCR *sp;
143 EXF *ep;
144 char *name;
145 FILE *fp;
146 MARK *fm;
147 recno_t *nlinesp;
148 int success_msg;
150 EX_PRIVATE *exp;
151 u_long ccnt;
152 size_t len;
153 recno_t lno, nlines;
154 int rval;
157 * Add in the lines from the output. Insertion starts at the line
158 * following the address.
160 ccnt = 0;
161 rval = 0;
162 exp = EXP(sp);
163 for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno) {
164 if (file_aline(sp, ep, 1, lno, exp->ibp, len)) {
165 rval = 1;
166 break;
168 ccnt += len;
171 if (ferror(fp)) {
172 msgq(sp, M_SYSERR, name);
173 rval = 1;
176 if (fclose(fp)) {
177 msgq(sp, M_SYSERR, name);
178 return (1);
181 if (rval)
182 return (1);
184 /* Return the number of lines read in. */
185 nlines = lno - fm->lno;
186 if (nlinesp != NULL)
187 *nlinesp = nlines;
189 if (success_msg)
190 msgq(sp, M_INFO, "%s: %lu line%s, %lu characters.",
191 name, nlines, nlines == 1 ? "" : "s", ccnt);
193 return (0);