/* * 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); }
/* * 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); }