1 /* $Header: /src/pub/tcsh/tc.prompt.c,v 3.41 2000/11/11 23:03:39 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. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 RCSID("$Id: tc.prompt.c,v 3.41 2000/11/11 23:03:39 christos Exp $")
45 * kfk 21oct1983 -- add @ (time) and / ($cwd) in prompt.
46 * PWP 4/27/87 -- rearange for tcsh.
47 * mrdch@com.tau.edu.il 6/26/89 - added ~, T and .# - rearanged to switch()
48 * instead of if/elseif
49 * Luke Mewburn, <lukem@cs.rmit.edu.au>
50 * 6-Sep-91 changed date format
51 * 16-Feb-94 rewrote directory prompt code, added $ellipsis
52 * 29-Dec-96 added rprompt support
55 static char *month_list[12];
56 static char *day_list[7];
64 setlocale(LC_TIME, "");
66 for (i = 0; i < 12; i++)
67 xfree((ptr_t) month_list[i]);
68 month_list[0] = strsave(_time_info->abbrev_month[0]);
69 month_list[1] = strsave(_time_info->abbrev_month[1]);
70 month_list[2] = strsave(_time_info->abbrev_month[2]);
71 month_list[3] = strsave(_time_info->abbrev_month[3]);
72 month_list[4] = strsave(_time_info->abbrev_month[4]);
73 month_list[5] = strsave(_time_info->abbrev_month[5]);
74 month_list[6] = strsave(_time_info->abbrev_month[6]);
75 month_list[7] = strsave(_time_info->abbrev_month[7]);
76 month_list[8] = strsave(_time_info->abbrev_month[8]);
77 month_list[9] = strsave(_time_info->abbrev_month[9]);
78 month_list[10] = strsave(_time_info->abbrev_month[10]);
79 month_list[11] = strsave(_time_info->abbrev_month[11]);
81 for (i = 0; i < 7; i++)
82 xfree((ptr_t) day_list[i]);
83 day_list[0] = strsave(_time_info->abbrev_wkday[0]);
84 day_list[1] = strsave(_time_info->abbrev_wkday[1]);
85 day_list[2] = strsave(_time_info->abbrev_wkday[2]);
86 day_list[3] = strsave(_time_info->abbrev_wkday[3]);
87 day_list[4] = strsave(_time_info->abbrev_wkday[4]);
88 day_list[5] = strsave(_time_info->abbrev_wkday[5]);
89 day_list[6] = strsave(_time_info->abbrev_wkday[6]);
91 month_list[0] = "Jan";
92 month_list[1] = "Feb";
93 month_list[2] = "Mar";
94 month_list[3] = "Apr";
95 month_list[4] = "May";
96 month_list[5] = "Jun";
97 month_list[6] = "Jul";
98 month_list[7] = "Aug";
99 month_list[8] = "Sep";
100 month_list[9] = "Oct";
101 month_list[10] = "Nov";
102 month_list[11] = "Dec";
115 printprompt(promptno, str)
119 static Char *ocp = NULL;
120 static char *ostr = NULL;
121 time_t lclock = time(NULL);
127 cp = varval(STRprompt);
130 cp = varval(STRprompt2);
133 cp = varval(STRprompt3);
141 cp = varval(STRprompt);
151 tprintf(FMT_PROMPT, PromptBuf, cp, 2 * INBUFSIZE - 2, str, lclock, NULL);
154 for (cp = PromptBuf; *cp ; )
155 (void) putraw(*cp++);
160 RPromptBuf[0] = '\0';
161 if (promptno == 0) { /* determine rprompt if using main prompt */
162 cp = varval(STRrprompt);
163 tprintf(FMT_PROMPT, RPromptBuf, cp, INBUFSIZE - 2, NULL, lclock, NULL);
165 /* if not editing, put rprompt after prompt */
166 if (!editing && RPromptBuf[0] != '\0') {
167 for (cp = RPromptBuf; *cp ; )
168 (void) putraw(*cp++);
177 tprintf(what, buf, fmt, siz, str, tim, info)
188 static int print_prompt_did_ding = 0;
190 /* Need to be unsigned to avoid sign extension */
191 const unsigned char *cz;
192 unsigned char cbuff[BUFSIZE];
196 const Char *cp = fmt;
198 struct tm *t = localtime(&tim);
201 static Char *olddir = NULL, *olduser = NULL;
202 extern int tlength; /* cache cleared */
210 if (Ismbyte1(*cp) && ! (cp[1] == '\0'))
212 *p++ = attributes | *cp++; /* normal character */
213 *p++ = attributes | *cp; /* normal character */
216 #endif /* DSPMBYTE */
217 if ((*cp == '%') && ! (cp[1] == '\0')) {
221 if (what == FMT_HISTORY)
222 fmthist('R', info, (char *) (cz = cbuff), sizeof(cbuff));
224 cz = (unsigned char *) str;
226 for (; *cz; *p++ = attributes | *cz++)
230 *p++ = attributes | ((uid == 0) ? PRCHROOT : PRCH);
236 fmthist('h', info, (char *) cbuff, sizeof(cbuff));
239 (void) xsnprintf((char *) cbuff, sizeof(cbuff), "%d",
243 (void) xsnprintf((char *) cbuff, sizeof(cbuff), "%d",
247 for (cz = cbuff; *cz; *p++ = attributes | *cz++)
250 case 'T': /* 24 hour format */
252 case 't': /* 12 hour am/pm format */
253 case 'p': /* With seconds */
259 if (p >= ep - 10) break;
261 /* addition by Hans J. Albertsson */
262 /* and another adapted from Justin Bur */
263 if (adrof(STRampm) || (*cp != 'T' && *cp != 'P')) {
271 } /* else do a 24 hour clock */
273 /* "DING!" stuff by Hans also */
274 if (t->tm_min || print_prompt_did_ding ||
275 what != FMT_PROMPT || adrof(STRnoding)) {
277 print_prompt_did_ding = 0;
278 p = Itoa(hr, p, 0, attributes);
279 *p++ = attributes | ':';
280 p = Itoa(t->tm_min, p, 2, attributes);
281 if (*cp == 'p' || *cp == 'P') {
282 *p++ = attributes | ':';
283 p = Itoa(t->tm_sec, p, 2, attributes);
285 if (adrof(STRampm) || (*cp != 'T' && *cp != 'P')) {
286 *p++ = attributes | ampm;
287 *p++ = attributes | 'm';
290 else { /* we need to ding */
293 (void) Strcpy(buff, STRDING);
295 *p++ = attributes | buff[i++];
297 print_prompt_did_ding = 1;
305 cz = (unsigned char *) who_info(info, 'M',
306 (char *) cbuff, sizeof(cbuff));
308 #endif /* HAVENOUTMP */
309 cz = (unsigned char *) getenv("HOST");
311 * Bug pointed out by Laurent Dami <dami@cui.unige.ch>: don't
312 * derefrence that NULL (if HOST is not set)...
315 for (; *cz ; *p++ = attributes | *cz++)
322 cz = (unsigned char *) who_info(info, 'm', (char *) cbuff,
325 #endif /* HAVENOUTMP */
326 cz = (unsigned char *) getenv("HOST");
329 for ( ; *cz && (what == FMT_WHO || *cz != '.')
330 ; *p++ = attributes | *cz++ )
334 /* lukem: new directory prompt code */
341 if (Scp == 'c') /* store format type (c == .) */
343 if ((z = varval(STRcwd)) == STRNULL)
344 break; /* no cwd, so don't do anything */
346 /* show ~ whenever possible - a la dirs */
347 if (Scp == '~' || Scp == '.' ) {
348 if (tlength == 0 || olddir != z) {
349 olddir = z; /* have we changed dir? */
350 olduser = getusername(&olddir);
357 /* option to determine fixed # of dirs from path */
358 if (Scp == '.' || Scp == 'C') {
362 *p++ = attributes | *z++;
363 *p++ = attributes | *z++;
365 if (*z == '/' && z[1] == '/') {
366 *p++ = attributes | *z++;
367 *p++ = attributes | *z++;
369 *p++ = attributes | *z++;
372 #endif /* WINNT_NATIVE */
374 while (*z) /* calc # of /'s */
377 if ((Scp == 'C' && *q != '/'))
380 if (cp[1] == '0') { /* print <x> or ... */
384 if (cp[1] >= '1' && cp[1] <= '9') { /* calc # to skip */
393 while ((z > q) && (*z != '/'))
398 if (*z == '/' && z != q)
403 if ((olduser) && ((Scp == '~') ||
404 (Scp == '.' && (pdirs || (!pdirs && updirs <= 0))) )) {
405 *p++ = attributes | '~';
407 for (q = olduser; *q; *p++ = attributes | *q++)
411 /* RWM - tell you how many dirs we've ignored */
412 /* and add '/' at front of this */
413 if (updirs > 0 && pdirs) {
414 if (p >= ep - 5) break;
415 if (adrof(STRellipsis)) {
416 *p++ = attributes | '.';
417 *p++ = attributes | '.';
418 *p++ = attributes | '.';
420 *p++ = attributes | '/';
421 *p++ = attributes | '<';
423 *p++ = attributes | '9';
424 *p++ = attributes | '+';
426 *p++ = attributes | ('0' + updirs);
427 *p++ = attributes | tcsh ? '>' : '%';
431 for (; *z ; *p++ = attributes | *z++)
434 /* lukem: end of new directory prompt code */
438 if (what == FMT_WHO) {
439 cz = (unsigned char *) who_info(info, 'n',
440 (char *) cbuff, sizeof(cbuff));
441 for (; cz && *cz ; *p++ = attributes | *cz++)
445 #endif /* HAVENOUTMP */
447 if ((z = varval(STRuser)) != STRNULL)
448 for (; *z; *p++ = attributes | *z++)
454 if (what == FMT_WHO) {
455 cz = (unsigned char *) who_info(info, 'l',
456 (char *) cbuff, sizeof(cbuff));
457 for (; cz && *cz ; *p++ = attributes | *cz++)
461 #endif /* HAVENOUTMP */
463 if ((z = varval(STRtty)) != STRNULL)
464 for (; *z; *p++ = attributes | *z++)
469 for (cz = (unsigned char *) day_list[t->tm_wday]; *cz;
470 *p++ = attributes | *cz++)
474 if (p >= ep - 3) break;
475 p = Itoa(t->tm_mday, p, 2, attributes);
478 if (p >= ep - 5) break;
479 for (cz = (unsigned char *) month_list[t->tm_mon]; *cz;
480 *p++ = attributes | *cz++)
484 if (p >= ep - 3) break;
485 p = Itoa(t->tm_mon + 1, p, 2, attributes);
488 if (p >= ep - 3) break;
489 p = Itoa(t->tm_year % 100, p, 2, attributes);
492 if (p >= ep - 5) break;
493 p = Itoa(t->tm_year + 1900, p, 4, attributes);
495 case 'S': /* start standout */
496 attributes |= STANDOUT;
498 case 'B': /* start bold */
501 case 'U': /* start underline */
504 case 's': /* end standout */
505 attributes &= ~STANDOUT;
507 case 'b': /* end bold */
510 case 'u': /* end underline */
511 attributes &= ~UNDER;
517 if ((z = varval(STRstatus)) != STRNULL)
518 for (; *z; *p++ = attributes | *z++)
523 (void) expdollar(&p, &cp, &sz, attributes);
526 *p++ = attributes | '%';
528 case '{': /* literal characters start */
531 * No literal capability, so skip all chars in the literal
534 while (*cp != '\0' && (*cp != '%' || cp[1] != '}'))
536 #endif /* LITERAL == 0 */
537 attributes |= LITERAL;
539 case '}': /* literal characters end */
540 attributes &= ~LITERAL;
544 if (*cp == 'a' && what == FMT_WHO) {
545 cz = who_info(info, 'a', (char *) cbuff, sizeof(cbuff));
546 for (; cz && *cz; *p++ = attributes | *cz++)
550 #endif /* HAVENOUTMP */
552 if (p >= ep - 3) break;
553 *p++ = attributes | '%';
554 *p++ = attributes | *cp;
559 else if (*cp == '\\' || *cp == '^')
560 *p++ = attributes | parseescape(&cp);
561 else if (*cp == HIST) { /* EGS: handle '!'s in prompts */
562 if (what == FMT_HISTORY)
563 fmthist('h', info, (char *) cbuff, sizeof(cbuff));
565 (void) xsnprintf((char *) cbuff, sizeof(cbuff), "%d", eventno + 1);
566 for (cz = cbuff; *cz; *p++ = attributes | *cz++)
570 *p++ = attributes | *cp; /* normal character */
576 expdollar(dstp, srcp, spp, attr)
584 const Char *src = *srcp;
589 /* found a variable, expand it */
590 for (i = 0; i < MAXVARLEN; i++) {
591 var[i] = *++src & TRIM;
592 if (i == 0 && var[i] == '{') {
594 var[i] = *++src & TRIM;
596 if (!alnum(var[i])) {
602 if (curly && (*src & TRIM) == '}')
606 val = (!vp) ? tgetenv(var) : NULL;
608 for (i = 0; vp->vec[i] != NULL; i++) {
609 for (val = vp->vec[i]; *spp > 0 && *val; (*spp)--)
610 *dst++ = *val++ | attr;
611 if (vp->vec[i+1] && *spp > 0) {
618 for (; *spp > 0 && *val; (*spp)--)
619 *dst++ = *val++ | attr;