sed 'y' command, simplify some other code
diff --git a/editors/sed.c b/editors/sed.c
index 292bc86..4c535b1 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -97,9 +97,10 @@
 	unsigned int sub_g:1; /* sed -e 's/foo/bar/g' (global) */
 	unsigned int sub_p:2; /* sed -e 's/foo/bar/p' (print substitution) */
 
-	/* GENERAL FIELDS */
-	char delimiter;	    /* The delimiter used to separate regexps */
+	/* TRANSLATE COMMAND */
+	char *translate;
 
+	/* GENERAL FIELDS */
 	/* the command */
 	char cmd; /* p,d,s (add more at your leisure :-) */
 
@@ -148,23 +149,23 @@
 }
 #endif
 
-
 /*
  * index_of_next_unescaped_regexp_delim - walks left to right through a string
  * beginning at a specified index and returns the index of the next regular
  * expression delimiter (typically a forward * slash ('/')) not preceeded by 
  * a backslash ('\').
  */
-static int index_of_next_unescaped_regexp_delim(const char delimiter, const char *str, int idx)
+static int index_of_next_unescaped_regexp_delim(const char delimiter, const char *str)
 {
 	int bracket = -1;
 	int escaped = 0;
+	int idx = 0;
 	char ch;
 
 	for ( ; (ch = str[idx]); idx++) {
 		if (bracket != -1) {
 			if (ch == ']' && !(bracket == idx - 1 ||
-									 (bracket == idx - 2 && str[idx-1] == '^')))
+					(bracket == idx - 2 && str[idx-1] == '^')))
 				bracket = -1;
 		} else if (escaped)
 			escaped = 0;
@@ -180,10 +181,43 @@
 	return -1;
 }
 
+static int parse_regex_delim(const char *cmdstr, char **match, char **replace)
+{
+	const char *cmdstr_ptr = cmdstr;
+	char delimiter;
+	int idx = 0;
+
+	/* verify that the 's' is followed by something.  That something
+	 * (typically a 'slash') is now our regexp delimiter... */
+	if (*cmdstr == '\0')
+		bb_error_msg_and_die("bad format in substitution expression");
+	else
+		delimiter = *cmdstr_ptr;
+
+	cmdstr_ptr++;
+
+	/* save the match string */
+	idx = index_of_next_unescaped_regexp_delim(delimiter, cmdstr_ptr);
+	if (idx == -1) {
+		bb_error_msg_and_die("bad format in substitution expression");
+	}
+	*match = bb_xstrndup(cmdstr_ptr, idx);
+
+	/* save the replacement string */
+	cmdstr_ptr += idx + 1;
+	idx = index_of_next_unescaped_regexp_delim(delimiter, cmdstr_ptr);
+	if (idx == -1) {
+		bb_error_msg_and_die("bad format in substitution expression");
+	}
+	*replace = bb_xstrndup(cmdstr_ptr, idx);
+
+	return((cmdstr_ptr - cmdstr) + idx);
+}
+
 /*
  * returns the index in the string just past where the address ends.
  */
-static int get_address(char *delimiter, char *my_str, int *linenum, regex_t **regex)
+static int get_address(char *my_str, int *linenum, regex_t **regex)
 {
 	int idx = 0;
 	if (isdigit(my_str[idx])) {
@@ -198,13 +232,15 @@
 	}
 	else if (my_str[idx] == '/' || my_str[idx] == '\\') {
 		int idx_start = 1;
+		char delimiter;
 
-		*delimiter = '/';
+		delimiter = '/';
 		if (my_str[idx] == '\\') {
 			idx_start++;
-			*delimiter = my_str[++idx];
+			delimiter = my_str[++idx];
 		}
-		idx = index_of_next_unescaped_regexp_delim(*delimiter, my_str, ++idx);
+		idx++;
+		idx += index_of_next_unescaped_regexp_delim(delimiter, my_str + idx);
 		if (idx == -1) {
 			bb_error_msg_and_die("unterminated match expression");
 		}
@@ -218,7 +254,6 @@
 
 static int parse_subst_cmd(sed_cmd_t * const sed_cmd, const char *substr)
 {
-	int oldidx;
 	int cflags = 0;
 	char *match;
 	int idx = 0;
@@ -233,19 +268,7 @@
 	 *    (all three of the '/' slashes are mandatory)
 	 */
 
-	/* verify that the 's' is followed by something.  That something
-	 * (typically a 'slash') is now our regexp delimiter... */
-	if (substr[idx] == '\0')
-		bb_error_msg_and_die("bad format in substitution expression");
-	else
-	    sed_cmd->delimiter=substr[idx];
-
-	/* save the match string */
-	oldidx = idx+1;
-	idx = index_of_next_unescaped_regexp_delim(sed_cmd->delimiter, substr, ++idx);
-	if (idx == -1)
-		bb_error_msg_and_die("bad format in substitution expression");
-	match = bb_xstrndup(substr + oldidx, idx - oldidx);
+	idx = parse_regex_delim(substr, &match, &sed_cmd->replace);
 
 	/* determine the number of back references in the match string */
 	/* Note: we compute this here rather than in the do_subst_command()
@@ -259,13 +282,6 @@
 			sed_cmd->num_backrefs++;
 	}
 
-	/* save the replacement string */
-	oldidx = idx+1;
-	idx = index_of_next_unescaped_regexp_delim(sed_cmd->delimiter, substr, ++idx);
-	if (idx == -1)
-		bb_error_msg_and_die("bad format in substitution expression");
-	sed_cmd->replace = bb_xstrndup(substr + oldidx, idx - oldidx);
-
 	/* process the flags */
 	while (substr[++idx]) {
 		switch (substr[idx]) {
@@ -297,6 +313,39 @@
 	return idx;
 }
 
+static void replace_slash_n(char *string)
+{
+	int i;
+	int remaining = strlen(string);
+
+	for (i = 0; string[i]; i++) {
+		if ((string[i] == '\\') && (string[i + 1] == 'n')) {
+			string[i] = '\n';
+			memmove(string + i + 1, string + i + 1, remaining - 1);
+		} else {
+			remaining--;
+		}
+	}
+}
+
+static int parse_translate_cmd(sed_cmd_t * const sed_cmd, const char *cmdstr)
+{
+	char *match;
+	char *replace;
+	int idx;
+	int i;
+
+	idx = parse_regex_delim(cmdstr, &match, &replace);
+	replace_slash_n(match);
+	replace_slash_n(replace);
+	sed_cmd->translate = xcalloc(1, (strlen(match) + 1) * 2);
+	for (i = 0; (match[i] != 0) && (replace[i] != 0); i++) {
+		sed_cmd->translate[i * 2] = match[i];
+		sed_cmd->translate[(i * 2) + 1] = replace[i];
+	}
+	return(idx);
+}
+
 static int parse_edit_cmd(sed_cmd_t *sed_cmd, const char *editstr)
 {
 	int i, j;
@@ -417,6 +466,10 @@
 		strncpy(sed_cmd->label, cmdstr, length);
         cmdstr += length;
 	}
+	/* translation command */
+	else if (sed_cmd->cmd == 'y') {
+		cmdstr += parse_translate_cmd(sed_cmd, cmdstr);
+	}
 	/* if it wasnt a single-letter command that takes no arguments
 	 * then it must be an invalid command.
 	 */
@@ -430,7 +483,6 @@
 
 static char *add_cmd(sed_cmd_t *sed_cmd, char *cmdstr)
 {
-
 	/* Skip over leading whitespace and semicolons */
 	cmdstr += strspn(cmdstr, semicolon_whitespace);
 
@@ -452,13 +504,13 @@
 	 */
 
 	/* first part (if present) is an address: either a '$', a number or a /regex/ */
-	cmdstr += get_address(&(sed_cmd->delimiter), cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match);
+	cmdstr += get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match);
 
 	/* second part (if present) will begin with a comma */
 	if (*cmdstr == ',') {
 		int idx;
 		cmdstr++;
-		idx = get_address(&(sed_cmd->delimiter), cmdstr, &sed_cmd->end_line, &sed_cmd->end_match);
+		idx = get_address(cmdstr, &sed_cmd->end_line, &sed_cmd->end_match);
 		if (idx == 0) {
 			bb_error_msg_and_die("get_address: no address found in string\n"
 				"\t(you probably didn't check the string you passed me)");
@@ -911,6 +963,18 @@
 							sed_cmd = branch_to(sed_cmd->label);
 						}
 						break;
+					case 'y': {
+							int i;
+							for (i = 0; line[i] != 0; i++) {
+								int j;
+								for (j = 0; sed_cmd->translate[j] ;j += 2) {
+									if (line[i] == sed_cmd->translate[j]) {
+										line[i] = sed_cmd->translate[j + 1];
+									}
+								}
+							}
+						}
+						break;
 //					case ':':
 //						break;
 				}