1 /* $Header: /p/tcsh/cvsroot/tcsh/tc.prompt.c,v 3.71 2014/08/23 09:07:57 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.71 2014/08/23 09:07:57 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 /* Check for being member of the Administrators group */
219 gid_t grps
[NGROUPS_MAX
];
222 gcnt
= getgroups(NGROUPS_MAX
, grps
);
223 # define DOMAIN_GROUP_RID_ADMINS 544
224 for (grp
= 0; grp
< gcnt
; ++grp
)
225 if (grps
[grp
] == DOMAIN_GROUP_RID_ADMINS
)
227 Scp
= (grp
< gcnt
) ? PRCHROOT
: PRCH
;
230 Scp
= (uid
== 0 || euid
== 0) ? PRCHROOT
: PRCH
;
233 Strbuf_append1(&buf
, attributes
| Scp
);
239 cz
= fmthist('h', info
);
242 cz
= xasprintf("%d", *(int *)info
);
245 cz
= xasprintf("%d", eventno
+ 1);
248 tprintf_append_mbs(&buf
, cz
, attributes
);
251 case 'T': /* 24 hour format */
253 case 't': /* 12 hour am/pm format */
254 case 'p': /* With seconds */
260 /* addition by Hans J. Albertsson */
261 /* and another adapted from Justin Bur */
262 if (adrof(STRampm
) || (*cp
!= 'T' && *cp
!= 'P')) {
270 } /* else do a 24 hour clock */
272 /* "DING!" stuff by Hans also */
273 if (t
->tm_min
|| print_prompt_did_ding
||
274 what
!= FMT_PROMPT
|| adrof(STRnoding
)) {
276 print_prompt_did_ding
= 0;
278 * Pad hour to 2 characters if padhour is set,
279 * by ADAM David Alan Martin
281 p
= Itoa(hr
, adrof(STRpadhour
) ? 2 : 0, attributes
);
282 Strbuf_append(&buf
, p
);
284 Strbuf_append1(&buf
, attributes
| ':');
285 p
= Itoa(t
->tm_min
, 2, attributes
);
286 Strbuf_append(&buf
, p
);
288 if (*cp
== 'p' || *cp
== 'P') {
289 Strbuf_append1(&buf
, attributes
| ':');
290 p
= Itoa(t
->tm_sec
, 2, attributes
);
291 Strbuf_append(&buf
, p
);
294 if (adrof(STRampm
) || (*cp
!= 'T' && *cp
!= 'P')) {
295 Strbuf_append1(&buf
, attributes
| ampm
);
296 Strbuf_append1(&buf
, attributes
| 'm');
299 else { /* we need to ding */
302 for (i
= 0; STRDING
[i
] != 0; i
++)
303 Strbuf_append1(&buf
, attributes
| STRDING
[i
]);
304 print_prompt_did_ding
= 1;
312 cz
= who_info(info
, 'M');
314 #endif /* HAVENOUTMP */
317 * Bug pointed out by Laurent Dami <dami@cui.unige.ch>: don't
318 * derefrence that NULL (if HOST is not set)...
321 tprintf_append_mbs(&buf
, cz
, attributes
);
330 scz
= cz
= who_info(info
, 'm');
332 #endif /* HAVENOUTMP */
336 while (*cz
!= 0 && (what
== FMT_WHO
|| *cz
!= '.')) {
339 cz
+= one_mbtowc(&wc
, cz
, MB_LEN_MAX
);
340 Strbuf_append1(&buf
, wc
| attributes
);
347 /* lukem: new directory prompt code */
354 if (Scp
== 'c') /* store format type (c == .) */
356 if ((z
= varval(STRcwd
)) == STRNULL
)
357 break; /* no cwd, so don't do anything */
359 /* show ~ whenever possible - a la dirs */
360 if (Scp
== '~' || Scp
== '.' ) {
361 static Char
*olddir
= NULL
;
363 if (tlength
== 0 || olddir
!= z
) {
364 olddir
= z
; /* have we changed dir? */
365 olduser
= getusername(&olddir
);
372 /* option to determine fixed # of dirs from path */
373 if (Scp
== '.' || Scp
== 'C') {
378 Strbuf_append1(&buf
, attributes
| *z
++);
379 Strbuf_append1(&buf
, attributes
| *z
++);
381 if (*z
== '/' && z
[1] == '/') {
382 Strbuf_append1(&buf
, attributes
| *z
++);
383 Strbuf_append1(&buf
, attributes
| *z
++);
385 Strbuf_append1(&buf
, attributes
| *z
++);
388 #endif /* WINNT_NATIVE */
390 while (*z
) /* calc # of /'s */
396 * for format type c, prompt will be following...
399 * //machine/share => //machine/share
400 * //machine/share/folder => //machine:folder
402 if (oldz
[0] == '/' && oldz
[1] == '/' && updirs
> 1)
403 Strbuf_append1(&buf
, attributes
| ':');
404 #endif /* WINNT_NATIVE */
405 if ((Scp
== 'C' && *q
!= '/'))
408 if (cp
[1] == '0') { /* print <x> or ... */
412 if (cp
[1] >= '1' && cp
[1] <= '9') { /* calc # to skip */
421 while ((z
> q
) && (*z
!= '/'))
426 if (*z
== '/' && z
!= q
)
431 if ((olduser
) && ((Scp
== '~') ||
432 (Scp
== '.' && (pdirs
|| (!pdirs
&& updirs
<= 0))) )) {
433 Strbuf_append1(&buf
, attributes
| '~');
434 for (q
= olduser
; *q
; q
++)
435 Strbuf_append1(&buf
, attributes
| *q
);
438 /* RWM - tell you how many dirs we've ignored */
439 /* and add '/' at front of this */
440 if (updirs
> 0 && pdirs
) {
441 if (adrof(STRellipsis
)) {
442 Strbuf_append1(&buf
, attributes
| '.');
443 Strbuf_append1(&buf
, attributes
| '.');
444 Strbuf_append1(&buf
, attributes
| '.');
446 Strbuf_append1(&buf
, attributes
| '/');
447 Strbuf_append1(&buf
, attributes
| '<');
449 Strbuf_append1(&buf
, attributes
| '9');
450 Strbuf_append1(&buf
, attributes
| '+');
452 Strbuf_append1(&buf
, attributes
| ('0' + updirs
));
453 Strbuf_append1(&buf
, attributes
| '>');
458 Strbuf_append1(&buf
, attributes
| *z
++);
460 /* lukem: end of new directory prompt code */
464 if (what
== FMT_WHO
) {
465 cz
= who_info(info
, 'n');
466 tprintf_append_mbs(&buf
, cz
, attributes
);
470 #endif /* HAVENOUTMP */
472 if ((z
= varval(STRuser
)) != STRNULL
)
474 Strbuf_append1(&buf
, attributes
| *z
++);
478 if ((z
= varval(STReuser
)) != STRNULL
)
480 Strbuf_append1(&buf
, attributes
| *z
++);
484 if (what
== FMT_WHO
) {
485 cz
= who_info(info
, 'l');
486 tprintf_append_mbs(&buf
, cz
, attributes
);
490 #endif /* HAVENOUTMP */
492 if ((z
= varval(STRtty
)) != STRNULL
)
494 Strbuf_append1(&buf
, attributes
| *z
++);
498 tprintf_append_mbs(&buf
, day_list
[t
->tm_wday
], attributes
);
501 p
= Itoa(t
->tm_mday
, 2, attributes
);
502 Strbuf_append(&buf
, p
);
506 tprintf_append_mbs(&buf
, month_list
[t
->tm_mon
], attributes
);
509 p
= Itoa(t
->tm_mon
+ 1, 2, attributes
);
510 Strbuf_append(&buf
, p
);
514 p
= Itoa(t
->tm_year
% 100, 2, attributes
);
515 Strbuf_append(&buf
, p
);
519 p
= Itoa(t
->tm_year
+ 1900, 4, attributes
);
520 Strbuf_append(&buf
, p
);
523 case 'S': /* start standout */
524 attributes
|= STANDOUT
;
526 case 'B': /* start bold */
529 case 'U': /* start underline */
532 case 's': /* end standout */
533 attributes
&= ~STANDOUT
;
535 case 'b': /* end bold */
538 case 'u': /* end underline */
539 attributes
&= ~UNDER
;
550 for (pp
= proclist
.p_next
; pp
; pp
= pp
->p_next
)
554 p
= Itoa(njobs
, 1, attributes
);
555 Strbuf_append(&buf
, p
);
560 if ((z
= varval(STRstatus
)) != STRNULL
)
562 Strbuf_append1(&buf
, attributes
| *z
++);
565 expdollar(&buf
, &cp
, attributes
);
566 /* cp should point the last char of current % sequence */
570 Strbuf_append1(&buf
, attributes
| '%');
572 case '{': /* literal characters start */
575 * No literal capability, so skip all chars in the literal
578 while (*cp
!= '\0' && (cp
[-1] != '%' || *cp
!= '}'))
580 #endif /* LITERAL == 0 */
581 attributes
|= LITERAL
;
583 case '}': /* literal characters end */
584 attributes
&= ~LITERAL
;
588 if (*cp
== 'a' && what
== FMT_WHO
) {
589 cz
= who_info(info
, 'a');
590 tprintf_append_mbs(&buf
, cz
, attributes
);
594 #endif /* HAVENOUTMP */
596 Strbuf_append1(&buf
, attributes
| '%');
597 Strbuf_append1(&buf
, attributes
| *cp
);
602 else if (*cp
== '\\' || *cp
== '^')
603 Strbuf_append1(&buf
, attributes
| parseescape(&cp
));
604 else if (*cp
== HIST
) { /* EGS: handle '!'s in prompts */
605 if (what
== FMT_HISTORY
)
606 cz
= fmthist('h', info
);
608 cz
= xasprintf("%d", eventno
+ 1);
609 tprintf_append_mbs(&buf
, cz
, attributes
);
613 Strbuf_append1(&buf
, attributes
| *cp
); /* normal character */
615 cleanup_ignore(&buf
);
617 return Strbuf_finish(&buf
);
621 expdollar(struct Strbuf
*buf
, const Char
**srcp
, Char attr
)
624 const Char
*src
= *srcp
;
629 /* found a variable, expand it */
630 var
= xmalloc((Strlen(src
) + 1) * sizeof (*var
));
632 var
[i
] = *++src
& TRIM
;
633 if (i
== 0 && var
[i
] == '{') {
635 var
[i
] = *++src
& TRIM
;
637 if (!alnum(var
[i
]) && var
[i
] != '_') {
643 if (curly
&& (*src
& TRIM
) == '}')
648 for (i
= 0; vp
->vec
[i
] != NULL
; i
++) {
649 for (val
= vp
->vec
[i
]; *val
; val
++)
650 if (*val
!= '\n' && *val
!= '\r')
651 Strbuf_append1(buf
, *val
| attr
);
653 Strbuf_append1(buf
, ' ' | attr
);
657 val
= (!vp
) ? tgetenv(var
) : NULL
;
660 if (*val
!= '\n' && *val
!= '\r')
661 Strbuf_append1(buf
, *val
| attr
);