diff options
Diffstat (limited to 'contrib/tcsh/tc.prompt.c')
-rw-r--r-- | contrib/tcsh/tc.prompt.c | 657 |
1 files changed, 657 insertions, 0 deletions
diff --git a/contrib/tcsh/tc.prompt.c b/contrib/tcsh/tc.prompt.c new file mode 100644 index 0000000..2ac2355 --- /dev/null +++ b/contrib/tcsh/tc.prompt.c @@ -0,0 +1,657 @@ +/* $Header: /p/tcsh/cvsroot/tcsh/tc.prompt.c,v 3.70 2011/10/27 22:41:06 christos Exp $ */ +/* + * tc.prompt.c: Prompt printing stuff + */ +/*- + * Copyright (c) 1980, 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "sh.h" + +RCSID("$tcsh: tc.prompt.c,v 3.70 2011/10/27 22:41:06 christos Exp $") + +#include "ed.h" +#include "tw.h" + +/* + * kfk 21oct1983 -- add @ (time) and / ($cwd) in prompt. + * PWP 4/27/87 -- rearange for tcsh. + * mrdch@com.tau.edu.il 6/26/89 - added ~, T and .# - rearanged to switch() + * instead of if/elseif + * Luke Mewburn, <lukem@cs.rmit.edu.au> + * 6-Sep-91 changed date format + * 16-Feb-94 rewrote directory prompt code, added $ellipsis + * 29-Dec-96 added rprompt support + */ + +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) { /* determine rprompt if using main prompt */ + cp = varval(STRrprompt); + RPrompt = tprintf(FMT_PROMPT, cp, NULL, lclock, NULL); + /* if not editing, put rprompt after prompt */ + 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); + + /* prompt stuff */ + 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 '#': + Scp = (uid == 0 || euid == 0) ? PRCHROOT : PRCH; + if (Scp != '\0') + Strbuf_append1(&buf, attributes | Scp); + 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': /* 24 hour format */ + case '@': + case 't': /* 12 hour am/pm format */ + case 'p': /* With seconds */ + case 'P': + { + char ampm = 'a'; + int hr = t->tm_hour; + + /* addition by Hans J. Albertsson */ + /* and another adapted from Justin Bur */ + if (adrof(STRampm) || (*cp != 'T' && *cp != 'P')) { + if (hr >= 12) { + if (hr > 12) + hr -= 12; + ampm = 'p'; + } + else if (hr == 0) + hr = 12; + } /* else do a 24 hour clock */ + + /* "DING!" stuff by Hans also */ + if (t->tm_min || print_prompt_did_ding || + what != FMT_PROMPT || adrof(STRnoding)) { + if (t->tm_min) + print_prompt_did_ding = 0; + /* + * Pad hour to 2 characters if padhour is set, + * by ADAM David Alan Martin + */ + 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 { /* we need to ding */ + 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 /* HAVENOUTMP */ + cz = getenv("HOST"); + /* + * Bug pointed out by Laurent Dami <dami@cui.unige.ch>: don't + * derefrence that NULL (if HOST is not set)... + */ + 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 /* HAVENOUTMP */ + 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; + } + + /* lukem: new directory prompt code */ + case '~': + case '/': + case '.': + case 'c': + case 'C': + Scp = *cp; + if (Scp == 'c') /* store format type (c == .) */ + Scp = '.'; + if ((z = varval(STRcwd)) == STRNULL) + break; /* no cwd, so don't do anything */ + + /* show ~ whenever possible - a la dirs */ + if (Scp == '~' || Scp == '.' ) { + static Char *olddir = NULL; + + if (tlength == 0 || olddir != z) { + olddir = z; /* have we changed dir? */ + olduser = getusername(&olddir); + } + if (olduser) + z = olddir; + } + updirs = pdirs = 0; + + /* option to determine fixed # of dirs from path */ + 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 /* WINNT_NATIVE */ + q = z; + while (*z) /* calc # of /'s */ + if (*z++ == '/') + updirs++; + +#ifdef WINNT_NATIVE + /* + * for format type c, prompt will be following... + * c:/path => c:/path + * c:/path/to => c:to + * //machine/share => //machine/share + * //machine/share/folder => //machine:folder + */ + if (oldz[0] == '/' && oldz[1] == '/' && updirs > 1) + Strbuf_append1(&buf, attributes | ':'); +#endif /* WINNT_NATIVE */ + if ((Scp == 'C' && *q != '/')) + updirs++; + + if (cp[1] == '0') { /* print <x> or ... */ + pdirs = 1; + cp++; + } + if (cp[1] >= '1' && cp[1] <= '9') { /* calc # to skip */ + skip = cp[1] - '0'; + cp++; + } + else + skip = 1; + + updirs -= skip; + while (skip-- > 0) { + while ((z > q) && (*z != '/')) + z--; /* back up */ + if (skip && z > q) + z--; + } + if (*z == '/' && z != q) + z++; + } /* . || C */ + + /* print ~[user] */ + if ((olduser) && ((Scp == '~') || + (Scp == '.' && (pdirs || (!pdirs && updirs <= 0))) )) { + Strbuf_append1(&buf, attributes | '~'); + for (q = olduser; *q; q++) + Strbuf_append1(&buf, attributes | *q); + } + + /* RWM - tell you how many dirs we've ignored */ + /* and add '/' at front of this */ + 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; + /* lukem: end of new directory prompt code */ + + case 'n': +#ifndef HAVENOUTMP + if (what == FMT_WHO) { + cz = who_info(info, 'n'); + tprintf_append_mbs(&buf, cz, attributes); + xfree(cz); + } + else +#endif /* HAVENOUTMP */ + { + if ((z = varval(STRuser)) != STRNULL) + while (*z) + Strbuf_append1(&buf, attributes | *z++); + } + break; + case 'N': + if ((z = varval(STReuser)) != 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 /* HAVENOUTMP */ + { + 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': /* start standout */ + attributes |= STANDOUT; + break; + case 'B': /* start bold */ + attributes |= BOLD; + break; + case 'U': /* start underline */ + attributes |= UNDER; + break; + case 's': /* end standout */ + attributes &= ~STANDOUT; + break; + case 'b': /* end bold */ + attributes &= ~BOLD; + break; + case 'u': /* end underline */ + 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++; + if (njobs == -1) + 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 should point the last char of current % sequence */ + cp--; + break; + case '%': + Strbuf_append1(&buf, attributes | '%'); + break; + case '{': /* literal characters start */ +#if LITERAL == 0 + /* + * No literal capability, so skip all chars in the literal + * string + */ + while (*cp != '\0' && (cp[-1] != '%' || *cp != '}')) + cp++; +#endif /* LITERAL == 0 */ + attributes |= LITERAL; + break; + case '}': /* literal characters end */ + 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 /* HAVENOUTMP */ + { + Strbuf_append1(&buf, attributes | '%'); + Strbuf_append1(&buf, attributes | *cp); + } + break; + } + } + else if (*cp == '\\' || *cp == '^') + Strbuf_append1(&buf, attributes | parseescape(&cp)); + else if (*cp == HIST) { /* EGS: handle '!'s in prompts */ + 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); /* normal character */ + } + 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; + + /* found a variable, expand it */ + 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; +} |