Resubmission of my patchset for ed, albeit much better formatted so as to ease
reading them.

--
Thomas Mannay <audiobarr...@openmailbox.org>
>From 14cb79fbab41b96ca3f4fcd85e178f38561e9211 Mon Sep 17 00:00:00 2001
From: Thomas Mannay <audiobarr...@openmailbox.org>
Date: Thu, 6 Oct 2016 10:46:14 +0000
Subject: [PATCH 1/4] ed: newly joined lines are placed correctly

---
 ed.c | 49 +++++++++++++++++++++++++++----------------------
 1 file changed, 27 insertions(+), 22 deletions(-)

diff --git a/ed.c b/ed.c
index 184ed30..2a1c0ba 100644
--- a/ed.c
+++ b/ed.c
@@ -297,13 +297,17 @@ undo(void)
 }
 
 static void
-inject(char *s)
+inject(char *s, int join)
 {
 	int off, k, begin, end;
 
-	begin = getindex(curln);
-	end = getindex(nextln(curln));
-
+	if (join) {
+		begin = getindex(curln-1);
+		end = getindex(nextln(curln-1));
+	} else {
+		begin = getindex(curln);
+		end = getindex(nextln(curln));
+	}
 	while (*s) {
 		k = makeline(s, &off);
 		s += off;
@@ -634,7 +638,7 @@ doread(char *fname)
 			s[n-1] = '\n';
 			s[n] = '\0';
 		}
-		inject(s);
+		inject(s, 0);
 	}
 	if (optdiag)
 		printf("%zu\n", cnt);
@@ -751,7 +755,7 @@ append(int num)
 	while (getline(&s, &len, stdin) > 0) {
 		if (*s == '.' && s[1] == '\n')
 			break;
-		inject(s);
+		inject(s, 0);
 	}
 	free(s);
 }
@@ -801,21 +805,22 @@ static void
 join(void)
 {
 	int i;
-	char *t, c;
-	size_t len = 0, cap = 0;
-	static char *s;
+        char *t, c;
+        size_t len = 0, cap = 0;
+        static char *s;
+
+        free(s);
+        for (s = NULL, i = line1; i <= line2; i = nextln(i)) {
+                for (t = gettxt(i); (c = *t) != '\n'; ++t)
+                        s = addchar(*t, s, &cap, &len);
+        }
+
+        s = addchar('\n', s, &cap, &len);
+        s = addchar('\0', s, &cap, &len);
+        delete(line1, line2);
+        inject(s);
+        free(s);
 
-	free(s);
-	for (s = NULL, i = line1; i <= line2; i = nextln(i)) {
-		for (t = gettxt(i); (c = *t) != '\n'; ++t)
-			s = addchar(*t, s, &cap, &len);
-	}
-
-	s = addchar('\n', s, &cap, &len);
-	s = addchar('\0', s, &cap, &len);
-	delete(line1, line2);
-	inject(s);
-	free(s);
 }
 
 static void
@@ -841,7 +846,7 @@ copy(int where)
 	curln = where;
 
 	for (i = line1; i <= line2; ++i)
-		inject(gettxt(i));
+		inject(gettxt(i), 0);
 }
 
 static void
@@ -1021,7 +1026,7 @@ subline(int num, int nth)
 	addpost(&s, &cap, &siz);
 	delete(num, num);
 	curln = prevln(num);
-	inject(s);
+	inject(s, 0);
 }

static void
-- 
2.10.0

>From e9d7579b23ace43ce023be35676431e03b62fa2a Mon Sep 17 00:00:00 2001
From: Thomas Mannay <audiobarr...@openmailbox.org>
Date: Thu, 6 Oct 2016 10:49:11 +0000
Subject: [PATCH 2/4] ed: if only one address is given to j, do nothing.

---
 ed.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/ed.c b/ed.c
index 2a1c0ba..651ed4e 100644
--- a/ed.c
+++ b/ed.c
@@ -1175,9 +1175,8 @@ repeat:
 	case 'j':
 		chkprint(1);
 		deflines(curln, curln+1);
-		if (!line1)
-			goto bad_address;
-		join();
+		if (line1 != line2)
+			join();
 		break;
 	case 'z':
 		if (nlines > 1)
-- 
2.10.0

>From 78b33fef64f832189c21d6c1e373e43ac4c623fa Mon Sep 17 00:00:00 2001
From: Thomas Mannay <audiobarr...@openmailbox.org>
Date: Thu, 6 Oct 2016 10:50:06 +0000
Subject: [PATCH 3/4] ed: fix double free and infinite loop in join().

---
 ed.c | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/ed.c b/ed.c
index 651ed4e..56c58e3 100644
--- a/ed.c
+++ b/ed.c
@@ -805,22 +805,22 @@ static void
 join(void)
 {
 	int i;
-        char *t, c;
-        size_t len = 0, cap = 0;
-        static char *s;
-
-        free(s);
-        for (s = NULL, i = line1; i <= line2; i = nextln(i)) {
-                for (t = gettxt(i); (c = *t) != '\n'; ++t)
-                        s = addchar(*t, s, &cap, &len);
-        }
-
-        s = addchar('\n', s, &cap, &len);
-        s = addchar('\0', s, &cap, &len);
-        delete(line1, line2);
-        inject(s);
-        free(s);
+	char *t, c;
+	size_t len = 0, cap = 0;
+	char *s;
+
+	for (s = NULL, i = line1;; i = nextln(i)) {
+		for (t = gettxt(i); (c = *t) != '\n'; ++t)
+			s = addchar(*t, s, &cap, &len);
+		if (i == line2)
+			break;
+	}
 
+	s = addchar('\n', s, &cap, &len);
+	s = addchar('\0', s, &cap, &len);
+	delete(line1, line2);
+	inject(s, 1);
+	free(s);
 }
 
 static void
-- 
2.10.0

>From d274376cfc2254d097a842d854f9a1cd08f19c1f Mon Sep 17 00:00:00 2001
From: Thomas Mannay <audiobarr...@openmailbox.org>
Date: Thu, 6 Oct 2016 10:55:31 +0000
Subject: [PATCH 4/4] ed: wrote manpage

---
 ed.1 | 205 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 204 insertions(+), 1 deletion(-)

diff --git a/ed.1 b/ed.1
index 93e3012..c9f8a68 100644
--- a/ed.1
+++ b/ed.1
@@ -6,4 +6,207 @@
 .Nd text editor
 .Sh SYNOPSIS
 .Nm
-is the standard text editor.
+.Op Fl s
+.Op Fl p Ar string
+.Op Ar file
+.Sh DESCRIPTION
+.Nm
+is the standard text editor. It performs line-oriented operations on a buffer;
+The buffer's contents are manipulated in command mode and text is written to the
+buffer in input mode. Command mode is the default. To exit input mode enter a
+dot ('.') on a line of its own.
+
+If
+.Nm
+is invoked with a file as an argument, it will simulate an edit command and read
+the file's contents into a buffer. Changes to this buffer are local to
+.Nm
+until a write command is given.
+
+.Nm
+uses the basic regular expression syntax and allows any character but space and
+newline to be used as a delimiter in regular expressions.
+.Sh OPTIONS
+.Bl -tag -width Ds
+.It Fl s
+Suppress diagnostic messages
+.It Fl p Ar string
+Use
+.Ar string
+as a prompt when in command mode
+.El
+.Sh EXTENDED DESCRIPTION
+.Ss Addresses
+Commands operate on addresses. Addresses are used to refer to lines
+within the buffer. Address ranges may have spaces before and after the separator.
+Unless otherwise specified, 0 is an invalid address. The following symbols are
+valid addresses:
+.Bl -tag -width Ds
+.It n
+The nth line.
+.It .
+The current line, or "dot".
+.It $
+The last line.
+.It +
+The next line.
+.It +n
+The nth next line.
+.It ^ or -
+The previous line.
+.It ^n or -n
+The nth previous line.
+.It x,y
+The range of lines from x to y. The default value of x is 1, and the default
+value of y is $.
+.It x;y
+As above, except that the current line is set to x. Omitting x in this case uses
+the current line as the default value.
+.It /re/
+The next line matching re.
+.It ?re?
+The last line matching re.
+.It 'c
+The line marked by c. See k below.
+.El
+.Ss Commands.
+.Nm
+expects to see one command per line, with the following exception: commands may
+be suffixed with either a list, number, or print command. These suffixed
+commands are run after the command they're suffixed to has executed.
+
+The following is the list of commands that
+.Nm
+knows about. The parentheses contain the default addresses that a command uses.
+.Bl -tag -width Ds
+.It (.)a
+Append text after the addressed line. The dot is set to the last line
+entered. If no text was entered, the dot is set to the addressed line. An
+address of 0 appends to the start of the buffer.
+.It (.,.)c
+Delete the addressed lines and then accept input to replace them. The dot
+is set to the last line entered. If no text was entered, the dot is set to
+the line before the deleted lines.
+.It (.,.)d
+Delete the addressed lines. If there is a line after the deleted range, the
+dot is set to it. Otherwise, the dot is set to the line before the deleted range.
+.It e Ar file
+Delete the contents of the buffer and load in
+.Ar file
+for editing, printing the bytes read to standard output. If no filename is
+given,
+.Nm
+uses the currently remembered filename. The remembered filename is set to
+.Ar file
+for later use.
+.It E Ar file
+As above, but without warning if the current buffer has unsaved changes.
+.It f Ar file
+Set the currently remembered filename to
+.Ar
+file
+, or print the currently remembered filename if
+.Ar
+file is omitted.
+.It (1,$)g/re/command
+Apply command to lines matching re. The dot is set to the matching line before
+command is executed. When each matching line has been operated on, the dot is
+set to the last line operated on. If no lines match then the dot remains
+unchanged. The command used may not be g, G, v, or V.
+.It (1,$)G/re/
+Interactively edit the range of line addresses that match re. The dot is set to
+the matching line and printed before a command is input. When each matching line
+has been operated on, the dot is set to the last line operated on. If no lines
+match then the dot remains unchanged. The command used may not be a, c, i, g,
+G, v, or V.
+.It h
+Print the reason for the most recent error.
+.It H
+Toggle error explanations. If on, the above behaviour is produced on all
+subsequent errors.
+.It (.)i
+Insert text into the buffer before the addressed line. The dot is set to the
+last line entered. If no text was entered, the dot is set to the addressed line
+.It (.,.+1)j
+Join two lines together. If only one address is given, nothing happens. The dot
+is set to the newly joined line.
+.It (.)kc
+Mark the line with the lower case character c. The dot is unchanged.
+.It (.,.)l
+Unambiguously print the addressed lines. The dot is set to the last line written.
+.It (.,.)m(.)
+Move lines in the buffer to the line address on the right hand side. An address
+of 0 on the right hand side moves to the start of the buffer. The dot is set to
+the last line moved.
+.It (.,.)n
+Print the addressed lines and their numbers. The dot is set to the last line
+printed.
+.It (.,.)p
+Print the addressed lines. The dot is set to the last line printed.
+.It P
+Toggle the prompt. Defaults to off, but is switched on if the -p flag is used.
+.It q
+Quit
+.Nm
+, warning if there are unsaved changes.
+.It Q
+As above, but without warning if the current buffer has unsaved changes.
+.It ($)r Ar file
+Read in
+.Ar file
+and append it to the current buffer, printing the bytes read to standard output.
+The currently remembered filename isn't changed unless it's empty. An address of
+0 reads the file into the start of the buffer.
+.It (.,.)s/re/replacement/flags
+Substitute re for replacement in lines matching re. An & within replacement is
+replaced with the whole string matched by re. Backrefs can be used with the form
+\\n, where n is a positive non-zero integer. When % is the only character in
+replacement, it is substituted for the replacement string from the last
+substitute command. If a newline is part of replacement then the matched string
+is split into two lines; this cannot be done as part of a g or v command. If
+flags contains an integer n, then the nth match is replaced. If flags contains
+g, all matches are replaced. The dot is set to the last line matched.
+.It (.,.)t(.)
+As m, but copying instead of moving. The dot is set to the last line added.
+.It u
+Undo the last change. The dot is set to whatever it was before the undone
+command was performed.
+.It (1.$)v/re/command
+As with g, but operating on lines that don't match re.
+.It (1.$)V/re/
+As with G, but operating on lines that don't match re.
+.It (1,$)w Ar file
+Write the addressed lines to
+.Ar file
+, overwriting its previous contents if the file exists, and print the number of
+bytes written. If no filename is given the currently remembered filename will be
+used instead. The dot is unchanged.
+.It (1,$)W Ar file
+As above, but instead of overwriting the contents of
+.Ar file
+the addressed lines are appended to
+.Ar file
+instead.
+.It (.+1)\\n
+Print the addressed line. Sets the dot to that line.
+.It ($)=
+Print the line number of the addressed line. The dot is unchanged.
+.It &
+Repeat the last command.
+.It ! Ar command
+Execute
+.Ar command
+using sh. If the first character of
+.Ar command
+is '!' then it is replaced with the text of the previous command. An unescaped %
+is replaced with the currently remembered filename. ! does not process escape
+characters. When
+.Ar command
+returns a '!' is printed. The dot is unchanged.
+.El
+.Sh STANDARDS
+g and v operate on single commands rather than lists delimited with '\\'.
+e, E, r, w, and W commands cannot accept shell escapes.
+.Sh SEE ALSO
+.Xr sed 1
+.Xr regexp 3
-- 
2.10.0

Reply via email to