]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcsh/tc.prompt.c
This commit was generated by cvs2svn to compensate for changes in r80260,
[FreeBSD/FreeBSD.git] / contrib / tcsh / tc.prompt.c
1 /* $Header: /src/pub/tcsh/tc.prompt.c,v 3.41 2000/11/11 23:03:39 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.
8  *
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. 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.
24  *
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
35  * SUCH DAMAGE.
36  */
37 #include "sh.h"
38
39 RCSID("$Id: tc.prompt.c,v 3.41 2000/11/11 23:03:39 christos Exp $")
40
41 #include "ed.h"
42 #include "tw.h"
43
44 /*
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
53  */
54
55 static char   *month_list[12];
56 static char   *day_list[7];
57
58 void
59 dateinit()
60 {
61 #ifdef notyet
62   int i;
63
64   setlocale(LC_TIME, "");
65
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]);
80
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]);
90 #else
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";
103
104   day_list[0] = "Sun";
105   day_list[1] = "Mon";
106   day_list[2] = "Tue";
107   day_list[3] = "Wed";
108   day_list[4] = "Thu";
109   day_list[5] = "Fri";
110   day_list[6] = "Sat";
111 #endif
112 }
113
114 void
115 printprompt(promptno, str)
116     int     promptno;
117     char   *str;
118 {
119     static  Char *ocp = NULL;
120     static  char *ostr = NULL;
121     time_t  lclock = time(NULL);
122     Char   *cp;
123
124     switch (promptno) {
125     default:
126     case 0:
127         cp = varval(STRprompt);
128         break;
129     case 1:
130         cp = varval(STRprompt2);
131         break;
132     case 2:
133         cp = varval(STRprompt3);
134         break;
135     case 3:
136         if (ocp != NULL) {
137             cp = ocp;
138             str = ostr;
139         }
140         else 
141             cp = varval(STRprompt);
142         break;
143     }
144
145     if (promptno < 2) {
146         ocp = cp;
147         ostr = str;
148     }
149
150     PromptBuf[0] = '\0';
151     tprintf(FMT_PROMPT, PromptBuf, cp, 2 * INBUFSIZE - 2, str, lclock, NULL);
152
153     if (!editing) {
154         for (cp = PromptBuf; *cp ; )
155             (void) putraw(*cp++);
156         SetAttributes(0);
157         flush();
158     }
159
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);
164
165                                 /* if not editing, put rprompt after prompt */
166         if (!editing && RPromptBuf[0] != '\0') {
167             for (cp = RPromptBuf; *cp ; )
168                 (void) putraw(*cp++);
169             SetAttributes(0);
170             putraw(' ');
171             flush();
172         }
173     }
174 }
175
176 void
177 tprintf(what, buf, fmt, siz, str, tim, info)
178     int what;
179     Char *buf;
180     const Char *fmt;
181     size_t siz;
182     char *str;
183     time_t tim;
184     ptr_t info;
185 {
186     Char   *z, *q;
187     Char    attributes = 0;
188     static int print_prompt_did_ding = 0;
189     Char    buff[BUFSIZE];
190     /* Need to be unsigned to avoid sign extension */
191     const unsigned char   *cz;
192     unsigned char    cbuff[BUFSIZE];
193
194     Char *p  = buf;
195     Char *ep = &p[siz];
196     const Char *cp = fmt;
197     Char Scp;
198     struct tm *t = localtime(&tim);
199
200                         /* prompt stuff */
201     static Char *olddir = NULL, *olduser = NULL;
202     extern int tlength; /* cache cleared */
203     int updirs, sz;
204     size_t pdirs;
205
206     for (; *cp; cp++) {
207         if (p >= ep)
208             break;
209 #ifdef DSPMBYTE
210         if (Ismbyte1(*cp) && ! (cp[1] == '\0'))
211         {
212             *p++ = attributes | *cp++;  /* normal character */
213             *p++ = attributes | *cp;    /* normal character */
214         }
215         else
216 #endif /* DSPMBYTE */
217         if ((*cp == '%') && ! (cp[1] == '\0')) {
218             cp++;
219             switch (*cp) {
220             case 'R':
221                 if (what == FMT_HISTORY)
222                     fmthist('R', info, (char *) (cz = cbuff), sizeof(cbuff));
223                 else
224                     cz = (unsigned char *) str;
225                 if (cz != NULL)
226                     for (; *cz; *p++ = attributes | *cz++)
227                         if (p >= ep) break;
228                 break;
229             case '#':
230                 *p++ = attributes | ((uid == 0) ? PRCHROOT : PRCH);
231                 break;
232             case '!':
233             case 'h':
234                 switch (what) {
235                 case FMT_HISTORY:
236                     fmthist('h', info, (char *) cbuff, sizeof(cbuff));
237                     break;
238                 case FMT_SCHED:
239                     (void) xsnprintf((char *) cbuff, sizeof(cbuff), "%d", 
240                         *(int *)info);
241                     break;
242                 default:
243                     (void) xsnprintf((char *) cbuff, sizeof(cbuff), "%d",
244                         eventno + 1);
245                     break;
246                 }
247                 for (cz = cbuff; *cz; *p++ = attributes | *cz++)
248                     if (p >= ep) break;
249                 break;
250             case 'T':           /* 24 hour format        */
251             case '@':
252             case 't':           /* 12 hour am/pm format */
253             case 'p':           /* With seconds */
254             case 'P':
255                 {
256                     char    ampm = 'a';
257                     int     hr = t->tm_hour;
258
259                     if (p >= ep - 10) break;
260
261                     /* addition by Hans J. Albertsson */
262                     /* and another adapted from Justin Bur */
263                     if (adrof(STRampm) || (*cp != 'T' && *cp != 'P')) {
264                         if (hr >= 12) {
265                             if (hr > 12)
266                                 hr -= 12;
267                             ampm = 'p';
268                         }
269                         else if (hr == 0)
270                             hr = 12;
271                     }           /* else do a 24 hour clock */
272
273                     /* "DING!" stuff by Hans also */
274                     if (t->tm_min || print_prompt_did_ding || 
275                         what != FMT_PROMPT || adrof(STRnoding)) {
276                         if (t->tm_min)
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);
284                         }
285                         if (adrof(STRampm) || (*cp != 'T' && *cp != 'P')) {
286                             *p++ = attributes | ampm;
287                             *p++ = attributes | 'm';
288                         }
289                     }
290                     else {      /* we need to ding */
291                         int     i = 0;
292
293                         (void) Strcpy(buff, STRDING);
294                         while (buff[i]) {
295                             *p++ = attributes | buff[i++];
296                         }
297                         print_prompt_did_ding = 1;
298                     }
299                 }
300                 break;
301
302             case 'M':
303 #ifndef HAVENOUTMP
304                 if (what == FMT_WHO)
305                     cz = (unsigned char *) who_info(info, 'M',
306                         (char *) cbuff, sizeof(cbuff));
307                 else 
308 #endif /* HAVENOUTMP */
309                     cz = (unsigned char *) getenv("HOST");
310                 /*
311                  * Bug pointed out by Laurent Dami <dami@cui.unige.ch>: don't
312                  * derefrence that NULL (if HOST is not set)...
313                  */
314                 if (cz != NULL)
315                     for (; *cz ; *p++ = attributes | *cz++)
316                         if (p >= ep) break;
317                 break;
318
319             case 'm':
320 #ifndef HAVENOUTMP
321                 if (what == FMT_WHO)
322                     cz = (unsigned char *) who_info(info, 'm', (char *) cbuff,
323                         sizeof(cbuff));
324                 else 
325 #endif /* HAVENOUTMP */
326                     cz = (unsigned char *) getenv("HOST");
327
328                 if (cz != NULL)
329                     for ( ; *cz && (what == FMT_WHO || *cz != '.')
330                           ; *p++ = attributes | *cz++ )
331                         if (p >= ep) break;
332                 break;
333
334                         /* lukem: new directory prompt code */
335             case '~':
336             case '/':
337             case '.':
338             case 'c':
339             case 'C':
340                 Scp = *cp;
341                 if (Scp == 'c')         /* store format type (c == .) */
342                     Scp = '.';
343                 if ((z = varval(STRcwd)) == STRNULL)
344                     break;              /* no cwd, so don't do anything */
345
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);
351                     }
352                     if (olduser)
353                         z = olddir;
354                 }
355                 updirs = pdirs = 0;
356
357                         /* option to determine fixed # of dirs from path */
358                 if (Scp == '.' || Scp == 'C') {
359                     int skip;
360 #ifdef WINNT_NATIVE
361                     if (z[1] == ':') {
362                         *p++ = attributes | *z++;
363                         *p++ = attributes | *z++;
364                     }
365                         if (*z == '/' && z[1] == '/') {
366                                 *p++ = attributes | *z++;
367                                 *p++ = attributes | *z++;
368                                 do {
369                                         *p++ = attributes | *z++;
370                                 }while(*z != '/');
371                         }
372 #endif /* WINNT_NATIVE */
373                     q = z;
374                     while (*z)                          /* calc # of /'s */
375                         if (*z++ == '/')
376                             updirs++;
377                     if ((Scp == 'C' && *q != '/'))
378                         updirs++;
379
380                     if (cp[1] == '0') {                 /* print <x> or ...  */
381                         pdirs = 1;
382                         cp++;
383                     }
384                     if (cp[1] >= '1' && cp[1] <= '9') { /* calc # to skip  */
385                         skip = cp[1] - '0';
386                         cp++;
387                     }
388                     else
389                         skip = 1;
390
391                     updirs -= skip;
392                     while (skip-- > 0) {
393                         while ((z > q) && (*z != '/'))
394                             z--;                        /* back up */
395                         if (skip && z > q)
396                             z--;
397                     }
398                     if (*z == '/' && z != q)
399                         z++;
400                 } /* . || C */
401
402                                                         /* print ~[user] */
403                 if ((olduser) && ((Scp == '~') ||
404                      (Scp == '.' && (pdirs || (!pdirs && updirs <= 0))) )) {
405                     *p++ = attributes | '~';
406                     if (p >= ep) break;
407                     for (q = olduser; *q; *p++ = attributes | *q++)
408                         if (p >= ep) break;
409                 }
410
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 | '.';
419                     } else {
420                         *p++ = attributes | '/';
421                         *p++ = attributes | '<';
422                         if (updirs > 9) {
423                             *p++ = attributes | '9';
424                             *p++ = attributes | '+';
425                         } else
426                             *p++ = attributes | ('0' + updirs);
427                         *p++ = attributes | tcsh ? '>' : '%';
428                     }
429                 }
430                 
431                 for (; *z ; *p++ = attributes | *z++)
432                     if (p >= ep) break;
433                 break;
434                         /* lukem: end of new directory prompt code */
435
436             case 'n':
437 #ifndef HAVENOUTMP
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++)
442                         if (p >= ep) break;
443                 }
444                 else  
445 #endif /* HAVENOUTMP */
446                 {
447                     if ((z = varval(STRuser)) != STRNULL)
448                         for (; *z; *p++ = attributes | *z++)
449                             if (p >= ep) break;
450                 }
451                 break;
452             case 'l':
453 #ifndef HAVENOUTMP
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++)
458                         if (p >= ep) break;
459                 }
460                 else  
461 #endif /* HAVENOUTMP */
462                 {
463                     if ((z = varval(STRtty)) != STRNULL)
464                         for (; *z; *p++ = attributes | *z++)
465                             if (p >= ep) break;
466                 }
467                 break;
468             case 'd':
469                 for (cz = (unsigned char *) day_list[t->tm_wday]; *cz;
470                     *p++ = attributes | *cz++)
471                     if (p >= ep) break;
472                 break;
473             case 'D':
474                 if (p >= ep - 3) break;
475                 p = Itoa(t->tm_mday, p, 2, attributes);
476                 break;
477             case 'w':
478                 if (p >= ep - 5) break;
479                 for (cz = (unsigned char *) month_list[t->tm_mon]; *cz;
480                     *p++ = attributes | *cz++)
481                     if (p >= ep) break;
482                 break;
483             case 'W':
484                 if (p >= ep - 3) break;
485                 p = Itoa(t->tm_mon + 1, p, 2, attributes);
486                 break;
487             case 'y':
488                 if (p >= ep - 3) break;
489                 p = Itoa(t->tm_year % 100, p, 2, attributes);
490                 break;
491             case 'Y':
492                 if (p >= ep - 5) break;
493                 p = Itoa(t->tm_year + 1900, p, 4, attributes);
494                 break;
495             case 'S':           /* start standout */
496                 attributes |= STANDOUT;
497                 break;
498             case 'B':           /* start bold */
499                 attributes |= BOLD;
500                 break;
501             case 'U':           /* start underline */
502                 attributes |= UNDER;
503                 break;
504             case 's':           /* end standout */
505                 attributes &= ~STANDOUT;
506                 break;
507             case 'b':           /* end bold */
508                 attributes &= ~BOLD;
509                 break;
510             case 'u':           /* end underline */
511                 attributes &= ~UNDER;
512                 break;
513             case 'L':
514                 ClearToBottom();
515                 break;
516             case '?':
517                 if ((z = varval(STRstatus)) != STRNULL)
518                     for (; *z; *p++ = attributes | *z++)
519                         if (p >= ep) break;
520                 break;
521             case '$':
522                 sz = (int) (ep - p);
523                 (void) expdollar(&p, &cp, &sz, attributes);
524                 break;
525             case '%':
526                 *p++ = attributes | '%';
527                 break;
528             case '{':           /* literal characters start */
529 #if LITERAL == 0
530                 /*
531                  * No literal capability, so skip all chars in the literal
532                  * string
533                  */
534                 while (*cp != '\0' && (*cp != '%' || cp[1] != '}'))
535                     cp++;
536 #endif                          /* LITERAL == 0 */
537                 attributes |= LITERAL;
538                 break;
539             case '}':           /* literal characters end */
540                 attributes &= ~LITERAL;
541                 break;
542             default:
543 #ifndef HAVENOUTMP
544                 if (*cp == 'a' && what == FMT_WHO) {
545                     cz = who_info(info, 'a', (char *) cbuff, sizeof(cbuff));
546                     for (; cz && *cz; *p++ = attributes | *cz++)
547                         if (p >= ep) break;
548                 }
549                 else 
550 #endif /* HAVENOUTMP */
551                 {
552                     if (p >= ep - 3) break;
553                     *p++ = attributes | '%';
554                     *p++ = attributes | *cp;
555                 }
556                 break;
557             }
558         }
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));
564             else
565                 (void) xsnprintf((char *) cbuff, sizeof(cbuff), "%d", eventno + 1);
566             for (cz = cbuff; *cz; *p++ = attributes | *cz++)
567                 if (p >= ep) break;
568         }
569         else 
570             *p++ = attributes | *cp;    /* normal character */
571     }
572     *p = '\0';
573 }
574
575 Char *
576 expdollar(dstp, srcp, spp, attr)
577     Char **dstp;
578     const Char **srcp;
579     size_t *spp;
580     int     attr;
581 {
582     struct varent *vp;
583     Char var[MAXVARLEN];
584     const Char *src = *srcp;
585     Char *val;
586     Char *dst = *dstp;
587     int i, curly = 0;
588
589     /* found a variable, expand it */
590     for (i = 0; i < MAXVARLEN; i++) {
591         var[i] = *++src & TRIM;
592         if (i == 0 && var[i] == '{') {
593             curly = 1;
594             var[i] = *++src & TRIM;
595         }
596         if (!alnum(var[i])) {
597             
598             var[i] = '\0';
599             break;
600         }
601     }
602     if (curly && (*src & TRIM) == '}')
603         src++;
604
605     vp = adrof(var);
606     val = (!vp) ? tgetenv(var) : NULL;
607     if (vp) {
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) {
612                 *dst++ = ' ' | attr;
613                 (*spp)--;
614             }
615         }
616     }
617     else if (val) {
618         for (; *spp > 0 && *val; (*spp)--)
619             *dst++ = *val++ | attr;
620     }
621     else {
622         **dstp = '\0';
623         *srcp = src;
624         return NULL;
625     }
626     *dst = '\0';
627
628     val = *dstp;
629     *srcp = src;
630     *dstp = dst;
631
632     return val;
633 }