Kernel part of bluetooth stack ported by Dmitry Komissaroff. Very much work
[dragonfly.git] / contrib / tcsh / tc.prompt.c
blob6c0a0a41fd6c12449c27cef2925296d56a320d5b
1 /* $Header: /src/pub/tcsh/tc.prompt.c,v 3.46 2002/07/12 13:16:19 christos Exp $ */
2 /*
3 * tc.prompt.c: Prompt printing stuff
4 */
5 /*-
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
7 * All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
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
31 * SUCH DAMAGE.
33 #include "sh.h"
35 RCSID("$Id: tc.prompt.c,v 3.46 2002/07/12 13:16:19 christos Exp $")
37 #include "ed.h"
38 #include "tw.h"
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];
54 void
55 dateinit()
57 #ifdef notyet
58 int i;
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]);
86 #else
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";
100 day_list[0] = "Sun";
101 day_list[1] = "Mon";
102 day_list[2] = "Tue";
103 day_list[3] = "Wed";
104 day_list[4] = "Thu";
105 day_list[5] = "Fri";
106 day_list[6] = "Sat";
107 #endif
110 void
111 printprompt(promptno, str)
112 int promptno;
113 char *str;
115 static Char *ocp = NULL;
116 static char *ostr = NULL;
117 time_t lclock = time(NULL);
118 Char *cp;
120 switch (promptno) {
121 default:
122 case 0:
123 cp = varval(STRprompt);
124 break;
125 case 1:
126 cp = varval(STRprompt2);
127 break;
128 case 2:
129 cp = varval(STRprompt3);
130 break;
131 case 3:
132 if (ocp != NULL) {
133 cp = ocp;
134 str = ostr;
136 else
137 cp = varval(STRprompt);
138 break;
141 if (promptno < 2) {
142 ocp = cp;
143 ostr = str;
146 PromptBuf[0] = '\0';
147 tprintf(FMT_PROMPT, PromptBuf, cp, 2 * INBUFSIZE - 2, str, lclock, NULL);
149 if (!editing) {
150 for (cp = PromptBuf; *cp ; )
151 (void) putraw(*cp++);
152 SetAttributes(0);
153 flush();
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++);
165 SetAttributes(0);
166 putraw(' ');
167 flush();
172 void
173 tprintf(what, buf, fmt, siz, str, tim, info)
174 int what;
175 Char *buf;
176 const Char *fmt;
177 size_t siz;
178 char *str;
179 time_t tim;
180 ptr_t info;
182 Char *z, *q;
183 Char attributes = 0;
184 static int print_prompt_did_ding = 0;
185 Char buff[BUFSIZE];
186 /* Need to be unsigned to avoid sign extension */
187 const unsigned char *cz;
188 unsigned char cbuff[BUFSIZE];
190 Char *p = buf;
191 Char *ep = &p[siz];
192 const Char *cp = fmt;
193 Char Scp;
194 struct tm *t = localtime(&tim);
196 /* prompt stuff */
197 static Char *olddir = NULL, *olduser = NULL;
198 extern int tlength; /* cache cleared */
199 int updirs;
200 size_t pdirs, sz;
202 for (; *cp; cp++) {
203 if (p >= ep)
204 break;
205 #ifdef DSPMBYTE
206 if (Ismbyte1(*cp) && ! (cp[1] == '\0'))
208 *p++ = attributes | *cp++; /* normal character */
209 *p++ = attributes | *cp; /* normal character */
211 else
212 #endif /* DSPMBYTE */
213 if ((*cp == '%') && ! (cp[1] == '\0')) {
214 cp++;
215 switch (*cp) {
216 case 'R':
217 if (what == FMT_HISTORY)
218 fmthist('R', info, (char *) (cz = cbuff), sizeof(cbuff));
219 else
220 cz = (unsigned char *) str;
221 if (cz != NULL)
222 for (; *cz; *p++ = attributes | *cz++)
223 if (p >= ep) break;
224 break;
225 case '#':
226 *p++ = attributes | ((uid == 0) ? PRCHROOT : PRCH);
227 break;
228 case '!':
229 case 'h':
230 switch (what) {
231 case FMT_HISTORY:
232 fmthist('h', info, (char *) cbuff, sizeof(cbuff));
233 break;
234 case FMT_SCHED:
235 (void) xsnprintf((char *) cbuff, sizeof(cbuff), "%d",
236 *(int *)info);
237 break;
238 default:
239 (void) xsnprintf((char *) cbuff, sizeof(cbuff), "%d",
240 eventno + 1);
241 break;
243 for (cz = cbuff; *cz; *p++ = attributes | *cz++)
244 if (p >= ep) break;
245 break;
246 case 'T': /* 24 hour format */
247 case '@':
248 case 't': /* 12 hour am/pm format */
249 case 'p': /* With seconds */
250 case 'P':
252 char ampm = 'a';
253 int hr = t->tm_hour;
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')) {
260 if (hr >= 12) {
261 if (hr > 12)
262 hr -= 12;
263 ampm = 'p';
265 else if (hr == 0)
266 hr = 12;
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)) {
272 if (t->tm_min)
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 */
287 int i = 0;
289 (void) Strcpy(buff, STRDING);
290 while (buff[i]) {
291 *p++ = attributes | buff[i++];
293 print_prompt_did_ding = 1;
296 break;
298 case 'M':
299 #ifndef HAVENOUTMP
300 if (what == FMT_WHO)
301 cz = (unsigned char *) who_info(info, 'M',
302 (char *) cbuff, sizeof(cbuff));
303 else
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)...
310 if (cz != NULL)
311 for (; *cz ; *p++ = attributes | *cz++)
312 if (p >= ep) break;
313 break;
315 case 'm':
316 #ifndef HAVENOUTMP
317 if (what == FMT_WHO)
318 cz = (unsigned char *) who_info(info, 'm', (char *) cbuff,
319 sizeof(cbuff));
320 else
321 #endif /* HAVENOUTMP */
322 cz = (unsigned char *) getenv("HOST");
324 if (cz != NULL)
325 for ( ; *cz && (what == FMT_WHO || *cz != '.')
326 ; *p++ = attributes | *cz++ )
327 if (p >= ep) break;
328 break;
330 /* lukem: new directory prompt code */
331 case '~':
332 case '/':
333 case '.':
334 case 'c':
335 case 'C':
336 Scp = *cp;
337 if (Scp == 'c') /* store format type (c == .) */
338 Scp = '.';
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);
348 if (olduser)
349 z = olddir;
351 updirs = pdirs = 0;
353 /* option to determine fixed # of dirs from path */
354 if (Scp == '.' || Scp == 'C') {
355 int skip;
356 #ifdef WINNT_NATIVE
357 if (z[1] == ':') {
358 *p++ = attributes | *z++;
359 *p++ = attributes | *z++;
361 if (*z == '/' && z[1] == '/') {
362 *p++ = attributes | *z++;
363 *p++ = attributes | *z++;
364 do {
365 *p++ = attributes | *z++;
366 }while(*z != '/');
368 #endif /* WINNT_NATIVE */
369 q = z;
370 while (*z) /* calc # of /'s */
371 if (*z++ == '/')
372 updirs++;
373 if ((Scp == 'C' && *q != '/'))
374 updirs++;
376 if (cp[1] == '0') { /* print <x> or ... */
377 pdirs = 1;
378 cp++;
380 if (cp[1] >= '1' && cp[1] <= '9') { /* calc # to skip */
381 skip = cp[1] - '0';
382 cp++;
384 else
385 skip = 1;
387 updirs -= skip;
388 while (skip-- > 0) {
389 while ((z > q) && (*z != '/'))
390 z--; /* back up */
391 if (skip && z > q)
392 z--;
394 if (*z == '/' && z != q)
395 z++;
396 } /* . || C */
398 /* print ~[user] */
399 if ((olduser) && ((Scp == '~') ||
400 (Scp == '.' && (pdirs || (!pdirs && updirs <= 0))) )) {
401 *p++ = attributes | '~';
402 if (p >= ep) break;
403 for (q = olduser; *q; *p++ = attributes | *q++)
404 if (p >= ep) break;
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 | '.';
415 } else {
416 *p++ = attributes | '/';
417 *p++ = attributes | '<';
418 if (updirs > 9) {
419 *p++ = attributes | '9';
420 *p++ = attributes | '+';
421 } else
422 *p++ = attributes | ('0' + updirs);
423 *p++ = attributes | '>';
427 for (; *z ; *p++ = attributes | *z++)
428 if (p >= ep) break;
429 break;
430 /* lukem: end of new directory prompt code */
432 case 'n':
433 #ifndef HAVENOUTMP
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++)
438 if (p >= ep) break;
440 else
441 #endif /* HAVENOUTMP */
443 if ((z = varval(STRuser)) != STRNULL)
444 for (; *z; *p++ = attributes | *z++)
445 if (p >= ep) break;
447 break;
448 case 'l':
449 #ifndef HAVENOUTMP
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++)
454 if (p >= ep) break;
456 else
457 #endif /* HAVENOUTMP */
459 if ((z = varval(STRtty)) != STRNULL)
460 for (; *z; *p++ = attributes | *z++)
461 if (p >= ep) break;
463 break;
464 case 'd':
465 for (cz = (unsigned char *) day_list[t->tm_wday]; *cz;
466 *p++ = attributes | *cz++)
467 if (p >= ep) break;
468 break;
469 case 'D':
470 if (p >= ep - 3) break;
471 p = Itoa(t->tm_mday, p, 2, attributes);
472 break;
473 case 'w':
474 if (p >= ep - 5) break;
475 for (cz = (unsigned char *) month_list[t->tm_mon]; *cz;
476 *p++ = attributes | *cz++)
477 if (p >= ep) break;
478 break;
479 case 'W':
480 if (p >= ep - 3) break;
481 p = Itoa(t->tm_mon + 1, p, 2, attributes);
482 break;
483 case 'y':
484 if (p >= ep - 3) break;
485 p = Itoa(t->tm_year % 100, p, 2, attributes);
486 break;
487 case 'Y':
488 if (p >= ep - 5) break;
489 p = Itoa(t->tm_year + 1900, p, 4, attributes);
490 break;
491 case 'S': /* start standout */
492 attributes |= STANDOUT;
493 break;
494 case 'B': /* start bold */
495 attributes |= BOLD;
496 break;
497 case 'U': /* start underline */
498 attributes |= UNDER;
499 break;
500 case 's': /* end standout */
501 attributes &= ~STANDOUT;
502 break;
503 case 'b': /* end bold */
504 attributes &= ~BOLD;
505 break;
506 case 'u': /* end underline */
507 attributes &= ~UNDER;
508 break;
509 case 'L':
510 ClearToBottom();
511 break;
513 case 'j':
515 Char buf[128], *ebuf, *q;
516 int njobs = -1;
517 struct process *pp;
518 for (pp = proclist.p_next; pp; pp = pp->p_next)
519 njobs++;
520 /* make sure we have space */
521 ebuf = Itoa(njobs, buf, 1, attributes);
522 for (q = buf; q < ebuf; *p++ = *q++)
523 if (p >= ep) break;
524 break;
526 case '?':
527 if ((z = varval(STRstatus)) != STRNULL)
528 for (; *z; *p++ = attributes | *z++)
529 if (p >= ep) break;
530 break;
531 case '$':
532 sz = ep - p;
533 (void) expdollar(&p, &cp, &sz, attributes);
534 /* cp should point the last char of currnet % sequence */
535 cp--;
536 break;
537 case '%':
538 *p++ = attributes | '%';
539 break;
540 case '{': /* literal characters start */
541 #if LITERAL == 0
543 * No literal capability, so skip all chars in the literal
544 * string
546 while (*cp != '\0' && (*cp != '%' || cp[1] != '}'))
547 cp++;
548 #endif /* LITERAL == 0 */
549 attributes |= LITERAL;
550 break;
551 case '}': /* literal characters end */
552 attributes &= ~LITERAL;
553 break;
554 default:
555 #ifndef HAVENOUTMP
556 if (*cp == 'a' && what == FMT_WHO) {
557 cz = who_info(info, 'a', (char *) cbuff, sizeof(cbuff));
558 for (; cz && *cz; *p++ = attributes | *cz++)
559 if (p >= ep) break;
561 else
562 #endif /* HAVENOUTMP */
564 if (p >= ep - 3) break;
565 *p++ = attributes | '%';
566 *p++ = attributes | *cp;
568 break;
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));
576 else
577 (void) xsnprintf((char *) cbuff, sizeof(cbuff), "%d", eventno + 1);
578 for (cz = cbuff; *cz; *p++ = attributes | *cz++)
579 if (p >= ep) break;
581 else
582 *p++ = attributes | *cp; /* normal character */
584 *p = '\0';
587 Char *
588 expdollar(dstp, srcp, spp, attr)
589 Char **dstp;
590 const Char **srcp;
591 size_t *spp;
592 int attr;
594 struct varent *vp;
595 Char var[MAXVARLEN];
596 const Char *src = *srcp;
597 Char *val;
598 Char *dst = *dstp;
599 int i, curly = 0;
601 /* found a variable, expand it */
602 for (i = 0; i < MAXVARLEN; i++) {
603 var[i] = *++src & TRIM;
604 if (i == 0 && var[i] == '{') {
605 curly = 1;
606 var[i] = *++src & TRIM;
608 if (!alnum(var[i])) {
610 var[i] = '\0';
611 break;
614 if (curly && (*src & TRIM) == '}')
615 src++;
617 vp = adrof(var);
618 val = (!vp) ? tgetenv(var) : NULL;
619 if (vp && vp->vec) {
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) {
624 *dst++ = ' ' | attr;
625 (*spp)--;
629 else if (val) {
630 for (; *spp > 0 && *val; (*spp)--)
631 *dst++ = *val++ | attr;
633 else {
634 **dstp = '\0';
635 *srcp = src;
636 return NULL;
638 *dst = '\0';
640 val = *dstp;
641 *srcp = src;
642 *dstp = dst;
644 return val;