xref: /freebsd/contrib/tcsh/tc.prompt.c (revision 19d2e3de755b7c9ca2f5c90b5902fc8f214b2490)
1*19d2e3deSDmitry Chagin /* $Header: /p/tcsh/cvsroot/tcsh/tc.prompt.c,v 3.71 2014/08/23 09:07:57 christos Exp $ */
2c80476e4SDavid E. O'Brien /*
3c80476e4SDavid E. O'Brien  * tc.prompt.c: Prompt printing stuff
4c80476e4SDavid E. O'Brien  */
5c80476e4SDavid E. O'Brien /*-
6c80476e4SDavid E. O'Brien  * Copyright (c) 1980, 1991 The Regents of the University of California.
7c80476e4SDavid E. O'Brien  * All rights reserved.
8c80476e4SDavid E. O'Brien  *
9c80476e4SDavid E. O'Brien  * Redistribution and use in source and binary forms, with or without
10c80476e4SDavid E. O'Brien  * modification, are permitted provided that the following conditions
11c80476e4SDavid E. O'Brien  * are met:
12c80476e4SDavid E. O'Brien  * 1. Redistributions of source code must retain the above copyright
13c80476e4SDavid E. O'Brien  *    notice, this list of conditions and the following disclaimer.
14c80476e4SDavid E. O'Brien  * 2. Redistributions in binary form must reproduce the above copyright
15c80476e4SDavid E. O'Brien  *    notice, this list of conditions and the following disclaimer in the
16c80476e4SDavid E. O'Brien  *    documentation and/or other materials provided with the distribution.
1729301572SMark Peek  * 3. Neither the name of the University nor the names of its contributors
18c80476e4SDavid E. O'Brien  *    may be used to endorse or promote products derived from this software
19c80476e4SDavid E. O'Brien  *    without specific prior written permission.
20c80476e4SDavid E. O'Brien  *
21c80476e4SDavid E. O'Brien  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22c80476e4SDavid E. O'Brien  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23c80476e4SDavid E. O'Brien  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24c80476e4SDavid E. O'Brien  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25c80476e4SDavid E. O'Brien  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26c80476e4SDavid E. O'Brien  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27c80476e4SDavid E. O'Brien  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28c80476e4SDavid E. O'Brien  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29c80476e4SDavid E. O'Brien  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30c80476e4SDavid E. O'Brien  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31c80476e4SDavid E. O'Brien  * SUCH DAMAGE.
32c80476e4SDavid E. O'Brien  */
33c80476e4SDavid E. O'Brien #include "sh.h"
34c80476e4SDavid E. O'Brien 
35*19d2e3deSDmitry Chagin RCSID("$tcsh: tc.prompt.c,v 3.71 2014/08/23 09:07:57 christos Exp $")
36c80476e4SDavid E. O'Brien 
37c80476e4SDavid E. O'Brien #include "ed.h"
38c80476e4SDavid E. O'Brien #include "tw.h"
39c80476e4SDavid E. O'Brien 
40c80476e4SDavid E. O'Brien /*
41c80476e4SDavid E. O'Brien  * kfk 21oct1983 -- add @ (time) and / ($cwd) in prompt.
42c80476e4SDavid E. O'Brien  * PWP 4/27/87 -- rearange for tcsh.
43c80476e4SDavid E. O'Brien  * mrdch@com.tau.edu.il 6/26/89 - added ~, T and .# - rearanged to switch()
44c80476e4SDavid E. O'Brien  *                 instead of if/elseif
45c80476e4SDavid E. O'Brien  * Luke Mewburn, <lukem@cs.rmit.edu.au>
46c80476e4SDavid E. O'Brien  *	6-Sep-91	changed date format
47c80476e4SDavid E. O'Brien  *	16-Feb-94	rewrote directory prompt code, added $ellipsis
48c80476e4SDavid E. O'Brien  *	29-Dec-96	added rprompt support
49c80476e4SDavid E. O'Brien  */
50c80476e4SDavid E. O'Brien 
5123338178SMark Peek static const char   *month_list[12];
5223338178SMark Peek static const char   *day_list[7];
53c80476e4SDavid E. O'Brien 
54c80476e4SDavid E. O'Brien void
5545e5710bSMark Peek dateinit(void)
56c80476e4SDavid E. O'Brien {
57c80476e4SDavid E. O'Brien #ifdef notyet
58c80476e4SDavid E. O'Brien   int i;
59c80476e4SDavid E. O'Brien 
60c80476e4SDavid E. O'Brien   setlocale(LC_TIME, "");
61c80476e4SDavid E. O'Brien 
62c80476e4SDavid E. O'Brien   for (i = 0; i < 12; i++)
63c80476e4SDavid E. O'Brien       xfree((ptr_t) month_list[i]);
64c80476e4SDavid E. O'Brien   month_list[0] = strsave(_time_info->abbrev_month[0]);
65c80476e4SDavid E. O'Brien   month_list[1] = strsave(_time_info->abbrev_month[1]);
66c80476e4SDavid E. O'Brien   month_list[2] = strsave(_time_info->abbrev_month[2]);
67c80476e4SDavid E. O'Brien   month_list[3] = strsave(_time_info->abbrev_month[3]);
68c80476e4SDavid E. O'Brien   month_list[4] = strsave(_time_info->abbrev_month[4]);
69c80476e4SDavid E. O'Brien   month_list[5] = strsave(_time_info->abbrev_month[5]);
70c80476e4SDavid E. O'Brien   month_list[6] = strsave(_time_info->abbrev_month[6]);
71c80476e4SDavid E. O'Brien   month_list[7] = strsave(_time_info->abbrev_month[7]);
72c80476e4SDavid E. O'Brien   month_list[8] = strsave(_time_info->abbrev_month[8]);
73c80476e4SDavid E. O'Brien   month_list[9] = strsave(_time_info->abbrev_month[9]);
74c80476e4SDavid E. O'Brien   month_list[10] = strsave(_time_info->abbrev_month[10]);
75c80476e4SDavid E. O'Brien   month_list[11] = strsave(_time_info->abbrev_month[11]);
76c80476e4SDavid E. O'Brien 
77c80476e4SDavid E. O'Brien   for (i = 0; i < 7; i++)
78c80476e4SDavid E. O'Brien       xfree((ptr_t) day_list[i]);
79c80476e4SDavid E. O'Brien   day_list[0] = strsave(_time_info->abbrev_wkday[0]);
80c80476e4SDavid E. O'Brien   day_list[1] = strsave(_time_info->abbrev_wkday[1]);
81c80476e4SDavid E. O'Brien   day_list[2] = strsave(_time_info->abbrev_wkday[2]);
82c80476e4SDavid E. O'Brien   day_list[3] = strsave(_time_info->abbrev_wkday[3]);
83c80476e4SDavid E. O'Brien   day_list[4] = strsave(_time_info->abbrev_wkday[4]);
84c80476e4SDavid E. O'Brien   day_list[5] = strsave(_time_info->abbrev_wkday[5]);
85c80476e4SDavid E. O'Brien   day_list[6] = strsave(_time_info->abbrev_wkday[6]);
86c80476e4SDavid E. O'Brien #else
87c80476e4SDavid E. O'Brien   month_list[0] = "Jan";
88c80476e4SDavid E. O'Brien   month_list[1] = "Feb";
89c80476e4SDavid E. O'Brien   month_list[2] = "Mar";
90c80476e4SDavid E. O'Brien   month_list[3] = "Apr";
91c80476e4SDavid E. O'Brien   month_list[4] = "May";
92c80476e4SDavid E. O'Brien   month_list[5] = "Jun";
93c80476e4SDavid E. O'Brien   month_list[6] = "Jul";
94c80476e4SDavid E. O'Brien   month_list[7] = "Aug";
95c80476e4SDavid E. O'Brien   month_list[8] = "Sep";
96c80476e4SDavid E. O'Brien   month_list[9] = "Oct";
97c80476e4SDavid E. O'Brien   month_list[10] = "Nov";
98c80476e4SDavid E. O'Brien   month_list[11] = "Dec";
99c80476e4SDavid E. O'Brien 
100c80476e4SDavid E. O'Brien   day_list[0] = "Sun";
101c80476e4SDavid E. O'Brien   day_list[1] = "Mon";
102c80476e4SDavid E. O'Brien   day_list[2] = "Tue";
103c80476e4SDavid E. O'Brien   day_list[3] = "Wed";
104c80476e4SDavid E. O'Brien   day_list[4] = "Thu";
105c80476e4SDavid E. O'Brien   day_list[5] = "Fri";
106c80476e4SDavid E. O'Brien   day_list[6] = "Sat";
107c80476e4SDavid E. O'Brien #endif
108c80476e4SDavid E. O'Brien }
109c80476e4SDavid E. O'Brien 
110c80476e4SDavid E. O'Brien void
11145e5710bSMark Peek printprompt(int promptno, const char *str)
112c80476e4SDavid E. O'Brien {
11345e5710bSMark Peek     static  const Char *ocp = NULL;
11423338178SMark Peek     static  const char *ostr = NULL;
115c80476e4SDavid E. O'Brien     time_t  lclock = time(NULL);
11645e5710bSMark Peek     const Char *cp;
117c80476e4SDavid E. O'Brien 
118c80476e4SDavid E. O'Brien     switch (promptno) {
119c80476e4SDavid E. O'Brien     default:
120c80476e4SDavid E. O'Brien     case 0:
121c80476e4SDavid E. O'Brien 	cp = varval(STRprompt);
122c80476e4SDavid E. O'Brien 	break;
123c80476e4SDavid E. O'Brien     case 1:
124c80476e4SDavid E. O'Brien 	cp = varval(STRprompt2);
125c80476e4SDavid E. O'Brien 	break;
126c80476e4SDavid E. O'Brien     case 2:
127c80476e4SDavid E. O'Brien 	cp = varval(STRprompt3);
128c80476e4SDavid E. O'Brien 	break;
129c80476e4SDavid E. O'Brien     case 3:
130c80476e4SDavid E. O'Brien 	if (ocp != NULL) {
131c80476e4SDavid E. O'Brien 	    cp = ocp;
132c80476e4SDavid E. O'Brien 	    str = ostr;
133c80476e4SDavid E. O'Brien 	}
134c80476e4SDavid E. O'Brien 	else
135c80476e4SDavid E. O'Brien 	    cp = varval(STRprompt);
136c80476e4SDavid E. O'Brien 	break;
137c80476e4SDavid E. O'Brien     }
138c80476e4SDavid E. O'Brien 
139c80476e4SDavid E. O'Brien     if (promptno < 2) {
140c80476e4SDavid E. O'Brien 	ocp = cp;
141c80476e4SDavid E. O'Brien 	ostr = str;
142c80476e4SDavid E. O'Brien     }
143c80476e4SDavid E. O'Brien 
14445e5710bSMark Peek     xfree(Prompt);
14545e5710bSMark Peek     Prompt = NULL;
14645e5710bSMark Peek     Prompt = tprintf(FMT_PROMPT, cp, str, lclock, NULL);
147c80476e4SDavid E. O'Brien     if (!editing) {
14845e5710bSMark Peek 	for (cp = Prompt; *cp ; )
14923338178SMark Peek 	    (void) putwraw(*cp++);
150c80476e4SDavid E. O'Brien 	SetAttributes(0);
151c80476e4SDavid E. O'Brien 	flush();
152c80476e4SDavid E. O'Brien     }
153c80476e4SDavid E. O'Brien 
15445e5710bSMark Peek     xfree(RPrompt);
15545e5710bSMark Peek     RPrompt = NULL;
156c80476e4SDavid E. O'Brien     if (promptno == 0) {	/* determine rprompt if using main prompt */
157c80476e4SDavid E. O'Brien 	cp = varval(STRrprompt);
15845e5710bSMark Peek 	RPrompt = tprintf(FMT_PROMPT, cp, NULL, lclock, NULL);
159c80476e4SDavid E. O'Brien 				/* if not editing, put rprompt after prompt */
16045e5710bSMark Peek 	if (!editing && RPrompt[0] != '\0') {
16145e5710bSMark Peek 	    for (cp = RPrompt; *cp ; )
16223338178SMark Peek 		(void) putwraw(*cp++);
163c80476e4SDavid E. O'Brien 	    SetAttributes(0);
164c80476e4SDavid E. O'Brien 	    putraw(' ');
165c80476e4SDavid E. O'Brien 	    flush();
166c80476e4SDavid E. O'Brien 	}
167c80476e4SDavid E. O'Brien     }
168c80476e4SDavid E. O'Brien }
169c80476e4SDavid E. O'Brien 
17045e5710bSMark Peek static void
17145e5710bSMark Peek tprintf_append_mbs(struct Strbuf *buf, const char *mbs, Char attributes)
172c80476e4SDavid E. O'Brien {
17345e5710bSMark Peek     while (*mbs != 0) {
17445e5710bSMark Peek 	Char wc;
17545e5710bSMark Peek 
17645e5710bSMark Peek 	mbs += one_mbtowc(&wc, mbs, MB_LEN_MAX);
17745e5710bSMark Peek 	Strbuf_append1(buf, wc | attributes);
17845e5710bSMark Peek     }
17945e5710bSMark Peek }
18045e5710bSMark Peek 
18145e5710bSMark Peek Char *
18245e5710bSMark Peek tprintf(int what, const Char *fmt, const char *str, time_t tim, ptr_t info)
18345e5710bSMark Peek {
18445e5710bSMark Peek     struct Strbuf buf = Strbuf_INIT;
185c80476e4SDavid E. O'Brien     Char   *z, *q;
186c80476e4SDavid E. O'Brien     Char    attributes = 0;
187c80476e4SDavid E. O'Brien     static int print_prompt_did_ding = 0;
18845e5710bSMark Peek     char *cz;
189c80476e4SDavid E. O'Brien 
19045e5710bSMark Peek     Char *p;
191c80476e4SDavid E. O'Brien     const Char *cp = fmt;
192c80476e4SDavid E. O'Brien     Char Scp;
193c80476e4SDavid E. O'Brien     struct tm *t = localtime(&tim);
194c80476e4SDavid E. O'Brien 
195c80476e4SDavid E. O'Brien 			/* prompt stuff */
19645e5710bSMark Peek     static Char *olduser = NULL;
19729301572SMark Peek     int updirs;
19845e5710bSMark Peek     size_t pdirs;
199c80476e4SDavid E. O'Brien 
20045e5710bSMark Peek     cleanup_push(&buf, Strbuf_cleanup);
201c80476e4SDavid E. O'Brien     for (; *cp; cp++) {
202c80476e4SDavid E. O'Brien 	if ((*cp == '%') && ! (cp[1] == '\0')) {
203c80476e4SDavid E. O'Brien 	    cp++;
204c80476e4SDavid E. O'Brien 	    switch (*cp) {
205c80476e4SDavid E. O'Brien 	    case 'R':
20623338178SMark Peek 		if (what == FMT_HISTORY) {
20745e5710bSMark Peek 		    cz = fmthist('R', info);
20845e5710bSMark Peek 		    tprintf_append_mbs(&buf, cz, attributes);
20945e5710bSMark Peek 		    xfree(cz);
21045e5710bSMark Peek 		} else {
21145e5710bSMark Peek 		    if (str != NULL)
21245e5710bSMark Peek 			tprintf_append_mbs(&buf, str, attributes);
21323338178SMark Peek 		}
214c80476e4SDavid E. O'Brien 		break;
215c80476e4SDavid E. O'Brien 	    case '#':
216*19d2e3deSDmitry Chagin #ifdef __CYGWIN__
217*19d2e3deSDmitry Chagin 		/* Check for being member of the Administrators group */
218*19d2e3deSDmitry Chagin 		{
219*19d2e3deSDmitry Chagin 			gid_t grps[NGROUPS_MAX];
220*19d2e3deSDmitry Chagin 			int grp, gcnt;
221*19d2e3deSDmitry Chagin 
222*19d2e3deSDmitry Chagin 			gcnt = getgroups(NGROUPS_MAX, grps);
223*19d2e3deSDmitry Chagin # define DOMAIN_GROUP_RID_ADMINS 544
224*19d2e3deSDmitry Chagin 			for (grp = 0; grp < gcnt; ++grp)
225*19d2e3deSDmitry Chagin 				if (grps[grp] == DOMAIN_GROUP_RID_ADMINS)
226*19d2e3deSDmitry Chagin 					break;
227*19d2e3deSDmitry Chagin 			Scp = (grp < gcnt) ? PRCHROOT : PRCH;
228*19d2e3deSDmitry Chagin 		}
229*19d2e3deSDmitry Chagin #else
2309ccc37e3SMark Peek 		Scp = (uid == 0 || euid == 0) ? PRCHROOT : PRCH;
231*19d2e3deSDmitry Chagin #endif
2329ccc37e3SMark Peek 		if (Scp != '\0')
2339ccc37e3SMark Peek 		    Strbuf_append1(&buf, attributes | Scp);
234c80476e4SDavid E. O'Brien 		break;
235c80476e4SDavid E. O'Brien 	    case '!':
236c80476e4SDavid E. O'Brien 	    case 'h':
237c80476e4SDavid E. O'Brien 		switch (what) {
238c80476e4SDavid E. O'Brien 		case FMT_HISTORY:
23945e5710bSMark Peek 		    cz = fmthist('h', info);
240c80476e4SDavid E. O'Brien 		    break;
241c80476e4SDavid E. O'Brien 		case FMT_SCHED:
24245e5710bSMark Peek 		    cz = xasprintf("%d", *(int *)info);
243c80476e4SDavid E. O'Brien 		    break;
244c80476e4SDavid E. O'Brien 		default:
24545e5710bSMark Peek 		    cz = xasprintf("%d", eventno + 1);
246c80476e4SDavid E. O'Brien 		    break;
247c80476e4SDavid E. O'Brien 		}
24845e5710bSMark Peek 		tprintf_append_mbs(&buf, cz, attributes);
24945e5710bSMark Peek 		xfree(cz);
250c80476e4SDavid E. O'Brien 		break;
251c80476e4SDavid E. O'Brien 	    case 'T':		/* 24 hour format	 */
252c80476e4SDavid E. O'Brien 	    case '@':
253c80476e4SDavid E. O'Brien 	    case 't':		/* 12 hour am/pm format */
254c80476e4SDavid E. O'Brien 	    case 'p':		/* With seconds	*/
255c80476e4SDavid E. O'Brien 	    case 'P':
256c80476e4SDavid E. O'Brien 		{
257c80476e4SDavid E. O'Brien 		    char    ampm = 'a';
258c80476e4SDavid E. O'Brien 		    int     hr = t->tm_hour;
259c80476e4SDavid E. O'Brien 
260c80476e4SDavid E. O'Brien 		    /* addition by Hans J. Albertsson */
261c80476e4SDavid E. O'Brien 		    /* and another adapted from Justin Bur */
262c80476e4SDavid E. O'Brien 		    if (adrof(STRampm) || (*cp != 'T' && *cp != 'P')) {
263c80476e4SDavid E. O'Brien 			if (hr >= 12) {
264c80476e4SDavid E. O'Brien 			    if (hr > 12)
265c80476e4SDavid E. O'Brien 				hr -= 12;
266c80476e4SDavid E. O'Brien 			    ampm = 'p';
267c80476e4SDavid E. O'Brien 			}
268c80476e4SDavid E. O'Brien 			else if (hr == 0)
269c80476e4SDavid E. O'Brien 			    hr = 12;
270c80476e4SDavid E. O'Brien 		    }		/* else do a 24 hour clock */
271c80476e4SDavid E. O'Brien 
272c80476e4SDavid E. O'Brien 		    /* "DING!" stuff by Hans also */
273c80476e4SDavid E. O'Brien 		    if (t->tm_min || print_prompt_did_ding ||
274c80476e4SDavid E. O'Brien 			what != FMT_PROMPT || adrof(STRnoding)) {
275c80476e4SDavid E. O'Brien 			if (t->tm_min)
276c80476e4SDavid E. O'Brien 			    print_prompt_did_ding = 0;
27745e5710bSMark Peek 			/*
27845e5710bSMark Peek 			 * Pad hour to 2 characters if padhour is set,
27945e5710bSMark Peek 			 * by ADAM David Alan Martin
28045e5710bSMark Peek 			 */
28145e5710bSMark Peek 			p = Itoa(hr, adrof(STRpadhour) ? 2 : 0, attributes);
28245e5710bSMark Peek 			Strbuf_append(&buf, p);
28345e5710bSMark Peek 			xfree(p);
28445e5710bSMark Peek 			Strbuf_append1(&buf, attributes | ':');
28545e5710bSMark Peek 			p = Itoa(t->tm_min, 2, attributes);
28645e5710bSMark Peek 			Strbuf_append(&buf, p);
28745e5710bSMark Peek 			xfree(p);
288c80476e4SDavid E. O'Brien 			if (*cp == 'p' || *cp == 'P') {
28945e5710bSMark Peek 			    Strbuf_append1(&buf, attributes | ':');
29045e5710bSMark Peek 			    p = Itoa(t->tm_sec, 2, attributes);
29145e5710bSMark Peek 			    Strbuf_append(&buf, p);
29245e5710bSMark Peek 			    xfree(p);
293c80476e4SDavid E. O'Brien 			}
294c80476e4SDavid E. O'Brien 			if (adrof(STRampm) || (*cp != 'T' && *cp != 'P')) {
29545e5710bSMark Peek 			    Strbuf_append1(&buf, attributes | ampm);
29645e5710bSMark Peek 			    Strbuf_append1(&buf, attributes | 'm');
297c80476e4SDavid E. O'Brien 			}
298c80476e4SDavid E. O'Brien 		    }
299c80476e4SDavid E. O'Brien 		    else {	/* we need to ding */
30045e5710bSMark Peek 			size_t i;
301c80476e4SDavid E. O'Brien 
30245e5710bSMark Peek 			for (i = 0; STRDING[i] != 0; i++)
30345e5710bSMark Peek 			    Strbuf_append1(&buf, attributes | STRDING[i]);
304c80476e4SDavid E. O'Brien 			print_prompt_did_ding = 1;
305c80476e4SDavid E. O'Brien 		    }
306c80476e4SDavid E. O'Brien 		}
307c80476e4SDavid E. O'Brien 		break;
308c80476e4SDavid E. O'Brien 
309c80476e4SDavid E. O'Brien 	    case 'M':
310c80476e4SDavid E. O'Brien #ifndef HAVENOUTMP
311c80476e4SDavid E. O'Brien 		if (what == FMT_WHO)
31245e5710bSMark Peek 		    cz = who_info(info, 'M');
313c80476e4SDavid E. O'Brien 		else
314c80476e4SDavid E. O'Brien #endif /* HAVENOUTMP */
31545e5710bSMark Peek 		    cz = getenv("HOST");
316c80476e4SDavid E. O'Brien 		/*
317c80476e4SDavid E. O'Brien 		 * Bug pointed out by Laurent Dami <dami@cui.unige.ch>: don't
318c80476e4SDavid E. O'Brien 		 * derefrence that NULL (if HOST is not set)...
319c80476e4SDavid E. O'Brien 		 */
320c80476e4SDavid E. O'Brien 		if (cz != NULL)
32145e5710bSMark Peek 		    tprintf_append_mbs(&buf, cz, attributes);
32245e5710bSMark Peek 		if (what == FMT_WHO)
32345e5710bSMark Peek 		    xfree(cz);
324c80476e4SDavid E. O'Brien 		break;
325c80476e4SDavid E. O'Brien 
32645e5710bSMark Peek 	    case 'm': {
32745e5710bSMark Peek 		char *scz = NULL;
328c80476e4SDavid E. O'Brien #ifndef HAVENOUTMP
329c80476e4SDavid E. O'Brien 		if (what == FMT_WHO)
33045e5710bSMark Peek 		    scz = cz = who_info(info, 'm');
331c80476e4SDavid E. O'Brien 		else
332c80476e4SDavid E. O'Brien #endif /* HAVENOUTMP */
33345e5710bSMark Peek 		    cz = getenv("HOST");
334c80476e4SDavid E. O'Brien 
335c80476e4SDavid E. O'Brien 		if (cz != NULL)
33645e5710bSMark Peek 		    while (*cz != 0 && (what == FMT_WHO || *cz != '.')) {
33745e5710bSMark Peek 			Char wc;
33845e5710bSMark Peek 
33945e5710bSMark Peek 			cz += one_mbtowc(&wc, cz, MB_LEN_MAX);
34045e5710bSMark Peek 			Strbuf_append1(&buf, wc | attributes);
34123338178SMark Peek 		    }
34245e5710bSMark Peek 		if (scz)
34345e5710bSMark Peek 		    xfree(scz);
344c80476e4SDavid E. O'Brien 		break;
34545e5710bSMark Peek 	    }
346c80476e4SDavid E. O'Brien 
347c80476e4SDavid E. O'Brien 			/* lukem: new directory prompt code */
348c80476e4SDavid E. O'Brien 	    case '~':
349c80476e4SDavid E. O'Brien 	    case '/':
350c80476e4SDavid E. O'Brien 	    case '.':
351c80476e4SDavid E. O'Brien 	    case 'c':
352c80476e4SDavid E. O'Brien 	    case 'C':
353c80476e4SDavid E. O'Brien 		Scp = *cp;
354c80476e4SDavid E. O'Brien 		if (Scp == 'c')		/* store format type (c == .) */
355c80476e4SDavid E. O'Brien 		    Scp = '.';
356c80476e4SDavid E. O'Brien 		if ((z = varval(STRcwd)) == STRNULL)
357c80476e4SDavid E. O'Brien 		    break;		/* no cwd, so don't do anything */
358c80476e4SDavid E. O'Brien 
359c80476e4SDavid E. O'Brien 			/* show ~ whenever possible - a la dirs */
360c80476e4SDavid E. O'Brien 		if (Scp == '~' || Scp == '.' ) {
36145e5710bSMark Peek 		    static Char *olddir = NULL;
36245e5710bSMark Peek 
363c80476e4SDavid E. O'Brien 		    if (tlength == 0 || olddir != z) {
364c80476e4SDavid E. O'Brien 			olddir = z;		/* have we changed dir? */
365c80476e4SDavid E. O'Brien 			olduser = getusername(&olddir);
366c80476e4SDavid E. O'Brien 		    }
367c80476e4SDavid E. O'Brien 		    if (olduser)
368c80476e4SDavid E. O'Brien 			z = olddir;
369c80476e4SDavid E. O'Brien 		}
370c80476e4SDavid E. O'Brien 		updirs = pdirs = 0;
371c80476e4SDavid E. O'Brien 
372c80476e4SDavid E. O'Brien 			/* option to determine fixed # of dirs from path */
373c80476e4SDavid E. O'Brien 		if (Scp == '.' || Scp == 'C') {
374c80476e4SDavid E. O'Brien 		    int skip;
3753b6eaa7bSAndrey A. Chernov #ifdef WINNT_NATIVE
37623338178SMark Peek 		    Char *oldz = z;
377c80476e4SDavid E. O'Brien 		    if (z[1] == ':') {
37845e5710bSMark Peek 			Strbuf_append1(&buf, attributes | *z++);
37945e5710bSMark Peek 			Strbuf_append1(&buf, attributes | *z++);
380c80476e4SDavid E. O'Brien 		    }
381c80476e4SDavid E. O'Brien 		    if (*z == '/' && z[1] == '/') {
38245e5710bSMark Peek 			Strbuf_append1(&buf, attributes | *z++);
38345e5710bSMark Peek 			Strbuf_append1(&buf, attributes | *z++);
384c80476e4SDavid E. O'Brien 			do {
38545e5710bSMark Peek 			    Strbuf_append1(&buf, attributes | *z++);
386c80476e4SDavid E. O'Brien 			} while(*z != '/');
387c80476e4SDavid E. O'Brien 		    }
3883b6eaa7bSAndrey A. Chernov #endif /* WINNT_NATIVE */
389c80476e4SDavid E. O'Brien 		    q = z;
390c80476e4SDavid E. O'Brien 		    while (*z)				/* calc # of /'s */
391c80476e4SDavid E. O'Brien 			if (*z++ == '/')
392c80476e4SDavid E. O'Brien 			    updirs++;
39323338178SMark Peek 
39423338178SMark Peek #ifdef WINNT_NATIVE
39523338178SMark Peek 		    /*
39623338178SMark Peek 		     * for format type c, prompt will be following...
39723338178SMark Peek 		     * c:/path                => c:/path
39823338178SMark Peek 		     * c:/path/to             => c:to
39923338178SMark Peek 		     * //machine/share        => //machine/share
40023338178SMark Peek 		     * //machine/share/folder => //machine:folder
40123338178SMark Peek 		     */
40223338178SMark Peek 		    if (oldz[0] == '/' && oldz[1] == '/' && updirs > 1)
40345e5710bSMark Peek 			Strbuf_append1(&buf, attributes | ':');
40423338178SMark Peek #endif /* WINNT_NATIVE */
405c80476e4SDavid E. O'Brien 		    if ((Scp == 'C' && *q != '/'))
406c80476e4SDavid E. O'Brien 			updirs++;
407c80476e4SDavid E. O'Brien 
408c80476e4SDavid E. O'Brien 		    if (cp[1] == '0') {			/* print <x> or ...  */
409c80476e4SDavid E. O'Brien 			pdirs = 1;
410c80476e4SDavid E. O'Brien 			cp++;
411c80476e4SDavid E. O'Brien 		    }
412c80476e4SDavid E. O'Brien 		    if (cp[1] >= '1' && cp[1] <= '9') {	/* calc # to skip  */
413c80476e4SDavid E. O'Brien 			skip = cp[1] - '0';
414c80476e4SDavid E. O'Brien 			cp++;
415c80476e4SDavid E. O'Brien 		    }
416c80476e4SDavid E. O'Brien 		    else
417c80476e4SDavid E. O'Brien 			skip = 1;
418c80476e4SDavid E. O'Brien 
419c80476e4SDavid E. O'Brien 		    updirs -= skip;
420c80476e4SDavid E. O'Brien 		    while (skip-- > 0) {
421c80476e4SDavid E. O'Brien 			while ((z > q) && (*z != '/'))
422c80476e4SDavid E. O'Brien 			    z--;			/* back up */
423c80476e4SDavid E. O'Brien 			if (skip && z > q)
424c80476e4SDavid E. O'Brien 			    z--;
425c80476e4SDavid E. O'Brien 		    }
426c80476e4SDavid E. O'Brien 		    if (*z == '/' && z != q)
427c80476e4SDavid E. O'Brien 			z++;
428c80476e4SDavid E. O'Brien 		} /* . || C */
429c80476e4SDavid E. O'Brien 
430c80476e4SDavid E. O'Brien 							/* print ~[user] */
431c80476e4SDavid E. O'Brien 		if ((olduser) && ((Scp == '~') ||
432c80476e4SDavid E. O'Brien 		     (Scp == '.' && (pdirs || (!pdirs && updirs <= 0))) )) {
43345e5710bSMark Peek 		    Strbuf_append1(&buf, attributes | '~');
43445e5710bSMark Peek 		    for (q = olduser; *q; q++)
43545e5710bSMark Peek 			Strbuf_append1(&buf, attributes | *q);
436c80476e4SDavid E. O'Brien 		}
437c80476e4SDavid E. O'Brien 
438c80476e4SDavid E. O'Brien 			/* RWM - tell you how many dirs we've ignored */
439c80476e4SDavid E. O'Brien 			/*       and add '/' at front of this         */
440c80476e4SDavid E. O'Brien 		if (updirs > 0 && pdirs) {
441c80476e4SDavid E. O'Brien 		    if (adrof(STRellipsis)) {
44245e5710bSMark Peek 			Strbuf_append1(&buf, attributes | '.');
44345e5710bSMark Peek 			Strbuf_append1(&buf, attributes | '.');
44445e5710bSMark Peek 			Strbuf_append1(&buf, attributes | '.');
445c80476e4SDavid E. O'Brien 		    } else {
44645e5710bSMark Peek 			Strbuf_append1(&buf, attributes | '/');
44745e5710bSMark Peek 			Strbuf_append1(&buf, attributes | '<');
448c80476e4SDavid E. O'Brien 			if (updirs > 9) {
44945e5710bSMark Peek 			    Strbuf_append1(&buf, attributes | '9');
45045e5710bSMark Peek 			    Strbuf_append1(&buf, attributes | '+');
451c80476e4SDavid E. O'Brien 			} else
45245e5710bSMark Peek 			    Strbuf_append1(&buf, attributes | ('0' + updirs));
45345e5710bSMark Peek 			Strbuf_append1(&buf, attributes | '>');
454c80476e4SDavid E. O'Brien 		    }
455c80476e4SDavid E. O'Brien 		}
456c80476e4SDavid E. O'Brien 
45745e5710bSMark Peek 		while (*z)
45845e5710bSMark Peek 		    Strbuf_append1(&buf, attributes | *z++);
459c80476e4SDavid E. O'Brien 		break;
460c80476e4SDavid E. O'Brien 			/* lukem: end of new directory prompt code */
461c80476e4SDavid E. O'Brien 
462c80476e4SDavid E. O'Brien 	    case 'n':
463c80476e4SDavid E. O'Brien #ifndef HAVENOUTMP
464c80476e4SDavid E. O'Brien 		if (what == FMT_WHO) {
46545e5710bSMark Peek 		    cz = who_info(info, 'n');
46645e5710bSMark Peek 		    tprintf_append_mbs(&buf, cz, attributes);
46745e5710bSMark Peek 		    xfree(cz);
468c80476e4SDavid E. O'Brien 		}
469c80476e4SDavid E. O'Brien 		else
470c80476e4SDavid E. O'Brien #endif /* HAVENOUTMP */
471c80476e4SDavid E. O'Brien 		{
472c80476e4SDavid E. O'Brien 		    if ((z = varval(STRuser)) != STRNULL)
47345e5710bSMark Peek 			while (*z)
47445e5710bSMark Peek 			    Strbuf_append1(&buf, attributes | *z++);
475c80476e4SDavid E. O'Brien 		}
476c80476e4SDavid E. O'Brien 		break;
4779ccc37e3SMark Peek 	    case 'N':
4789ccc37e3SMark Peek 		if ((z = varval(STReuser)) != STRNULL)
4799ccc37e3SMark Peek 		    while (*z)
4809ccc37e3SMark Peek 			Strbuf_append1(&buf, attributes | *z++);
4819ccc37e3SMark Peek 		break;
482c80476e4SDavid E. O'Brien 	    case 'l':
483c80476e4SDavid E. O'Brien #ifndef HAVENOUTMP
484c80476e4SDavid E. O'Brien 		if (what == FMT_WHO) {
48545e5710bSMark Peek 		    cz = who_info(info, 'l');
48645e5710bSMark Peek 		    tprintf_append_mbs(&buf, cz, attributes);
48745e5710bSMark Peek 		    xfree(cz);
488c80476e4SDavid E. O'Brien 		}
489c80476e4SDavid E. O'Brien 		else
490c80476e4SDavid E. O'Brien #endif /* HAVENOUTMP */
491c80476e4SDavid E. O'Brien 		{
492c80476e4SDavid E. O'Brien 		    if ((z = varval(STRtty)) != STRNULL)
49345e5710bSMark Peek 			while (*z)
49445e5710bSMark Peek 			    Strbuf_append1(&buf, attributes | *z++);
495c80476e4SDavid E. O'Brien 		}
496c80476e4SDavid E. O'Brien 		break;
497c80476e4SDavid E. O'Brien 	    case 'd':
49845e5710bSMark Peek 		tprintf_append_mbs(&buf, day_list[t->tm_wday], attributes);
499c80476e4SDavid E. O'Brien 		break;
500c80476e4SDavid E. O'Brien 	    case 'D':
50145e5710bSMark Peek 		p = Itoa(t->tm_mday, 2, attributes);
50245e5710bSMark Peek 		Strbuf_append(&buf, p);
50345e5710bSMark Peek 		xfree(p);
504c80476e4SDavid E. O'Brien 		break;
505c80476e4SDavid E. O'Brien 	    case 'w':
50645e5710bSMark Peek 		tprintf_append_mbs(&buf, month_list[t->tm_mon], attributes);
507c80476e4SDavid E. O'Brien 		break;
508c80476e4SDavid E. O'Brien 	    case 'W':
50945e5710bSMark Peek 		p = Itoa(t->tm_mon + 1, 2, attributes);
51045e5710bSMark Peek 		Strbuf_append(&buf, p);
51145e5710bSMark Peek 		xfree(p);
512c80476e4SDavid E. O'Brien 		break;
513c80476e4SDavid E. O'Brien 	    case 'y':
51445e5710bSMark Peek 		p = Itoa(t->tm_year % 100, 2, attributes);
51545e5710bSMark Peek 		Strbuf_append(&buf, p);
51645e5710bSMark Peek 		xfree(p);
517c80476e4SDavid E. O'Brien 		break;
518c80476e4SDavid E. O'Brien 	    case 'Y':
51945e5710bSMark Peek 		p = Itoa(t->tm_year + 1900, 4, attributes);
52045e5710bSMark Peek 		Strbuf_append(&buf, p);
52145e5710bSMark Peek 		xfree(p);
522c80476e4SDavid E. O'Brien 		break;
523c80476e4SDavid E. O'Brien 	    case 'S':		/* start standout */
524c80476e4SDavid E. O'Brien 		attributes |= STANDOUT;
525c80476e4SDavid E. O'Brien 		break;
526c80476e4SDavid E. O'Brien 	    case 'B':		/* start bold */
527c80476e4SDavid E. O'Brien 		attributes |= BOLD;
528c80476e4SDavid E. O'Brien 		break;
529c80476e4SDavid E. O'Brien 	    case 'U':		/* start underline */
530c80476e4SDavid E. O'Brien 		attributes |= UNDER;
531c80476e4SDavid E. O'Brien 		break;
532c80476e4SDavid E. O'Brien 	    case 's':		/* end standout */
533c80476e4SDavid E. O'Brien 		attributes &= ~STANDOUT;
534c80476e4SDavid E. O'Brien 		break;
535c80476e4SDavid E. O'Brien 	    case 'b':		/* end bold */
536c80476e4SDavid E. O'Brien 		attributes &= ~BOLD;
537c80476e4SDavid E. O'Brien 		break;
538c80476e4SDavid E. O'Brien 	    case 'u':		/* end underline */
539c80476e4SDavid E. O'Brien 		attributes &= ~UNDER;
540c80476e4SDavid E. O'Brien 		break;
541c80476e4SDavid E. O'Brien 	    case 'L':
542c80476e4SDavid E. O'Brien 		ClearToBottom();
543c80476e4SDavid E. O'Brien 		break;
54429301572SMark Peek 
54529301572SMark Peek 	    case 'j':
54629301572SMark Peek 		{
54729301572SMark Peek 		    int njobs = -1;
54829301572SMark Peek 		    struct process *pp;
54945e5710bSMark Peek 
55029301572SMark Peek 		    for (pp = proclist.p_next; pp; pp = pp->p_next)
55129301572SMark Peek 			njobs++;
5529ccc37e3SMark Peek 		    if (njobs == -1)
5539ccc37e3SMark Peek 			njobs++;
55445e5710bSMark Peek 		    p = Itoa(njobs, 1, attributes);
55545e5710bSMark Peek 		    Strbuf_append(&buf, p);
55645e5710bSMark Peek 		    xfree(p);
55729301572SMark Peek 		    break;
55829301572SMark Peek 		}
559c80476e4SDavid E. O'Brien 	    case '?':
560c80476e4SDavid E. O'Brien 		if ((z = varval(STRstatus)) != STRNULL)
56145e5710bSMark Peek 		    while (*z)
56245e5710bSMark Peek 			Strbuf_append1(&buf, attributes | *z++);
563c80476e4SDavid E. O'Brien 		break;
564c80476e4SDavid E. O'Brien 	    case '$':
56545e5710bSMark Peek 		expdollar(&buf, &cp, attributes);
56645e5710bSMark Peek 		/* cp should point the last char of current % sequence */
56729301572SMark Peek 		cp--;
568c80476e4SDavid E. O'Brien 		break;
569c80476e4SDavid E. O'Brien 	    case '%':
57045e5710bSMark Peek 		Strbuf_append1(&buf, attributes | '%');
571c80476e4SDavid E. O'Brien 		break;
572c80476e4SDavid E. O'Brien 	    case '{':		/* literal characters start */
573c80476e4SDavid E. O'Brien #if LITERAL == 0
574c80476e4SDavid E. O'Brien 		/*
575c80476e4SDavid E. O'Brien 		 * No literal capability, so skip all chars in the literal
576c80476e4SDavid E. O'Brien 		 * string
577c80476e4SDavid E. O'Brien 		 */
57845e5710bSMark Peek 		while (*cp != '\0' && (cp[-1] != '%' || *cp != '}'))
579c80476e4SDavid E. O'Brien 		    cp++;
580c80476e4SDavid E. O'Brien #endif				/* LITERAL == 0 */
581c80476e4SDavid E. O'Brien 		attributes |= LITERAL;
582c80476e4SDavid E. O'Brien 		break;
583c80476e4SDavid E. O'Brien 	    case '}':		/* literal characters end */
584c80476e4SDavid E. O'Brien 		attributes &= ~LITERAL;
585c80476e4SDavid E. O'Brien 		break;
586c80476e4SDavid E. O'Brien 	    default:
587c80476e4SDavid E. O'Brien #ifndef HAVENOUTMP
588c80476e4SDavid E. O'Brien 		if (*cp == 'a' && what == FMT_WHO) {
58945e5710bSMark Peek 		    cz = who_info(info, 'a');
59045e5710bSMark Peek 		    tprintf_append_mbs(&buf, cz, attributes);
59145e5710bSMark Peek 		    xfree(cz);
592c80476e4SDavid E. O'Brien 		}
593c80476e4SDavid E. O'Brien 		else
594c80476e4SDavid E. O'Brien #endif /* HAVENOUTMP */
595c80476e4SDavid E. O'Brien 		{
59645e5710bSMark Peek 		    Strbuf_append1(&buf, attributes | '%');
59745e5710bSMark Peek 		    Strbuf_append1(&buf, attributes | *cp);
598c80476e4SDavid E. O'Brien 		}
599c80476e4SDavid E. O'Brien 		break;
600c80476e4SDavid E. O'Brien 	    }
601c80476e4SDavid E. O'Brien 	}
602c80476e4SDavid E. O'Brien 	else if (*cp == '\\' || *cp == '^')
60345e5710bSMark Peek 	    Strbuf_append1(&buf, attributes | parseescape(&cp));
604c80476e4SDavid E. O'Brien 	else if (*cp == HIST) {	/* EGS: handle '!'s in prompts */
605c80476e4SDavid E. O'Brien 	    if (what == FMT_HISTORY)
60645e5710bSMark Peek 		cz = fmthist('h', info);
607c80476e4SDavid E. O'Brien 	    else
60845e5710bSMark Peek 		cz = xasprintf("%d", eventno + 1);
60945e5710bSMark Peek 	    tprintf_append_mbs(&buf, cz, attributes);
61045e5710bSMark Peek 	    xfree(cz);
611c80476e4SDavid E. O'Brien 	}
612c80476e4SDavid E. O'Brien 	else
61345e5710bSMark Peek 	    Strbuf_append1(&buf, attributes | *cp); /* normal character */
614c80476e4SDavid E. O'Brien     }
61545e5710bSMark Peek     cleanup_ignore(&buf);
61645e5710bSMark Peek     cleanup_until(&buf);
61745e5710bSMark Peek     return Strbuf_finish(&buf);
618c80476e4SDavid E. O'Brien }
619c80476e4SDavid E. O'Brien 
62045e5710bSMark Peek int
62145e5710bSMark Peek expdollar(struct Strbuf *buf, const Char **srcp, Char attr)
622c80476e4SDavid E. O'Brien {
623c80476e4SDavid E. O'Brien     struct varent *vp;
624c80476e4SDavid E. O'Brien     const Char *src = *srcp;
62545e5710bSMark Peek     Char *var, *val;
62645e5710bSMark Peek     size_t i;
62745e5710bSMark Peek     int curly = 0;
628c80476e4SDavid E. O'Brien 
629c80476e4SDavid E. O'Brien     /* found a variable, expand it */
63045e5710bSMark Peek     var = xmalloc((Strlen(src) + 1) * sizeof (*var));
63145e5710bSMark Peek     for (i = 0; ; i++) {
632c80476e4SDavid E. O'Brien 	var[i] = *++src & TRIM;
633c80476e4SDavid E. O'Brien 	if (i == 0 && var[i] == '{') {
634c80476e4SDavid E. O'Brien 	    curly = 1;
635c80476e4SDavid E. O'Brien 	    var[i] = *++src & TRIM;
636c80476e4SDavid E. O'Brien 	}
63745e5710bSMark Peek 	if (!alnum(var[i]) && var[i] != '_') {
638c80476e4SDavid E. O'Brien 
639c80476e4SDavid E. O'Brien 	    var[i] = '\0';
640c80476e4SDavid E. O'Brien 	    break;
641c80476e4SDavid E. O'Brien 	}
642c80476e4SDavid E. O'Brien     }
643c80476e4SDavid E. O'Brien     if (curly && (*src & TRIM) == '}')
644c80476e4SDavid E. O'Brien 	src++;
645c80476e4SDavid E. O'Brien 
646c80476e4SDavid E. O'Brien     vp = adrof(var);
64729301572SMark Peek     if (vp && vp->vec) {
648c80476e4SDavid E. O'Brien 	for (i = 0; vp->vec[i] != NULL; i++) {
64945e5710bSMark Peek 	    for (val = vp->vec[i]; *val; val++)
65045e5710bSMark Peek 		if (*val != '\n' && *val != '\r')
65145e5710bSMark Peek 		    Strbuf_append1(buf, *val | attr);
65245e5710bSMark Peek 	    if (vp->vec[i+1])
65345e5710bSMark Peek 		Strbuf_append1(buf, ' ' | attr);
654c80476e4SDavid E. O'Brien 	}
655c80476e4SDavid E. O'Brien     }
656c80476e4SDavid E. O'Brien     else {
65745e5710bSMark Peek 	val = (!vp) ? tgetenv(var) : NULL;
65845e5710bSMark Peek 	if (val) {
65945e5710bSMark Peek 	    for (; *val; val++)
66045e5710bSMark Peek 		if (*val != '\n' && *val != '\r')
66145e5710bSMark Peek 		    Strbuf_append1(buf, *val | attr);
66245e5710bSMark Peek 	} else {
663c80476e4SDavid E. O'Brien 	    *srcp = src;
66445e5710bSMark Peek 	    xfree(var);
66545e5710bSMark Peek 	    return 0;
666c80476e4SDavid E. O'Brien 	}
66745e5710bSMark Peek     }
668c80476e4SDavid E. O'Brien 
669c80476e4SDavid E. O'Brien     *srcp = src;
67045e5710bSMark Peek     xfree(var);
67145e5710bSMark Peek     return 1;
672c80476e4SDavid E. O'Brien }
673