Module Name:    src
Committed By:   asau
Date:           Sat Feb 28 21:56:53 UTC 2015

Modified Files:
        src/usr.bin/sed: compile.c extern.h main.c process.c

Log Message:
Improve modularity of "sed" source:
- move program source input subroutines into compiler part;
- move data I/O subroutines into processor part.


To generate a diff of this commit:
cvs rdiff -u -r1.43 -r1.44 src/usr.bin/sed/compile.c
cvs rdiff -u -r1.14 -r1.15 src/usr.bin/sed/extern.h
cvs rdiff -u -r1.30 -r1.31 src/usr.bin/sed/main.c
cvs rdiff -u -r1.46 -r1.47 src/usr.bin/sed/process.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.bin/sed/compile.c
diff -u src/usr.bin/sed/compile.c:1.43 src/usr.bin/sed/compile.c:1.44
--- src/usr.bin/sed/compile.c:1.43	Thu Jun 26 02:14:32 2014
+++ src/usr.bin/sed/compile.c	Sat Feb 28 21:56:53 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: compile.c,v 1.43 2014/06/26 02:14:32 christos Exp $	*/
+/*	$NetBSD: compile.c,v 1.44 2015/02/28 21:56:53 asau Exp $	*/
 
 /*-
  * Copyright (c) 1992 Diomidis Spinellis.
@@ -38,7 +38,7 @@
 #endif
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: compile.c,v 1.43 2014/06/26 02:14:32 christos Exp $");
+__RCSID("$NetBSD: compile.c,v 1.44 2015/02/28 21:56:53 asau Exp $");
 #ifdef __FBSDID
 __FBSDID("$FreeBSD: head/usr.bin/sed/compile.c 259132 2013-12-09 18:57:20Z eadler $");
 #endif
@@ -73,6 +73,8 @@ static struct labhash {
 	int	lh_ref;
 } *labels[LHSZ];
 
+static char	 *cu_fgets(char *, int, int *);
+
 static char	 *compile_addr(char *, struct s_addr *);
 static char	 *compile_ccl(char **, char *);
 static char	 *compile_delimited(char *, char *, int);
@@ -91,6 +93,14 @@ static void	  fixuplabel(struct s_comman
 static void	  uselabel(void);
 
 /*
+ * Current file and line number; line numbers restart across compilation
+ * units, but span across input files.  The latter is optional if editing
+ * in place.
+ */
+static const char *fname;	/* File name. */
+static u_long linenum;
+
+/*
  * Command specification.  This is used to drive the command parser.
  */
 struct s_format {
@@ -945,3 +955,99 @@ uselabel(void)
 		}
 	}
 }
+
+/*
+ * Like fgets, but go through the chain of compilation units chaining them
+ * together.  Empty strings and files are ignored.
+ */
+char *
+cu_fgets(char *buf, int n, int *more)
+{
+	static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF;
+	static FILE *f;		/* Current open file */
+	static char *s;		/* Current pointer inside string */
+	static char string_ident[30];
+	char *p;
+
+again:
+	switch (state) {
+	case ST_EOF:
+		if (script == NULL) {
+			if (more != NULL)
+				*more = 0;
+			return (NULL);
+		}
+		linenum = 0;
+		switch (script->type) {
+		case CU_FILE:
+			if ((f = fopen(script->s, "r")) == NULL)
+				err(1, "%s", script->s);
+			fname = script->s;
+			state = ST_FILE;
+			goto again;
+		case CU_STRING:
+			if (((size_t)snprintf(string_ident,
+			    sizeof(string_ident), "\"%s\"", script->s)) >=
+			    sizeof(string_ident) - 1)
+				(void)strcpy(string_ident +
+				    sizeof(string_ident) - 6, " ...\"");
+			fname = string_ident;
+			s = script->s;
+			state = ST_STRING;
+			goto again;
+		}
+	case ST_FILE:
+		if ((p = fgets(buf, n, f)) != NULL) {
+			linenum++;
+			if (linenum == 1 && buf[0] == '#' && buf[1] == 'n')
+				nflag = 1;
+			if (more != NULL)
+				*more = !feof(f);
+			return (p);
+		}
+		script = script->next;
+		(void)fclose(f);
+		state = ST_EOF;
+		goto again;
+	case ST_STRING:
+		if (linenum == 0 && s[0] == '#' && s[1] == 'n')
+			nflag = 1;
+		p = buf;
+		for (;;) {
+			if (n-- <= 1) {
+				*p = '\0';
+				linenum++;
+				if (more != NULL)
+					*more = 1;
+				return (buf);
+			}
+			switch (*s) {
+			case '\0':
+				state = ST_EOF;
+				if (s == script->s) {
+					script = script->next;
+					goto again;
+				} else {
+					script = script->next;
+					*p = '\0';
+					linenum++;
+					if (more != NULL)
+						*more = 0;
+					return (buf);
+				}
+			case '\n':
+				*p++ = '\n';
+				*p = '\0';
+				s++;
+				linenum++;
+				if (more != NULL)
+					*more = 0;
+				return (buf);
+			default:
+				*p++ = *s++;
+			}
+		}
+	}
+	/* NOTREACHED */
+	return (NULL);
+}

Index: src/usr.bin/sed/extern.h
diff -u src/usr.bin/sed/extern.h:1.14 src/usr.bin/sed/extern.h:1.15
--- src/usr.bin/sed/extern.h:1.14	Fri Jun  6 21:56:39 2014
+++ src/usr.bin/sed/extern.h	Sat Feb 28 21:56:53 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: extern.h,v 1.14 2014/06/06 21:56:39 wiz Exp $	*/
+/*	$NetBSD: extern.h,v 1.15 2015/02/28 21:56:53 asau Exp $	*/
 
 /*-
  * Copyright (c) 1992 Diomidis Spinellis.
@@ -36,24 +36,39 @@
  * $FreeBSD: head/usr.bin/sed/extern.h 170608 2007-06-12 12:05:24Z yar $
  */
 
+/*
+ * Linked list of units (strings and files) to be compiled
+ */
+struct s_compunit {
+	struct s_compunit *next;
+	enum e_cut {CU_FILE, CU_STRING} type;
+	char *s;			/* Pointer to string or fname */
+};
+
+/*
+ * Linked list of files to be processed
+ */
+struct s_flist {
+	char *fname;
+	struct s_flist *next;
+};
+
+extern struct s_compunit *script;
+extern struct s_flist *files;
 extern struct s_command *prog;
 extern struct s_appends *appends;
 extern regmatch_t *match;
 extern size_t maxnsub;
-extern u_long linenum;
 extern size_t appendnum;
-extern int aflag, eflag, nflag;
-extern const char *fname, *outfname;
+extern int aflag, nflag;
+extern int ispan;
 extern FILE *infile, *outfile;
 extern int rflags;	/* regex flags to use */
 
 void	 cfclose(struct s_command *, struct s_command *);
 void	 compile(void);
 void	 cspace(SPACE *, const char *, size_t, enum e_spflag);
-char	*cu_fgets(char *, int, int *);
-int	 mf_fgets(SPACE *, enum e_spflag);
-int	 lastline(void);
-void	 process(void);
+int	 process(void);
 void	 resetstate(void);
 char	*strregerror(int, regex_t *);
 void	*xmalloc(size_t);

Index: src/usr.bin/sed/main.c
diff -u src/usr.bin/sed/main.c:1.30 src/usr.bin/sed/main.c:1.31
--- src/usr.bin/sed/main.c:1.30	Thu Jun 26 02:14:32 2014
+++ src/usr.bin/sed/main.c	Sat Feb 28 21:56:53 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: main.c,v 1.30 2014/06/26 02:14:32 christos Exp $	*/
+/*	$NetBSD: main.c,v 1.31 2015/02/28 21:56:53 asau Exp $	*/
 
 /*-
  * Copyright (c) 2013 Johann 'Myrkraverk' Oskarsson.
@@ -39,7 +39,7 @@
 #endif
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: main.c,v 1.30 2014/06/26 02:14:32 christos Exp $");
+__RCSID("$NetBSD: main.c,v 1.31 2015/02/28 21:56:53 asau Exp $");
 #ifdef __FBSDID
 __FBSDID("$FreeBSD: head/usr.bin/sed/main.c 252231 2013-06-26 04:14:19Z pfg $");
 #endif
@@ -61,7 +61,6 @@ static const char sccsid[] = "@(#)main.c
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <libgen.h>
 #include <limits.h>
 #include <locale.h>
 #include <regex.h>
@@ -76,54 +75,29 @@ static const char sccsid[] = "@(#)main.c
 #include "extern.h"
 
 /*
- * Linked list of units (strings and files) to be compiled
- */
-struct s_compunit {
-	struct s_compunit *next;
-	enum e_cut {CU_FILE, CU_STRING} type;
-	char *s;			/* Pointer to string or fname */
-};
-
-/*
  * Linked list pointer to compilation units and pointer to current
  * next pointer.
  */
-static struct s_compunit *script, **cu_nextp = &script;
-
-/*
- * Linked list of files to be processed
- */
-struct s_flist {
-	char *fname;
-	struct s_flist *next;
-};
+struct s_compunit *script;
+static struct s_compunit **cu_nextp = &script;
 
 /*
  * Linked list pointer to files and pointer to current
  * next pointer.
  */
-static struct s_flist *files, **fl_nextp = &files;
+struct s_flist *files;
+static struct s_flist **fl_nextp = &files;
 
 FILE *infile;			/* Current input file */
 FILE *outfile;			/* Current output file */
 
-int aflag, eflag, nflag;
+int aflag;
+static int eflag;
+int nflag;
 int rflags = 0;
-static int rval;		/* Exit status */
 
-static int ispan;		/* Whether inplace editing spans across files */
-
-/*
- * Current file and line number; line numbers restart across compilation
- * units, but span across input files.  The latter is optional if editing
- * in place.
- */
-const char *fname;		/* File name. */
-const char *outfname;		/* Output file name */
-static char oldfname[PATH_MAX];	/* Old file name (for in-place editing) */
-static char tmpfname[PATH_MAX];	/* Temporary file name (for in-place editing) */
-static const char *inplace;	/* Inplace edit file extension. */
-u_long linenum;
+int ispan;			/* Whether inplace editing spans across files */
+const char *inplace;		/* Inplace edit file extension. */
 
 static void add_compunit(enum e_cut, char *);
 static void add_file(char *);
@@ -132,6 +106,7 @@ static void usage(void) __dead;
 int
 main(int argc, char *argv[])
 {
+	int rval;		/* Exit status */
 	int c, fflag;
 	char *temp_arg;
 
@@ -212,7 +187,7 @@ main(int argc, char *argv[])
 			add_file(*argv);
 	else
 		add_file(NULL);
-	process();
+	rval = process();
 	cfclose(prog, NULL);
 	if (fclose(stdout))
 		err(1, "stdout");
@@ -230,249 +205,6 @@ usage(void)
 }
 
 /*
- * Like fgets, but go through the chain of compilation units chaining them
- * together.  Empty strings and files are ignored.
- */
-char *
-cu_fgets(char *buf, int n, int *more)
-{
-	static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF;
-	static FILE *f;		/* Current open file */
-	static char *s;		/* Current pointer inside string */
-	static char string_ident[30];
-	char *p;
-
-again:
-	switch (state) {
-	case ST_EOF:
-		if (script == NULL) {
-			if (more != NULL)
-				*more = 0;
-			return (NULL);
-		}
-		linenum = 0;
-		switch (script->type) {
-		case CU_FILE:
-			if ((f = fopen(script->s, "r")) == NULL)
-				err(1, "%s", script->s);
-			fname = script->s;
-			state = ST_FILE;
-			goto again;
-		case CU_STRING:
-			if (((size_t)snprintf(string_ident,
-			    sizeof(string_ident), "\"%s\"", script->s)) >=
-			    sizeof(string_ident) - 1)
-				(void)strcpy(string_ident +
-				    sizeof(string_ident) - 6, " ...\"");
-			fname = string_ident;
-			s = script->s;
-			state = ST_STRING;
-			goto again;
-		}
-	case ST_FILE:
-		if ((p = fgets(buf, n, f)) != NULL) {
-			linenum++;
-			if (linenum == 1 && buf[0] == '#' && buf[1] == 'n')
-				nflag = 1;
-			if (more != NULL)
-				*more = !feof(f);
-			return (p);
-		}
-		script = script->next;
-		(void)fclose(f);
-		state = ST_EOF;
-		goto again;
-	case ST_STRING:
-		if (linenum == 0 && s[0] == '#' && s[1] == 'n')
-			nflag = 1;
-		p = buf;
-		for (;;) {
-			if (n-- <= 1) {
-				*p = '\0';
-				linenum++;
-				if (more != NULL)
-					*more = 1;
-				return (buf);
-			}
-			switch (*s) {
-			case '\0':
-				state = ST_EOF;
-				if (s == script->s) {
-					script = script->next;
-					goto again;
-				} else {
-					script = script->next;
-					*p = '\0';
-					linenum++;
-					if (more != NULL)
-						*more = 0;
-					return (buf);
-				}
-			case '\n':
-				*p++ = '\n';
-				*p = '\0';
-				s++;
-				linenum++;
-				if (more != NULL)
-					*more = 0;
-				return (buf);
-			default:
-				*p++ = *s++;
-			}
-		}
-	}
-	/* NOTREACHED */
-	return (NULL);
-}
-
-/*
- * 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;
-	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 > sizeof(oldfname))
-					errx(1, "%s: name too long", fname);
-			}
-			char d_name[PATH_MAX], f_name[PATH_MAX];
-			(void)strlcpy(d_name, fname, sizeof(d_name));
-			(void)strlcpy(f_name, fname, sizeof(f_name));
-			len = (size_t)snprintf(tmpfname, sizeof(tmpfname),
-			    "%s/.!%ld!%s", dirname(d_name), (long)getpid(),
-			    basename(f_name));
-			if (len >= 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 & 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 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.
-	 */
-	ssize_t slen = getline(&p, &plen, infile);
-	if (slen == -1)
-		err(1, "%s", fname);
-	if (slen != 0 && p[slen - 1] == '\n')
-		slen--;
-	cspace(sp, p, (size_t)slen, spflag);
-
-	linenum++;
-
-	return (1);
-}
-
-/*
  * Add a compilation unit to the linked list
  */
 static void
@@ -502,16 +234,3 @@ add_file(char *s)
 	fp->fname = s;
 	fl_nextp = &fp->next;
 }
-
-int
-lastline(void)
-{
-	int ch;
-
-	if (files->next != NULL && (inplace == NULL || ispan))
-		return (0);
-	if ((ch = getc(infile)) == EOF)
-		return (1);
-	ungetc(ch, infile);
-	return (0);
-}

Index: src/usr.bin/sed/process.c
diff -u src/usr.bin/sed/process.c:1.46 src/usr.bin/sed/process.c:1.47
--- src/usr.bin/sed/process.c:1.46	Wed Aug 13 11:35:34 2014
+++ src/usr.bin/sed/process.c	Sat Feb 28 21:56:53 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: process.c,v 1.46 2014/08/13 11:35:34 christos Exp $	*/
+/*	$NetBSD: process.c,v 1.47 2015/02/28 21:56:53 asau Exp $	*/
 
 /*-
  * Copyright (c) 1992 Diomidis Spinellis.
@@ -38,7 +38,7 @@
 #endif
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: process.c,v 1.46 2014/08/13 11:35:34 christos Exp $");
+__RCSID("$NetBSD: process.c,v 1.47 2015/02/28 21:56:53 asau Exp $");
 #ifdef __FBSDID
 __FBSDID("$FreeBSD: head/usr.bin/sed/process.c 192732 2009-05-25 06:45:33Z brian $");
 #endif
@@ -56,6 +56,7 @@ static const char sccsid[] = "@(#)proces
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <libgen.h>
 #include <limits.h>
 #include <regex.h>
 #include <stdio.h>
@@ -75,6 +76,9 @@ static SPACE HS, PS, SS, YS;
 #define	hs		HS.space
 #define	hsl		HS.len
 
+static int mf_fgets(SPACE *, enum e_spflag);
+static int lastline(void);
+
 static __inline int	 applies(struct s_command *);
 static void		 do_tr(struct s_tr *);
 static void		 flush_appends(void);
@@ -83,6 +87,20 @@ static __inline int	 regexec_e(regex_t *
 static void		 regsub(SPACE *, char *, char *);
 static int		 substitute(struct s_command *);
 
+/*
+ * Current file and line number; line numbers restart across compilation
+ * units, but span across input files.  The latter is optional if editing
+ * in place.
+ */
+static const char *fname;	/* File name. */
+static const char *outfname;	/* Output file name */
+static char oldfname[PATH_MAX];	/* Old file name (for in-place editing) */
+static char tmpfname[PATH_MAX];	/* Temporary file name (for in-place editing) */
+static const char *inplace;	/* Inplace edit file extension. */
+static u_long linenum;
+
+static int rval;		/* Exit status */
+
 struct s_appends *appends;	/* Array of pointers to strings to append. */
 static size_t appendx;		/* Index into appends array. */
 size_t appendnum;			/* Size of appends array. */
@@ -96,7 +114,7 @@ regmatch_t *match;
 
 #define OUT() do {fwrite(ps, 1, psl, outfile); fputc('\n', outfile);} while (0)
 
-void
+int
 process(void)
 {
 	struct s_command *cp;
@@ -271,6 +289,7 @@ new:		if (!nflag && !pd)
 			OUT();
 		flush_appends();
 	} /* for all lines */
+	return rval;
 }
 
 /*
@@ -790,3 +809,163 @@ cfclose(struct s_command *cp, struct s_c
 			break;
 		}
 }
+
+/*
+ * 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;
+	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 > sizeof(oldfname))
+					errx(1, "%s: name too long", fname);
+			}
+			char d_name[PATH_MAX], f_name[PATH_MAX];
+			(void)strlcpy(d_name, fname, sizeof(d_name));
+			(void)strlcpy(f_name, fname, sizeof(f_name));
+			len = (size_t)snprintf(tmpfname, sizeof(tmpfname),
+			    "%s/.!%ld!%s", dirname(d_name), (long)getpid(),
+			    basename(f_name));
+			if (len >= 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 & 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 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.
+	 */
+	ssize_t slen = getline(&p, &plen, infile);
+	if (slen == -1)
+		err(1, "%s", fname);
+	if (slen != 0 && p[slen - 1] == '\n')
+		slen--;
+	cspace(sp, p, (size_t)slen, spflag);
+
+	linenum++;
+
+	return (1);
+}
+
+static int
+lastline(void)
+{
+	int ch;
+
+	if (files->next != NULL && (inplace == NULL || ispan))
+		return (0);
+	if ((ch = getc(infile)) == EOF)
+		return (1);
+	ungetc(ch, infile);
+	return (0);
+}

Reply via email to