示例#1
0
文件: ex_read.c 项目: fishman/nvi
/*
 * ex_readfp --
 *	Read lines into the file.
 *
 * PUBLIC: int ex_readfp __P((SCR *, char *, FILE *, MARK *, db_recno_t *, int));
 */
int
ex_readfp(SCR *sp, char *name, FILE *fp, MARK *fm, db_recno_t *nlinesp, int silent)
{
	EX_PRIVATE *exp;
	GS *gp;
	db_recno_t lcnt, lno;
	size_t len;
	u_long ccnt;			/* XXX: can't print off_t portably. */
	int nf, rval;
	char *p;
	size_t wlen;
	CHAR_T *wp;

	gp = sp->gp;
	exp = EXP(sp);

	/*
	 * Add in the lines from the output.  Insertion starts at the line
	 * following the address.
	 */
	ccnt = 0;
	lcnt = 0;
	p = "147|Reading...";
	for (lno = fm->lno; !ex_getline(sp, fp, &len); ++lno, ++lcnt) {
		if ((lcnt + 1) % INTERRUPT_CHECK == 0) {
			if (INTERRUPTED(sp))
				break;
			if (!silent) {
				gp->scr_busy(sp, p,
				    p == NULL ? BUSY_UPDATE : BUSY_ON);
				p = NULL;
			}
		}
		FILE2INT5(sp, exp->ibcw, exp->ibp, len, wp, wlen);
		if (db_append(sp, 1, lno, wp, wlen))
			goto err;
		ccnt += len;
	}

	if (ferror(fp) || fclose(fp))
		goto err;

	/* Return the number of lines read in. */
	if (nlinesp != NULL)
		*nlinesp = lcnt;

	if (!silent) {
		p = msg_print(sp, name, &nf);
		msgq(sp, M_INFO,
		    "148|%s: %lu lines, %lu characters", p, lcnt, ccnt);
		if (nf)
			FREE_SPACE(sp, p, 0);
	}

	rval = 0;
	if (0) {
err:		msgq_str(sp, M_SYSERR, name, "%s");
		(void)fclose(fp);
		rval = 1;
	}

	if (!silent)
		gp->scr_busy(sp, NULL, BUSY_OFF);
	return (rval);
}
示例#2
0
/*
 * ex_writefp --
 *	Write a range of lines to a FILE *.
 *
 * PUBLIC: int ex_writefp __P((SCR *,
 * PUBLIC:    char *, FILE *, MARK *, MARK *, u_long *, u_long *, int));
 */
int
ex_writefp(SCR *sp, char *name, FILE *fp, MARK *fm, MARK *tm, u_long *nlno, u_long *nch, int silent)
{
	struct stat sb;
	GS *gp;
	u_long ccnt;			/* XXX: can't print off_t portably. */
	recno_t fline, tline, lcnt;
	size_t len;
	int rval;
	char *msg;
	CHAR_T *p;
	char *f;
	size_t flen;
	int isutf16;

	gp = sp->gp;
	fline = fm->lno;
	tline = tm->lno;

	if (nlno != NULL) {
		*nch = 0;
		*nlno = 0;
	}

	/*
	 * The vi filter code has multiple processes running simultaneously,
	 * and one of them calls ex_writefp().  The "unsafe" function calls
	 * in this code are to db_get() and msgq().  Db_get() is safe, see
	 * the comment in ex_filter.c:ex_filter() for details.  We don't call
	 * msgq if the multiple process bit in the EXF is set.
	 *
	 * !!!
	 * Historic vi permitted files of 0 length to be written.  However,
	 * since the way vi got around dealing with "empty" files was to
	 * always have a line in the file no matter what, it wrote them as
	 * files of a single, empty line.  We write empty files.
	 *
	 * "Alex, I'll take vi trivia for $1000."
	 */
	ccnt = 0;
	lcnt = 0;
	msg = "253|Writing...";

	if (O_ISSET(sp, O_FILEENCODING)) {
		isutf16 = !strncasecmp(O_STR(sp, O_FILEENCODING), "utf-16", 6);
		isutf16 += !strncasecmp(O_STR(sp, O_FILEENCODING), "utf-16le", 8);
	} else isutf16 = 0;

	if (tline != 0) {
		if (isutf16 == 1 && fwrite("\xfe\xff", 1, 2, fp) != 2)
			goto err;
		if (isutf16 == 2 && fwrite("\xff\xfe", 1, 2, fp) != 2)
			goto err;
		for (; fline <= tline; ++fline, ++lcnt) {
			/* Caller has to provide any interrupt message. */
			if ((lcnt + 1) % INTERRUPT_CHECK == 0) {
				if (INTERRUPTED(sp))
					break;
				if (!silent) {
					gp->scr_busy(sp, msg, msg == NULL ?
					    BUSY_UPDATE : BUSY_ON);
					msg = NULL;
				}
			}
			if (db_get(sp, fline, DBG_FATAL, &p, &len))
				goto err;
			INT2FILE(sp, p, len, f, flen);
			if (fwrite(f, 1, flen, fp) != flen)
				goto err;
			ccnt += len;
			/* UTF-16 w/o BOM is big-endian */
			switch (isutf16) {
			case 1:		/* UTF-16BE */
				if (fwrite("\0\x0a", 1, 2, fp) != 2)
					goto done;
				break;
			case 2:		/* UTF-16LE */
				if (fwrite("\x0a\0", 1, 2, fp) != 2)
					goto done;
				break;
			default:
				if (putc('\n', fp) != '\n')
					goto done;
			}
			++ccnt;
		}
	}

done:	if (fflush(fp))
		goto err;
	/*
	 * XXX
	 * I don't trust NFS -- check to make sure that we're talking to
	 * a regular file and sync so that NFS is forced to flush.
	 */
	if (!fstat(fileno(fp), &sb) &&
	    S_ISREG(sb.st_mode) && fsync(fileno(fp)))
		goto err;

	if (fclose(fp)) {
		fp = NULL;
		goto err;
	}

	rval = 0;
	if (0) {
err:		if (!F_ISSET(sp->ep, F_MULTILOCK))
			msgq_str(sp, M_SYSERR, name, "%s");
		if (fp != NULL)
			fclose(fp);
		rval = 1;
	}

	if (!silent)
		gp->scr_busy(sp, NULL, BUSY_OFF);

	/* Report the possibly partial transfer. */
	if (nlno != NULL) {
		*nch = ccnt;
		*nlno = lcnt;
	}
	return (rval);
}