159243Sobrien/* 259243Sobrien * tc.prompt.c: Prompt printing stuff 359243Sobrien */ 459243Sobrien/*- 559243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 659243Sobrien * All rights reserved. 759243Sobrien * 859243Sobrien * Redistribution and use in source and binary forms, with or without 959243Sobrien * modification, are permitted provided that the following conditions 1059243Sobrien * are met: 1159243Sobrien * 1. Redistributions of source code must retain the above copyright 1259243Sobrien * notice, this list of conditions and the following disclaimer. 1359243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1459243Sobrien * notice, this list of conditions and the following disclaimer in the 1559243Sobrien * documentation and/or other materials provided with the distribution. 16100616Smp * 3. Neither the name of the University nor the names of its contributors 1759243Sobrien * may be used to endorse or promote products derived from this software 1859243Sobrien * without specific prior written permission. 1959243Sobrien * 2059243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2159243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2259243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2359243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2459243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2559243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2659243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2759243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2859243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2959243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3059243Sobrien * SUCH DAMAGE. 3159243Sobrien */ 3259243Sobrien#include "sh.h" 3359243Sobrien#include "ed.h" 3459243Sobrien#include "tw.h" 3559243Sobrien 3659243Sobrien/* 3759243Sobrien * kfk 21oct1983 -- add @ (time) and / ($cwd) in prompt. 3859243Sobrien * PWP 4/27/87 -- rearange for tcsh. 3959243Sobrien * mrdch@com.tau.edu.il 6/26/89 - added ~, T and .# - rearanged to switch() 4059243Sobrien * instead of if/elseif 4159243Sobrien * Luke Mewburn, <lukem@cs.rmit.edu.au> 4259243Sobrien * 6-Sep-91 changed date format 4359243Sobrien * 16-Feb-94 rewrote directory prompt code, added $ellipsis 4459243Sobrien * 29-Dec-96 added rprompt support 4559243Sobrien */ 4659243Sobrien 47145479Smpstatic const char *month_list[12]; 48145479Smpstatic const char *day_list[7]; 4959243Sobrien 5059243Sobrienvoid 51167465Smpdateinit(void) 5259243Sobrien{ 5359243Sobrien#ifdef notyet 5459243Sobrien int i; 5559243Sobrien 5659243Sobrien setlocale(LC_TIME, ""); 5759243Sobrien 5859243Sobrien for (i = 0; i < 12; i++) 5959243Sobrien xfree((ptr_t) month_list[i]); 6059243Sobrien month_list[0] = strsave(_time_info->abbrev_month[0]); 6159243Sobrien month_list[1] = strsave(_time_info->abbrev_month[1]); 6259243Sobrien month_list[2] = strsave(_time_info->abbrev_month[2]); 6359243Sobrien month_list[3] = strsave(_time_info->abbrev_month[3]); 6459243Sobrien month_list[4] = strsave(_time_info->abbrev_month[4]); 6559243Sobrien month_list[5] = strsave(_time_info->abbrev_month[5]); 6659243Sobrien month_list[6] = strsave(_time_info->abbrev_month[6]); 6759243Sobrien month_list[7] = strsave(_time_info->abbrev_month[7]); 6859243Sobrien month_list[8] = strsave(_time_info->abbrev_month[8]); 6959243Sobrien month_list[9] = strsave(_time_info->abbrev_month[9]); 7059243Sobrien month_list[10] = strsave(_time_info->abbrev_month[10]); 7159243Sobrien month_list[11] = strsave(_time_info->abbrev_month[11]); 7259243Sobrien 7359243Sobrien for (i = 0; i < 7; i++) 7459243Sobrien xfree((ptr_t) day_list[i]); 7559243Sobrien day_list[0] = strsave(_time_info->abbrev_wkday[0]); 7659243Sobrien day_list[1] = strsave(_time_info->abbrev_wkday[1]); 7759243Sobrien day_list[2] = strsave(_time_info->abbrev_wkday[2]); 7859243Sobrien day_list[3] = strsave(_time_info->abbrev_wkday[3]); 7959243Sobrien day_list[4] = strsave(_time_info->abbrev_wkday[4]); 8059243Sobrien day_list[5] = strsave(_time_info->abbrev_wkday[5]); 8159243Sobrien day_list[6] = strsave(_time_info->abbrev_wkday[6]); 8259243Sobrien#else 8359243Sobrien month_list[0] = "Jan"; 8459243Sobrien month_list[1] = "Feb"; 8559243Sobrien month_list[2] = "Mar"; 8659243Sobrien month_list[3] = "Apr"; 8759243Sobrien month_list[4] = "May"; 8859243Sobrien month_list[5] = "Jun"; 8959243Sobrien month_list[6] = "Jul"; 9059243Sobrien month_list[7] = "Aug"; 9159243Sobrien month_list[8] = "Sep"; 9259243Sobrien month_list[9] = "Oct"; 9359243Sobrien month_list[10] = "Nov"; 9459243Sobrien month_list[11] = "Dec"; 9559243Sobrien 9659243Sobrien day_list[0] = "Sun"; 9759243Sobrien day_list[1] = "Mon"; 9859243Sobrien day_list[2] = "Tue"; 9959243Sobrien day_list[3] = "Wed"; 10059243Sobrien day_list[4] = "Thu"; 10159243Sobrien day_list[5] = "Fri"; 10259243Sobrien day_list[6] = "Sat"; 10359243Sobrien#endif 10459243Sobrien} 10559243Sobrien 10659243Sobrienvoid 107167465Smpprintprompt(int promptno, const char *str) 10859243Sobrien{ 109167465Smp static const Char *ocp = NULL; 110145479Smp static const char *ostr = NULL; 11159243Sobrien time_t lclock = time(NULL); 112167465Smp const Char *cp; 11359243Sobrien 11459243Sobrien switch (promptno) { 11559243Sobrien default: 11659243Sobrien case 0: 11759243Sobrien cp = varval(STRprompt); 11859243Sobrien break; 11959243Sobrien case 1: 12059243Sobrien cp = varval(STRprompt2); 12159243Sobrien break; 12259243Sobrien case 2: 12359243Sobrien cp = varval(STRprompt3); 12459243Sobrien break; 12559243Sobrien case 3: 12659243Sobrien if (ocp != NULL) { 12759243Sobrien cp = ocp; 12859243Sobrien str = ostr; 12959243Sobrien } 13059243Sobrien else 13159243Sobrien cp = varval(STRprompt); 13259243Sobrien break; 13359243Sobrien } 13459243Sobrien 13559243Sobrien if (promptno < 2) { 13659243Sobrien ocp = cp; 13759243Sobrien ostr = str; 13859243Sobrien } 13959243Sobrien 140167465Smp xfree(Prompt); 141167465Smp Prompt = NULL; 142167465Smp Prompt = tprintf(FMT_PROMPT, cp, str, lclock, NULL); 14359243Sobrien if (!editing) { 144167465Smp for (cp = Prompt; *cp ; ) 145145479Smp (void) putwraw(*cp++); 14659243Sobrien SetAttributes(0); 14759243Sobrien flush(); 14859243Sobrien } 14959243Sobrien 150167465Smp xfree(RPrompt); 151167465Smp RPrompt = NULL; 15259243Sobrien if (promptno == 0) { /* determine rprompt if using main prompt */ 15359243Sobrien cp = varval(STRrprompt); 154167465Smp RPrompt = tprintf(FMT_PROMPT, cp, NULL, lclock, NULL); 15559243Sobrien /* if not editing, put rprompt after prompt */ 156167465Smp if (!editing && RPrompt[0] != '\0') { 157167465Smp for (cp = RPrompt; *cp ; ) 158145479Smp (void) putwraw(*cp++); 15959243Sobrien SetAttributes(0); 16059243Sobrien putraw(' '); 16159243Sobrien flush(); 16259243Sobrien } 16359243Sobrien } 16459243Sobrien} 16559243Sobrien 166167465Smpstatic void 167167465Smptprintf_append_mbs(struct Strbuf *buf, const char *mbs, Char attributes) 16859243Sobrien{ 169167465Smp while (*mbs != 0) { 170167465Smp Char wc; 171167465Smp 172167465Smp mbs += one_mbtowc(&wc, mbs, MB_LEN_MAX); 173167465Smp Strbuf_append1(buf, wc | attributes); 174167465Smp } 175167465Smp} 176167465Smp 177167465SmpChar * 178167465Smptprintf(int what, const Char *fmt, const char *str, time_t tim, ptr_t info) 179167465Smp{ 180167465Smp struct Strbuf buf = Strbuf_INIT; 18159243Sobrien Char *z, *q; 18259243Sobrien Char attributes = 0; 18359243Sobrien static int print_prompt_did_ding = 0; 184167465Smp char *cz; 18559243Sobrien 186167465Smp Char *p; 18759243Sobrien const Char *cp = fmt; 18859243Sobrien Char Scp; 18959243Sobrien struct tm *t = localtime(&tim); 19059243Sobrien 19159243Sobrien /* prompt stuff */ 192167465Smp static Char *olduser = NULL; 193100616Smp int updirs; 194167465Smp size_t pdirs; 19559243Sobrien 196167465Smp cleanup_push(&buf, Strbuf_cleanup); 19759243Sobrien for (; *cp; cp++) { 19859243Sobrien if ((*cp == '%') && ! (cp[1] == '\0')) { 19959243Sobrien cp++; 20059243Sobrien switch (*cp) { 20159243Sobrien case 'R': 202145479Smp if (what == FMT_HISTORY) { 203167465Smp cz = fmthist('R', info); 204167465Smp tprintf_append_mbs(&buf, cz, attributes); 205167465Smp xfree(cz); 206167465Smp } else { 207167465Smp if (str != NULL) 208167465Smp tprintf_append_mbs(&buf, str, attributes); 209167465Smp } 21059243Sobrien break; 21159243Sobrien case '#': 212316957Sdchagin#ifdef __CYGWIN__ 213316957Sdchagin /* Check for being member of the Administrators group */ 214316957Sdchagin { 215316957Sdchagin gid_t grps[NGROUPS_MAX]; 216316957Sdchagin int grp, gcnt; 217316957Sdchagin 218316957Sdchagin gcnt = getgroups(NGROUPS_MAX, grps); 219316957Sdchagin# define DOMAIN_GROUP_RID_ADMINS 544 220316957Sdchagin for (grp = 0; grp < gcnt; ++grp) 221316957Sdchagin if (grps[grp] == DOMAIN_GROUP_RID_ADMINS) 222316957Sdchagin break; 223316957Sdchagin Scp = (grp < gcnt) ? PRCHROOT : PRCH; 224316957Sdchagin } 225316957Sdchagin#else 226231990Smp Scp = (uid == 0 || euid == 0) ? PRCHROOT : PRCH; 227316957Sdchagin#endif 228231990Smp if (Scp != '\0') 229231990Smp Strbuf_append1(&buf, attributes | Scp); 23059243Sobrien break; 23159243Sobrien case '!': 23259243Sobrien case 'h': 23359243Sobrien switch (what) { 23459243Sobrien case FMT_HISTORY: 235167465Smp cz = fmthist('h', info); 23659243Sobrien break; 23759243Sobrien case FMT_SCHED: 238167465Smp cz = xasprintf("%d", *(int *)info); 23959243Sobrien break; 24059243Sobrien default: 241167465Smp cz = xasprintf("%d", eventno + 1); 24259243Sobrien break; 24359243Sobrien } 244167465Smp tprintf_append_mbs(&buf, cz, attributes); 245167465Smp xfree(cz); 24659243Sobrien break; 24759243Sobrien case 'T': /* 24 hour format */ 24859243Sobrien case '@': 24959243Sobrien case 't': /* 12 hour am/pm format */ 25059243Sobrien case 'p': /* With seconds */ 25159243Sobrien case 'P': 25259243Sobrien { 25359243Sobrien char ampm = 'a'; 25459243Sobrien int hr = t->tm_hour; 25559243Sobrien 25659243Sobrien /* addition by Hans J. Albertsson */ 25759243Sobrien /* and another adapted from Justin Bur */ 25859243Sobrien if (adrof(STRampm) || (*cp != 'T' && *cp != 'P')) { 25959243Sobrien if (hr >= 12) { 26059243Sobrien if (hr > 12) 26159243Sobrien hr -= 12; 26259243Sobrien ampm = 'p'; 26359243Sobrien } 26459243Sobrien else if (hr == 0) 26559243Sobrien hr = 12; 26659243Sobrien } /* else do a 24 hour clock */ 26759243Sobrien 26859243Sobrien /* "DING!" stuff by Hans also */ 26959243Sobrien if (t->tm_min || print_prompt_did_ding || 27059243Sobrien what != FMT_PROMPT || adrof(STRnoding)) { 27159243Sobrien if (t->tm_min) 27259243Sobrien print_prompt_did_ding = 0; 273167465Smp /* 274167465Smp * Pad hour to 2 characters if padhour is set, 275167465Smp * by ADAM David Alan Martin 276167465Smp */ 277167465Smp p = Itoa(hr, adrof(STRpadhour) ? 2 : 0, attributes); 278167465Smp Strbuf_append(&buf, p); 279167465Smp xfree(p); 280167465Smp Strbuf_append1(&buf, attributes | ':'); 281167465Smp p = Itoa(t->tm_min, 2, attributes); 282167465Smp Strbuf_append(&buf, p); 283167465Smp xfree(p); 28459243Sobrien if (*cp == 'p' || *cp == 'P') { 285167465Smp Strbuf_append1(&buf, attributes | ':'); 286167465Smp p = Itoa(t->tm_sec, 2, attributes); 287167465Smp Strbuf_append(&buf, p); 288167465Smp xfree(p); 28959243Sobrien } 29059243Sobrien if (adrof(STRampm) || (*cp != 'T' && *cp != 'P')) { 291167465Smp Strbuf_append1(&buf, attributes | ampm); 292167465Smp Strbuf_append1(&buf, attributes | 'm'); 29359243Sobrien } 29459243Sobrien } 29559243Sobrien else { /* we need to ding */ 296167465Smp size_t i; 29759243Sobrien 298167465Smp for (i = 0; STRDING[i] != 0; i++) 299167465Smp Strbuf_append1(&buf, attributes | STRDING[i]); 30059243Sobrien print_prompt_did_ding = 1; 30159243Sobrien } 30259243Sobrien } 30359243Sobrien break; 30459243Sobrien 30559243Sobrien case 'M': 30659243Sobrien#ifndef HAVENOUTMP 30759243Sobrien if (what == FMT_WHO) 308167465Smp cz = who_info(info, 'M'); 30959243Sobrien else 31059243Sobrien#endif /* HAVENOUTMP */ 311167465Smp cz = getenv("HOST"); 31259243Sobrien /* 31359243Sobrien * Bug pointed out by Laurent Dami <dami@cui.unige.ch>: don't 31459243Sobrien * derefrence that NULL (if HOST is not set)... 31559243Sobrien */ 31659243Sobrien if (cz != NULL) 317167465Smp tprintf_append_mbs(&buf, cz, attributes); 318167465Smp if (what == FMT_WHO) 319167465Smp xfree(cz); 32059243Sobrien break; 32159243Sobrien 322167465Smp case 'm': { 323167465Smp char *scz = NULL; 32459243Sobrien#ifndef HAVENOUTMP 32559243Sobrien if (what == FMT_WHO) 326167465Smp scz = cz = who_info(info, 'm'); 327167465Smp else 32859243Sobrien#endif /* HAVENOUTMP */ 329167465Smp cz = getenv("HOST"); 33059243Sobrien 33159243Sobrien if (cz != NULL) 332167465Smp while (*cz != 0 && (what == FMT_WHO || *cz != '.')) { 333167465Smp Char wc; 334167465Smp 335167465Smp cz += one_mbtowc(&wc, cz, MB_LEN_MAX); 336167465Smp Strbuf_append1(&buf, wc | attributes); 337145479Smp } 338167465Smp if (scz) 339167465Smp xfree(scz); 34059243Sobrien break; 341167465Smp } 34259243Sobrien 34359243Sobrien /* lukem: new directory prompt code */ 34459243Sobrien case '~': 34559243Sobrien case '/': 34659243Sobrien case '.': 34759243Sobrien case 'c': 34859243Sobrien case 'C': 34959243Sobrien Scp = *cp; 35059243Sobrien if (Scp == 'c') /* store format type (c == .) */ 35159243Sobrien Scp = '.'; 35259243Sobrien if ((z = varval(STRcwd)) == STRNULL) 35359243Sobrien break; /* no cwd, so don't do anything */ 35459243Sobrien 35559243Sobrien /* show ~ whenever possible - a la dirs */ 35659243Sobrien if (Scp == '~' || Scp == '.' ) { 357167465Smp static Char *olddir = NULL; 358167465Smp 35959243Sobrien if (tlength == 0 || olddir != z) { 36059243Sobrien olddir = z; /* have we changed dir? */ 36159243Sobrien olduser = getusername(&olddir); 36259243Sobrien } 36359243Sobrien if (olduser) 36459243Sobrien z = olddir; 36559243Sobrien } 36659243Sobrien updirs = pdirs = 0; 36759243Sobrien 36859243Sobrien /* option to determine fixed # of dirs from path */ 36959243Sobrien if (Scp == '.' || Scp == 'C') { 37059243Sobrien int skip; 37169408Sache#ifdef WINNT_NATIVE 372145479Smp Char *oldz = z; 37359243Sobrien if (z[1] == ':') { 374167465Smp Strbuf_append1(&buf, attributes | *z++); 375167465Smp Strbuf_append1(&buf, attributes | *z++); 37659243Sobrien } 377167465Smp if (*z == '/' && z[1] == '/') { 378167465Smp Strbuf_append1(&buf, attributes | *z++); 379167465Smp Strbuf_append1(&buf, attributes | *z++); 380167465Smp do { 381167465Smp Strbuf_append1(&buf, attributes | *z++); 382167465Smp } while(*z != '/'); 383167465Smp } 38469408Sache#endif /* WINNT_NATIVE */ 38559243Sobrien q = z; 38659243Sobrien while (*z) /* calc # of /'s */ 38759243Sobrien if (*z++ == '/') 38859243Sobrien updirs++; 389145479Smp 390145479Smp#ifdef WINNT_NATIVE 391145479Smp /* 392145479Smp * for format type c, prompt will be following... 393145479Smp * c:/path => c:/path 394145479Smp * c:/path/to => c:to 395145479Smp * //machine/share => //machine/share 396145479Smp * //machine/share/folder => //machine:folder 397145479Smp */ 398145479Smp if (oldz[0] == '/' && oldz[1] == '/' && updirs > 1) 399167465Smp Strbuf_append1(&buf, attributes | ':'); 400145479Smp#endif /* WINNT_NATIVE */ 40159243Sobrien if ((Scp == 'C' && *q != '/')) 40259243Sobrien updirs++; 40359243Sobrien 40459243Sobrien if (cp[1] == '0') { /* print <x> or ... */ 40559243Sobrien pdirs = 1; 40659243Sobrien cp++; 40759243Sobrien } 40859243Sobrien if (cp[1] >= '1' && cp[1] <= '9') { /* calc # to skip */ 40959243Sobrien skip = cp[1] - '0'; 41059243Sobrien cp++; 41159243Sobrien } 41259243Sobrien else 41359243Sobrien skip = 1; 41459243Sobrien 41559243Sobrien updirs -= skip; 41659243Sobrien while (skip-- > 0) { 41759243Sobrien while ((z > q) && (*z != '/')) 41859243Sobrien z--; /* back up */ 41959243Sobrien if (skip && z > q) 42059243Sobrien z--; 42159243Sobrien } 42259243Sobrien if (*z == '/' && z != q) 42359243Sobrien z++; 42459243Sobrien } /* . || C */ 42559243Sobrien 42659243Sobrien /* print ~[user] */ 42759243Sobrien if ((olduser) && ((Scp == '~') || 42859243Sobrien (Scp == '.' && (pdirs || (!pdirs && updirs <= 0))) )) { 429167465Smp Strbuf_append1(&buf, attributes | '~'); 430167465Smp for (q = olduser; *q; q++) 431167465Smp Strbuf_append1(&buf, attributes | *q); 43259243Sobrien } 43359243Sobrien 43459243Sobrien /* RWM - tell you how many dirs we've ignored */ 43559243Sobrien /* and add '/' at front of this */ 43659243Sobrien if (updirs > 0 && pdirs) { 43759243Sobrien if (adrof(STRellipsis)) { 438167465Smp Strbuf_append1(&buf, attributes | '.'); 439167465Smp Strbuf_append1(&buf, attributes | '.'); 440167465Smp Strbuf_append1(&buf, attributes | '.'); 44159243Sobrien } else { 442167465Smp Strbuf_append1(&buf, attributes | '/'); 443167465Smp Strbuf_append1(&buf, attributes | '<'); 44459243Sobrien if (updirs > 9) { 445167465Smp Strbuf_append1(&buf, attributes | '9'); 446167465Smp Strbuf_append1(&buf, attributes | '+'); 44759243Sobrien } else 448167465Smp Strbuf_append1(&buf, attributes | ('0' + updirs)); 449167465Smp Strbuf_append1(&buf, attributes | '>'); 45059243Sobrien } 45159243Sobrien } 452167465Smp 453167465Smp while (*z) 454167465Smp Strbuf_append1(&buf, attributes | *z++); 45559243Sobrien break; 45659243Sobrien /* lukem: end of new directory prompt code */ 45759243Sobrien 45859243Sobrien case 'n': 45959243Sobrien#ifndef HAVENOUTMP 46059243Sobrien if (what == FMT_WHO) { 461167465Smp cz = who_info(info, 'n'); 462167465Smp tprintf_append_mbs(&buf, cz, attributes); 463167465Smp xfree(cz); 46459243Sobrien } 46559243Sobrien else 46659243Sobrien#endif /* HAVENOUTMP */ 46759243Sobrien { 46859243Sobrien if ((z = varval(STRuser)) != STRNULL) 469167465Smp while (*z) 470167465Smp Strbuf_append1(&buf, attributes | *z++); 47159243Sobrien } 47259243Sobrien break; 473231990Smp case 'N': 474231990Smp if ((z = varval(STReuser)) != STRNULL) 475231990Smp while (*z) 476231990Smp Strbuf_append1(&buf, attributes | *z++); 477231990Smp break; 47859243Sobrien case 'l': 47959243Sobrien#ifndef HAVENOUTMP 48059243Sobrien if (what == FMT_WHO) { 481167465Smp cz = who_info(info, 'l'); 482167465Smp tprintf_append_mbs(&buf, cz, attributes); 483167465Smp xfree(cz); 48459243Sobrien } 48559243Sobrien else 48659243Sobrien#endif /* HAVENOUTMP */ 48759243Sobrien { 48859243Sobrien if ((z = varval(STRtty)) != STRNULL) 489167465Smp while (*z) 490167465Smp Strbuf_append1(&buf, attributes | *z++); 49159243Sobrien } 49259243Sobrien break; 49359243Sobrien case 'd': 494167465Smp tprintf_append_mbs(&buf, day_list[t->tm_wday], attributes); 49559243Sobrien break; 49659243Sobrien case 'D': 497167465Smp p = Itoa(t->tm_mday, 2, attributes); 498167465Smp Strbuf_append(&buf, p); 499167465Smp xfree(p); 50059243Sobrien break; 50159243Sobrien case 'w': 502167465Smp tprintf_append_mbs(&buf, month_list[t->tm_mon], attributes); 50359243Sobrien break; 50459243Sobrien case 'W': 505167465Smp p = Itoa(t->tm_mon + 1, 2, attributes); 506167465Smp Strbuf_append(&buf, p); 507167465Smp xfree(p); 50859243Sobrien break; 50959243Sobrien case 'y': 510167465Smp p = Itoa(t->tm_year % 100, 2, attributes); 511167465Smp Strbuf_append(&buf, p); 512167465Smp xfree(p); 51359243Sobrien break; 51459243Sobrien case 'Y': 515167465Smp p = Itoa(t->tm_year + 1900, 4, attributes); 516167465Smp Strbuf_append(&buf, p); 517167465Smp xfree(p); 51859243Sobrien break; 51959243Sobrien case 'S': /* start standout */ 52059243Sobrien attributes |= STANDOUT; 52159243Sobrien break; 52259243Sobrien case 'B': /* start bold */ 52359243Sobrien attributes |= BOLD; 52459243Sobrien break; 52559243Sobrien case 'U': /* start underline */ 52659243Sobrien attributes |= UNDER; 52759243Sobrien break; 52859243Sobrien case 's': /* end standout */ 52959243Sobrien attributes &= ~STANDOUT; 53059243Sobrien break; 53159243Sobrien case 'b': /* end bold */ 53259243Sobrien attributes &= ~BOLD; 53359243Sobrien break; 53459243Sobrien case 'u': /* end underline */ 53559243Sobrien attributes &= ~UNDER; 53659243Sobrien break; 53759243Sobrien case 'L': 53859243Sobrien ClearToBottom(); 53959243Sobrien break; 540100616Smp 541100616Smp case 'j': 542100616Smp { 543100616Smp int njobs = -1; 544100616Smp struct process *pp; 545167465Smp 546100616Smp for (pp = proclist.p_next; pp; pp = pp->p_next) 547100616Smp njobs++; 548231990Smp if (njobs == -1) 549231990Smp njobs++; 550167465Smp p = Itoa(njobs, 1, attributes); 551167465Smp Strbuf_append(&buf, p); 552167465Smp xfree(p); 553100616Smp break; 554100616Smp } 55559243Sobrien case '?': 55659243Sobrien if ((z = varval(STRstatus)) != STRNULL) 557167465Smp while (*z) 558167465Smp Strbuf_append1(&buf, attributes | *z++); 55959243Sobrien break; 56059243Sobrien case '$': 561167465Smp expdollar(&buf, &cp, attributes); 562167465Smp /* cp should point the last char of current % sequence */ 563100616Smp cp--; 56459243Sobrien break; 56559243Sobrien case '%': 566167465Smp Strbuf_append1(&buf, attributes | '%'); 56759243Sobrien break; 56859243Sobrien case '{': /* literal characters start */ 56959243Sobrien#if LITERAL == 0 57059243Sobrien /* 57159243Sobrien * No literal capability, so skip all chars in the literal 57259243Sobrien * string 57359243Sobrien */ 574167465Smp while (*cp != '\0' && (cp[-1] != '%' || *cp != '}')) 57559243Sobrien cp++; 57659243Sobrien#endif /* LITERAL == 0 */ 57759243Sobrien attributes |= LITERAL; 57859243Sobrien break; 57959243Sobrien case '}': /* literal characters end */ 58059243Sobrien attributes &= ~LITERAL; 58159243Sobrien break; 58259243Sobrien default: 58359243Sobrien#ifndef HAVENOUTMP 58459243Sobrien if (*cp == 'a' && what == FMT_WHO) { 585167465Smp cz = who_info(info, 'a'); 586167465Smp tprintf_append_mbs(&buf, cz, attributes); 587167465Smp xfree(cz); 58859243Sobrien } 589167465Smp else 59059243Sobrien#endif /* HAVENOUTMP */ 59159243Sobrien { 592167465Smp Strbuf_append1(&buf, attributes | '%'); 593167465Smp Strbuf_append1(&buf, attributes | *cp); 59459243Sobrien } 59559243Sobrien break; 59659243Sobrien } 59759243Sobrien } 598167465Smp else if (*cp == '\\' || *cp == '^') 599167465Smp Strbuf_append1(&buf, attributes | parseescape(&cp)); 60059243Sobrien else if (*cp == HIST) { /* EGS: handle '!'s in prompts */ 601167465Smp if (what == FMT_HISTORY) 602167465Smp cz = fmthist('h', info); 60359243Sobrien else 604167465Smp cz = xasprintf("%d", eventno + 1); 605167465Smp tprintf_append_mbs(&buf, cz, attributes); 606167465Smp xfree(cz); 60759243Sobrien } 608167465Smp else 609167465Smp Strbuf_append1(&buf, attributes | *cp); /* normal character */ 61059243Sobrien } 611167465Smp cleanup_ignore(&buf); 612167465Smp cleanup_until(&buf); 613167465Smp return Strbuf_finish(&buf); 61459243Sobrien} 61559243Sobrien 616167465Smpint 617167465Smpexpdollar(struct Strbuf *buf, const Char **srcp, Char attr) 61859243Sobrien{ 61959243Sobrien struct varent *vp; 62059243Sobrien const Char *src = *srcp; 621167465Smp Char *var, *val; 622167465Smp size_t i; 623167465Smp int curly = 0; 62459243Sobrien 62559243Sobrien /* found a variable, expand it */ 626167465Smp var = xmalloc((Strlen(src) + 1) * sizeof (*var)); 627167465Smp for (i = 0; ; i++) { 62859243Sobrien var[i] = *++src & TRIM; 62959243Sobrien if (i == 0 && var[i] == '{') { 63059243Sobrien curly = 1; 63159243Sobrien var[i] = *++src & TRIM; 63259243Sobrien } 633167465Smp if (!alnum(var[i]) && var[i] != '_') { 634167465Smp 63559243Sobrien var[i] = '\0'; 63659243Sobrien break; 63759243Sobrien } 63859243Sobrien } 63959243Sobrien if (curly && (*src & TRIM) == '}') 64059243Sobrien src++; 64159243Sobrien 64259243Sobrien vp = adrof(var); 643100616Smp if (vp && vp->vec) { 64459243Sobrien for (i = 0; vp->vec[i] != NULL; i++) { 645167465Smp for (val = vp->vec[i]; *val; val++) 646167465Smp if (*val != '\n' && *val != '\r') 647167465Smp Strbuf_append1(buf, *val | attr); 648167465Smp if (vp->vec[i+1]) 649167465Smp Strbuf_append1(buf, ' ' | attr); 65059243Sobrien } 65159243Sobrien } 65259243Sobrien else { 653167465Smp val = (!vp) ? tgetenv(var) : NULL; 654167465Smp if (val) { 655167465Smp for (; *val; val++) 656167465Smp if (*val != '\n' && *val != '\r') 657167465Smp Strbuf_append1(buf, *val | attr); 658167465Smp } else { 659167465Smp *srcp = src; 660167465Smp xfree(var); 661167465Smp return 0; 662167465Smp } 66359243Sobrien } 66459243Sobrien 66559243Sobrien *srcp = src; 666167465Smp xfree(var); 667167465Smp return 1; 66859243Sobrien} 669