Logo Search packages:      
Sourcecode: tcsh version File versions  Download package

tc.prompt.c

/* $Header: /src/pub/tcsh/tc.prompt.c,v 3.53 2005/01/05 18:06:43 christos Exp $ */
/*
 * tc.prompt.c: Prompt printing stuff
 */
/*-
 * Copyright (c) 1980, 1991 The Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
#include "sh.h"

RCSID("$Id: tc.prompt.c,v 3.53 2005/01/05 18:06:43 christos Exp $")

#include "ed.h"
#include "tw.h"

/*
 * kfk 21oct1983 -- add @ (time) and / ($cwd) in prompt.
 * PWP 4/27/87 -- rearange for tcsh.
 * mrdch@com.tau.edu.il 6/26/89 - added ~, T and .# - rearanged to switch()
 *                 instead of if/elseif
 * Luke Mewburn, <lukem@cs.rmit.edu.au>
 *    6-Sep-91    changed date format
 *    16-Feb-94   rewrote directory prompt code, added $ellipsis
 *    29-Dec-96   added rprompt support
 */

static const char   *month_list[12];
static const char   *day_list[7];

void
dateinit()
{
#ifdef notyet
  int i;

  setlocale(LC_TIME, "");

  for (i = 0; i < 12; i++)
      xfree((ptr_t) month_list[i]);
  month_list[0] = strsave(_time_info->abbrev_month[0]);
  month_list[1] = strsave(_time_info->abbrev_month[1]);
  month_list[2] = strsave(_time_info->abbrev_month[2]);
  month_list[3] = strsave(_time_info->abbrev_month[3]);
  month_list[4] = strsave(_time_info->abbrev_month[4]);
  month_list[5] = strsave(_time_info->abbrev_month[5]);
  month_list[6] = strsave(_time_info->abbrev_month[6]);
  month_list[7] = strsave(_time_info->abbrev_month[7]);
  month_list[8] = strsave(_time_info->abbrev_month[8]);
  month_list[9] = strsave(_time_info->abbrev_month[9]);
  month_list[10] = strsave(_time_info->abbrev_month[10]);
  month_list[11] = strsave(_time_info->abbrev_month[11]);

  for (i = 0; i < 7; i++)
      xfree((ptr_t) day_list[i]);
  day_list[0] = strsave(_time_info->abbrev_wkday[0]);
  day_list[1] = strsave(_time_info->abbrev_wkday[1]);
  day_list[2] = strsave(_time_info->abbrev_wkday[2]);
  day_list[3] = strsave(_time_info->abbrev_wkday[3]);
  day_list[4] = strsave(_time_info->abbrev_wkday[4]);
  day_list[5] = strsave(_time_info->abbrev_wkday[5]);
  day_list[6] = strsave(_time_info->abbrev_wkday[6]);
#else
  month_list[0] = "Jan";
  month_list[1] = "Feb";
  month_list[2] = "Mar";
  month_list[3] = "Apr";
  month_list[4] = "May";
  month_list[5] = "Jun";
  month_list[6] = "Jul";
  month_list[7] = "Aug";
  month_list[8] = "Sep";
  month_list[9] = "Oct";
  month_list[10] = "Nov";
  month_list[11] = "Dec";

  day_list[0] = "Sun";
  day_list[1] = "Mon";
  day_list[2] = "Tue";
  day_list[3] = "Wed";
  day_list[4] = "Thu";
  day_list[5] = "Fri";
  day_list[6] = "Sat";
#endif
}

void
printprompt(promptno, str)
    int     promptno;
    const char   *str;
{
    static  Char *ocp = NULL;
    static  const char *ostr = NULL;
    time_t  lclock = time(NULL);
    Char   *cp;

    switch (promptno) {
    default:
    case 0:
      cp = varval(STRprompt);
      break;
    case 1:
      cp = varval(STRprompt2);
      break;
    case 2:
      cp = varval(STRprompt3);
      break;
    case 3:
      if (ocp != NULL) {
          cp = ocp;
          str = ostr;
      }
      else 
          cp = varval(STRprompt);
      break;
    }

    if (promptno < 2) {
      ocp = cp;
      ostr = str;
    }

    PromptBuf[0] = '\0';
    tprintf(FMT_PROMPT, PromptBuf, cp, 2 * INBUFSIZE - 2, str, lclock, NULL);
    if (!editing) {
      for (cp = PromptBuf; *cp ; )
          (void) putwraw(*cp++);
      SetAttributes(0);
      flush();
    }

    RPromptBuf[0] = '\0';
    if (promptno == 0) {      /* determine rprompt if using main prompt */
      cp = varval(STRrprompt);
      tprintf(FMT_PROMPT, RPromptBuf, cp, INBUFSIZE - 2, NULL, lclock, NULL);
                        /* if not editing, put rprompt after prompt */
      if (!editing && RPromptBuf[0] != '\0') {
          for (cp = RPromptBuf; *cp ; )
            (void) putwraw(*cp++);
          SetAttributes(0);
          putraw(' ');
          flush();
      }
    }
}

void
tprintf(what, buf, fmt, siz, str, tim, info)
    int what;
    Char *buf;
    const Char *fmt;
    size_t siz;
    const char *str;
    time_t tim;
    ptr_t info;
{
    Char   *z, *q;
    Char    attributes = 0;
    static int print_prompt_did_ding = 0;
    Char    buff[BUFSIZE];
    /* Need to be unsigned to avoid sign extension */
    const unsigned char   *cz;
    unsigned char    cbuff[BUFSIZE];

    Char *p  = buf;
    Char *ep = &p[siz];
    const Char *cp = fmt;
    Char Scp;
    struct tm *t = localtime(&tim);

                  /* prompt stuff */
    static Char *olddir = NULL, *olduser = NULL;
    int updirs;
    size_t pdirs, sz;
    int l;

    for (; *cp; cp++) {
      if (p >= ep)
          break;
      l = NLSSize(cp, -1);
      if (l > 1) {
          while (l--)
            *p++ = attributes | *cp++;
          cp--;
          continue;
      }
      if ((*cp == '%') && ! (cp[1] == '\0')) {
          cp++;
          switch (*cp) {
          case 'R':
            if (what == FMT_HISTORY) {
                fmthist('R', info, (char *) cbuff, sizeof(cbuff));
                cz = cbuff;
            } else
                cz = (const unsigned char *) str;
            if (cz != NULL)
                for (; *cz && p < ep; p++) {
                  cz += one_mbtowc(p, (const char *)cz, MB_LEN_MAX);
                  *p |= attributes;
                }
            break;
          case '#':
            *p++ = attributes | ((uid == 0) ? PRCHROOT : PRCH);
            break;
          case '!':
          case 'h':
            switch (what) {
            case FMT_HISTORY:
                fmthist('h', info, (char *) cbuff, sizeof(cbuff));
                break;
            case FMT_SCHED:
                (void) xsnprintf((char *) cbuff, sizeof(cbuff), "%d", 
                  *(int *)info);
                break;
            default:
                (void) xsnprintf((char *) cbuff, sizeof(cbuff), "%d",
                  eventno + 1);
                break;
            }
            for (cz = cbuff; *cz && p < ep; p++) {
                cz += one_mbtowc(p, (const char *)cz, MB_LEN_MAX);
                *p |= attributes;
            }
            break;
          case 'T':           /* 24 hour format  */
          case '@':
          case 't':           /* 12 hour am/pm format */
          case 'p':           /* With seconds   */
          case 'P':
            {
                char    ampm = 'a';
                int     hr = t->tm_hour;

                if (p >= ep - 10) break;

                /* addition by Hans J. Albertsson */
                /* and another adapted from Justin Bur */
                if (adrof(STRampm) || (*cp != 'T' && *cp != 'P')) {
                  if (hr >= 12) {
                      if (hr > 12)
                        hr -= 12;
                      ampm = 'p';
                  }
                  else if (hr == 0)
                      hr = 12;
                }       /* else do a 24 hour clock */

                /* "DING!" stuff by Hans also */
                if (t->tm_min || print_prompt_did_ding || 
                  what != FMT_PROMPT || adrof(STRnoding)) {
                  if (t->tm_min)
                      print_prompt_did_ding = 0;
                  p = Itoa(hr, p, 0, attributes);
                  *p++ = attributes | ':';
                  p = Itoa(t->tm_min, p, 2, attributes);
                  if (*cp == 'p' || *cp == 'P') {
                      *p++ = attributes | ':';
                      p = Itoa(t->tm_sec, p, 2, attributes);
                  }
                  if (adrof(STRampm) || (*cp != 'T' && *cp != 'P')) {
                      *p++ = attributes | ampm;
                      *p++ = attributes | 'm';
                  }
                }
                else {  /* we need to ding */
                  int     i = 0;

                  (void) Strcpy(buff, STRDING);
                  while (buff[i]) {
                      *p++ = attributes | buff[i++];
                  }
                  print_prompt_did_ding = 1;
                }
            }
            break;

          case 'M':
#ifndef HAVENOUTMP
            if (what == FMT_WHO)
                cz = (const unsigned char *) who_info(info, 'M',
                  (char *) cbuff, sizeof(cbuff));
            else 
#endif /* HAVENOUTMP */
                cz = (const unsigned char *) getenv("HOST");
            /*
             * Bug pointed out by Laurent Dami <dami@cui.unige.ch>: don't
             * derefrence that NULL (if HOST is not set)...
             */
            if (cz != NULL)
                for (; *cz && p < ep; p++) {
                  cz += one_mbtowc(p, (const char *)cz, MB_LEN_MAX);
                  *p |= attributes;
                }
            break;

          case 'm':
#ifndef HAVENOUTMP
            if (what == FMT_WHO)
                cz = (const unsigned char *) who_info(info, 'm',
                  (char *) cbuff, sizeof(cbuff));
            else 
#endif /* HAVENOUTMP */
                cz = (const unsigned char *) getenv("HOST");

            if (cz != NULL)
                for (; *cz && (what == FMT_WHO || *cz != '.') && p < ep;
                   p++) {
                  cz += one_mbtowc(p, (const char *)cz, MB_LEN_MAX);
                  *p |= attributes;
                }
            break;

                  /* lukem: new directory prompt code */
          case '~':
          case '/':
          case '.':
          case 'c':
          case 'C':
            Scp = *cp;
            if (Scp == 'c')         /* store format type (c == .) */
                Scp = '.';
            if ((z = varval(STRcwd)) == STRNULL)
                break;        /* no cwd, so don't do anything */

                  /* show ~ whenever possible - a la dirs */
            if (Scp == '~' || Scp == '.' ) {
                if (tlength == 0 || olddir != z) {
                  olddir = z;       /* have we changed dir? */
                  olduser = getusername(&olddir);
                }
                if (olduser)
                  z = olddir;
            }
            updirs = pdirs = 0;

                  /* option to determine fixed # of dirs from path */
            if (Scp == '.' || Scp == 'C') {
                int skip;
#ifdef WINNT_NATIVE
                Char *oldz = z;
                if (z[1] == ':') {
                  *p++ = attributes | *z++;
                  *p++ = attributes | *z++;
                }
                  if (*z == '/' && z[1] == '/') {
                        *p++ = attributes | *z++;
                        *p++ = attributes | *z++;
                        do {
                              *p++ = attributes | *z++;
                        }while(*z != '/');
                  }
#endif /* WINNT_NATIVE */
                q = z;
                while (*z)                      /* calc # of /'s */
                  if (*z++ == '/')
                      updirs++;

#ifdef WINNT_NATIVE
                /*
                 * for format type c, prompt will be following...
                 * c:/path                => c:/path
                 * c:/path/to             => c:to
                 * //machine/share        => //machine/share
                 * //machine/share/folder => //machine:folder
                 */
                if (oldz[0] == '/' && oldz[1] == '/' && updirs > 1)
                  *p++ = attributes | ':';
#endif /* WINNT_NATIVE */
                if ((Scp == 'C' && *q != '/'))
                  updirs++;

                if (cp[1] == '0') {             /* print <x> or ...  */
                  pdirs = 1;
                  cp++;
                }
                if (cp[1] >= '1' && cp[1] <= '9') {   /* calc # to skip  */
                  skip = cp[1] - '0';
                  cp++;
                }
                else
                  skip = 1;

                updirs -= skip;
                while (skip-- > 0) {
                  while ((z > q) && (*z != '/'))
                      z--;                /* back up */
                  if (skip && z > q)
                      z--;
                }
                if (*z == '/' && z != q)
                  z++;
            } /* . || C */

                                          /* print ~[user] */
            if ((olduser) && ((Scp == '~') ||
                 (Scp == '.' && (pdirs || (!pdirs && updirs <= 0))) )) {
                *p++ = attributes | '~';
                if (p >= ep) break;
                for (q = olduser; *q; *p++ = attributes | *q++)
                  if (p >= ep) break;
            }

                  /* RWM - tell you how many dirs we've ignored */
                  /*       and add '/' at front of this         */
            if (updirs > 0 && pdirs) {
                if (p >= ep - 5) break;
                if (adrof(STRellipsis)) {
                  *p++ = attributes | '.';
                  *p++ = attributes | '.';
                  *p++ = attributes | '.';
                } else {
                  *p++ = attributes | '/';
                  *p++ = attributes | '<';
                  if (updirs > 9) {
                      *p++ = attributes | '9';
                      *p++ = attributes | '+';
                  } else
                      *p++ = attributes | ('0' + updirs);
                  *p++ = attributes | '>';
                }
            }
            
            for (; *z ; *p++ = attributes | *z++)
                if (p >= ep) break;
            break;
                  /* lukem: end of new directory prompt code */

          case 'n':
#ifndef HAVENOUTMP
            if (what == FMT_WHO) {
                cz = (const unsigned char *) who_info(info, 'n',
                  (char *) cbuff, sizeof(cbuff));
                for (; *cz && p < ep; p++) {
                  cz += one_mbtowc(p, (const char *)cz, MB_LEN_MAX);
                  *p |= attributes;
                }
            }
            else  
#endif /* HAVENOUTMP */
            {
                if ((z = varval(STRuser)) != STRNULL)
                  for (; *z; *p++ = attributes | *z++)
                      if (p >= ep) break;
            }
            break;
          case 'l':
#ifndef HAVENOUTMP
            if (what == FMT_WHO) {
                cz = (const unsigned char *) who_info(info, 'l',
                  (char *) cbuff, sizeof(cbuff));
                for (; *cz && p < ep; p++) {
                  cz += one_mbtowc(p, (const char *)cz, MB_LEN_MAX);
                  *p |= attributes;
                }
            }
            else  
#endif /* HAVENOUTMP */
            {
                if ((z = varval(STRtty)) != STRNULL)
                  for (; *z; *p++ = attributes | *z++)
                      if (p >= ep) break;
            }
            break;
          case 'd':
            for (cz = (const unsigned char *) day_list[t->tm_wday];
                 *cz && p < ep; p++) {
                cz += one_mbtowc(p, (const char *)cz, MB_LEN_MAX);
                *p |= attributes;
            }
            break;
          case 'D':
            if (p >= ep - 3) break;
            p = Itoa(t->tm_mday, p, 2, attributes);
            break;
          case 'w':
            if (p >= ep - 5) break;
            for (cz = (const unsigned char *) month_list[t->tm_mon];
                *cz && p < ep; p++) {
                cz += one_mbtowc(p, (const char *)cz, MB_LEN_MAX);
                *p |= attributes;
            }
            break;
          case 'W':
            if (p >= ep - 3) break;
            p = Itoa(t->tm_mon + 1, p, 2, attributes);
            break;
          case 'y':
            if (p >= ep - 3) break;
            p = Itoa(t->tm_year % 100, p, 2, attributes);
            break;
          case 'Y':
            if (p >= ep - 5) break;
            p = Itoa(t->tm_year + 1900, p, 4, attributes);
            break;
          case 'S':           /* start standout */
            attributes |= STANDOUT;
            break;
          case 'B':           /* start bold */
            attributes |= BOLD;
            break;
          case 'U':           /* start underline */
            attributes |= UNDER;
            break;
          case 's':           /* end standout */
            attributes &= ~STANDOUT;
            break;
          case 'b':           /* end bold */
            attributes &= ~BOLD;
            break;
          case 'u':           /* end underline */
            attributes &= ~UNDER;
            break;
          case 'L':
            ClearToBottom();
            break;

          case 'j':
            {
                Char xbuf[128], *ebuf, *xq;
                int njobs = -1;
                struct process *pp;
                for (pp = proclist.p_next; pp; pp = pp->p_next)
                  njobs++;
                /* make sure we have space */
                ebuf = Itoa(njobs, buf, 1, attributes);
                for (xq = xbuf; xq < ebuf; *p++ = *xq++)
                  if (p >= ep) break;
                break;
            }
          case '?':
            if ((z = varval(STRstatus)) != STRNULL)
                for (; *z; *p++ = attributes | *z++)
                  if (p >= ep) break;
            break;
          case '$':
            sz = ep - p;
            (void) expdollar(&p, &cp, &sz, attributes);
            /* cp should point the last char of currnet % sequence */
            cp--;
            break;
          case '%':
            *p++ = attributes | '%';
            break;
          case '{':           /* literal characters start */
#if LITERAL == 0
            /*
             * No literal capability, so skip all chars in the literal
             * string
             */
            while (*cp != '\0' && (*cp != '%' || cp[1] != '}'))
                cp++;
#endif                        /* LITERAL == 0 */
            attributes |= LITERAL;
            break;
          case '}':           /* literal characters end */
            attributes &= ~LITERAL;
            break;
          default:
#ifndef HAVENOUTMP
            if (*cp == 'a' && what == FMT_WHO) {
                cz = (const unsigned char *) who_info(info, 'a',
                  (char *) cbuff, sizeof(cbuff));
                for (; *cz && p < ep; p++) {
                  cz += one_mbtowc(p, (const char *)cz, MB_LEN_MAX);
                  *p |= attributes;
                }
            }
            else 
#endif /* HAVENOUTMP */
            {
                if (p >= ep - 3) break;
                *p++ = attributes | '%';
                *p++ = attributes | *cp;
            }
            break;
          }
      }
      else if (*cp == '\\' || *cp == '^') 
          *p++ = attributes | parseescape(&cp);
      else if (*cp == HIST) { /* EGS: handle '!'s in prompts */
          if (what == FMT_HISTORY) 
            fmthist('h', info, (char *) cbuff, sizeof(cbuff));
          else
            (void) xsnprintf((char *) cbuff, sizeof(cbuff), "%d", eventno + 1);
          for (cz = cbuff; *cz && p < ep; p++) {
            cz += one_mbtowc(p, (const char *)cz, MB_LEN_MAX);
            *p |= attributes;
          }
      }
      else 
          *p++ = attributes | *cp;  /* normal character */
    }
    *p = '\0';
}

Char *
expdollar(dstp, srcp, spp, attr)
    Char **dstp;
    const Char **srcp;
    size_t *spp;
    int         attr;
{
    struct varent *vp;
    Char var[MAXVARLEN];
    const Char *src = *srcp;
    Char *val;
    Char *dst = *dstp;
    int i, curly = 0;

    /* found a variable, expand it */
    for (i = 0; i < MAXVARLEN; i++) {
      var[i] = *++src & TRIM;
      if (i == 0 && var[i] == '{') {
          curly = 1;
          var[i] = *++src & TRIM;
      }
      if (!alnum(var[i])) {
          
          var[i] = '\0';
          break;
      }
    }
    if (curly && (*src & TRIM) == '}')
      src++;

    vp = adrof(var);
    val = (!vp) ? tgetenv(var) : NULL;
    if (vp && vp->vec) {
      for (i = 0; vp->vec[i] != NULL; i++) {
          for (val = vp->vec[i]; *spp > 0 && *val; (*spp)--)
            *dst++ = *val++ | attr;
          if (vp->vec[i+1] && *spp > 0) {
            *dst++ = ' ' | attr;
            (*spp)--;
          }
      }
    }
    else if (val) {
      for (; *spp > 0 && *val; (*spp)--)
          *dst++ = *val++ | attr;
    }
    else {
      **dstp = '\0';
      *srcp = src;
      return NULL;
    }
    *dst = '\0';

    val = *dstp;
    *srcp = src;
    *dstp = dst;

    return val;
}

Generated by  Doxygen 1.6.0   Back to index