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(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(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 } 362