#include "sh.h"
RCSID("$tcsh: tc.prompt.c,v 3.67 2006/11/17 16:26:58 christos Exp $")
#include "ed.h"
#include "tw.h"
static const char *month_list[12];
static const char *day_list[7];
void
dateinit(void)
{
#ifdef notyet
int i;
setlocale(LC_TIME, "");
for (i = 0; i < 12; i++)
xfree((ptr_t) month_list[i]);
month_list[0] = strsave(_time_info->abbrev_month[0]);
month_list[1] = strsave(_time_info->abbrev_month[1]);
month_list[2] = strsave(_time_info->abbrev_month[2]);
month_list[3] = strsave(_time_info->abbrev_month[3]);
month_list[4] = strsave(_time_info->abbrev_month[4]);
month_list[5] = strsave(_time_info->abbrev_month[5]);
month_list[6] = strsave(_time_info->abbrev_month[6]);
month_list[7] = strsave(_time_info->abbrev_month[7]);
month_list[8] = strsave(_time_info->abbrev_month[8]);
month_list[9] = strsave(_time_info->abbrev_month[9]);
month_list[10] = strsave(_time_info->abbrev_month[10]);
month_list[11] = strsave(_time_info->abbrev_month[11]);
for (i = 0; i < 7; i++)
xfree((ptr_t) day_list[i]);
day_list[0] = strsave(_time_info->abbrev_wkday[0]);
day_list[1] = strsave(_time_info->abbrev_wkday[1]);
day_list[2] = strsave(_time_info->abbrev_wkday[2]);
day_list[3] = strsave(_time_info->abbrev_wkday[3]);
day_list[4] = strsave(_time_info->abbrev_wkday[4]);
day_list[5] = strsave(_time_info->abbrev_wkday[5]);
day_list[6] = strsave(_time_info->abbrev_wkday[6]);
#else
month_list[0] = "Jan";
month_list[1] = "Feb";
month_list[2] = "Mar";
month_list[3] = "Apr";
month_list[4] = "May";
month_list[5] = "Jun";
month_list[6] = "Jul";
month_list[7] = "Aug";
month_list[8] = "Sep";
month_list[9] = "Oct";
month_list[10] = "Nov";
month_list[11] = "Dec";
day_list[0] = "Sun";
day_list[1] = "Mon";
day_list[2] = "Tue";
day_list[3] = "Wed";
day_list[4] = "Thu";
day_list[5] = "Fri";
day_list[6] = "Sat";
#endif
}
void
printprompt(int promptno, const char *str)
{
static const Char *ocp = NULL;
static const char *ostr = NULL;
time_t lclock = time(NULL);
const Char *cp;
switch (promptno) {
default:
case 0:
cp = varval(STRprompt);
break;
case 1:
cp = varval(STRprompt2);
break;
case 2:
cp = varval(STRprompt3);
break;
case 3:
if (ocp != NULL) {
cp = ocp;
str = ostr;
}
else
cp = varval(STRprompt);
break;
}
if (promptno < 2) {
ocp = cp;
ostr = str;
}
xfree(Prompt);
Prompt = NULL;
Prompt = tprintf(FMT_PROMPT, cp, str, lclock, NULL);
if (!editing) {
for (cp = Prompt; *cp ; )
(void) putwraw(*cp++);
SetAttributes(0);
flush();
}
xfree(RPrompt);
RPrompt = NULL;
if (promptno == 0) {
cp = varval(STRrprompt);
RPrompt = tprintf(FMT_PROMPT, cp, NULL, lclock, NULL);
if (!editing && RPrompt[0] != '\0') {
for (cp = RPrompt; *cp ; )
(void) putwraw(*cp++);
SetAttributes(0);
putraw(' ');
flush();
}
}
}
static void
tprintf_append_mbs(struct Strbuf *buf, const char *mbs, Char attributes)
{
while (*mbs != 0) {
Char wc;
mbs += one_mbtowc(&wc, mbs, MB_LEN_MAX);
Strbuf_append1(buf, wc | attributes);
}
}
Char *
tprintf(int what, const Char *fmt, const char *str, time_t tim, ptr_t info)
{
struct Strbuf buf = Strbuf_INIT;
Char *z, *q;
Char attributes = 0;
static int print_prompt_did_ding = 0;
char *cz;
Char *p;
const Char *cp = fmt;
Char Scp;
struct tm *t = localtime(&tim);
static Char *olduser = NULL;
int updirs;
size_t pdirs;
cleanup_push(&buf, Strbuf_cleanup);
for (; *cp; cp++) {
if ((*cp == '%') && ! (cp[1] == '\0')) {
cp++;
switch (*cp) {
case 'R':
if (what == FMT_HISTORY) {
cz = fmthist('R', info);
tprintf_append_mbs(&buf, cz, attributes);
xfree(cz);
} else {
if (str != NULL)
tprintf_append_mbs(&buf, str, attributes);
}
break;
case '#':
Strbuf_append1(&buf,
attributes | ((uid == 0) ? PRCHROOT : PRCH));
break;
case '!':
case 'h':
switch (what) {
case FMT_HISTORY:
cz = fmthist('h', info);
break;
case FMT_SCHED:
cz = xasprintf("%d", *(int *)info);
break;
default:
cz = xasprintf("%d", eventno + 1);
break;
}
tprintf_append_mbs(&buf, cz, attributes);
xfree(cz);
break;
case 'T':
case '@':
case 't':
case 'p':
case 'P':
{
char ampm = 'a';
int hr = t->tm_hour;
if (adrof(STRampm) || (*cp != 'T' && *cp != 'P')) {
if (hr >= 12) {
if (hr > 12)
hr -= 12;
ampm = 'p';
}
else if (hr == 0)
hr = 12;
}
if (t->tm_min || print_prompt_did_ding ||
what != FMT_PROMPT || adrof(STRnoding)) {
if (t->tm_min)
print_prompt_did_ding = 0;
p = Itoa(hr, adrof(STRpadhour) ? 2 : 0, attributes);
Strbuf_append(&buf, p);
xfree(p);
Strbuf_append1(&buf, attributes | ':');
p = Itoa(t->tm_min, 2, attributes);
Strbuf_append(&buf, p);
xfree(p);
if (*cp == 'p' || *cp == 'P') {
Strbuf_append1(&buf, attributes | ':');
p = Itoa(t->tm_sec, 2, attributes);
Strbuf_append(&buf, p);
xfree(p);
}
if (adrof(STRampm) || (*cp != 'T' && *cp != 'P')) {
Strbuf_append1(&buf, attributes | ampm);
Strbuf_append1(&buf, attributes | 'm');
}
}
else {
size_t i;
for (i = 0; STRDING[i] != 0; i++)
Strbuf_append1(&buf, attributes | STRDING[i]);
print_prompt_did_ding = 1;
}
}
break;
case 'M':
#ifndef HAVENOUTMP
if (what == FMT_WHO)
cz = who_info(info, 'M');
else
#endif
cz = getenv("HOST");
if (cz != NULL)
tprintf_append_mbs(&buf, cz, attributes);
if (what == FMT_WHO)
xfree(cz);
break;
case 'm': {
char *scz = NULL;
#ifndef HAVENOUTMP
if (what == FMT_WHO)
scz = cz = who_info(info, 'm');
else
#endif
cz = getenv("HOST");
if (cz != NULL)
while (*cz != 0 && (what == FMT_WHO || *cz != '.')) {
Char wc;
cz += one_mbtowc(&wc, cz, MB_LEN_MAX);
Strbuf_append1(&buf, wc | attributes);
}
if (scz)
xfree(scz);
break;
}
case '~':
case '/':
case '.':
case 'c':
case 'C':
Scp = *cp;
if (Scp == 'c')
Scp = '.';
if ((z = varval(STRcwd)) == STRNULL)
break;
if (Scp == '~' || Scp == '.' ) {
static Char *olddir = NULL;
if (tlength == 0 || olddir != z) {
olddir = z;
olduser = getusername(&olddir);
}
if (olduser)
z = olddir;
}
updirs = pdirs = 0;
if (Scp == '.' || Scp == 'C') {
int skip;
#ifdef WINNT_NATIVE
Char *oldz = z;
if (z[1] == ':') {
Strbuf_append1(&buf, attributes | *z++);
Strbuf_append1(&buf, attributes | *z++);
}
if (*z == '/' && z[1] == '/') {
Strbuf_append1(&buf, attributes | *z++);
Strbuf_append1(&buf, attributes | *z++);
do {
Strbuf_append1(&buf, attributes | *z++);
} while(*z != '/');
}
#endif
q = z;
while (*z)
if (*z++ == '/')
updirs++;
#ifdef WINNT_NATIVE
if (oldz[0] == '/' && oldz[1] == '/' && updirs > 1)
Strbuf_append1(&buf, attributes | ':');
#endif
if ((Scp == 'C' && *q != '/'))
updirs++;
if (cp[1] == '0') {
pdirs = 1;
cp++;
}
if (cp[1] >= '1' && cp[1] <= '9') {
skip = cp[1] - '0';
cp++;
}
else
skip = 1;
updirs -= skip;
while (skip-- > 0) {
while ((z > q) && (*z != '/'))
z--;
if (skip && z > q)
z--;
}
if (*z == '/' && z != q)
z++;
}
if ((olduser) && ((Scp == '~') ||
(Scp == '.' && (pdirs || (!pdirs && updirs <= 0))) )) {
Strbuf_append1(&buf, attributes | '~');
for (q = olduser; *q; q++)
Strbuf_append1(&buf, attributes | *q);
}
if (updirs > 0 && pdirs) {
if (adrof(STRellipsis)) {
Strbuf_append1(&buf, attributes | '.');
Strbuf_append1(&buf, attributes | '.');
Strbuf_append1(&buf, attributes | '.');
} else {
Strbuf_append1(&buf, attributes | '/');
Strbuf_append1(&buf, attributes | '<');
if (updirs > 9) {
Strbuf_append1(&buf, attributes | '9');
Strbuf_append1(&buf, attributes | '+');
} else
Strbuf_append1(&buf, attributes | ('0' + updirs));
Strbuf_append1(&buf, attributes | '>');
}
}
while (*z)
Strbuf_append1(&buf, attributes | *z++);
break;
case 'n':
#ifndef HAVENOUTMP
if (what == FMT_WHO) {
cz = who_info(info, 'n');
tprintf_append_mbs(&buf, cz, attributes);
xfree(cz);
}
else
#endif
{
if ((z = varval(STRuser)) != STRNULL)
while (*z)
Strbuf_append1(&buf, attributes | *z++);
}
break;
case 'l':
#ifndef HAVENOUTMP
if (what == FMT_WHO) {
cz = who_info(info, 'l');
tprintf_append_mbs(&buf, cz, attributes);
xfree(cz);
}
else
#endif
{
if ((z = varval(STRtty)) != STRNULL)
while (*z)
Strbuf_append1(&buf, attributes | *z++);
}
break;
case 'd':
tprintf_append_mbs(&buf, day_list[t->tm_wday], attributes);
break;
case 'D':
p = Itoa(t->tm_mday, 2, attributes);
Strbuf_append(&buf, p);
xfree(p);
break;
case 'w':
tprintf_append_mbs(&buf, month_list[t->tm_mon], attributes);
break;
case 'W':
p = Itoa(t->tm_mon + 1, 2, attributes);
Strbuf_append(&buf, p);
xfree(p);
break;
case 'y':
p = Itoa(t->tm_year % 100, 2, attributes);
Strbuf_append(&buf, p);
xfree(p);
break;
case 'Y':
p = Itoa(t->tm_year + 1900, 4, attributes);
Strbuf_append(&buf, p);
xfree(p);
break;
case 'S':
attributes |= STANDOUT;
break;
case 'B':
attributes |= BOLD;
break;
case 'U':
attributes |= UNDER;
break;
case 's':
attributes &= ~STANDOUT;
break;
case 'b':
attributes &= ~BOLD;
break;
case 'u':
attributes &= ~UNDER;
break;
case 'L':
ClearToBottom();
break;
case 'j':
{
int njobs = -1;
struct process *pp;
for (pp = proclist.p_next; pp; pp = pp->p_next)
njobs++;
p = Itoa(njobs, 1, attributes);
Strbuf_append(&buf, p);
xfree(p);
break;
}
case '?':
if ((z = varval(STRstatus)) != STRNULL)
while (*z)
Strbuf_append1(&buf, attributes | *z++);
break;
case '$':
expdollar(&buf, &cp, attributes);
cp--;
break;
case '%':
Strbuf_append1(&buf, attributes | '%');
break;
case '{':
#if LITERAL == 0
while (*cp != '\0' && (cp[-1] != '%' || *cp != '}'))
cp++;
#endif
attributes |= LITERAL;
break;
case '}':
attributes &= ~LITERAL;
break;
default:
#ifndef HAVENOUTMP
if (*cp == 'a' && what == FMT_WHO) {
cz = who_info(info, 'a');
tprintf_append_mbs(&buf, cz, attributes);
xfree(cz);
}
else
#endif
{
Strbuf_append1(&buf, attributes | '%');
Strbuf_append1(&buf, attributes | *cp);
}
break;
}
}
else if (*cp == '\\' || *cp == '^')
Strbuf_append1(&buf, attributes | parseescape(&cp));
else if (*cp == HIST) {
if (what == FMT_HISTORY)
cz = fmthist('h', info);
else
cz = xasprintf("%d", eventno + 1);
tprintf_append_mbs(&buf, cz, attributes);
xfree(cz);
}
else
Strbuf_append1(&buf, attributes | *cp);
}
cleanup_ignore(&buf);
cleanup_until(&buf);
return Strbuf_finish(&buf);
}
int
expdollar(struct Strbuf *buf, const Char **srcp, Char attr)
{
struct varent *vp;
const Char *src = *srcp;
Char *var, *val;
size_t i;
int curly = 0;
var = xmalloc((Strlen(src) + 1) * sizeof (*var));
for (i = 0; ; i++) {
var[i] = *++src & TRIM;
if (i == 0 && var[i] == '{') {
curly = 1;
var[i] = *++src & TRIM;
}
if (!alnum(var[i]) && var[i] != '_') {
var[i] = '\0';
break;
}
}
if (curly && (*src & TRIM) == '}')
src++;
vp = adrof(var);
if (vp && vp->vec) {
for (i = 0; vp->vec[i] != NULL; i++) {
for (val = vp->vec[i]; *val; val++)
if (*val != '\n' && *val != '\r')
Strbuf_append1(buf, *val | attr);
if (vp->vec[i+1])
Strbuf_append1(buf, ' ' | attr);
}
}
else {
val = (!vp) ? tgetenv(var) : NULL;
if (val) {
for (; *val; val++)
if (*val != '\n' && *val != '\r')
Strbuf_append1(buf, *val | attr);
} else {
*srcp = src;
xfree(var);
return 0;
}
}
*srcp = src;
xfree(var);
return 1;
}