1 /* $Header: /src/pub/tcsh/tc.prompt.c,v 3.46 2002/07/12 13:16:19 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.46 2002/07/12 13:16:19 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 char *month_list
[12];
52 static 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 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
);
150 for (cp
= PromptBuf
; *cp
; )
151 (void) putraw(*cp
++);
156 RPromptBuf
[0] = '\0';
157 if (promptno
== 0) { /* determine rprompt if using main prompt */
158 cp
= varval(STRrprompt
);
159 tprintf(FMT_PROMPT
, RPromptBuf
, cp
, INBUFSIZE
- 2, NULL
, lclock
, NULL
);
161 /* if not editing, put rprompt after prompt */
162 if (!editing
&& RPromptBuf
[0] != '\0') {
163 for (cp
= RPromptBuf
; *cp
; )
164 (void) putraw(*cp
++);
173 tprintf(what
, buf
, fmt
, siz
, str
, tim
, info
)
184 static int print_prompt_did_ding
= 0;
186 /* Need to be unsigned to avoid sign extension */
187 const unsigned char *cz
;
188 unsigned char cbuff
[BUFSIZE
];
192 const Char
*cp
= fmt
;
194 struct tm
*t
= localtime(&tim
);
197 static Char
*olddir
= NULL
, *olduser
= NULL
;
198 extern int tlength
; /* cache cleared */
206 if (Ismbyte1(*cp
) && ! (cp
[1] == '\0'))
208 *p
++ = attributes
| *cp
++; /* normal character */
209 *p
++ = attributes
| *cp
; /* normal character */
212 #endif /* DSPMBYTE */
213 if ((*cp
== '%') && ! (cp
[1] == '\0')) {
217 if (what
== FMT_HISTORY
)
218 fmthist('R', info
, (char *) (cz
= cbuff
), sizeof(cbuff
));
220 cz
= (unsigned char *) str
;
222 for (; *cz
; *p
++ = attributes
| *cz
++)
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
++ = attributes
| *cz
++)
246 case 'T': /* 24 hour format */
248 case 't': /* 12 hour am/pm format */
249 case 'p': /* With seconds */
255 if (p
>= ep
- 10) break;
257 /* addition by Hans J. Albertsson */
258 /* and another adapted from Justin Bur */
259 if (adrof(STRampm
) || (*cp
!= 'T' && *cp
!= 'P')) {
267 } /* else do a 24 hour clock */
269 /* "DING!" stuff by Hans also */
270 if (t
->tm_min
|| print_prompt_did_ding
||
271 what
!= FMT_PROMPT
|| adrof(STRnoding
)) {
273 print_prompt_did_ding
= 0;
274 p
= Itoa(hr
, p
, 0, attributes
);
275 *p
++ = attributes
| ':';
276 p
= Itoa(t
->tm_min
, p
, 2, attributes
);
277 if (*cp
== 'p' || *cp
== 'P') {
278 *p
++ = attributes
| ':';
279 p
= Itoa(t
->tm_sec
, p
, 2, attributes
);
281 if (adrof(STRampm
) || (*cp
!= 'T' && *cp
!= 'P')) {
282 *p
++ = attributes
| ampm
;
283 *p
++ = attributes
| 'm';
286 else { /* we need to ding */
289 (void) Strcpy(buff
, STRDING
);
291 *p
++ = attributes
| buff
[i
++];
293 print_prompt_did_ding
= 1;
301 cz
= (unsigned char *) who_info(info
, 'M',
302 (char *) cbuff
, sizeof(cbuff
));
304 #endif /* HAVENOUTMP */
305 cz
= (unsigned char *) getenv("HOST");
307 * Bug pointed out by Laurent Dami <dami@cui.unige.ch>: don't
308 * derefrence that NULL (if HOST is not set)...
311 for (; *cz
; *p
++ = attributes
| *cz
++)
318 cz
= (unsigned char *) who_info(info
, 'm', (char *) cbuff
,
321 #endif /* HAVENOUTMP */
322 cz
= (unsigned char *) getenv("HOST");
325 for ( ; *cz
&& (what
== FMT_WHO
|| *cz
!= '.')
326 ; *p
++ = attributes
| *cz
++ )
330 /* lukem: new directory prompt code */
337 if (Scp
== 'c') /* store format type (c == .) */
339 if ((z
= varval(STRcwd
)) == STRNULL
)
340 break; /* no cwd, so don't do anything */
342 /* show ~ whenever possible - a la dirs */
343 if (Scp
== '~' || Scp
== '.' ) {
344 if (tlength
== 0 || olddir
!= z
) {
345 olddir
= z
; /* have we changed dir? */
346 olduser
= getusername(&olddir
);
353 /* option to determine fixed # of dirs from path */
354 if (Scp
== '.' || Scp
== 'C') {
358 *p
++ = attributes
| *z
++;
359 *p
++ = attributes
| *z
++;
361 if (*z
== '/' && z
[1] == '/') {
362 *p
++ = attributes
| *z
++;
363 *p
++ = attributes
| *z
++;
365 *p
++ = attributes
| *z
++;
368 #endif /* WINNT_NATIVE */
370 while (*z
) /* calc # of /'s */
373 if ((Scp
== 'C' && *q
!= '/'))
376 if (cp
[1] == '0') { /* print <x> or ... */
380 if (cp
[1] >= '1' && cp
[1] <= '9') { /* calc # to skip */
389 while ((z
> q
) && (*z
!= '/'))
394 if (*z
== '/' && z
!= q
)
399 if ((olduser
) && ((Scp
== '~') ||
400 (Scp
== '.' && (pdirs
|| (!pdirs
&& updirs
<= 0))) )) {
401 *p
++ = attributes
| '~';
403 for (q
= olduser
; *q
; *p
++ = attributes
| *q
++)
407 /* RWM - tell you how many dirs we've ignored */
408 /* and add '/' at front of this */
409 if (updirs
> 0 && pdirs
) {
410 if (p
>= ep
- 5) break;
411 if (adrof(STRellipsis
)) {
412 *p
++ = attributes
| '.';
413 *p
++ = attributes
| '.';
414 *p
++ = attributes
| '.';
416 *p
++ = attributes
| '/';
417 *p
++ = attributes
| '<';
419 *p
++ = attributes
| '9';
420 *p
++ = attributes
| '+';
422 *p
++ = attributes
| ('0' + updirs
);
423 *p
++ = attributes
| '>';
427 for (; *z
; *p
++ = attributes
| *z
++)
430 /* lukem: end of new directory prompt code */
434 if (what
== FMT_WHO
) {
435 cz
= (unsigned char *) who_info(info
, 'n',
436 (char *) cbuff
, sizeof(cbuff
));
437 for (; cz
&& *cz
; *p
++ = attributes
| *cz
++)
441 #endif /* HAVENOUTMP */
443 if ((z
= varval(STRuser
)) != STRNULL
)
444 for (; *z
; *p
++ = attributes
| *z
++)
450 if (what
== FMT_WHO
) {
451 cz
= (unsigned char *) who_info(info
, 'l',
452 (char *) cbuff
, sizeof(cbuff
));
453 for (; cz
&& *cz
; *p
++ = attributes
| *cz
++)
457 #endif /* HAVENOUTMP */
459 if ((z
= varval(STRtty
)) != STRNULL
)
460 for (; *z
; *p
++ = attributes
| *z
++)
465 for (cz
= (unsigned char *) day_list
[t
->tm_wday
]; *cz
;
466 *p
++ = attributes
| *cz
++)
470 if (p
>= ep
- 3) break;
471 p
= Itoa(t
->tm_mday
, p
, 2, attributes
);
474 if (p
>= ep
- 5) break;
475 for (cz
= (unsigned char *) month_list
[t
->tm_mon
]; *cz
;
476 *p
++ = attributes
| *cz
++)
480 if (p
>= ep
- 3) break;
481 p
= Itoa(t
->tm_mon
+ 1, p
, 2, attributes
);
484 if (p
>= ep
- 3) break;
485 p
= Itoa(t
->tm_year
% 100, p
, 2, attributes
);
488 if (p
>= ep
- 5) break;
489 p
= Itoa(t
->tm_year
+ 1900, p
, 4, attributes
);
491 case 'S': /* start standout */
492 attributes
|= STANDOUT
;
494 case 'B': /* start bold */
497 case 'U': /* start underline */
500 case 's': /* end standout */
501 attributes
&= ~STANDOUT
;
503 case 'b': /* end bold */
506 case 'u': /* end underline */
507 attributes
&= ~UNDER
;
515 Char buf
[128], *ebuf
, *q
;
518 for (pp
= proclist
.p_next
; pp
; pp
= pp
->p_next
)
520 /* make sure we have space */
521 ebuf
= Itoa(njobs
, buf
, 1, attributes
);
522 for (q
= buf
; q
< ebuf
; *p
++ = *q
++)
527 if ((z
= varval(STRstatus
)) != STRNULL
)
528 for (; *z
; *p
++ = attributes
| *z
++)
533 (void) expdollar(&p
, &cp
, &sz
, attributes
);
534 /* cp should point the last char of currnet % sequence */
538 *p
++ = attributes
| '%';
540 case '{': /* literal characters start */
543 * No literal capability, so skip all chars in the literal
546 while (*cp
!= '\0' && (*cp
!= '%' || cp
[1] != '}'))
548 #endif /* LITERAL == 0 */
549 attributes
|= LITERAL
;
551 case '}': /* literal characters end */
552 attributes
&= ~LITERAL
;
556 if (*cp
== 'a' && what
== FMT_WHO
) {
557 cz
= who_info(info
, 'a', (char *) cbuff
, sizeof(cbuff
));
558 for (; cz
&& *cz
; *p
++ = attributes
| *cz
++)
562 #endif /* HAVENOUTMP */
564 if (p
>= ep
- 3) break;
565 *p
++ = attributes
| '%';
566 *p
++ = attributes
| *cp
;
571 else if (*cp
== '\\' || *cp
== '^')
572 *p
++ = attributes
| parseescape(&cp
);
573 else if (*cp
== HIST
) { /* EGS: handle '!'s in prompts */
574 if (what
== FMT_HISTORY
)
575 fmthist('h', info
, (char *) cbuff
, sizeof(cbuff
));
577 (void) xsnprintf((char *) cbuff
, sizeof(cbuff
), "%d", eventno
+ 1);
578 for (cz
= cbuff
; *cz
; *p
++ = attributes
| *cz
++)
582 *p
++ = attributes
| *cp
; /* normal character */
588 expdollar(dstp
, srcp
, spp
, attr
)
596 const Char
*src
= *srcp
;
601 /* found a variable, expand it */
602 for (i
= 0; i
< MAXVARLEN
; i
++) {
603 var
[i
] = *++src
& TRIM
;
604 if (i
== 0 && var
[i
] == '{') {
606 var
[i
] = *++src
& TRIM
;
608 if (!alnum(var
[i
])) {
614 if (curly
&& (*src
& TRIM
) == '}')
618 val
= (!vp
) ? tgetenv(var
) : NULL
;
620 for (i
= 0; vp
->vec
[i
] != NULL
; i
++) {
621 for (val
= vp
->vec
[i
]; *spp
> 0 && *val
; (*spp
)--)
622 *dst
++ = *val
++ | attr
;
623 if (vp
->vec
[i
+1] && *spp
> 0) {
630 for (; *spp
> 0 && *val
; (*spp
)--)
631 *dst
++ = *val
++ | attr
;