Esempio n. 1
0
/*
 * Like fgets, but go through the list of files chaining them together.
 * Set len to the length of the line.
 */
int
mf_fgets(SPACE *sp, enum e_spflag spflag)
{
	struct stat sb;
	size_t len;
	char *p;
	int c;
	static int firstfile;

	if (infile == NULL) {
		/* stdin? */
		if (files->fname == NULL) {
			if (inplace != NULL)
				errx(1, "-I or -i may not be used with stdin");
			infile = stdin;
			fname = "stdin";
			outfile = stdout;
			outfname = "stdout";
		}
		firstfile = 1;
	}

	for (;;) {
		if (infile != NULL && (c = getc(infile)) != EOF) {
			(void)ungetc(c, infile);
			break;
		}
		/* If we are here then either eof or no files are open yet */
		if (infile == stdin) {
			sp->len = 0;
			return (0);
		}
		if (infile != NULL) {
			fclose(infile);
			if (*oldfname != '\0') {
				if (rename(fname, oldfname) != 0) {
					warn("rename()");
					unlink(tmpfname);
					exit(1);
				}
				*oldfname = '\0';
			}
			if (*tmpfname != '\0') {
				if (outfile != NULL && outfile != stdout)
					fclose(outfile);
				outfile = NULL;
				rename(tmpfname, fname);
				*tmpfname = '\0';
			}
			outfname = NULL;
		}
		if (firstfile == 0)
			files = files->next;
		else
			firstfile = 0;
		if (files == NULL) {
			sp->len = 0;
			return (0);
		}
		fname = files->fname;
		if (inplace != NULL) {
			if (lstat(fname, &sb) != 0)
				err(1, "%s", fname);
			if (!(sb.st_mode & S_IFREG))
				errx(1, "%s: %s %s", fname,
				    "in-place editing only",
				    "works for regular files");
			if (*inplace != '\0') {
				strlcpy(oldfname, fname,
				    sizeof(oldfname));
				len = strlcat(oldfname, inplace,
				    sizeof(oldfname));
				if (len > sizeof(oldfname))
					errx(1, "%s: name too long", fname);
			}
			len = snprintf(tmpfname, sizeof(tmpfname),
			    "%s/.!%ld!%s", dirname(fname), (long)getpid(),
			    basename(fname));
			if (len >= sizeof(tmpfname))
				errx(1, "%s: name too long", fname);
			unlink(tmpfname);
			if ((outfile = fopen(tmpfname, "w")) == NULL)
				err(1, "%s", fname);
			fchown(fileno(outfile), sb.st_uid, sb.st_gid);
			fchmod(fileno(outfile), sb.st_mode & ALLPERMS);
			outfname = tmpfname;
			if (!ispan) {
				linenum = 0;
				resetstate();
			}
		} else {
			outfile = stdout;
			outfname = "stdout";
		}
		if ((infile = fopen(fname, "r")) == NULL) {
			warn("%s", fname);
			rval = 1;
			continue;
		}
	}
	/*
	 * We are here only when infile is open and we still have something
	 * to read from it.
	 *
	 * Use fgetln so that we can handle essentially infinite input data.
	 * Can't use the pointer into the stdio buffer as the process space
	 * because the ungetc() can cause it to move.
	 */
	p = fgetln(infile, &len);
	if (ferror(infile))
		errx(1, "%s: %s", fname, strerror(errno ? errno : EIO));
	if (len != 0 && p[len - 1] == '\n')
		len--;
	cspace(sp, p, len, spflag);

	linenum++;

	return (1);
}
Esempio n. 2
0
/*
 * Like fgets, but go through the list of files chaining them together.
 * Set len to the length of the line.
 */
int
mf_fgets(SPACE *sp, enum e_spflag spflag)
{
	struct stat sb;
	ssize_t len;
	static char *p = NULL;
	static size_t plen = 0;
	int c;
	static int firstfile;

	if (infile == NULL) {
		/* stdin? */
		if (files->fname == NULL) {
			if (inplace != NULL)
				errx(1, "-I or -i may not be used with stdin");
			infile = stdin;
			fname = "stdin";
			outfile = stdout;
			outfname = "stdout";
		}
		firstfile = 1;
	}

	for (;;) {
		if (infile != NULL && (c = getc(infile)) != EOF) {
			(void)ungetc(c, infile);
			break;
		}
		/* If we are here then either eof or no files are open yet */
		if (infile == stdin) {
			sp->len = 0;
			return (0);
		}
		if (infile != NULL) {
			fclose(infile);
			if (*oldfname != '\0') {
				/* if there was a backup file, remove it */
				unlink(oldfname);
				/*
				 * Backup the original.  Note that hard links
				 * are not supported on all filesystems.
				 */
				if ((link(fname, oldfname) != 0) &&
				   (rename(fname, oldfname) != 0)) {
					warn("rename()");
					if (*tmpfname)
						unlink(tmpfname);
					exit(1);
				}
				*oldfname = '\0';
			}
			if (*tmpfname != '\0') {
				if (outfile != NULL && outfile != stdout)
					if (fclose(outfile) != 0) {
						warn("fclose()");
						unlink(tmpfname);
						exit(1);
					}
				outfile = NULL;
				if (rename(tmpfname, fname) != 0) {
					/* this should not happen really! */
					warn("rename()");
					unlink(tmpfname);
					exit(1);
				}
				*tmpfname = '\0';
			}
			outfname = NULL;
		}
		if (firstfile == 0)
			files = files->next;
		else
			firstfile = 0;
		if (files == NULL) {
			sp->len = 0;
			return (0);
		}
		fname = files->fname;
		if (inplace != NULL) {
			if (lstat(fname, &sb) != 0)
				err(1, "%s", fname);
			if (!(sb.st_mode & S_IFREG))
				errx(1, "%s: %s %s", fname,
				    "in-place editing only",
				    "works for regular files");
			if (*inplace != '\0') {
				strlcpy(oldfname, fname,
				    sizeof(oldfname));
				len = strlcat(oldfname, inplace,
				    sizeof(oldfname));
				if (len > (ssize_t)sizeof(oldfname))
					errx(1, "%s: name too long", fname);
			}
			len = snprintf(tmpfname, sizeof(tmpfname),
			    "%s/.!%ld!%s", dirname(fname), (long)getpid(),
			    basename(fname));
			if (len >= (ssize_t)sizeof(tmpfname))
				errx(1, "%s: name too long", fname);
			unlink(tmpfname);
			if (outfile != NULL && outfile != stdout)
				fclose(outfile);
			if ((outfile = fopen(tmpfname, "w")) == NULL)
				err(1, "%s", fname);
			fchown(fileno(outfile), sb.st_uid, sb.st_gid);
			fchmod(fileno(outfile), sb.st_mode & 777);
			outfname = tmpfname;
			if (!ispan) {
				linenum = 0;
				resetstate();
			}
		} else {
			outfile = stdout;
			outfname = "stdout";
		}
		if ((infile = fopen(fname, "r")) == NULL) {
			warn("%s", fname);
			rval = 1;
			continue;
		}
	}
	/*
	 * We are here only when infile is open and we still have something
	 * to read from it.
	 *
	 * Use getline() so that we can handle essentially infinite input
	 * data.  The p and plen are static so each invocation gives
	 * getline() the same buffer which is expanded as needed.
	 */
	len = getline(&p, &plen, infile);
	if (len == -1)
		err(1, "%s", fname);
	if (len != 0 && p[len - 1] == '\n') {
		sp->append_newline = 1;
		len--;
	} else if (!lastline()) {
		sp->append_newline = 1;
	} else {
		sp->append_newline = 0;
	}
	cspace(sp, p, len, spflag);

	linenum++;

	return (1);
}
Esempio n. 3
0
/*
 * Like fgets, but go through the list of files chaining them together.
 * Set len to the length of the line.
 */
int
mf_fgets(SPACE *sp, enum e_spflag spflag)
{
	struct stat sb, nsb;
	ssize_t len;
	static char *p = NULL;
	static size_t plen = 0;
	int c;
	static int firstfile;

	if (infile == NULL) {
		/* stdin? */
		if (files->fname == NULL) {
			if (inplace != NULL)
				errx(1,
				    _("-I or -i may not be used with stdin"));
			infile = stdin;
			fname = "stdin";
			outfile = stdout;
			outfname = "stdout";
		}
		firstfile = 1;
	}

	for (;;) {
		if (infile != NULL && (c = getc(infile)) != EOF) {
			(void) ungetc(c, infile);
			break;
		}
		/* If we are here then either eof or no files are open yet */
		if (infile == stdin) {
			sp->len = 0;
			return (0);
		}
		if (infile != NULL) {
			(void) fclose(infile);
			if (*oldfname != '\0') {
				/* if there was a backup file, remove it */
				(void) unlink(oldfname);
				/*
				 * Backup the original.  Note that hard links
				 * are not supported on all filesystems.
				 */
				if ((link(fname, oldfname) != 0) &&
				    (rename(fname, oldfname) != 0)) {
					warn("rename()");
					if (*tmpfname)
						(void) unlink(tmpfname);
					exit(1);
				}
				*oldfname = '\0';
			}
			if (*tmpfname != '\0') {
				if (outfile != NULL && outfile != stdout)
					if (fclose(outfile) != 0) {
						warn("fclose()");
						(void) unlink(tmpfname);
						exit(1);
					}
				outfile = NULL;
				if (rename(tmpfname, fname) != 0) {
					/* this should not happen really! */
					warn("rename()");
					(void) unlink(tmpfname);
					exit(1);
				}
				*tmpfname = '\0';
			}
			outfname = NULL;
		}
		if (firstfile == 0)
			files = files->next;
		else
			firstfile = 0;
		if (files == NULL) {
			sp->len = 0;
			return (0);
		}
		fname = files->fname;
		if (inplace != NULL) {
			char bn[PATH_MAX];
			char dn[PATH_MAX];
			(void) strlcpy(bn, fname, sizeof (bn));
			(void) strlcpy(dn, fname, sizeof (dn));
			if (lstat(fname, &sb) != 0)
				err(1, "%s", fname);
			if (!(sb.st_mode & S_IFREG))
				fatal(_("in-place editing only "
				    "works for regular files"));
			if (*inplace != '\0') {
				(void) strlcpy(oldfname, fname,
				    sizeof (oldfname));
				len = strlcat(oldfname, inplace,
				    sizeof (oldfname));
				if (len > sizeof (oldfname))
					fatal(_("name too long"));
			}
			len = snprintf(tmpfname, sizeof (tmpfname),
			    "%s/.!%ld!%s", dirname(dn), (long)getpid(),
			    basename(bn));
			if (len >= sizeof (tmpfname))
				fatal(_("name too long"));
			(void) unlink(tmpfname);
			if ((outfile = fopen(tmpfname, "w")) == NULL)
				err(1, "%s", fname);
			/*
			 * Some file systems don't support chown or
			 * chmod fully.  On those, the owner/group and
			 * permissions will already be set to what
			 * they need to be.
			 */
			if (fstat(fileno(outfile), &nsb) != 0) {
				warn("fstat()");
			}
			if (((sb.st_uid != nsb.st_uid) ||
			    (sb.st_gid != nsb.st_gid)) &&
			    (fchown(fileno(outfile), sb.st_uid, sb.st_gid)
			    != 0))
				warn("fchown()");
			if ((sb.st_mode != nsb.st_mode) &&
			    (fchmod(fileno(outfile), sb.st_mode & 07777) != 0))
				warn("fchmod()");
			outfname = tmpfname;
			if (!ispan) {
				linenum = 0;
				resetstate();
			}
		} else {
			outfile = stdout;
			outfname = "stdout";
		}
		if ((infile = fopen(fname, "r")) == NULL) {
			warn("%s", fname);
			rval = 1;
			continue;
		}
	}
	/*
	 * We are here only when infile is open and we still have something
	 * to read from it.
	 *
	 * Use getline() so that we can handle essentially infinite
	 * input data.  The p and plen are static so each invocation gives
	 * getline() the same buffer which is expanded as needed.
	 */
	len = getline(&p, &plen, infile);
	if (len == -1)
		err(1, "%s", fname);
	if (len != 0 && p[len - 1] == '\n')
		len--;
	cspace(sp, p, len, spflag);

	linenum++;

	return (1);
}