Initial import from FreeBSD RELENG_4:
[dragonfly.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[] = "@(#)ex_read.c     10.38 (Berkeley) 8/12/96";
14 #endif /* not lint */
15
16 #include <sys/types.h>
17 #include <sys/queue.h>
18 #include <sys/stat.h>
19 #include <sys/time.h>
20
21 #include <bitstring.h>
22 #include <ctype.h>
23 #include <errno.h>
24 #include <limits.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "../common/common.h"
30 #include "../vi/vi.h"
31
32 /*
33  * ex_read --   :read [file]
34  *              :read [!cmd]
35  *      Read from a file or utility.
36  *
37  * !!!
38  * Historical vi wouldn't undo a filter read, for no apparent reason.
39  *
40  * PUBLIC: int ex_read __P((SCR *, EXCMD *));
41  */
42 int
43 ex_read(sp, cmdp)
44         SCR *sp;
45         EXCMD *cmdp;
46 {
47         enum { R_ARG, R_EXPANDARG, R_FILTER } which;
48         struct stat sb;
49         CHAR_T *arg, *name;
50         EX_PRIVATE *exp;
51         FILE *fp;
52         FREF *frp;
53         GS *gp;
54         MARK rm;
55         recno_t nlines;
56         size_t arglen;
57         int argc, rval;
58         char *p;
59
60         gp = sp->gp;
61
62         /*
63          * 0 args: read the current pathname.
64          * 1 args: check for "read !arg".
65          */
66         switch (cmdp->argc) {
67         case 0:
68                 which = R_ARG;
69                 break;
70         case 1:
71                 arg = cmdp->argv[0]->bp;
72                 arglen = cmdp->argv[0]->len;
73                 if (*arg == '!') {
74                         ++arg;
75                         --arglen;
76                         which = R_FILTER;
77
78                         /* Secure means no shell access. */
79                         if (O_ISSET(sp, O_SECURE)) {
80                                 ex_emsg(sp, cmdp->cmd->name, EXM_SECURE_F);
81                                 return (1);
82                         }
83                 } else
84                         which = R_EXPANDARG;
85                 break;
86         default:
87                 abort();
88                 /* NOTREACHED */
89         }
90
91         /* Load a temporary file if no file being edited. */
92         if (sp->ep == NULL) {
93                 if ((frp = file_add(sp, NULL)) == NULL)
94                         return (1);
95                 if (file_init(sp, frp, NULL, 0))
96                         return (1);
97         }
98
99         switch (which) {
100         case R_FILTER:
101                 /*
102                  * File name and bang expand the user's argument.  If
103                  * we don't get an additional argument, it's illegal.
104                  */
105                 argc = cmdp->argc;
106                 if (argv_exp1(sp, cmdp, arg, arglen, 1))
107                         return (1);
108                 if (argc == cmdp->argc) {
109                         ex_emsg(sp, cmdp->cmd->usage, EXM_USAGE);
110                         return (1);
111                 }
112                 argc = cmdp->argc - 1;
113
114                 /* Set the last bang command. */
115                 exp = EXP(sp);
116                 if (exp->lastbcomm != NULL)
117                         free(exp->lastbcomm);
118                 if ((exp->lastbcomm =
119                     strdup(cmdp->argv[argc]->bp)) == 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                                     "!%s\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_emsg(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                         name = cmdp->argv[1]->bp;
211                         /*
212                          * !!!
213                          * Historically, the read and write commands renamed
214                          * "unnamed" files, or, if the file had a name, set
215                          * the alternate file name.
216                          */
217                         if (F_ISSET(sp->frp, FR_TMPFILE) &&
218                             !F_ISSET(sp->frp, FR_EXNAMED)) {
219                                 if ((p = v_strdup(sp, cmdp->argv[1]->bp,
220                                     cmdp->argv[1]->len)) != 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                         } else
234                                 set_alt_name(sp, name);
235                         break;
236                 default:
237                         ex_emsg(sp, cmdp->argv[0]->bp, EXM_FILECOUNT);
238                         return (1);
239                 
240                 }
241                 break;
242         }
243
244         /*
245          * !!!
246          * Historically, vi did not permit reads from non-regular files, nor
247          * did it distinguish between "read !" and "read!", so there was no
248          * way to "force" it.  We permit reading from named pipes too, since
249          * they didn't exist when the original implementation of vi was done
250          * and they seem a reasonable addition.
251          */
252         if ((fp = fopen(name, "r")) == NULL || fstat(fileno(fp), &sb)) {
253                 msgq_str(sp, M_SYSERR, name, "%s");
254                 return (1);
255         }
256         if (!S_ISFIFO(sb.st_mode) && !S_ISREG(sb.st_mode)) {
257                 (void)fclose(fp);
258                 msgq(sp, M_ERR,
259                     "145|Only regular files and named pipes may be read");
260                 return (1);
261         }
262
263         /* Try and get a lock. */
264         if (file_lock(sp, NULL, NULL, fileno(fp), 0) == LOCK_UNAVAIL)
265                 msgq(sp, M_ERR, "146|%s: read lock was unavailable", name);
266
267         rval = ex_readfp(sp, name, fp, &cmdp->addr1, &nlines, 0);
268
269         /*
270          * In vi, set the cursor to the first line read in, if anything read
271          * in, otherwise, the address.  (Historic vi set it to the line after
272          * the address regardless, but since that line may not exist we don't
273          * bother.)
274          *
275          * In ex, set the cursor to the last line read in, if anything read in,
276          * otherwise, the address.
277          */
278         if (F_ISSET(sp, SC_VI)) {
279                 sp->lno = cmdp->addr1.lno;
280                 if (nlines)
281                         ++sp->lno;
282         } else
283                 sp->lno = cmdp->addr1.lno + nlines;
284         return (rval);
285 }
286
287 /*
288  * ex_readfp --
289  *      Read lines into the file.
290  *
291  * PUBLIC: int ex_readfp __P((SCR *, char *, FILE *, MARK *, recno_t *, int));
292  */
293 int
294 ex_readfp(sp, name, fp, fm, nlinesp, silent)
295         SCR *sp;
296         char *name;
297         FILE *fp;
298         MARK *fm;
299         recno_t *nlinesp;
300         int silent;
301 {
302         EX_PRIVATE *exp;
303         GS *gp;
304         recno_t lcnt, lno;
305         size_t len;
306         u_long ccnt;                    /* XXX: can't print off_t portably. */
307         int nf, rval;
308         char *p;
309
310         gp = sp->gp;
311         exp = EXP(sp);
312
313         /*
314          * Add in the lines from the output.  Insertion starts at the line
315          * following the address.
316          */
317         ccnt = 0;
318         lcnt = 0;
319         p = "147|Reading...";
320         for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno, ++lcnt) {
321                 if ((lcnt + 1) % INTERRUPT_CHECK == 0) {
322                         if (INTERRUPTED(sp))
323                                 break;
324                         if (!silent) {
325                                 gp->scr_busy(sp, p,
326                                     p == NULL ? BUSY_UPDATE : BUSY_ON);
327                                 p = NULL;
328                         }
329                 }
330                 if (db_append(sp, 1, lno, exp->ibp, len))
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, lcnt, ccnt);
346                 if (nf)
347                         FREE_SPACE(sp, p, 0);
348         }
349
350         rval = 0;
351         if (0) {
352 err:            msgq_str(sp, M_SYSERR, name, "%s");
353                 (void)fclose(fp);
354                 rval = 1;
355         }
356
357         if (!silent)
358                 gp->scr_busy(sp, NULL, BUSY_OFF);
359         return (rval);
360 }