source: trunk/third/tcsh/tc.prompt.c @ 12609

Revision 12609, 16.3 KB checked in by danw, 26 years ago (diff)
y2k fix for %y in prompt
Line 
1/* $Header: /afs/dev.mit.edu/source/repository/third/tcsh/tc.prompt.c,v 1.4 1999-03-01 19:32:45 danw 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
39RCSID("$Id: tc.prompt.c,v 1.4 1999-03-01 19:32:45 danw 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
55static char   *month_list[12];
56static char   *day_list[7];
57
58void
59dateinit()
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
114void
115printprompt(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
176void
177tprintf(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    const char   *cz;
190    Char    buff[BUFSIZE];
191    char    cbuff[BUFSIZE];
192
193    Char *p  = buf;
194    Char *ep = &p[siz];
195    const Char *cp = fmt;
196    Char Scp;
197    struct tm *t = localtime(&tim);
198
199                        /* prompt stuff */
200    static Char *olddir = NULL, *olduser = NULL;
201    extern int tlength; /* cache cleared */
202    int updirs, sz;
203    size_t pdirs;
204
205    for (; *cp; cp++) {
206        if (p >= ep)
207            break;
208        if (*cp == '%') {
209            cp++;
210            switch (*cp) {
211            case 'R':
212                if (what == FMT_HISTORY)
213                    fmthist('R', info, str = cbuff, sizeof(cbuff));
214                if (str != NULL)
215                    for (; *str; *p++ = attributes | *str++)
216                        if (p >= ep) break;
217                break;
218            case '#':
219                *p++ = attributes | ((uid == 0) ? PRCHROOT : PRCH);
220                break;
221            case '!':
222            case 'h':
223                switch (what) {
224                case FMT_HISTORY:
225                    fmthist('h', info, (char *) cbuff, sizeof(cbuff));
226                    break;
227                case FMT_SCHED:
228                    (void) xsnprintf((char *) cbuff, sizeof(cbuff), "%d", *(int *)info);
229                    break;
230                default:
231                    (void) xsnprintf((char *) cbuff, sizeof(cbuff), "%d", eventno + 1);
232                    break;
233                }
234                for (cz = cbuff; *cz; *p++ = attributes | *cz++)
235                    if (p >= ep) break;
236                break;
237            case 'T':           /* 24 hour format        */
238            case '@':
239            case 't':           /* 12 hour am/pm format */
240            case 'p':           /* With seconds */
241            case 'P':
242                {
243                    char    ampm = 'a';
244                    int     hr = t->tm_hour;
245
246                    if (p >= ep - 10) break;
247
248                    /* addition by Hans J. Albertsson */
249                    /* and another adapted from Justin Bur */
250                    if (adrof(STRampm) || (*cp != 'T' && *cp != 'P')) {
251                        if (hr >= 12) {
252                            if (hr > 12)
253                                hr -= 12;
254                            ampm = 'p';
255                        }
256                        else if (hr == 0)
257                            hr = 12;
258                    }           /* else do a 24 hour clock */
259
260                    /* "DING!" stuff by Hans also */
261                    if (t->tm_min || print_prompt_did_ding ||
262                        what != FMT_PROMPT || adrof(STRnoding)) {
263                        if (t->tm_min)
264                            print_prompt_did_ding = 0;
265                        Itoa(hr, buff);
266                        *p++ = attributes | buff[0];
267                        if (buff[1])
268                            *p++ = attributes | buff[1];
269                        *p++ = attributes | ':';
270                        Itoa(t->tm_min, buff);
271                        if (buff[1]) {
272                            *p++ = attributes | buff[0];
273                            *p++ = attributes | buff[1];
274                        }
275                        else {
276                            *p++ = attributes | '0';
277                            *p++ = attributes | buff[0];
278                        }
279                        if (*cp == 'p' || *cp == 'P') {
280                            *p++ = attributes | ':';
281                            Itoa(t->tm_sec, buff);
282                            if (buff[1]) {
283                                *p++ = attributes | buff[0];
284                                *p++ = attributes | buff[1];
285                            }
286                            else {
287                                *p++ = attributes | '0';
288                                *p++ = attributes | buff[0];
289                            }
290                        }
291                        if (adrof(STRampm) || (*cp != 'T' && *cp != 'P')) {
292                            *p++ = attributes | ampm;
293                            *p++ = attributes | 'm';
294                        }
295                    }
296                    else {      /* we need to ding */
297                        int     i = 0;
298
299                        (void) Strcpy(buff, STRDING);
300                        while (buff[i]) {
301                            *p++ = attributes | buff[i++];
302                        }
303                        print_prompt_did_ding = 1;
304                    }
305                }
306                break;
307
308            case 'M':
309#ifndef HAVENOUTMP
310                if (what == FMT_WHO)
311                    cz = who_info(info, 'M', (char *) cbuff, sizeof(cbuff));
312                else
313#endif /* HAVENOUTMP */
314                    cz = getenv("HOST");
315                /*
316                 * Bug pointed out by Laurent Dami <dami@cui.unige.ch>: don't
317                 * derefrence that NULL (if HOST is not set)...
318                 */
319                if (cz != NULL)
320                    for (; *cz ; *p++ = attributes | *cz++)
321                        if (p >= ep) break;
322                break;
323
324            case 'm':
325#ifndef HAVENOUTMP
326                if (what == FMT_WHO)
327                    cz = who_info(info, 'm', (char *) cbuff, sizeof(cbuff));
328                else
329#endif /* HAVENOUTMP */
330                    cz = getenv("HOST");
331
332                if (cz != NULL)
333                    for ( ; *cz && (what == FMT_WHO || *cz != '.')
334                          ; *p++ = attributes | *cz++ )
335                        if (p >= ep) break;
336                break;
337
338                        /* lukem: new directory prompt code */
339            case '~':
340            case 'd':
341            case '/':
342            case '.':
343            case 'c':
344            case 'C':
345                Scp = *cp;
346                if (Scp == 'c')         /* store format type (c == .) */
347                    Scp = '.';
348                if (Scp == 'd')         /* and d == ~ (Athena back compat */
349                    Scp = '~';
350                if ((z = varval(STRcwd)) == STRNULL)
351                    break;              /* no cwd, so don't do anything */
352
353                        /* show ~ whenever possible - a la dirs */
354                if (Scp == '~' || Scp == '.' ) {
355                    if (tlength == 0 || olddir != z) {
356                        olddir = z;             /* have we changed dir? */
357                        olduser = getusername(&olddir);
358                    }
359                    if (olduser)
360                        z = olddir;
361                }
362                updirs = pdirs = 0;
363
364                        /* option to determine fixed # of dirs from path */
365                if (Scp == '.' || Scp == 'C') {
366                    int skip;
367#ifdef WINNT
368                    if (z[1] == ':') {
369                        *p++ = attributes | *z++;
370                        *p++ = attributes | *z++;
371                    }
372                        if (*z == '/' && z[1] == '/') {
373                                *p++ = attributes | *z++;
374                                *p++ = attributes | *z++;
375                                do {
376                                        *p++ = attributes | *z++;
377                                }while(*z != '/');
378                        }
379#endif /* WINNT */
380                    q = z;
381                    while (*z)                          /* calc # of /'s */
382                        if (*z++ == '/')
383                            updirs++;
384                    if ((Scp == 'C' && *q != '/'))
385                        updirs++;
386
387                    if (cp[1] == '0') {                 /* print <x> or ...  */
388                        pdirs = 1;
389                        cp++;
390                    }
391                    if (cp[1] >= '1' && cp[1] <= '9') { /* calc # to skip  */
392                        skip = cp[1] - '0';
393                        cp++;
394                    }
395                    else
396                        skip = 1;
397
398                    updirs -= skip;
399                    while (skip-- > 0) {
400                        while ((z > q) && (*z != '/'))
401                            z--;                        /* back up */
402                        if (skip && z > q)
403                            z--;
404                    }
405                    if (*z == '/' && z != q)
406                        z++;
407                } /* . || C */
408
409                                                        /* print ~[user] */
410                if ((olduser) && ((Scp == '~') ||
411                     (Scp == '.' && (pdirs || (!pdirs && updirs <= 0))) )) {
412                    *p++ = attributes | '~';
413                    if (p >= ep) break;
414                    for (q = olduser; *q; *p++ = attributes | *q++)
415                        if (p >= ep) break;
416                }
417
418                        /* RWM - tell you how many dirs we've ignored */
419                        /*       and add '/' at front of this         */
420                if (updirs > 0 && pdirs) {
421                    if (p >= ep - 5) break;
422                    if (adrof(STRellipsis)) {
423                        *p++ = attributes | '.';
424                        *p++ = attributes | '.';
425                        *p++ = attributes | '.';
426                    } else {
427                        *p++ = attributes | '/';
428                        *p++ = attributes | '<';
429                        if (updirs > 9) {
430                            *p++ = attributes | '9';
431                            *p++ = attributes | '+';
432                        } else
433                            *p++ = attributes | ('0' + updirs);
434                        *p++ = attributes | tcsh ? '>' : '%';
435                    }
436                }
437               
438                for (; *z ; *p++ = attributes | *z++)
439                    if (p >= ep) break;
440                break;
441                        /* lukem: end of new directory prompt code */
442
443            case 'n':
444#ifndef HAVENOUTMP
445                if (what == FMT_WHO) {
446                    cz = who_info(info, 'n', (char *) cbuff, sizeof(cbuff));
447                    for (; cz && *cz ; *p++ = attributes | *cz++)
448                        if (p >= ep) break;
449                }
450                else 
451#endif /* HAVENOUTMP */
452                {
453                    if ((z = varval(STRuser)) != STRNULL)
454                        for (; *z; *p++ = attributes | *z++)
455                            if (p >= ep) break;
456                }
457                break;
458            case 'l':
459#ifndef HAVENOUTMP
460                if (what == FMT_WHO) {
461                    cz = who_info(info, 'l', (char *) cbuff, sizeof(cbuff));
462                    for (; cz && *cz ; *p++ = attributes | *cz++)
463                        if (p >= ep) break;
464                }
465                else 
466#endif /* HAVENOUTMP */
467                {
468                    if ((z = varval(STRtty)) != STRNULL)
469                        for (; *z; *p++ = attributes | *z++)
470                            if (p >= ep) break;
471                }
472                break;
473            case 'k':
474                for (cz = day_list[t->tm_wday]; *cz; *p++ = attributes | *cz++)
475                    if (p >= ep) break;
476                break;
477            case 'D':
478                Itoa(t->tm_mday, buff);
479                if (p >= ep - 3) break;
480                if (buff[1]) {
481                    *p++ = attributes | buff[0];
482                    *p++ = attributes | buff[1];
483                }
484                else {
485                    *p++ = attributes | '0';
486                    *p++ = attributes | buff[0];
487                }
488                break;
489            case 'w':
490                if (p >= ep - 5) break;
491                for (cz = month_list[t->tm_mon]; *cz;)
492                    *p++ = attributes | *cz++;
493                break;
494            case 'W':
495                if (p >= ep - 3) break;
496                Itoa(t->tm_mon + 1, buff);
497                if (buff[1]) {
498                    *p++ = attributes | buff[0];
499                    *p++ = attributes | buff[1];
500                }
501                else {
502                    *p++ = attributes | '0';
503                    *p++ = attributes | buff[0];
504                }
505                break;
506            case 'y':
507                if (p >= ep - 3) break;
508                Itoa(t->tm_year % 100, buff);
509                if (buff[1]) {
510                    *p++ = attributes | buff[0];
511                    *p++ = attributes | buff[1];
512                }
513                else {
514                    *p++ = attributes | '0';
515                    *p++ = attributes | buff[0];
516                }
517                break;
518            case 'Y':
519                if (p >= ep - 5) break;
520                Itoa(t->tm_year + 1900, buff);
521                *p++ = attributes | buff[0];
522                *p++ = attributes | buff[1];
523                *p++ = attributes | buff[2];
524                *p++ = attributes | buff[3];
525                break;
526            case 'S':           /* start standout */
527                attributes |= STANDOUT;
528                break;
529            case 'B':           /* start bold */
530                attributes |= BOLD;
531                break;
532            case 'U':           /* start underline */
533                attributes |= UNDER;
534                break;
535            case 's':           /* end standout */
536                attributes &= ~STANDOUT;
537                break;
538            case 'b':           /* end bold */
539                attributes &= ~BOLD;
540                break;
541            case 'u':           /* end underline */
542                attributes &= ~UNDER;
543                break;
544            case 'L':
545                ClearToBottom();
546                break;
547            case '?':
548                if ((z = varval(STRstatus)) != STRNULL)
549                    for (; *z; *p++ = attributes | *z++)
550                        if (p >= ep) break;
551                break;
552            case '$':
553                sz = ep - p;
554                (void) expdollar(&p, &cp, &pdirs, attributes);
555                break;
556            case '%':
557                *p++ = attributes | '%';
558                break;
559            case '{':           /* literal characters start */
560#if LITERAL == 0
561                /*
562                 * No literal capability, so skip all chars in the literal
563                 * string
564                 */
565                while (*cp != '\0' && (*cp != '%' || cp[1] != '}'))
566                    cp++;
567#endif                          /* LITERAL == 0 */
568                attributes |= LITERAL;
569                break;
570            case '}':           /* literal characters end */
571                attributes &= ~LITERAL;
572                break;
573            default:
574#ifndef HAVENOUTMP
575                if (*cp == 'a' && what == FMT_WHO) {
576                    cz = who_info(info, 'a', (char *) cbuff, sizeof(cbuff));
577                    for (; cz && *cz; *p++ = attributes | *cz++)
578                        if (p >= ep) break;
579                }
580                else
581#endif /* HAVENOUTMP */
582                {
583                    if (p >= ep - 3) break;
584                    *p++ = attributes | '%';
585                    *p++ = attributes | *cp;
586                }
587                break;
588            }
589        }
590        else if (*cp == '\\' || *cp == '^')
591            *p++ = attributes | parseescape(&cp);
592        else if (*cp == HIST) { /* EGS: handle '!'s in prompts */
593            if (what == FMT_HISTORY)
594                fmthist('h', info, (char *) cbuff, sizeof(cbuff));
595            else
596                (void) xsnprintf((char *) cbuff, sizeof(cbuff), "%d", eventno + 1);
597            for (cz = cbuff; *cz; *p++ = attributes | *cz++)
598                if (p >= ep) break;
599        }
600        else
601            *p++ = attributes | *cp;    /* normal character */
602    }
603    *p = '\0';
604}
605
606Char *
607expdollar(dstp, srcp, spp, attr)
608    Char **dstp;
609    const Char **srcp;
610    size_t *spp;
611    int     attr;
612{
613    struct varent *vp;
614    Char var[MAXVARLEN];
615    const Char *src = *srcp;
616    Char *val;
617    Char *dst = *dstp;
618    int i, curly = 0;
619
620    /* found a variable, expand it */
621    for (i = 0; i < MAXVARLEN; i++) {
622        var[i] = *++src & TRIM;
623        if (i == 0 && var[i] == '{') {
624            curly = 1;
625            var[i] = *++src & TRIM;
626        }
627        if (!alnum(var[i])) {
628           
629            var[i] = '\0';
630            break;
631        }
632    }
633    if (curly && (*src & TRIM) == '}')
634        src++;
635
636    vp = adrof(var);
637    val = (!vp) ? tgetenv(var) : NULL;
638    if (vp) {
639        for (i = 0; vp->vec[i] != NULL; i++) {
640            for (val = vp->vec[i]; *spp > 0 && *val; (*spp)--)
641                *dst++ = *val++ | attr;
642            if (vp->vec[i+1] && *spp > 0) {
643                *dst++ = ' ' | attr;
644                (*spp)--;
645            }
646        }
647    }
648    else if (val) {
649        for (; *spp > 0 && *val; (*spp)--)
650            *dst++ = *val++ | attr;
651    }
652    else {
653        **dstp = '\0';
654        *srcp = src;
655        return NULL;
656    }
657    *dst = '\0';
658
659    val = *dstp;
660    *srcp = src;
661    *dstp = dst;
662
663    return val;
664}
Note: See TracBrowser for help on using the repository browser.