1 /* $OpenBSD: ex_read.c,v 1.13 2016/05/27 09:18:12 martijn 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 if (exp->lastbcomm != NULL) 115 free(exp->lastbcomm); 116 if ((exp->lastbcomm = 117 strdup(cmdp->argv[argc]->bp)) == NULL) { 118 msgq(sp, M_SYSERR, NULL); 119 return (1); 120 } 121 122 /* 123 * Vi redisplayed the user's argument if it changed, ex 124 * always displayed a !, plus the user's argument if it 125 * changed. 126 */ 127 if (F_ISSET(sp, SC_VI)) { 128 if (F_ISSET(cmdp, E_MODIFY)) 129 (void)vs_update(sp, "!", cmdp->argv[argc]->bp); 130 } else { 131 if (F_ISSET(cmdp, E_MODIFY)) 132 (void)ex_printf(sp, 133 "!%s\n", cmdp->argv[argc]->bp); 134 else 135 (void)ex_puts(sp, "!\n"); 136 (void)ex_fflush(sp); 137 } 138 139 /* 140 * Historically, filter reads as the first ex command didn't 141 * wait for the user. If SC_SCR_EXWROTE not already set, set 142 * the don't-wait flag. 143 */ 144 if (!F_ISSET(sp, SC_SCR_EXWROTE)) 145 F_SET(sp, SC_EX_WAIT_NO); 146 147 /* 148 * Switch into ex canonical mode. The reason to restore the 149 * original terminal modes for read filters is so that users 150 * can do things like ":r! cat /dev/tty". 151 * 152 * !!! 153 * We do not output an extra <newline>, so that we don't touch 154 * the screen on a normal read. 155 */ 156 if (F_ISSET(sp, SC_VI)) { 157 if (gp->scr_screen(sp, SC_EX)) { 158 ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON_F); 159 return (1); 160 } 161 /* 162 * !!! 163 * Historically, the read command doesn't switch to 164 * the alternate X11 xterm screen, if doing a filter 165 * read -- don't set SA_ALTERNATE. 166 */ 167 F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE); 168 } 169 170 if (ex_filter(sp, cmdp, &cmdp->addr1, 171 NULL, &rm, cmdp->argv[argc]->bp, FILTER_READ)) 172 return (1); 173 174 /* The filter version of read set the autoprint flag. */ 175 F_SET(cmdp, E_AUTOPRINT); 176 177 /* 178 * If in vi mode, move to the first nonblank. Might have 179 * switched into ex mode, so saved the original SC_VI value. 180 */ 181 sp->lno = rm.lno; 182 if (F_ISSET(sp, SC_VI)) { 183 sp->cno = 0; 184 (void)nonblank(sp, sp->lno, &sp->cno); 185 } 186 return (0); 187 case R_ARG: 188 name = sp->frp->name; 189 break; 190 case R_EXPANDARG: 191 if (argv_exp2(sp, cmdp, arg, arglen)) 192 return (1); 193 /* 194 * 0 args: impossible. 195 * 1 args: impossible (I hope). 196 * 2 args: read it. 197 * >2 args: object, too many args. 198 * 199 * The 1 args case depends on the argv_sexp() function refusing 200 * to return success without at least one non-blank character. 201 */ 202 switch (cmdp->argc) { 203 case 0: 204 case 1: 205 abort(); 206 /* NOTREACHED */ 207 case 2: 208 name = cmdp->argv[1]->bp; 209 /* 210 * !!! 211 * Historically, the read and write commands renamed 212 * "unnamed" files, or, if the file had a name, set 213 * the alternate file name. 214 */ 215 if (F_ISSET(sp->frp, FR_TMPFILE) && 216 !F_ISSET(sp->frp, FR_EXNAMED)) { 217 if ((p = v_strdup(sp, cmdp->argv[1]->bp, 218 cmdp->argv[1]->len)) != NULL) { 219 free(sp->frp->name); 220 sp->frp->name = p; 221 } 222 /* 223 * The file has a real name, it's no longer a 224 * temporary, clear the temporary file flags. 225 */ 226 F_CLR(sp->frp, FR_TMPEXIT | FR_TMPFILE); 227 F_SET(sp->frp, FR_NAMECHANGE | FR_EXNAMED); 228 229 /* Notify the screen. */ 230 (void)sp->gp->scr_rename(sp, sp->frp->name, 1); 231 } else 232 set_alt_name(sp, name); 233 break; 234 default: 235 ex_emsg(sp, cmdp->argv[0]->bp, EXM_FILECOUNT); 236 return (1); 237 238 } 239 break; 240 default: 241 abort(); 242 /* NOTREACHED */ 243 } 244 245 /* 246 * !!! 247 * Historically, vi did not permit reads from non-regular files, nor 248 * did it distinguish between "read !" and "read!", so there was no 249 * way to "force" it. We permit reading from named pipes too, since 250 * they didn't exist when the original implementation of vi was done 251 * and they seem a reasonable addition. 252 */ 253 if ((fp = fopen(name, "r")) == NULL || fstat(fileno(fp), &sb)) { 254 msgq_str(sp, M_SYSERR, name, "%s"); 255 return (1); 256 } 257 if (!S_ISFIFO(sb.st_mode) && !S_ISREG(sb.st_mode)) { 258 (void)fclose(fp); 259 msgq(sp, M_ERR, 260 "Only regular files and named pipes may be read"); 261 return (1); 262 } 263 264 /* Try and get a lock. */ 265 if (file_lock(sp, NULL, NULL, fileno(fp), 0) == LOCK_UNAVAIL) 266 msgq(sp, M_ERR, "%s: read lock was unavailable", name); 267 268 rval = ex_readfp(sp, name, fp, &cmdp->addr1, &nlines, 0); 269 270 /* 271 * In vi, set the cursor to the first line read in, if anything read 272 * in, otherwise, the address. (Historic vi set it to the line after 273 * the address regardless, but since that line may not exist we don't 274 * bother.) 275 * 276 * In ex, set the cursor to the last line read in, if anything read in, 277 * otherwise, the address. 278 */ 279 if (F_ISSET(sp, SC_VI)) { 280 sp->lno = cmdp->addr1.lno; 281 if (nlines) 282 ++sp->lno; 283 } else 284 sp->lno = cmdp->addr1.lno + nlines; 285 return (rval); 286 } 287 288 /* 289 * ex_readfp -- 290 * Read lines into the file. 291 * 292 * PUBLIC: int ex_readfp(SCR *, char *, FILE *, MARK *, recno_t *, int); 293 */ 294 int 295 ex_readfp(SCR *sp, char *name, FILE *fp, MARK *fm, recno_t *nlinesp, 296 int silent) 297 { 298 EX_PRIVATE *exp; 299 GS *gp; 300 recno_t lcnt, lno; 301 size_t len; 302 u_long ccnt; /* XXX: can't print off_t portably. */ 303 int nf, rval; 304 char *p; 305 306 gp = sp->gp; 307 exp = EXP(sp); 308 309 /* 310 * Add in the lines from the output. Insertion starts at the line 311 * following the address. 312 */ 313 ccnt = 0; 314 lcnt = 0; 315 p = "Reading..."; 316 for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno, ++lcnt) { 317 if ((lcnt + 1) % INTERRUPT_CHECK == 0) { 318 if (INTERRUPTED(sp)) 319 break; 320 if (!silent) { 321 gp->scr_busy(sp, p, 322 p == NULL ? BUSY_UPDATE : BUSY_ON); 323 p = NULL; 324 } 325 } 326 if (db_append(sp, 1, lno, exp->ibp, len)) 327 goto err; 328 ccnt += len; 329 } 330 331 if (ferror(fp) || fclose(fp)) 332 goto err; 333 334 /* Return the number of lines read in. */ 335 if (nlinesp != NULL) 336 *nlinesp = lcnt; 337 338 if (!silent) { 339 p = msg_print(sp, name, &nf); 340 msgq(sp, M_INFO, 341 "%s: %lu lines, %lu characters", p, lcnt, ccnt); 342 if (nf) 343 FREE_SPACE(sp, p, 0); 344 } 345 346 rval = 0; 347 if (0) { 348 err: msgq_str(sp, M_SYSERR, name, "%s"); 349 (void)fclose(fp); 350 rval = 1; 351 } 352 353 if (!silent) 354 gp->scr_busy(sp, NULL, BUSY_OFF); 355 return (rval); 356 } 357