1 /* $Header: /src/pub/tcsh/tc.prompt.c,v 3.53 2005/01/05 18:06:43 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("$Id: tc.prompt.c,v 3.53 2005/01/05 18:06:43 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(promptno, str)
115 static Char *ocp = NULL;
116 static const char *ostr = NULL;
117 time_t lclock = time(NULL);
123 cp = varval(STRprompt);
126 cp = varval(STRprompt2);
129 cp = varval(STRprompt3);
137 cp = varval(STRprompt);
147 tprintf(FMT_PROMPT, PromptBuf, cp, 2 * INBUFSIZE - 2, str, lclock, NULL);
149 for (cp = PromptBuf; *cp ; )
150 (void) putwraw(*cp++);
155 RPromptBuf[0] = '\0';
156 if (promptno == 0) { /* determine rprompt if using main prompt */
157 cp = varval(STRrprompt);
158 tprintf(FMT_PROMPT, RPromptBuf, cp, INBUFSIZE - 2, NULL, lclock, NULL);
159 /* if not editing, put rprompt after prompt */
160 if (!editing && RPromptBuf[0] != '\0') {
161 for (cp = RPromptBuf; *cp ; )
162 (void) putwraw(*cp++);
171 tprintf(what, buf, fmt, siz, str, tim, info)
182 static int print_prompt_did_ding = 0;
184 /* Need to be unsigned to avoid sign extension */
185 const unsigned char *cz;
186 unsigned char cbuff[BUFSIZE];
190 const Char *cp = fmt;
192 struct tm *t = localtime(&tim);
195 static Char *olddir = NULL, *olduser = NULL;
206 *p++ = attributes | *cp++;
210 if ((*cp == '%') && ! (cp[1] == '\0')) {
214 if (what == FMT_HISTORY) {
215 fmthist('R', info, (char *) cbuff, sizeof(cbuff));
218 cz = (const unsigned char *) str;
220 for (; *cz && p < ep; p++) {
221 cz += one_mbtowc(p, (const char *)cz, MB_LEN_MAX);
226 *p++ = attributes | ((uid == 0) ? PRCHROOT : PRCH);
232 fmthist('h', info, (char *) cbuff, sizeof(cbuff));
235 (void) xsnprintf((char *) cbuff, sizeof(cbuff), "%d",
239 (void) xsnprintf((char *) cbuff, sizeof(cbuff), "%d",
243 for (cz = cbuff; *cz && p < ep; p++) {
244 cz += one_mbtowc(p, (const char *)cz, MB_LEN_MAX);
248 case 'T': /* 24 hour format */
250 case 't': /* 12 hour am/pm format */
251 case 'p': /* With seconds */
257 if (p >= ep - 10) break;
259 /* addition by Hans J. Albertsson */
260 /* and another adapted from Justin Bur */
261 if (adrof(STRampm) || (*cp != 'T' && *cp != 'P')) {
269 } /* else do a 24 hour clock */
271 /* "DING!" stuff by Hans also */
272 if (t->tm_min || print_prompt_did_ding ||
273 what != FMT_PROMPT || adrof(STRnoding)) {
275 print_prompt_did_ding = 0;
276 p = Itoa(hr, p, 0, attributes);
277 *p++ = attributes | ':';
278 p = Itoa(t->tm_min, p, 2, attributes);
279 if (*cp == 'p' || *cp == 'P') {
280 *p++ = attributes | ':';
281 p = Itoa(t->tm_sec, p, 2, attributes);
283 if (adrof(STRampm) || (*cp != 'T' && *cp != 'P')) {
284 *p++ = attributes | ampm;
285 *p++ = attributes | 'm';
288 else { /* we need to ding */
291 (void) Strcpy(buff, STRDING);
293 *p++ = attributes | buff[i++];
295 print_prompt_did_ding = 1;
303 cz = (const unsigned char *) who_info(info, 'M',
304 (char *) cbuff, sizeof(cbuff));
306 #endif /* HAVENOUTMP */
307 cz = (const unsigned char *) getenv("HOST");
309 * Bug pointed out by Laurent Dami <dami@cui.unige.ch>: don't
310 * derefrence that NULL (if HOST is not set)...
313 for (; *cz && p < ep; p++) {
314 cz += one_mbtowc(p, (const char *)cz, MB_LEN_MAX);
322 cz = (const unsigned char *) who_info(info, 'm',
323 (char *) cbuff, sizeof(cbuff));
325 #endif /* HAVENOUTMP */
326 cz = (const unsigned char *) getenv("HOST");
329 for (; *cz && (what == FMT_WHO || *cz != '.') && p < ep;
331 cz += one_mbtowc(p, (const char *)cz, MB_LEN_MAX);
336 /* lukem: new directory prompt code */
343 if (Scp == 'c') /* store format type (c == .) */
345 if ((z = varval(STRcwd)) == STRNULL)
346 break; /* no cwd, so don't do anything */
348 /* show ~ whenever possible - a la dirs */
349 if (Scp == '~' || Scp == '.' ) {
350 if (tlength == 0 || olddir != z) {
351 olddir = z; /* have we changed dir? */
352 olduser = getusername(&olddir);
359 /* option to determine fixed # of dirs from path */
360 if (Scp == '.' || Scp == 'C') {
365 *p++ = attributes | *z++;
366 *p++ = attributes | *z++;
368 if (*z == '/' && z[1] == '/') {
369 *p++ = attributes | *z++;
370 *p++ = attributes | *z++;
372 *p++ = attributes | *z++;
375 #endif /* WINNT_NATIVE */
377 while (*z) /* calc # of /'s */
383 * for format type c, prompt will be following...
386 * //machine/share => //machine/share
387 * //machine/share/folder => //machine:folder
389 if (oldz[0] == '/' && oldz[1] == '/' && updirs > 1)
390 *p++ = attributes | ':';
391 #endif /* WINNT_NATIVE */
392 if ((Scp == 'C' && *q != '/'))
395 if (cp[1] == '0') { /* print <x> or ... */
399 if (cp[1] >= '1' && cp[1] <= '9') { /* calc # to skip */
408 while ((z > q) && (*z != '/'))
413 if (*z == '/' && z != q)
418 if ((olduser) && ((Scp == '~') ||
419 (Scp == '.' && (pdirs || (!pdirs && updirs <= 0))) )) {
420 *p++ = attributes | '~';
422 for (q = olduser; *q; *p++ = attributes | *q++)
426 /* RWM - tell you how many dirs we've ignored */
427 /* and add '/' at front of this */
428 if (updirs > 0 && pdirs) {
429 if (p >= ep - 5) break;
430 if (adrof(STRellipsis)) {
431 *p++ = attributes | '.';
432 *p++ = attributes | '.';
433 *p++ = attributes | '.';
435 *p++ = attributes | '/';
436 *p++ = attributes | '<';
438 *p++ = attributes | '9';
439 *p++ = attributes | '+';
441 *p++ = attributes | ('0' + updirs);
442 *p++ = attributes | '>';
446 for (; *z ; *p++ = attributes | *z++)
449 /* lukem: end of new directory prompt code */
453 if (what == FMT_WHO) {
454 cz = (const unsigned char *) who_info(info, 'n',
455 (char *) cbuff, sizeof(cbuff));
456 for (; *cz && p < ep; p++) {
457 cz += one_mbtowc(p, (const char *)cz, MB_LEN_MAX);
462 #endif /* HAVENOUTMP */
464 if ((z = varval(STRuser)) != STRNULL)
465 for (; *z; *p++ = attributes | *z++)
471 if (what == FMT_WHO) {
472 cz = (const unsigned char *) who_info(info, 'l',
473 (char *) cbuff, sizeof(cbuff));
474 for (; *cz && p < ep; p++) {
475 cz += one_mbtowc(p, (const char *)cz, MB_LEN_MAX);
480 #endif /* HAVENOUTMP */
482 if ((z = varval(STRtty)) != STRNULL)
483 for (; *z; *p++ = attributes | *z++)
488 for (cz = (const unsigned char *) day_list[t->tm_wday];
489 *cz && p < ep; p++) {
490 cz += one_mbtowc(p, (const char *)cz, MB_LEN_MAX);
495 if (p >= ep - 3) break;
496 p = Itoa(t->tm_mday, p, 2, attributes);
499 if (p >= ep - 5) break;
500 for (cz = (const unsigned char *) month_list[t->tm_mon];
501 *cz && p < ep; p++) {
502 cz += one_mbtowc(p, (const char *)cz, MB_LEN_MAX);
507 if (p >= ep - 3) break;
508 p = Itoa(t->tm_mon + 1, p, 2, attributes);
511 if (p >= ep - 3) break;
512 p = Itoa(t->tm_year % 100, p, 2, attributes);
515 if (p >= ep - 5) break;
516 p = Itoa(t->tm_year + 1900, p, 4, attributes);
518 case 'S': /* start standout */
519 attributes |= STANDOUT;
521 case 'B': /* start bold */
524 case 'U': /* start underline */
527 case 's': /* end standout */
528 attributes &= ~STANDOUT;
530 case 'b': /* end bold */
533 case 'u': /* end underline */
534 attributes &= ~UNDER;
542 Char xbuf[128], *ebuf, *xq;
545 for (pp = proclist.p_next; pp; pp = pp->p_next)
547 /* make sure we have space */
548 ebuf = Itoa(njobs, buf, 1, attributes);
549 for (xq = xbuf; xq < ebuf; *p++ = *xq++)
554 if ((z = varval(STRstatus)) != STRNULL)
555 for (; *z; *p++ = attributes | *z++)
560 (void) expdollar(&p, &cp, &sz, attributes);
561 /* cp should point the last char of currnet % sequence */
565 *p++ = attributes | '%';
567 case '{': /* literal characters start */
570 * No literal capability, so skip all chars in the literal
573 while (*cp != '\0' && (*cp != '%' || cp[1] != '}'))
575 #endif /* LITERAL == 0 */
576 attributes |= LITERAL;
578 case '}': /* literal characters end */
579 attributes &= ~LITERAL;
583 if (*cp == 'a' && what == FMT_WHO) {
584 cz = (const unsigned char *) who_info(info, 'a',
585 (char *) cbuff, sizeof(cbuff));
586 for (; *cz && p < ep; p++) {
587 cz += one_mbtowc(p, (const char *)cz, MB_LEN_MAX);
592 #endif /* HAVENOUTMP */
594 if (p >= ep - 3) break;
595 *p++ = attributes | '%';
596 *p++ = attributes | *cp;
601 else if (*cp == '\\' || *cp == '^')
602 *p++ = attributes | parseescape(&cp);
603 else if (*cp == HIST) { /* EGS: handle '!'s in prompts */
604 if (what == FMT_HISTORY)
605 fmthist('h', info, (char *) cbuff, sizeof(cbuff));
607 (void) xsnprintf((char *) cbuff, sizeof(cbuff), "%d", eventno + 1);
608 for (cz = cbuff; *cz && p < ep; p++) {
609 cz += one_mbtowc(p, (const char *)cz, MB_LEN_MAX);
614 *p++ = attributes | *cp; /* normal character */
620 expdollar(dstp, srcp, spp, attr)
628 const Char *src = *srcp;
633 /* found a variable, expand it */
634 for (i = 0; i < MAXVARLEN; i++) {
635 var[i] = *++src & TRIM;
636 if (i == 0 && var[i] == '{') {
638 var[i] = *++src & TRIM;
640 if (!alnum(var[i])) {
646 if (curly && (*src & TRIM) == '}')
650 val = (!vp) ? tgetenv(var) : NULL;
652 for (i = 0; vp->vec[i] != NULL; i++) {
653 for (val = vp->vec[i]; *spp > 0 && *val; (*spp)--)
654 *dst++ = *val++ | attr;
655 if (vp->vec[i+1] && *spp > 0) {
662 for (; *spp > 0 && *val; (*spp)--)
663 *dst++ = *val++ | attr;