1232633Smp/* $Header: /p/tcsh/cvsroot/tcsh/tc.prompt.c,v 3.70 2011/10/27 22:41:06 christos Exp $ */ 259243Sobrien/* 359243Sobrien * tc.prompt.c: Prompt printing stuff 459243Sobrien */ 559243Sobrien/*- 659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 759243Sobrien * All rights reserved. 859243Sobrien * 959243Sobrien * Redistribution and use in source and binary forms, with or without 1059243Sobrien * modification, are permitted provided that the following conditions 1159243Sobrien * are met: 1259243Sobrien * 1. Redistributions of source code must retain the above copyright 1359243Sobrien * notice, this list of conditions and the following disclaimer. 1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1559243Sobrien * notice, this list of conditions and the following disclaimer in the 1659243Sobrien * documentation and/or other materials provided with the distribution. 17100616Smp * 3. Neither the name of the University nor the names of its contributors 1859243Sobrien * may be used to endorse or promote products derived from this software 1959243Sobrien * without specific prior written permission. 2059243Sobrien * 2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2459243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3159243Sobrien * SUCH DAMAGE. 3259243Sobrien */ 3359243Sobrien#include "sh.h" 3459243Sobrien 35232633SmpRCSID("$tcsh: tc.prompt.c,v 3.70 2011/10/27 22:41:06 christos Exp $") 3659243Sobrien 3759243Sobrien#include "ed.h" 3859243Sobrien#include "tw.h" 3959243Sobrien 4059243Sobrien/* 4159243Sobrien * kfk 21oct1983 -- add @ (time) and / ($cwd) in prompt. 4259243Sobrien * PWP 4/27/87 -- rearange for tcsh. 4359243Sobrien * mrdch@com.tau.edu.il 6/26/89 - added ~, T and .# - rearanged to switch() 4459243Sobrien * instead of if/elseif 4559243Sobrien * Luke Mewburn, <lukem@cs.rmit.edu.au> 4659243Sobrien * 6-Sep-91 changed date format 4759243Sobrien * 16-Feb-94 rewrote directory prompt code, added $ellipsis 4859243Sobrien * 29-Dec-96 added rprompt support 4959243Sobrien */ 5059243Sobrien 51145479Smpstatic const char *month_list[12]; 52145479Smpstatic const char *day_list[7]; 5359243Sobrien 5459243Sobrienvoid 55167465Smpdateinit(void) 5659243Sobrien{ 5759243Sobrien#ifdef notyet 5859243Sobrien int i; 5959243Sobrien 6059243Sobrien setlocale(LC_TIME, ""); 6159243Sobrien 6259243Sobrien for (i = 0; i < 12; i++) 6359243Sobrien xfree((ptr_t) month_list[i]); 6459243Sobrien month_list[0] = strsave(_time_info->abbrev_month[0]); 6559243Sobrien month_list[1] = strsave(_time_info->abbrev_month[1]); 6659243Sobrien month_list[2] = strsave(_time_info->abbrev_month[2]); 6759243Sobrien month_list[3] = strsave(_time_info->abbrev_month[3]); 6859243Sobrien month_list[4] = strsave(_time_info->abbrev_month[4]); 6959243Sobrien month_list[5] = strsave(_time_info->abbrev_month[5]); 7059243Sobrien month_list[6] = strsave(_time_info->abbrev_month[6]); 7159243Sobrien month_list[7] = strsave(_time_info->abbrev_month[7]); 7259243Sobrien month_list[8] = strsave(_time_info->abbrev_month[8]); 7359243Sobrien month_list[9] = strsave(_time_info->abbrev_month[9]); 7459243Sobrien month_list[10] = strsave(_time_info->abbrev_month[10]); 7559243Sobrien month_list[11] = strsave(_time_info->abbrev_month[11]); 7659243Sobrien 7759243Sobrien for (i = 0; i < 7; i++) 7859243Sobrien xfree((ptr_t) day_list[i]); 7959243Sobrien day_list[0] = strsave(_time_info->abbrev_wkday[0]); 8059243Sobrien day_list[1] = strsave(_time_info->abbrev_wkday[1]); 8159243Sobrien day_list[2] = strsave(_time_info->abbrev_wkday[2]); 8259243Sobrien day_list[3] = strsave(_time_info->abbrev_wkday[3]); 8359243Sobrien day_list[4] = strsave(_time_info->abbrev_wkday[4]); 8459243Sobrien day_list[5] = strsave(_time_info->abbrev_wkday[5]); 8559243Sobrien day_list[6] = strsave(_time_info->abbrev_wkday[6]); 8659243Sobrien#else 8759243Sobrien month_list[0] = "Jan"; 8859243Sobrien month_list[1] = "Feb"; 8959243Sobrien month_list[2] = "Mar"; 9059243Sobrien month_list[3] = "Apr"; 9159243Sobrien month_list[4] = "May"; 9259243Sobrien month_list[5] = "Jun"; 9359243Sobrien month_list[6] = "Jul"; 9459243Sobrien month_list[7] = "Aug"; 9559243Sobrien month_list[8] = "Sep"; 9659243Sobrien month_list[9] = "Oct"; 9759243Sobrien month_list[10] = "Nov"; 9859243Sobrien month_list[11] = "Dec"; 9959243Sobrien 10059243Sobrien day_list[0] = "Sun"; 10159243Sobrien day_list[1] = "Mon"; 10259243Sobrien day_list[2] = "Tue"; 10359243Sobrien day_list[3] = "Wed"; 10459243Sobrien day_list[4] = "Thu"; 10559243Sobrien day_list[5] = "Fri"; 10659243Sobrien day_list[6] = "Sat"; 10759243Sobrien#endif 10859243Sobrien} 10959243Sobrien 11059243Sobrienvoid 111167465Smpprintprompt(int promptno, const char *str) 11259243Sobrien{ 113167465Smp static const Char *ocp = NULL; 114145479Smp static const char *ostr = NULL; 11559243Sobrien time_t lclock = time(NULL); 116167465Smp const Char *cp; 11759243Sobrien 11859243Sobrien switch (promptno) { 11959243Sobrien default: 12059243Sobrien case 0: 12159243Sobrien cp = varval(STRprompt); 12259243Sobrien break; 12359243Sobrien case 1: 12459243Sobrien cp = varval(STRprompt2); 12559243Sobrien break; 12659243Sobrien case 2: 12759243Sobrien cp = varval(STRprompt3); 12859243Sobrien break; 12959243Sobrien case 3: 13059243Sobrien if (ocp != NULL) { 13159243Sobrien cp = ocp; 13259243Sobrien str = ostr; 13359243Sobrien } 13459243Sobrien else 13559243Sobrien cp = varval(STRprompt); 13659243Sobrien break; 13759243Sobrien } 13859243Sobrien 13959243Sobrien if (promptno < 2) { 14059243Sobrien ocp = cp; 14159243Sobrien ostr = str; 14259243Sobrien } 14359243Sobrien 144167465Smp xfree(Prompt); 145167465Smp Prompt = NULL; 146167465Smp Prompt = tprintf(FMT_PROMPT, cp, str, lclock, NULL); 14759243Sobrien if (!editing) { 148167465Smp for (cp = Prompt; *cp ; ) 149145479Smp (void) putwraw(*cp++); 15059243Sobrien SetAttributes(0); 15159243Sobrien flush(); 15259243Sobrien } 15359243Sobrien 154167465Smp xfree(RPrompt); 155167465Smp RPrompt = NULL; 15659243Sobrien if (promptno == 0) { /* determine rprompt if using main prompt */ 15759243Sobrien cp = varval(STRrprompt); 158167465Smp RPrompt = tprintf(FMT_PROMPT, cp, NULL, lclock, NULL); 15959243Sobrien /* if not editing, put rprompt after prompt */ 160167465Smp if (!editing && RPrompt[0] != '\0') { 161167465Smp for (cp = RPrompt; *cp ; ) 162145479Smp (void) putwraw(*cp++); 16359243Sobrien SetAttributes(0); 16459243Sobrien putraw(' '); 16559243Sobrien flush(); 16659243Sobrien } 16759243Sobrien } 16859243Sobrien} 16959243Sobrien 170167465Smpstatic void 171167465Smptprintf_append_mbs(struct Strbuf *buf, const char *mbs, Char attributes) 17259243Sobrien{ 173167465Smp while (*mbs != 0) { 174167465Smp Char wc; 175167465Smp 176167465Smp mbs += one_mbtowc(&wc, mbs, MB_LEN_MAX); 177167465Smp Strbuf_append1(buf, wc | attributes); 178167465Smp } 179167465Smp} 180167465Smp 181167465SmpChar * 182167465Smptprintf(int what, const Char *fmt, const char *str, time_t tim, ptr_t info) 183167465Smp{ 184167465Smp struct Strbuf buf = Strbuf_INIT; 18559243Sobrien Char *z, *q; 18659243Sobrien Char attributes = 0; 18759243Sobrien static int print_prompt_did_ding = 0; 188167465Smp char *cz; 18959243Sobrien 190167465Smp Char *p; 19159243Sobrien const Char *cp = fmt; 19259243Sobrien Char Scp; 19359243Sobrien struct tm *t = localtime(&tim); 19459243Sobrien 19559243Sobrien /* prompt stuff */ 196167465Smp static Char *olduser = NULL; 197100616Smp int updirs; 198167465Smp size_t pdirs; 19959243Sobrien 200167465Smp cleanup_push(&buf, Strbuf_cleanup); 20159243Sobrien for (; *cp; cp++) { 20259243Sobrien if ((*cp == '%') && ! (cp[1] == '\0')) { 20359243Sobrien cp++; 20459243Sobrien switch (*cp) { 20559243Sobrien case 'R': 206145479Smp if (what == FMT_HISTORY) { 207167465Smp cz = fmthist('R', info); 208167465Smp tprintf_append_mbs(&buf, cz, attributes); 209167465Smp xfree(cz); 210167465Smp } else { 211167465Smp if (str != NULL) 212167465Smp tprintf_append_mbs(&buf, str, attributes); 213167465Smp } 21459243Sobrien break; 21559243Sobrien case '#': 216232633Smp Scp = (uid == 0 || euid == 0) ? PRCHROOT : PRCH; 217232633Smp if (Scp != '\0') 218232633Smp Strbuf_append1(&buf, attributes | Scp); 21959243Sobrien break; 22059243Sobrien case '!': 22159243Sobrien case 'h': 22259243Sobrien switch (what) { 22359243Sobrien case FMT_HISTORY: 224167465Smp cz = fmthist('h', info); 22559243Sobrien break; 22659243Sobrien case FMT_SCHED: 227167465Smp cz = xasprintf("%d", *(int *)info); 22859243Sobrien break; 22959243Sobrien default: 230167465Smp cz = xasprintf("%d", eventno + 1); 23159243Sobrien break; 23259243Sobrien } 233167465Smp tprintf_append_mbs(&buf, cz, attributes); 234167465Smp xfree(cz); 23559243Sobrien break; 23659243Sobrien case 'T': /* 24 hour format */ 23759243Sobrien case '@': 23859243Sobrien case 't': /* 12 hour am/pm format */ 23959243Sobrien case 'p': /* With seconds */ 24059243Sobrien case 'P': 24159243Sobrien { 24259243Sobrien char ampm = 'a'; 24359243Sobrien int hr = t->tm_hour; 24459243Sobrien 24559243Sobrien /* addition by Hans J. Albertsson */ 24659243Sobrien /* and another adapted from Justin Bur */ 24759243Sobrien if (adrof(STRampm) || (*cp != 'T' && *cp != 'P')) { 24859243Sobrien if (hr >= 12) { 24959243Sobrien if (hr > 12) 25059243Sobrien hr -= 12; 25159243Sobrien ampm = 'p'; 25259243Sobrien } 25359243Sobrien else if (hr == 0) 25459243Sobrien hr = 12; 25559243Sobrien } /* else do a 24 hour clock */ 25659243Sobrien 25759243Sobrien /* "DING!" stuff by Hans also */ 25859243Sobrien if (t->tm_min || print_prompt_did_ding || 25959243Sobrien what != FMT_PROMPT || adrof(STRnoding)) { 26059243Sobrien if (t->tm_min) 26159243Sobrien print_prompt_did_ding = 0; 262167465Smp /* 263167465Smp * Pad hour to 2 characters if padhour is set, 264167465Smp * by ADAM David Alan Martin 265167465Smp */ 266167465Smp p = Itoa(hr, adrof(STRpadhour) ? 2 : 0, attributes); 267167465Smp Strbuf_append(&buf, p); 268167465Smp xfree(p); 269167465Smp Strbuf_append1(&buf, attributes | ':'); 270167465Smp p = Itoa(t->tm_min, 2, attributes); 271167465Smp Strbuf_append(&buf, p); 272167465Smp xfree(p); 27359243Sobrien if (*cp == 'p' || *cp == 'P') { 274167465Smp Strbuf_append1(&buf, attributes | ':'); 275167465Smp p = Itoa(t->tm_sec, 2, attributes); 276167465Smp Strbuf_append(&buf, p); 277167465Smp xfree(p); 27859243Sobrien } 27959243Sobrien if (adrof(STRampm) || (*cp != 'T' && *cp != 'P')) { 280167465Smp Strbuf_append1(&buf, attributes | ampm); 281167465Smp Strbuf_append1(&buf, attributes | 'm'); 28259243Sobrien } 28359243Sobrien } 28459243Sobrien else { /* we need to ding */ 285167465Smp size_t i; 28659243Sobrien 287167465Smp for (i = 0; STRDING[i] != 0; i++) 288167465Smp Strbuf_append1(&buf, attributes | STRDING[i]); 28959243Sobrien print_prompt_did_ding = 1; 29059243Sobrien } 29159243Sobrien } 29259243Sobrien break; 29359243Sobrien 29459243Sobrien case 'M': 29559243Sobrien#ifndef HAVENOUTMP 29659243Sobrien if (what == FMT_WHO) 297167465Smp cz = who_info(info, 'M'); 29859243Sobrien else 29959243Sobrien#endif /* HAVENOUTMP */ 300167465Smp cz = getenv("HOST"); 30159243Sobrien /* 30259243Sobrien * Bug pointed out by Laurent Dami <dami@cui.unige.ch>: don't 30359243Sobrien * derefrence that NULL (if HOST is not set)... 30459243Sobrien */ 30559243Sobrien if (cz != NULL) 306167465Smp tprintf_append_mbs(&buf, cz, attributes); 307167465Smp if (what == FMT_WHO) 308167465Smp xfree(cz); 30959243Sobrien break; 31059243Sobrien 311167465Smp case 'm': { 312167465Smp char *scz = NULL; 31359243Sobrien#ifndef HAVENOUTMP 31459243Sobrien if (what == FMT_WHO) 315167465Smp scz = cz = who_info(info, 'm'); 316167465Smp else 31759243Sobrien#endif /* HAVENOUTMP */ 318167465Smp cz = getenv("HOST"); 31959243Sobrien 32059243Sobrien if (cz != NULL) 321167465Smp while (*cz != 0 && (what == FMT_WHO || *cz != '.')) { 322167465Smp Char wc; 323167465Smp 324167465Smp cz += one_mbtowc(&wc, cz, MB_LEN_MAX); 325167465Smp Strbuf_append1(&buf, wc | attributes); 326145479Smp } 327167465Smp if (scz) 328167465Smp xfree(scz); 32959243Sobrien break; 330167465Smp } 33159243Sobrien 33259243Sobrien /* lukem: new directory prompt code */ 33359243Sobrien case '~': 33459243Sobrien case '/': 33559243Sobrien case '.': 33659243Sobrien case 'c': 33759243Sobrien case 'C': 33859243Sobrien Scp = *cp; 33959243Sobrien if (Scp == 'c') /* store format type (c == .) */ 34059243Sobrien Scp = '.'; 34159243Sobrien if ((z = varval(STRcwd)) == STRNULL) 34259243Sobrien break; /* no cwd, so don't do anything */ 34359243Sobrien 34459243Sobrien /* show ~ whenever possible - a la dirs */ 34559243Sobrien if (Scp == '~' || Scp == '.' ) { 346167465Smp static Char *olddir = NULL; 347167465Smp 34859243Sobrien if (tlength == 0 || olddir != z) { 34959243Sobrien olddir = z; /* have we changed dir? */ 35059243Sobrien olduser = getusername(&olddir); 35159243Sobrien } 35259243Sobrien if (olduser) 35359243Sobrien z = olddir; 35459243Sobrien } 35559243Sobrien updirs = pdirs = 0; 35659243Sobrien 35759243Sobrien /* option to determine fixed # of dirs from path */ 35859243Sobrien if (Scp == '.' || Scp == 'C') { 35959243Sobrien int skip; 36069408Sache#ifdef WINNT_NATIVE 361145479Smp Char *oldz = z; 36259243Sobrien if (z[1] == ':') { 363167465Smp Strbuf_append1(&buf, attributes | *z++); 364167465Smp Strbuf_append1(&buf, attributes | *z++); 36559243Sobrien } 366167465Smp if (*z == '/' && z[1] == '/') { 367167465Smp Strbuf_append1(&buf, attributes | *z++); 368167465Smp Strbuf_append1(&buf, attributes | *z++); 369167465Smp do { 370167465Smp Strbuf_append1(&buf, attributes | *z++); 371167465Smp } while(*z != '/'); 372167465Smp } 37369408Sache#endif /* WINNT_NATIVE */ 37459243Sobrien q = z; 37559243Sobrien while (*z) /* calc # of /'s */ 37659243Sobrien if (*z++ == '/') 37759243Sobrien updirs++; 378145479Smp 379145479Smp#ifdef WINNT_NATIVE 380145479Smp /* 381145479Smp * for format type c, prompt will be following... 382145479Smp * c:/path => c:/path 383145479Smp * c:/path/to => c:to 384145479Smp * //machine/share => //machine/share 385145479Smp * //machine/share/folder => //machine:folder 386145479Smp */ 387145479Smp if (oldz[0] == '/' && oldz[1] == '/' && updirs > 1) 388167465Smp Strbuf_append1(&buf, attributes | ':'); 389145479Smp#endif /* WINNT_NATIVE */ 39059243Sobrien if ((Scp == 'C' && *q != '/')) 39159243Sobrien updirs++; 39259243Sobrien 39359243Sobrien if (cp[1] == '0') { /* print <x> or ... */ 39459243Sobrien pdirs = 1; 39559243Sobrien cp++; 39659243Sobrien } 39759243Sobrien if (cp[1] >= '1' && cp[1] <= '9') { /* calc # to skip */ 39859243Sobrien skip = cp[1] - '0'; 39959243Sobrien cp++; 40059243Sobrien } 40159243Sobrien else 40259243Sobrien skip = 1; 40359243Sobrien 40459243Sobrien updirs -= skip; 40559243Sobrien while (skip-- > 0) { 40659243Sobrien while ((z > q) && (*z != '/')) 40759243Sobrien z--; /* back up */ 40859243Sobrien if (skip && z > q) 40959243Sobrien z--; 41059243Sobrien } 41159243Sobrien if (*z == '/' && z != q) 41259243Sobrien z++; 41359243Sobrien } /* . || C */ 41459243Sobrien 41559243Sobrien /* print ~[user] */ 41659243Sobrien if ((olduser) && ((Scp == '~') || 41759243Sobrien (Scp == '.' && (pdirs || (!pdirs && updirs <= 0))) )) { 418167465Smp Strbuf_append1(&buf, attributes | '~'); 419167465Smp for (q = olduser; *q; q++) 420167465Smp Strbuf_append1(&buf, attributes | *q); 42159243Sobrien } 42259243Sobrien 42359243Sobrien /* RWM - tell you how many dirs we've ignored */ 42459243Sobrien /* and add '/' at front of this */ 42559243Sobrien if (updirs > 0 && pdirs) { 42659243Sobrien if (adrof(STRellipsis)) { 427167465Smp Strbuf_append1(&buf, attributes | '.'); 428167465Smp Strbuf_append1(&buf, attributes | '.'); 429167465Smp Strbuf_append1(&buf, attributes | '.'); 43059243Sobrien } else { 431167465Smp Strbuf_append1(&buf, attributes | '/'); 432167465Smp Strbuf_append1(&buf, attributes | '<'); 43359243Sobrien if (updirs > 9) { 434167465Smp Strbuf_append1(&buf, attributes | '9'); 435167465Smp Strbuf_append1(&buf, attributes | '+'); 43659243Sobrien } else 437167465Smp Strbuf_append1(&buf, attributes | ('0' + updirs)); 438167465Smp Strbuf_append1(&buf, attributes | '>'); 43959243Sobrien } 44059243Sobrien } 441167465Smp 442167465Smp while (*z) 443167465Smp Strbuf_append1(&buf, attributes | *z++); 44459243Sobrien break; 44559243Sobrien /* lukem: end of new directory prompt code */ 44659243Sobrien 44759243Sobrien case 'n': 44859243Sobrien#ifndef HAVENOUTMP 44959243Sobrien if (what == FMT_WHO) { 450167465Smp cz = who_info(info, 'n'); 451167465Smp tprintf_append_mbs(&buf, cz, attributes); 452167465Smp xfree(cz); 45359243Sobrien } 45459243Sobrien else 45559243Sobrien#endif /* HAVENOUTMP */ 45659243Sobrien { 45759243Sobrien if ((z = varval(STRuser)) != STRNULL) 458167465Smp while (*z) 459167465Smp Strbuf_append1(&buf, attributes | *z++); 46059243Sobrien } 46159243Sobrien break; 462232633Smp case 'N': 463232633Smp if ((z = varval(STReuser)) != STRNULL) 464232633Smp while (*z) 465232633Smp Strbuf_append1(&buf, attributes | *z++); 466232633Smp break; 46759243Sobrien case 'l': 46859243Sobrien#ifndef HAVENOUTMP 46959243Sobrien if (what == FMT_WHO) { 470167465Smp cz = who_info(info, 'l'); 471167465Smp tprintf_append_mbs(&buf, cz, attributes); 472167465Smp xfree(cz); 47359243Sobrien } 47459243Sobrien else 47559243Sobrien#endif /* HAVENOUTMP */ 47659243Sobrien { 47759243Sobrien if ((z = varval(STRtty)) != STRNULL) 478167465Smp while (*z) 479167465Smp Strbuf_append1(&buf, attributes | *z++); 48059243Sobrien } 48159243Sobrien break; 48259243Sobrien case 'd': 483167465Smp tprintf_append_mbs(&buf, day_list[t->tm_wday], attributes); 48459243Sobrien break; 48559243Sobrien case 'D': 486167465Smp p = Itoa(t->tm_mday, 2, attributes); 487167465Smp Strbuf_append(&buf, p); 488167465Smp xfree(p); 48959243Sobrien break; 49059243Sobrien case 'w': 491167465Smp tprintf_append_mbs(&buf, month_list[t->tm_mon], attributes); 49259243Sobrien break; 49359243Sobrien case 'W': 494167465Smp p = Itoa(t->tm_mon + 1, 2, attributes); 495167465Smp Strbuf_append(&buf, p); 496167465Smp xfree(p); 49759243Sobrien break; 49859243Sobrien case 'y': 499167465Smp p = Itoa(t->tm_year % 100, 2, attributes); 500167465Smp Strbuf_append(&buf, p); 501167465Smp xfree(p); 50259243Sobrien break; 50359243Sobrien case 'Y': 504167465Smp p = Itoa(t->tm_year + 1900, 4, attributes); 505167465Smp Strbuf_append(&buf, p); 506167465Smp xfree(p); 50759243Sobrien break; 50859243Sobrien case 'S': /* start standout */ 50959243Sobrien attributes |= STANDOUT; 51059243Sobrien break; 51159243Sobrien case 'B': /* start bold */ 51259243Sobrien attributes |= BOLD; 51359243Sobrien break; 51459243Sobrien case 'U': /* start underline */ 51559243Sobrien attributes |= UNDER; 51659243Sobrien break; 51759243Sobrien case 's': /* end standout */ 51859243Sobrien attributes &= ~STANDOUT; 51959243Sobrien break; 52059243Sobrien case 'b': /* end bold */ 52159243Sobrien attributes &= ~BOLD; 52259243Sobrien break; 52359243Sobrien case 'u': /* end underline */ 52459243Sobrien attributes &= ~UNDER; 52559243Sobrien break; 52659243Sobrien case 'L': 52759243Sobrien ClearToBottom(); 52859243Sobrien break; 529100616Smp 530100616Smp case 'j': 531100616Smp { 532100616Smp int njobs = -1; 533100616Smp struct process *pp; 534167465Smp 535100616Smp for (pp = proclist.p_next; pp; pp = pp->p_next) 536100616Smp njobs++; 537232633Smp if (njobs == -1) 538232633Smp njobs++; 539167465Smp p = Itoa(njobs, 1, attributes); 540167465Smp Strbuf_append(&buf, p); 541167465Smp xfree(p); 542100616Smp break; 543100616Smp } 54459243Sobrien case '?': 54559243Sobrien if ((z = varval(STRstatus)) != STRNULL) 546167465Smp while (*z) 547167465Smp Strbuf_append1(&buf, attributes | *z++); 54859243Sobrien break; 54959243Sobrien case '$': 550167465Smp expdollar(&buf, &cp, attributes); 551167465Smp /* cp should point the last char of current % sequence */ 552100616Smp cp--; 55359243Sobrien break; 55459243Sobrien case '%': 555167465Smp Strbuf_append1(&buf, attributes | '%'); 55659243Sobrien break; 55759243Sobrien case '{': /* literal characters start */ 55859243Sobrien#if LITERAL == 0 55959243Sobrien /* 56059243Sobrien * No literal capability, so skip all chars in the literal 56159243Sobrien * string 56259243Sobrien */ 563167465Smp while (*cp != '\0' && (cp[-1] != '%' || *cp != '}')) 56459243Sobrien cp++; 56559243Sobrien#endif /* LITERAL == 0 */ 56659243Sobrien attributes |= LITERAL; 56759243Sobrien break; 56859243Sobrien case '}': /* literal characters end */ 56959243Sobrien attributes &= ~LITERAL; 57059243Sobrien break; 57159243Sobrien default: 57259243Sobrien#ifndef HAVENOUTMP 57359243Sobrien if (*cp == 'a' && what == FMT_WHO) { 574167465Smp cz = who_info(info, 'a'); 575167465Smp tprintf_append_mbs(&buf, cz, attributes); 576167465Smp xfree(cz); 57759243Sobrien } 578167465Smp else 57959243Sobrien#endif /* HAVENOUTMP */ 58059243Sobrien { 581167465Smp Strbuf_append1(&buf, attributes | '%'); 582167465Smp Strbuf_append1(&buf, attributes | *cp); 58359243Sobrien } 58459243Sobrien break; 58559243Sobrien } 58659243Sobrien } 587167465Smp else if (*cp == '\\' || *cp == '^') 588167465Smp Strbuf_append1(&buf, attributes | parseescape(&cp)); 58959243Sobrien else if (*cp == HIST) { /* EGS: handle '!'s in prompts */ 590167465Smp if (what == FMT_HISTORY) 591167465Smp cz = fmthist('h', info); 59259243Sobrien else 593167465Smp cz = xasprintf("%d", eventno + 1); 594167465Smp tprintf_append_mbs(&buf, cz, attributes); 595167465Smp xfree(cz); 59659243Sobrien } 597167465Smp else 598167465Smp Strbuf_append1(&buf, attributes | *cp); /* normal character */ 59959243Sobrien } 600167465Smp cleanup_ignore(&buf); 601167465Smp cleanup_until(&buf); 602167465Smp return Strbuf_finish(&buf); 60359243Sobrien} 60459243Sobrien 605167465Smpint 606167465Smpexpdollar(struct Strbuf *buf, const Char **srcp, Char attr) 60759243Sobrien{ 60859243Sobrien struct varent *vp; 60959243Sobrien const Char *src = *srcp; 610167465Smp Char *var, *val; 611167465Smp size_t i; 612167465Smp int curly = 0; 61359243Sobrien 61459243Sobrien /* found a variable, expand it */ 615167465Smp var = xmalloc((Strlen(src) + 1) * sizeof (*var)); 616167465Smp for (i = 0; ; i++) { 61759243Sobrien var[i] = *++src & TRIM; 61859243Sobrien if (i == 0 && var[i] == '{') { 61959243Sobrien curly = 1; 62059243Sobrien var[i] = *++src & TRIM; 62159243Sobrien } 622167465Smp if (!alnum(var[i]) && var[i] != '_') { 623167465Smp 62459243Sobrien var[i] = '\0'; 62559243Sobrien break; 62659243Sobrien } 62759243Sobrien } 62859243Sobrien if (curly && (*src & TRIM) == '}') 62959243Sobrien src++; 63059243Sobrien 63159243Sobrien vp = adrof(var); 632100616Smp if (vp && vp->vec) { 63359243Sobrien for (i = 0; vp->vec[i] != NULL; i++) { 634167465Smp for (val = vp->vec[i]; *val; val++) 635167465Smp if (*val != '\n' && *val != '\r') 636167465Smp Strbuf_append1(buf, *val | attr); 637167465Smp if (vp->vec[i+1]) 638167465Smp Strbuf_append1(buf, ' ' | attr); 63959243Sobrien } 64059243Sobrien } 64159243Sobrien else { 642167465Smp val = (!vp) ? tgetenv(var) : NULL; 643167465Smp if (val) { 644167465Smp for (; *val; val++) 645167465Smp if (*val != '\n' && *val != '\r') 646167465Smp Strbuf_append1(buf, *val | attr); 647167465Smp } else { 648167465Smp *srcp = src; 649167465Smp xfree(var); 650167465Smp return 0; 651167465Smp } 65259243Sobrien } 65359243Sobrien 65459243Sobrien *srcp = src; 655167465Smp xfree(var); 656167465Smp return 1; 65759243Sobrien} 658