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