]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/nvi/ex/ex_read.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / nvi / ex / ex_read.c
1 /*-
2  * Copyright (c) 1992, 1993, 1994
3  *      The Regents of the University of California.  All rights reserved.
4  * Copyright (c) 1992, 1993, 1994, 1995, 1996
5  *      Keith Bostic.  All rights reserved.
6  *
7  * See the LICENSE file for redistribution information.
8  */
9
10 #include "config.h"
11
12 #ifndef lint
13 static const char sccsid[] = "$Id: ex_read.c,v 10.44 2001/06/25 15:19:19 skimo Exp $";
14 #endif /* not lint */
15
16 #include <sys/types.h>
17 #include <sys/queue.h>
18 #include <sys/stat.h>
19
20 #include <bitstring.h>
21 #include <ctype.h>
22 #include <errno.h>
23 #include <limits.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "../common/common.h"
29 #include "../vi/vi.h"
30
31 /*
32  * ex_read --   :read [file]
33  *              :read [!cmd]
34  *      Read from a file or utility.
35  *
36  * !!!
37  * Historical vi wouldn't undo a filter read, for no apparent reason.
38  *
39  * PUBLIC: int ex_read __P((SCR *, EXCMD *));
40  */
41 int
42 ex_read(SCR *sp, EXCMD *cmdp)
43 {
44         enum { R_ARG, R_EXPANDARG, R_FILTER } which;
45         struct stat sb;
46         CHAR_T *arg = NULL;
47         char *name = NULL;
48         size_t nlen;
49         EX_PRIVATE *exp;
50         FILE *fp;
51         FREF *frp;
52         GS *gp;
53         MARK rm;
54         recno_t nlines;
55         size_t arglen = 0;
56         int argc, rval;
57         char *p;
58
59         gp = sp->gp;
60
61         /*
62          * 0 args: read the current pathname.
63          * 1 args: check for "read !arg".
64          */
65         switch (cmdp->argc) {
66         case 0:
67                 which = R_ARG;
68                 break;
69         case 1:
70                 arg = cmdp->argv[0]->bp;
71                 arglen = cmdp->argv[0]->len;
72                 if (*arg == '!') {
73                         ++arg;
74                         --arglen;
75                         which = R_FILTER;
76
77                         /* Secure means no shell access. */
78                         if (O_ISSET(sp, O_SECURE)) {
79                                 ex_wemsg(sp, cmdp->cmd->name, EXM_SECURE_F);
80                                 return (1);
81                         }
82                 } else
83                         which = R_EXPANDARG;
84                 break;
85         default:
86                 abort();
87                 /* NOTREACHED */
88         }
89
90         /* Load a temporary file if no file being edited. */
91         if (sp->ep == NULL) {
92                 if ((frp = file_add(sp, NULL)) == NULL)
93                         return (1);
94                 if (file_init(sp, frp, NULL, 0))
95                         return (1);
96         }
97
98         switch (which) {
99         case R_FILTER:
100                 /*
101                  * File name and bang expand the user's argument.  If
102                  * we don't get an additional argument, it's illegal.
103                  */
104                 argc = cmdp->argc;
105                 if (argv_exp1(sp, cmdp, arg, arglen, 1))
106                         return (1);
107                 if (argc == cmdp->argc) {
108                         ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
109                         return (1);
110                 }
111                 argc = cmdp->argc - 1;
112
113                 /* Set the last bang command. */
114                 exp = EXP(sp);
115                 if (exp->lastbcomm != NULL)
116                         free(exp->lastbcomm);
117                 if ((exp->lastbcomm =
118                     v_wstrdup(sp, cmdp->argv[argc]->bp,
119                                 cmdp->argv[argc]->len)) == NULL) {
120                         msgq(sp, M_SYSERR, NULL);
121                         return (1);
122                 }
123
124                 /*
125                  * Vi redisplayed the user's argument if it changed, ex
126                  * always displayed a !, plus the user's argument if it
127                  * changed.
128                  */
129                 if (F_ISSET(sp, SC_VI)) {
130                         if (F_ISSET(cmdp, E_MODIFY))
131                                 (void)vs_update(sp, "!", cmdp->argv[argc]->bp);
132                 } else {
133                         if (F_ISSET(cmdp, E_MODIFY))
134                                 (void)ex_printf(sp,
135                                     "!"WS"\n", cmdp->argv[argc]->bp);
136                         else
137                                 (void)ex_puts(sp, "!\n");
138                         (void)ex_fflush(sp);
139                 }
140
141                 /*
142                  * Historically, filter reads as the first ex command didn't
143                  * wait for the user. If SC_SCR_EXWROTE not already set, set
144                  * the don't-wait flag.
145                  */
146                 if (!F_ISSET(sp, SC_SCR_EXWROTE))
147                         F_SET(sp, SC_EX_WAIT_NO);
148
149                 /*
150                  * Switch into ex canonical mode.  The reason to restore the
151                  * original terminal modes for read filters is so that users
152                  * can do things like ":r! cat /dev/tty".
153                  *
154                  * !!!
155                  * We do not output an extra <newline>, so that we don't touch
156                  * the screen on a normal read.
157                  */
158                 if (F_ISSET(sp, SC_VI)) {
159                         if (gp->scr_screen(sp, SC_EX)) {
160                                 ex_wemsg(sp, cmdp->cmd->name, EXM_NOCANON_F);
161                                 return (1);
162                         }
163                         /*
164                          * !!!
165                          * Historically, the read command doesn't switch to
166                          * the alternate X11 xterm screen, if doing a filter
167                          * read -- don't set SA_ALTERNATE.
168                          */
169                         F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE);
170                 }
171
172                 if (ex_filter(sp, cmdp, &cmdp->addr1,
173                     NULL, &rm, cmdp->argv[argc]->bp, FILTER_READ))
174                         return (1);
175
176                 /* The filter version of read set the autoprint flag. */
177                 F_SET(cmdp, E_AUTOPRINT);
178
179                 /*
180                  * If in vi mode, move to the first nonblank.  Might have
181                  * switched into ex mode, so saved the original SC_VI value.
182                  */
183                 sp->lno = rm.lno;
184                 if (F_ISSET(sp, SC_VI)) {
185                         sp->cno = 0;
186                         (void)nonblank(sp, sp->lno, &sp->cno);
187                 }
188                 return (0);
189         case R_ARG:
190                 name = sp->frp->name;
191                 break;
192         case R_EXPANDARG:
193                 if (argv_exp2(sp, cmdp, arg, arglen))
194                         return (1);
195                 /*
196                  *  0 args: impossible.
197                  *  1 args: impossible (I hope).
198                  *  2 args: read it.
199                  * >2 args: object, too many args.
200                  *
201                  * The 1 args case depends on the argv_sexp() function refusing
202                  * to return success without at least one non-blank character.
203                  */
204                 switch (cmdp->argc) {
205                 case 0:
206                 case 1:
207                         abort();
208                         /* NOTREACHED */
209                 case 2:
210                         INT2CHAR(sp, cmdp->argv[1]->bp, cmdp->argv[1]->len + 1, 
211                                  name, nlen);
212                         /*
213                          * !!!
214                          * Historically, the read and write commands renamed
215                          * "unnamed" files, or, if the file had a name, set
216                          * the alternate file name.
217                          */
218                         if (F_ISSET(sp->frp, FR_TMPFILE) &&
219                             !F_ISSET(sp->frp, FR_EXNAMED)) {
220                                 if ((p = strdup(name)) != NULL) {
221                                         free(sp->frp->name);
222                                         sp->frp->name = p;
223                                 }
224                                 /*
225                                  * The file has a real name, it's no longer a
226                                  * temporary, clear the temporary file flags.
227                                  */
228                                 F_CLR(sp->frp, FR_TMPEXIT | FR_TMPFILE);
229                                 F_SET(sp->frp, FR_NAMECHANGE | FR_EXNAMED);
230
231                                 /* Notify the screen. */
232                                 (void)sp->gp->scr_rename(sp, sp->frp->name, 1);
233                                 name = sp->frp->name;
234                         } else {
235                                 set_alt_name(sp, name);
236                                 name = sp->alt_name;
237                         }
238                         break;
239                 default:
240                         ex_wemsg(sp, cmdp->argv[0]->bp, EXM_FILECOUNT);
241                         return (1);
242                 
243                 }
244                 break;
245         }
246
247         /*
248          * !!!
249          * Historically, vi did not permit reads from non-regular files, nor
250          * did it distinguish between "read !" and "read!", so there was no
251          * way to "force" it.  We permit reading from named pipes too, since
252          * they didn't exist when the original implementation of vi was done
253          * and they seem a reasonable addition.
254          */
255         if ((fp = fopen(name, "r")) == NULL || fstat(fileno(fp), &sb)) {
256                 msgq_str(sp, M_SYSERR, name, "%s");
257                 return (1);
258         }
259         if (!S_ISFIFO(sb.st_mode) && !S_ISREG(sb.st_mode)) {
260                 (void)fclose(fp);
261                 msgq(sp, M_ERR,
262                     "145|Only regular files and named pipes may be read");
263                 return (1);
264         }
265
266         /* Try and get a lock. */
267         if (file_lock(sp, NULL, fileno(fp), 0) == LOCK_UNAVAIL)
268                 msgq(sp, M_ERR, "146|%s: read lock was unavailable", name);
269
270         rval = ex_readfp(sp, name, fp, &cmdp->addr1, &nlines, 0);
271
272         /*
273          * In vi, set the cursor to the first line read in, if anything read
274          * in, otherwise, the address.  (Historic vi set it to the line after
275          * the address regardless, but since that line may not exist we don't
276          * bother.)
277          *
278          * In ex, set the cursor to the last line read in, if anything read in,
279          * otherwise, the address.
280          */
281         if (F_ISSET(sp, SC_VI)) {
282                 sp->lno = cmdp->addr1.lno;
283                 if (nlines)
284                         ++sp->lno;
285         } else
286                 sp->lno = cmdp->addr1.lno + nlines;
287         return (rval);
288 }
289
290 /*
291  * ex_readfp --
292  *      Read lines into the file.
293  *
294  * PUBLIC: int ex_readfp __P((SCR *, char *, FILE *, MARK *, recno_t *, int));
295  */
296 int
297 ex_readfp(SCR *sp, char *name, FILE *fp, MARK *fm, recno_t *nlinesp, int silent)
298 {
299         EX_PRIVATE *exp;
300         GS *gp;
301         recno_t lcnt, lno;
302         size_t len;
303         u_long ccnt;                    /* XXX: can't print off_t portably. */
304         int nf, rval;
305         char *p;
306         size_t wlen;
307         CHAR_T *wp;
308
309         gp = sp->gp;
310         exp = EXP(sp);
311
312         /*
313          * Add in the lines from the output.  Insertion starts at the line
314          * following the address.
315          */
316         ccnt = 0;
317         lcnt = 0;
318         p = "147|Reading...";
319         for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno, ++lcnt) {
320                 if ((lcnt + 1) % INTERRUPT_CHECK == 0) {
321                         if (INTERRUPTED(sp))
322                                 break;
323                         if (!silent) {
324                                 gp->scr_busy(sp, p,
325                                     p == NULL ? BUSY_UPDATE : BUSY_ON);
326                                 p = NULL;
327                         }
328                 }
329                 FILE2INT5(sp, exp->ibcw, exp->ibp, len, wp, wlen);
330                 if (db_append(sp, 1, lno, wp, wlen))
331                         goto err;
332                 ccnt += len;
333         }
334
335         if (ferror(fp) || fclose(fp))
336                 goto err;
337
338         /* Return the number of lines read in. */
339         if (nlinesp != NULL)
340                 *nlinesp = lcnt;
341
342         if (!silent) {
343                 p = msg_print(sp, name, &nf);
344                 msgq(sp, M_INFO,
345                     "148|%s: %lu lines, %lu characters", p,
346                     (u_long)lcnt, ccnt);
347                 if (nf)
348                         FREE_SPACE(sp, p, 0);
349         }
350
351         rval = 0;
352         if (0) {
353 err:            msgq_str(sp, M_SYSERR, name, "%s");
354                 (void)fclose(fp);
355                 rval = 1;
356         }
357
358         if (!silent)
359                 gp->scr_busy(sp, NULL, BUSY_OFF);
360         return (rval);
361 }