Subject: bin/16226: Prompt expansion for /bin/sh
To: None <gnats-bugs@gnats.netbsd.org>
From: None <slink@unixbsd.org>
List: netbsd-bugs
Date: 04/07/2002 16:16:09
>Number:         16226
>Category:       bin
>Synopsis:       Prompt expansion for /bin/sh
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Sun Apr 07 07:16:00 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator:     Julio Merino
>Release:        NetBSD 1.5ZC
>Organization:
HispaBSD
>Environment:
	
	
System: NetBSD darkstar 1.5ZC NetBSD 1.5ZC (DARKSTAR) #3: Sat Apr 6 17:36:25 CEST 2002 root@darkstar:/home/archive/NetBSD/src/sys/arch/i386/compile/DARKSTAR i386
Architecture: i386
Machine: i386
>Description:
	I've added support to /bin/sh for macro expansion in the prompt.
	It recognizes some simple macros like '%m' or '%w' which are
	expanded to the hostname and working directory. The syntax is
	similar to the one found in the zsh shell.

	The attached patch adds this feature to sh's code and modifies the
	manpage with information about this new functionality.
>How-To-Repeat:
	
>Fix:
Index: parser.c
===================================================================
RCS file: /cvsroot/basesrc/bin/sh/parser.c,v
retrieving revision 1.52
diff -u -u -r1.52 parser.c
--- parser.c	2002/02/20 21:42:35	1.52
+++ parser.c	2002/04/07 14:06:42
@@ -46,6 +46,9 @@
 #endif /* not lint */
 
 #include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/param.h>
 
 #include "shell.h"
 #include "parser.h"
@@ -121,6 +124,8 @@
 STATIC void synexpect __P((int)) __attribute__((noreturn));
 STATIC void synerror __P((const char *)) __attribute__((noreturn));
 STATIC void setprompt __P((int));
+STATIC const char *expandprompt __P((const char *));
+STATIC void strappend __P((char **, const char *));
 
 
 /*
@@ -1608,6 +1613,74 @@
 }
 
 /*
+ * Used by expandprompt, this function appends str2 to str1 doing
+ * a realloc of the first string to the total size.
+ */
+STATIC void strappend(char **str1, const char *str2)
+{
+	*str1 = (char*) realloc(*str1, strlen(*str1) + strlen(str2) + 1);
+	strcat(*str1, str2);
+}
+
+/*
+ * Search variables for expansion in the prompt, passed to the str
+ * variable. The prompt with variables expanded is returned by
+ * the function.
+ */
+STATIC const char *
+expandprompt(const char *str)
+{
+	/* Prompt to return */
+	char *ret;
+	/* Some temporary strings to do parsing */
+	char chartostr[2];
+	char hosttostr[MAXHOSTNAMELEN + 1];
+	char *tmp;
+
+	ret = (char*) malloc(1);
+	*ret = '\0';
+	chartostr[1] = '\0';
+
+	while (*str != '\0') {
+		switch (*str) {
+		case '%': /* Option parsing */
+			++str;
+			switch (*str) {
+			case 'w': /* Current working directory */
+				tmp = getcwd(NULL, 0);
+				strappend(&ret, tmp);
+				free(tmp);
+				break;
+			case 'm': /* Hostname, without domain */
+				gethostname(hosttostr, MAXHOSTNAMELEN);
+				strappend(&ret, hosttostr);
+				break;
+			case '#': /* % for user, # for root */
+				if (geteuid())
+					strappend(&ret, "%");
+				else
+					strappend(&ret, "#");
+				break;
+			default: /* Unknown options */
+				goto singlechar;
+				/* NOTREACHED */
+			}
+			break;
+
+		default:
+singlechar:
+			chartostr[0] = *str;
+			strappend(&ret, chartostr);
+			break;
+		}
+		++str;
+	}
+
+	ret[strlen(ret)] = '\0';
+	return ret;
+}
+
+/*
  * called by editline -- any expansions to the prompt
  *    should be added here.
  */
@@ -1618,9 +1691,9 @@
 	case 0:
 		return "";
 	case 1:
-		return ps1val();
+		return expandprompt(ps1val());
 	case 2:
-		return ps2val();
+		return expandprompt(ps2val());
 	default:
 		return "<internal prompt error>";
 	}
Index: sh.1
===================================================================
RCS file: /cvsroot/basesrc/bin/sh/sh.1,v
retrieving revision 1.46
diff -u -u -r1.46 sh.1
--- sh.1	2002/02/24 21:41:52	1.46
+++ sh.1	2002/04/07 14:06:50
@@ -960,6 +960,17 @@
 patterns used for both Pathname Expansion and the
 .Ic case
 command.
+.Ss Prompt Expansion
+Prompt variables are subject to a special expansion. The following macros
+are recognized and are replaced each time the prompt is shown.
+.Bl -tag -width 5n
+.It \fB%%\fP
+A `\fB%\fP'\&.
+.It \fB%w\fP
+Present working directory (\fB$PWD\fP)\&.
+.It \fB%m\fP
+The hostname up to the first `\fB\&.\fP'\&.
+.El
 .Ss Shell Patterns
 A pattern consists of normal characters, which match themselves,
 and meta-characters.   The meta-characters are
>Release-Note:
>Audit-Trail:
>Unformatted: