diff --git a/bin/sh/parser.c b/bin/sh/parser.c --- a/bin/sh/parser.c +++ b/bin/sh/parser.c @@ -43,6 +43,7 @@ #include #include #include +#include #include "shell.h" #include "parser.h" @@ -2100,6 +2101,49 @@ } break; + /* + * Print the current time as per provided strftime format. + */ + case 'D': { + char tfmt[128] = "%X"; /* \D{} means %X. */ + struct tm *now; + + if (fmt[1] != '{') { + /* + * "\D" but not "\D{", so treat the '\' + * literally and rewind fmt to treat 'D' + * literally next iteration. + */ + ps[i] = '\\'; + fmt--; + break; + } + fmt += 2; /* Consume "D{". */ + if (fmt[0] != '}') { + char *end; + + end = memccpy(tfmt, fmt, '}', sizeof(tfmt)); + if (end == NULL) { + /* + * Format too long or no '}', so + * ignore "\D{" altogether. + * The loop will do i++, but nothing + * was written to ps, so do i-- here. + * Rewind fmt for similar reason. + */ + i--; + fmt--; + break; + } + *--end = '\0'; /* Ignore the copy of '}'. */ + fmt += end - tfmt; + } + now = localtime(&(time_t){time(NULL)}); + i += strftime(&ps[i], PROMPTLEN - i - 1, tfmt, now); + i--; /* The loop will do i++. */ + break; + } + /* * Hostname. * diff --git a/bin/sh/sh.1 b/bin/sh/sh.1 --- a/bin/sh/sh.1 +++ b/bin/sh/sh.1 @@ -1427,6 +1427,16 @@ may include any of the following formatting sequences, which are replaced by the given information: .Bl -tag -width indent +.It Li \eD{format} +The current time in +.Xr strftime 3 +.Ar format . +The braces are required. +Empty +.Ar format +is equivalent to +\&%X, +national representation of the time. .It Li \eH This system's fully-qualified hostname (FQDN). .It Li \eh