summaryrefslogtreecommitdiffstats
path: root/contrib/tcsh/tc.prompt.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/tcsh/tc.prompt.c')
-rw-r--r--contrib/tcsh/tc.prompt.c657
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;
+}
OpenPOWER on IntegriCloud