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