rework ARGS structures as part of ex parser rework
[nvi.git] / ex / ex_read.c
blobe6e996425d02b38740b0059bba4a544683ef30a6
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.14 1993/11/28 12:37:18 bostic Exp $ (Berkeley) $Date: 1993/11/28 12:37:18 $";
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 if (cmdp->argv[0][0] == '\0') {
51 msgq(sp, M_ERR, "Usage: %s.", cmdp->cmd->usage);
52 return (1);
54 if (argv_exp1(sp, ep, cmdp, cmdp->argv[0], 0))
55 return (1);
56 if (F_ISSET(cmdp, E_MODIFY) && IN_VI_MODE(sp)) {
57 len = strlen(cmdp->argv[0]);
58 GET_SPACE(sp, bp, blen, len + 2);
59 bp[0] = '!';
60 memmove(bp + 1, cmdp->argv[0], len + 1);
61 (void)sp->s_busy(sp, bp);
62 FREE_SPACE(sp, bp, blen);
64 if (filtercmd(sp, ep,
65 &cmdp->addr1, NULL, &rm, cmdp->argv[0], FILTER_READ))
66 return (1);
67 sp->lno = rm.lno;
68 return (0);
71 /* If no file arguments, read the alternate file. */
72 if (cmdp->argv[0][0] == '\0') {
73 if (sp->alt_name == NULL) {
74 msgq(sp, M_ERR,
75 "No default filename from which to read.");
76 return (1);
78 name = sp->alt_name;
79 } else {
80 if (argv_exp2(sp, ep, cmdp, cmdp->argv[0], 0))
81 return (1);
83 switch (cmdp->argc) {
84 case 0:
85 name = FILENAME(sp->frp);
86 break;
87 case 1:
88 name = (char *)cmdp->argv[0];
89 set_alt_name(sp, name);
90 break;
91 default:
92 msgq(sp, M_ERR, "Usage: %s.", cmdp->cmd->usage);
93 return (1);
98 * !!!
99 * Historically, vi did not permit reads from non-regular files,
100 * nor did it distinguish between "read !" and "read!", so there
101 * was no way to "force" it.
103 if ((fp = fopen(name, "r")) == NULL || fstat(fileno(fp), &sb)) {
104 msgq(sp, M_SYSERR, name);
105 return (1);
107 if (!S_ISREG(sb.st_mode)) {
108 (void)fclose(fp);
109 msgq(sp, M_ERR, "Only regular files may be read.");
110 return (1);
113 rval = ex_readfp(sp, ep, name, fp, &cmdp->addr1, &nlines, 1);
116 * Set the cursor to the first line read in, if anything read
117 * in, otherwise, the address. (Historic vi set it to the
118 * line after the address regardless, but since that line may
119 * not exist we don't bother.)
121 sp->lno = cmdp->addr1.lno;
122 if (nlines)
123 ++sp->lno;
125 /* Set autoprint. */
126 F_SET(sp, S_AUTOPRINT);
128 return (rval);
132 * ex_readfp --
133 * Read lines into the file.
136 ex_readfp(sp, ep, name, fp, fm, nlinesp, success_msg)
137 SCR *sp;
138 EXF *ep;
139 char *name;
140 FILE *fp;
141 MARK *fm;
142 recno_t *nlinesp;
143 int success_msg;
145 EX_PRIVATE *exp;
146 u_long ccnt;
147 size_t len;
148 recno_t lno, nlines;
149 int rval;
152 * Add in the lines from the output. Insertion starts at the line
153 * following the address.
155 ccnt = 0;
156 rval = 0;
157 exp = EXP(sp);
158 for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno) {
159 if (file_aline(sp, ep, 1, lno, exp->ibp, len)) {
160 rval = 1;
161 break;
163 ccnt += len;
166 if (ferror(fp)) {
167 msgq(sp, M_SYSERR, name);
168 rval = 1;
171 if (fclose(fp)) {
172 msgq(sp, M_SYSERR, name);
173 return (1);
176 if (rval)
177 return (1);
179 /* Return the number of lines read in. */
180 nlines = lno - fm->lno;
181 if (nlinesp != NULL)
182 *nlinesp = nlines;
184 if (success_msg)
185 msgq(sp, M_INFO, "%s: %lu line%s, %lu characters.",
186 name, nlines, nlines == 1 ? "" : "s", ccnt);
188 return (0);