1 /* $Header: /p/tcsh/cvsroot/tcsh/tc.prompt.c,v 3.67 2006/11/17 16:26:58 christos Exp $ */
3 * tc.prompt.c: Prompt printing stuff
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 RCSID("$tcsh: tc.prompt.c,v 3.67 2006/11/17 16:26:58 christos Exp $")
41 * kfk 21oct1983 -- add @ (time) and / ($cwd) in prompt.
42 * PWP 4/27/87 -- rearange for tcsh.
43 * mrdch@com.tau.edu.il 6/26/89 - added ~, T and .# - rearanged to switch()
44 * instead of if/elseif
45 * Luke Mewburn, <lukem@cs.rmit.edu.au>
46 * 6-Sep-91 changed date format
47 * 16-Feb-94 rewrote directory prompt code, added $ellipsis
48 * 29-Dec-96 added rprompt support
51 static const char *month_list[12];
52 static const char *day_list[7];
60 setlocale(LC_TIME, "");
62 for (i = 0; i < 12; i++)
63 xfree((ptr_t) month_list[i]);
64 month_list[0] = strsave(_time_info->abbrev_month[0]);
65 month_list[1] = strsave(_time_info->abbrev_month[1]);
66 month_list[2] = strsave(_time_info->abbrev_month[2]);
67 month_list[3] = strsave(_time_info->abbrev_month[3]);
68 month_list[4] = strsave(_time_info->abbrev_month[4]);
69 month_list[5] = strsave(_time_info->abbrev_month[5]);
70 month_list[6] = strsave(_time_info->abbrev_month[6]);
71 month_list[7] = strsave(_time_info->abbrev_month[7]);
72 month_list[8] = strsave(_time_info->abbrev_month[8]);
73 month_list[9] = strsave(_time_info->abbrev_month[9]);
74 month_list[10] = strsave(_time_info->abbrev_month[10]);
75 month_list[11] = strsave(_time_info->abbrev_month[11]);
77 for (i = 0; i < 7; i++)
78 xfree((ptr_t) day_list[i]);
79 day_list[0] = strsave(_time_info->abbrev_wkday[0]);
80 day_list[1] = strsave(_time_info->abbrev_wkday[1]);
81 day_list[2] = strsave(_time_info->abbrev_wkday[2]);
82 day_list[3] = strsave(_time_info->abbrev_wkday[3]);
83 day_list[4] = strsave(_time_info->abbrev_wkday[4]);
84 day_list[5] = strsave(_time_info->abbrev_wkday[5]);
85 day_list[6] = strsave(_time_info->abbrev_wkday[6]);
87 month_list[0] = "Jan";
88 month_list[1] = "Feb";
89 month_list[2] = "Mar";
90 month_list[3] = "Apr";
91 month_list[4] = "May";
92 month_list[5] = "Jun";
93 month_list[6] = "Jul";
94 month_list[7] = "Aug";
95 month_list[8] = "Sep";
96 month_list[9] = "Oct";
97 month_list[10] = "Nov";
98 month_list[11] = "Dec";
111 printprompt(int promptno, const char *str)
113 static const Char *ocp = NULL;
114 static const char *ostr = NULL;
115 time_t lclock = time(NULL);
121 cp = varval(STRprompt);
124 cp = varval(STRprompt2);
127 cp = varval(STRprompt3);
135 cp = varval(STRprompt);
146 Prompt = tprintf(FMT_PROMPT, cp, str, lclock, NULL);
148 for (cp = Prompt; *cp ; )
149 (void) putwraw(*cp++);
156 if (promptno == 0) { /* determine rprompt if using main prompt */
157 cp = varval(STRrprompt);
158 RPrompt = tprintf(FMT_PROMPT, cp, NULL, lclock, NULL);
159 /* if not editing, put rprompt after prompt */
160 if (!editing && RPrompt[0] != '\0') {
161 for (cp = RPrompt; *cp ; )
162 (void) putwraw(*cp++);
171 tprintf_append_mbs(struct Strbuf *buf, const char *mbs, Char attributes)
176 mbs += one_mbtowc(&wc, mbs, MB_LEN_MAX);
177 Strbuf_append1(buf, wc | attributes);
182 tprintf(int what, const Char *fmt, const char *str, time_t tim, ptr_t info)
184 struct Strbuf buf = Strbuf_INIT;
187 static int print_prompt_did_ding = 0;
191 const Char *cp = fmt;
193 struct tm *t = localtime(&tim);
196 static Char *olduser = NULL;
200 cleanup_push(&buf, Strbuf_cleanup);
202 if ((*cp == '%') && ! (cp[1] == '\0')) {
206 if (what == FMT_HISTORY) {
207 cz = fmthist('R', info);
208 tprintf_append_mbs(&buf, cz, attributes);
212 tprintf_append_mbs(&buf, str, attributes);
217 attributes | ((uid == 0) ? PRCHROOT : PRCH));
223 cz = fmthist('h', info);
226 cz = xasprintf("%d", *(int *)info);
229 cz = xasprintf("%d", eventno + 1);
232 tprintf_append_mbs(&buf, cz, attributes);
235 case 'T': /* 24 hour format */
237 case 't': /* 12 hour am/pm format */
238 case 'p': /* With seconds */
244 /* addition by Hans J. Albertsson */
245 /* and another adapted from Justin Bur */
246 if (adrof(STRampm) || (*cp != 'T' && *cp != 'P')) {
254 } /* else do a 24 hour clock */
256 /* "DING!" stuff by Hans also */
257 if (t->tm_min || print_prompt_did_ding ||
258 what != FMT_PROMPT || adrof(STRnoding)) {
260 print_prompt_did_ding = 0;
262 * Pad hour to 2 characters if padhour is set,
263 * by ADAM David Alan Martin
265 p = Itoa(hr, adrof(STRpadhour) ? 2 : 0, attributes);
266 Strbuf_append(&buf, p);
268 Strbuf_append1(&buf, attributes | ':');
269 p = Itoa(t->tm_min, 2, attributes);
270 Strbuf_append(&buf, p);
272 if (*cp == 'p' || *cp == 'P') {
273 Strbuf_append1(&buf, attributes | ':');
274 p = Itoa(t->tm_sec, 2, attributes);
275 Strbuf_append(&buf, p);
278 if (adrof(STRampm) || (*cp != 'T' && *cp != 'P')) {
279 Strbuf_append1(&buf, attributes | ampm);
280 Strbuf_append1(&buf, attributes | 'm');
283 else { /* we need to ding */
286 for (i = 0; STRDING[i] != 0; i++)
287 Strbuf_append1(&buf, attributes | STRDING[i]);
288 print_prompt_did_ding = 1;
296 cz = who_info(info, 'M');
298 #endif /* HAVENOUTMP */
301 * Bug pointed out by Laurent Dami <dami@cui.unige.ch>: don't
302 * derefrence that NULL (if HOST is not set)...
305 tprintf_append_mbs(&buf, cz, attributes);
314 scz = cz = who_info(info, 'm');
316 #endif /* HAVENOUTMP */
320 while (*cz != 0 && (what == FMT_WHO || *cz != '.')) {
323 cz += one_mbtowc(&wc, cz, MB_LEN_MAX);
324 Strbuf_append1(&buf, wc | attributes);
331 /* lukem: new directory prompt code */
338 if (Scp == 'c') /* store format type (c == .) */
340 if ((z = varval(STRcwd)) == STRNULL)
341 break; /* no cwd, so don't do anything */
343 /* show ~ whenever possible - a la dirs */
344 if (Scp == '~' || Scp == '.' ) {
345 static Char *olddir = NULL;
347 if (tlength == 0 || olddir != z) {
348 olddir = z; /* have we changed dir? */
349 olduser = getusername(&olddir);
356 /* option to determine fixed # of dirs from path */
357 if (Scp == '.' || Scp == 'C') {
362 Strbuf_append1(&buf, attributes | *z++);
363 Strbuf_append1(&buf, attributes | *z++);
365 if (*z == '/' && z[1] == '/') {
366 Strbuf_append1(&buf, attributes | *z++);
367 Strbuf_append1(&buf, attributes | *z++);
369 Strbuf_append1(&buf, attributes | *z++);
372 #endif /* WINNT_NATIVE */
374 while (*z) /* calc # of /'s */
380 * for format type c, prompt will be following...
383 * //machine/share => //machine/share
384 * //machine/share/folder => //machine:folder
386 if (oldz[0] == '/' && oldz[1] == '/' && updirs > 1)
387 Strbuf_append1(&buf, attributes | ':');
388 #endif /* WINNT_NATIVE */
389 if ((Scp == 'C' && *q != '/'))
392 if (cp[1] == '0') { /* print <x> or ... */
396 if (cp[1] >= '1' && cp[1] <= '9') { /* calc # to skip */
405 while ((z > q) && (*z != '/'))
410 if (*z == '/' && z != q)
415 if ((olduser) && ((Scp == '~') ||
416 (Scp == '.' && (pdirs || (!pdirs && updirs <= 0))) )) {
417 Strbuf_append1(&buf, attributes | '~');
418 for (q = olduser; *q; q++)
419 Strbuf_append1(&buf, attributes | *q);
422 /* RWM - tell you how many dirs we've ignored */
423 /* and add '/' at front of this */
424 if (updirs > 0 && pdirs) {
425 if (adrof(STRellipsis)) {
426 Strbuf_append1(&buf, attributes | '.');
427 Strbuf_append1(&buf, attributes | '.');
428 Strbuf_append1(&buf, attributes | '.');
430 Strbuf_append1(&buf, attributes | '/');
431 Strbuf_append1(&buf, attributes | '<');
433 Strbuf_append1(&buf, attributes | '9');
434 Strbuf_append1(&buf, attributes | '+');
436 Strbuf_append1(&buf, attributes | ('0' + updirs));
437 Strbuf_append1(&buf, attributes | '>');
442 Strbuf_append1(&buf, attributes | *z++);
444 /* lukem: end of new directory prompt code */
448 if (what == FMT_WHO) {
449 cz = who_info(info, 'n');
450 tprintf_append_mbs(&buf, cz, attributes);
454 #endif /* HAVENOUTMP */
456 if ((z = varval(STRuser)) != STRNULL)
458 Strbuf_append1(&buf, attributes | *z++);
463 if (what == FMT_WHO) {
464 cz = who_info(info, 'l');
465 tprintf_append_mbs(&buf, cz, attributes);
469 #endif /* HAVENOUTMP */
471 if ((z = varval(STRtty)) != STRNULL)
473 Strbuf_append1(&buf, attributes | *z++);
477 tprintf_append_mbs(&buf, day_list[t->tm_wday], attributes);
480 p = Itoa(t->tm_mday, 2, attributes);
481 Strbuf_append(&buf, p);
485 tprintf_append_mbs(&buf, month_list[t->tm_mon], attributes);
488 p = Itoa(t->tm_mon + 1, 2, attributes);
489 Strbuf_append(&buf, p);
493 p = Itoa(t->tm_year % 100, 2, attributes);
494 Strbuf_append(&buf, p);
498 p = Itoa(t->tm_year + 1900, 4, attributes);
499 Strbuf_append(&buf, p);
502 case 'S': /* start standout */
503 attributes |= STANDOUT;
505 case 'B': /* start bold */
508 case 'U': /* start underline */
511 case 's': /* end standout */
512 attributes &= ~STANDOUT;
514 case 'b': /* end bold */
517 case 'u': /* end underline */
518 attributes &= ~UNDER;
529 for (pp = proclist.p_next; pp; pp = pp->p_next)
531 p = Itoa(njobs, 1, attributes);
532 Strbuf_append(&buf, p);
537 if ((z = varval(STRstatus)) != STRNULL)
539 Strbuf_append1(&buf, attributes | *z++);
542 expdollar(&buf, &cp, attributes);
543 /* cp should point the last char of current % sequence */
547 Strbuf_append1(&buf, attributes | '%');
549 case '{': /* literal characters start */
552 * No literal capability, so skip all chars in the literal
555 while (*cp != '\0' && (cp[-1] != '%' || *cp != '}'))
557 #endif /* LITERAL == 0 */
558 attributes |= LITERAL;
560 case '}': /* literal characters end */
561 attributes &= ~LITERAL;
565 if (*cp == 'a' && what == FMT_WHO) {
566 cz = who_info(info, 'a');
567 tprintf_append_mbs(&buf, cz, attributes);
571 #endif /* HAVENOUTMP */
573 Strbuf_append1(&buf, attributes | '%');
574 Strbuf_append1(&buf, attributes | *cp);
579 else if (*cp == '\\' || *cp == '^')
580 Strbuf_append1(&buf, attributes | parseescape(&cp));
581 else if (*cp == HIST) { /* EGS: handle '!'s in prompts */
582 if (what == FMT_HISTORY)
583 cz = fmthist('h', info);
585 cz = xasprintf("%d", eventno + 1);
586 tprintf_append_mbs(&buf, cz, attributes);
590 Strbuf_append1(&buf, attributes | *cp); /* normal character */
592 cleanup_ignore(&buf);
594 return Strbuf_finish(&buf);
598 expdollar(struct Strbuf *buf, const Char **srcp, Char attr)
601 const Char *src = *srcp;
606 /* found a variable, expand it */
607 var = xmalloc((Strlen(src) + 1) * sizeof (*var));
609 var[i] = *++src & TRIM;
610 if (i == 0 && var[i] == '{') {
612 var[i] = *++src & TRIM;
614 if (!alnum(var[i]) && var[i] != '_') {
620 if (curly && (*src & TRIM) == '}')
625 for (i = 0; vp->vec[i] != NULL; i++) {
626 for (val = vp->vec[i]; *val; val++)
627 if (*val != '\n' && *val != '\r')
628 Strbuf_append1(buf, *val | attr);
630 Strbuf_append1(buf, ' ' | attr);
634 val = (!vp) ? tgetenv(var) : NULL;
637 if (*val != '\n' && *val != '\r')
638 Strbuf_append1(buf, *val | attr);