tc.prompt.c revision 131962
11553Srgrimes/* $Header: /src/pub/tcsh/tc.prompt.c,v 3.47 2002/07/25 17:14:59 christos Exp $ */ 21553Srgrimes/* 31553Srgrimes * tc.prompt.c: Prompt printing stuff 41553Srgrimes */ 51553Srgrimes/*- 61553Srgrimes * Copyright (c) 1980, 1991 The Regents of the University of California. 71553Srgrimes * All rights reserved. 81553Srgrimes * 91553Srgrimes * Redistribution and use in source and binary forms, with or without 101553Srgrimes * modification, are permitted provided that the following conditions 111553Srgrimes * are met: 121553Srgrimes * 1. Redistributions of source code must retain the above copyright 131553Srgrimes * notice, this list of conditions and the following disclaimer. 141553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 151553Srgrimes * notice, this list of conditions and the following disclaimer in the 161553Srgrimes * documentation and/or other materials provided with the distribution. 171553Srgrimes * 3. Neither the name of the University nor the names of its contributors 181553Srgrimes * may be used to endorse or promote products derived from this software 191553Srgrimes * without specific prior written permission. 201553Srgrimes * 211553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3130642Scharnier * SUCH DAMAGE. 321553Srgrimes */ 3330642Scharnier#include "sh.h" 3430642Scharnier 3550479SpeterRCSID("$Id: tc.prompt.c,v 3.47 2002/07/25 17:14:59 christos Exp $") 361553Srgrimes 371553Srgrimes#include "ed.h" 381553Srgrimes#include "tw.h" 391553Srgrimes 401553Srgrimes/* 411553Srgrimes * kfk 21oct1983 -- add @ (time) and / ($cwd) in prompt. 421553Srgrimes * PWP 4/27/87 -- rearange for tcsh. 431553Srgrimes * mrdch@com.tau.edu.il 6/26/89 - added ~, T and .# - rearanged to switch() 441553Srgrimes * instead of if/elseif 451553Srgrimes * Luke Mewburn, <lukem@cs.rmit.edu.au> 461553Srgrimes * 6-Sep-91 changed date format 471553Srgrimes * 16-Feb-94 rewrote directory prompt code, added $ellipsis 481553Srgrimes * 29-Dec-96 added rprompt support 491553Srgrimes */ 501553Srgrimes 511553Srgrimesstatic char *month_list[12]; 521553Srgrimesstatic char *day_list[7]; 531553Srgrimes 541553Srgrimesvoid 551553Srgrimesdateinit() 561553Srgrimes{ 571553Srgrimes#ifdef notyet 581553Srgrimes int i; 59246209Scharnier 60246209Scharnier setlocale(LC_TIME, ""); 61246209Scharnier 621553Srgrimes for (i = 0; i < 12; i++) 631553Srgrimes xfree((ptr_t) month_list[i]); 64246209Scharnier month_list[0] = strsave(_time_info->abbrev_month[0]); 651553Srgrimes month_list[1] = strsave(_time_info->abbrev_month[1]); 661553Srgrimes month_list[2] = strsave(_time_info->abbrev_month[2]); 671553Srgrimes month_list[3] = strsave(_time_info->abbrev_month[3]); 681553Srgrimes month_list[4] = strsave(_time_info->abbrev_month[4]); 691553Srgrimes month_list[5] = strsave(_time_info->abbrev_month[5]); 701553Srgrimes month_list[6] = strsave(_time_info->abbrev_month[6]); 711553Srgrimes month_list[7] = strsave(_time_info->abbrev_month[7]); 721553Srgrimes month_list[8] = strsave(_time_info->abbrev_month[8]); 731553Srgrimes month_list[9] = strsave(_time_info->abbrev_month[9]); 741553Srgrimes month_list[10] = strsave(_time_info->abbrev_month[10]); 751553Srgrimes month_list[11] = strsave(_time_info->abbrev_month[11]); 761553Srgrimes 771553Srgrimes for (i = 0; i < 7; i++) 781553Srgrimes xfree((ptr_t) day_list[i]); 791553Srgrimes day_list[0] = strsave(_time_info->abbrev_wkday[0]); 801553Srgrimes day_list[1] = strsave(_time_info->abbrev_wkday[1]); 811553Srgrimes day_list[2] = strsave(_time_info->abbrev_wkday[2]); 821553Srgrimes day_list[3] = strsave(_time_info->abbrev_wkday[3]); 83209344Sgavin day_list[4] = strsave(_time_info->abbrev_wkday[4]); 841553Srgrimes day_list[5] = strsave(_time_info->abbrev_wkday[5]); 851553Srgrimes day_list[6] = strsave(_time_info->abbrev_wkday[6]); 861553Srgrimes#else 871553Srgrimes month_list[0] = "Jan"; 881553Srgrimes month_list[1] = "Feb"; 891553Srgrimes month_list[2] = "Mar"; 901553Srgrimes month_list[3] = "Apr"; 911553Srgrimes month_list[4] = "May"; 921553Srgrimes month_list[5] = "Jun"; 931553Srgrimes month_list[6] = "Jul"; 941553Srgrimes month_list[7] = "Aug"; 958857Srgrimes month_list[8] = "Sep"; 961553Srgrimes month_list[9] = "Oct"; 971553Srgrimes month_list[10] = "Nov"; 981553Srgrimes month_list[11] = "Dec"; 991553Srgrimes 1001553Srgrimes day_list[0] = "Sun"; 1011553Srgrimes day_list[1] = "Mon"; 1021553Srgrimes day_list[2] = "Tue"; 1031553Srgrimes day_list[3] = "Wed"; 1041553Srgrimes day_list[4] = "Thu"; 1051553Srgrimes day_list[5] = "Fri"; 1061553Srgrimes day_list[6] = "Sat"; 1071553Srgrimes#endif 1081553Srgrimes} 1091553Srgrimes 1101553Srgrimesvoid 1111553Srgrimesprintprompt(promptno, str) 1121553Srgrimes int promptno; 1131553Srgrimes char *str; 1141553Srgrimes{ 1151553Srgrimes static Char *ocp = NULL; 1161553Srgrimes static char *ostr = NULL; 1171553Srgrimes time_t lclock = time(NULL); 1181553Srgrimes Char *cp; 1191553Srgrimes 1201553Srgrimes switch (promptno) { 1211553Srgrimes default: 1221553Srgrimes case 0: 1231553Srgrimes cp = varval(STRprompt); 1241553Srgrimes break; 1251553Srgrimes case 1: 1261553Srgrimes cp = varval(STRprompt2); 1271553Srgrimes break; 1281553Srgrimes case 2: 129239991Sed cp = varval(STRprompt3); 1301553Srgrimes break; 1311553Srgrimes case 3: 1321553Srgrimes if (ocp != NULL) { 1331553Srgrimes cp = ocp; 1341553Srgrimes str = ostr; 1351553Srgrimes } 1361553Srgrimes else 137239991Sed cp = varval(STRprompt); 1381553Srgrimes break; 1391553Srgrimes } 1401553Srgrimes 1411553Srgrimes if (promptno < 2) { 1421553Srgrimes ocp = cp; 1431553Srgrimes ostr = str; 14430761Scharnier } 1454840Sbde 1461553Srgrimes PromptBuf[0] = '\0'; 1471553Srgrimes tprintf(FMT_PROMPT, PromptBuf, cp, 2 * INBUFSIZE - 2, str, lclock, NULL); 1481553Srgrimes 1491553Srgrimes if (!editing) { 1501553Srgrimes for (cp = PromptBuf; *cp ; ) 1511553Srgrimes (void) putraw(*cp++); 1521553Srgrimes SetAttributes(0); 1531553Srgrimes flush(); 1541553Srgrimes } 1551553Srgrimes 1561553Srgrimes RPromptBuf[0] = '\0'; 1571553Srgrimes if (promptno == 0) { /* determine rprompt if using main prompt */ 1581553Srgrimes cp = varval(STRrprompt); 1591553Srgrimes tprintf(FMT_PROMPT, RPromptBuf, cp, INBUFSIZE - 2, NULL, lclock, NULL); 1601553Srgrimes 1611553Srgrimes /* if not editing, put rprompt after prompt */ 1621553Srgrimes if (!editing && RPromptBuf[0] != '\0') { 1631553Srgrimes for (cp = RPromptBuf; *cp ; ) 1641553Srgrimes (void) putraw(*cp++); 1651553Srgrimes SetAttributes(0); 1661553Srgrimes putraw(' '); 1671553Srgrimes flush(); 1681553Srgrimes } 1691553Srgrimes } 1701553Srgrimes} 1711553Srgrimes 1721553Srgrimesvoid 1731553Srgrimestprintf(what, buf, fmt, siz, str, tim, info) 174239991Sed int what; 1751553Srgrimes Char *buf; 1761553Srgrimes const Char *fmt; 1771553Srgrimes size_t siz; 1781553Srgrimes char *str; 1791553Srgrimes time_t tim; 1801553Srgrimes ptr_t info; 1811553Srgrimes{ 1821553Srgrimes Char *z, *q; 1831553Srgrimes Char attributes = 0; 1848857Srgrimes static int print_prompt_did_ding = 0; 1851553Srgrimes Char buff[BUFSIZE]; 1861553Srgrimes /* Need to be unsigned to avoid sign extension */ 1871553Srgrimes const unsigned char *cz; 1881553Srgrimes unsigned char cbuff[BUFSIZE]; 1891553Srgrimes 1901553Srgrimes Char *p = buf; 1911553Srgrimes Char *ep = &p[siz]; 1921553Srgrimes const Char *cp = fmt; 1931553Srgrimes Char Scp; 1941553Srgrimes struct tm *t = localtime(&tim); 1951553Srgrimes 1961553Srgrimes /* prompt stuff */ 1971553Srgrimes static Char *olddir = NULL, *olduser = NULL; 1981553Srgrimes extern int tlength; /* cache cleared */ 1991553Srgrimes int updirs; 2001553Srgrimes size_t pdirs, sz; 2011553Srgrimes 2021553Srgrimes for (; *cp; cp++) { 2031553Srgrimes if (p >= ep) 2041553Srgrimes break; 2051553Srgrimes#ifdef DSPMBYTE 2061553Srgrimes if (Ismbyte1(*cp) && ! (cp[1] == '\0')) 2071553Srgrimes { 2081553Srgrimes *p++ = attributes | *cp++; /* normal character */ 2091553Srgrimes *p++ = attributes | *cp; /* normal character */ 2101553Srgrimes } 2111553Srgrimes else 2121553Srgrimes#endif /* DSPMBYTE */ 2131553Srgrimes if ((*cp == '%') && ! (cp[1] == '\0')) { 2141553Srgrimes cp++; 2151553Srgrimes switch (*cp) { 2161553Srgrimes case 'R': 2171553Srgrimes if (what == FMT_HISTORY) 2181553Srgrimes fmthist('R', info, (char *) (cz = cbuff), sizeof(cbuff)); 2191553Srgrimes else 2201553Srgrimes cz = (unsigned char *) str; 2211553Srgrimes if (cz != NULL) 2221553Srgrimes for (; *cz; *p++ = attributes | *cz++) 2231553Srgrimes if (p >= ep) break; 2241553Srgrimes break; 2251553Srgrimes case '#': 2261553Srgrimes *p++ = attributes | ((uid == 0) ? PRCHROOT : PRCH); 2271553Srgrimes break; 2281553Srgrimes case '!': 2291553Srgrimes case 'h': 2301553Srgrimes switch (what) { 2311553Srgrimes case FMT_HISTORY: 2321553Srgrimes fmthist('h', info, (char *) cbuff, sizeof(cbuff)); 2331553Srgrimes break; 2341553Srgrimes case FMT_SCHED: 2351553Srgrimes (void) xsnprintf((char *) cbuff, sizeof(cbuff), "%d", 2361553Srgrimes *(int *)info); 2371553Srgrimes break; 2381553Srgrimes default: 2391553Srgrimes (void) xsnprintf((char *) cbuff, sizeof(cbuff), "%d", 2401553Srgrimes eventno + 1); 2411553Srgrimes break; 2421553Srgrimes } 2431553Srgrimes for (cz = cbuff; *cz; *p++ = attributes | *cz++) 2441553Srgrimes if (p >= ep) break; 2451553Srgrimes break; 2461553Srgrimes case 'T': /* 24 hour format */ 2471553Srgrimes case '@': 2481553Srgrimes case 't': /* 12 hour am/pm format */ 2491553Srgrimes case 'p': /* With seconds */ 2501553Srgrimes case 'P': 2511553Srgrimes { 2521553Srgrimes char ampm = 'a'; 2531553Srgrimes int hr = t->tm_hour; 2541553Srgrimes 2551553Srgrimes if (p >= ep - 10) break; 2561553Srgrimes 2571553Srgrimes /* addition by Hans J. Albertsson */ 2581553Srgrimes /* and another adapted from Justin Bur */ 2591553Srgrimes if (adrof(STRampm) || (*cp != 'T' && *cp != 'P')) { 2601553Srgrimes if (hr >= 12) { 2611553Srgrimes if (hr > 12) 2621553Srgrimes hr -= 12; 2631553Srgrimes ampm = 'p'; 2641553Srgrimes } 2651553Srgrimes else if (hr == 0) 2661553Srgrimes hr = 12; 26730642Scharnier } /* else do a 24 hour clock */ 2681553Srgrimes 2691553Srgrimes /* "DING!" stuff by Hans also */ 2701553Srgrimes if (t->tm_min || print_prompt_did_ding || 2711553Srgrimes what != FMT_PROMPT || adrof(STRnoding)) { 2721553Srgrimes if (t->tm_min) 2731553Srgrimes print_prompt_did_ding = 0; 2741553Srgrimes p = Itoa(hr, p, 0, attributes); 2751553Srgrimes *p++ = attributes | ':'; 2761553Srgrimes p = Itoa(t->tm_min, p, 2, attributes); 2771553Srgrimes if (*cp == 'p' || *cp == 'P') { 2781553Srgrimes *p++ = attributes | ':'; 2791553Srgrimes p = Itoa(t->tm_sec, p, 2, attributes); 2801553Srgrimes } 2811553Srgrimes if (adrof(STRampm) || (*cp != 'T' && *cp != 'P')) { 2821553Srgrimes *p++ = attributes | ampm; 2831553Srgrimes *p++ = attributes | 'm'; 2841553Srgrimes } 2851553Srgrimes } 2861553Srgrimes else { /* we need to ding */ 2871553Srgrimes int i = 0; 2881553Srgrimes 2891553Srgrimes (void) Strcpy(buff, STRDING); 2901553Srgrimes while (buff[i]) { 2911553Srgrimes *p++ = attributes | buff[i++]; 2921553Srgrimes } 293246209Scharnier print_prompt_did_ding = 1; 2941553Srgrimes } 2951553Srgrimes } 2961553Srgrimes break; 2971553Srgrimes 2981553Srgrimes case 'M': 2991553Srgrimes#ifndef HAVENOUTMP 3001553Srgrimes if (what == FMT_WHO) 3011553Srgrimes cz = (unsigned char *) who_info(info, 'M', 3021553Srgrimes (char *) cbuff, sizeof(cbuff)); 3031553Srgrimes else 3041553Srgrimes#endif /* HAVENOUTMP */ 3051553Srgrimes cz = (unsigned char *) getenv("HOST"); 3061553Srgrimes /* 3071553Srgrimes * Bug pointed out by Laurent Dami <dami@cui.unige.ch>: don't 3081553Srgrimes * derefrence that NULL (if HOST is not set)... 309246209Scharnier */ 3101553Srgrimes if (cz != NULL) 3111553Srgrimes for (; *cz ; *p++ = attributes | *cz++) 3121553Srgrimes if (p >= ep) break; 3131553Srgrimes break; 3141553Srgrimes 3151553Srgrimes case 'm': 3161553Srgrimes#ifndef HAVENOUTMP 3171553Srgrimes if (what == FMT_WHO) 3181553Srgrimes cz = (unsigned char *) who_info(info, 'm', (char *) cbuff, 3191553Srgrimes sizeof(cbuff)); 3201553Srgrimes else 3211553Srgrimes#endif /* HAVENOUTMP */ 3221553Srgrimes cz = (unsigned char *) getenv("HOST"); 3231553Srgrimes 324246209Scharnier if (cz != NULL) 3251553Srgrimes for ( ; *cz && (what == FMT_WHO || *cz != '.') 3261553Srgrimes ; *p++ = attributes | *cz++ ) 3271553Srgrimes if (p >= ep) break; 3281553Srgrimes break; 3291553Srgrimes 3301553Srgrimes /* lukem: new directory prompt code */ 3311553Srgrimes case '~': 3321553Srgrimes case '/': 3331553Srgrimes case '.': 3341553Srgrimes case 'c': 3351553Srgrimes case 'C': 3361553Srgrimes Scp = *cp; 337 if (Scp == 'c') /* store format type (c == .) */ 338 Scp = '.'; 339 if ((z = varval(STRcwd)) == STRNULL) 340 break; /* no cwd, so don't do anything */ 341 342 /* show ~ whenever possible - a la dirs */ 343 if (Scp == '~' || Scp == '.' ) { 344 if (tlength == 0 || olddir != z) { 345 olddir = z; /* have we changed dir? */ 346 olduser = getusername(&olddir); 347 } 348 if (olduser) 349 z = olddir; 350 } 351 updirs = pdirs = 0; 352 353 /* option to determine fixed # of dirs from path */ 354 if (Scp == '.' || Scp == 'C') { 355 int skip; 356#ifdef WINNT_NATIVE 357 if (z[1] == ':') { 358 *p++ = attributes | *z++; 359 *p++ = attributes | *z++; 360 } 361 if (*z == '/' && z[1] == '/') { 362 *p++ = attributes | *z++; 363 *p++ = attributes | *z++; 364 do { 365 *p++ = attributes | *z++; 366 }while(*z != '/'); 367 } 368#endif /* WINNT_NATIVE */ 369 q = z; 370 while (*z) /* calc # of /'s */ 371 if (*z++ == '/') 372 updirs++; 373 if ((Scp == 'C' && *q != '/')) 374 updirs++; 375 376 if (cp[1] == '0') { /* print <x> or ... */ 377 pdirs = 1; 378 cp++; 379 } 380 if (cp[1] >= '1' && cp[1] <= '9') { /* calc # to skip */ 381 skip = cp[1] - '0'; 382 cp++; 383 } 384 else 385 skip = 1; 386 387 updirs -= skip; 388 while (skip-- > 0) { 389 while ((z > q) && (*z != '/')) 390 z--; /* back up */ 391 if (skip && z > q) 392 z--; 393 } 394 if (*z == '/' && z != q) 395 z++; 396 } /* . || C */ 397 398 /* print ~[user] */ 399 if ((olduser) && ((Scp == '~') || 400 (Scp == '.' && (pdirs || (!pdirs && updirs <= 0))) )) { 401 *p++ = attributes | '~'; 402 if (p >= ep) break; 403 for (q = olduser; *q; *p++ = attributes | *q++) 404 if (p >= ep) break; 405 } 406 407 /* RWM - tell you how many dirs we've ignored */ 408 /* and add '/' at front of this */ 409 if (updirs > 0 && pdirs) { 410 if (p >= ep - 5) break; 411 if (adrof(STRellipsis)) { 412 *p++ = attributes | '.'; 413 *p++ = attributes | '.'; 414 *p++ = attributes | '.'; 415 } else { 416 *p++ = attributes | '/'; 417 *p++ = attributes | '<'; 418 if (updirs > 9) { 419 *p++ = attributes | '9'; 420 *p++ = attributes | '+'; 421 } else 422 *p++ = attributes | ('0' + updirs); 423 *p++ = attributes | '>'; 424 } 425 } 426 427 for (; *z ; *p++ = attributes | *z++) 428 if (p >= ep) break; 429 break; 430 /* lukem: end of new directory prompt code */ 431 432 case 'n': 433#ifndef HAVENOUTMP 434 if (what == FMT_WHO) { 435 cz = (unsigned char *) who_info(info, 'n', 436 (char *) cbuff, sizeof(cbuff)); 437 for (; cz && *cz ; *p++ = attributes | *cz++) 438 if (p >= ep) break; 439 } 440 else 441#endif /* HAVENOUTMP */ 442 { 443 if ((z = varval(STRuser)) != STRNULL) 444 for (; *z; *p++ = attributes | *z++) 445 if (p >= ep) break; 446 } 447 break; 448 case 'l': 449#ifndef HAVENOUTMP 450 if (what == FMT_WHO) { 451 cz = (unsigned char *) who_info(info, 'l', 452 (char *) cbuff, sizeof(cbuff)); 453 for (; cz && *cz ; *p++ = attributes | *cz++) 454 if (p >= ep) break; 455 } 456 else 457#endif /* HAVENOUTMP */ 458 { 459 if ((z = varval(STRtty)) != STRNULL) 460 for (; *z; *p++ = attributes | *z++) 461 if (p >= ep) break; 462 } 463 break; 464 case 'd': 465 for (cz = (unsigned char *) day_list[t->tm_wday]; *cz; 466 *p++ = attributes | *cz++) 467 if (p >= ep) break; 468 break; 469 case 'D': 470 if (p >= ep - 3) break; 471 p = Itoa(t->tm_mday, p, 2, attributes); 472 break; 473 case 'w': 474 if (p >= ep - 5) break; 475 for (cz = (unsigned char *) month_list[t->tm_mon]; *cz; 476 *p++ = attributes | *cz++) 477 if (p >= ep) break; 478 break; 479 case 'W': 480 if (p >= ep - 3) break; 481 p = Itoa(t->tm_mon + 1, p, 2, attributes); 482 break; 483 case 'y': 484 if (p >= ep - 3) break; 485 p = Itoa(t->tm_year % 100, p, 2, attributes); 486 break; 487 case 'Y': 488 if (p >= ep - 5) break; 489 p = Itoa(t->tm_year + 1900, p, 4, attributes); 490 break; 491 case 'S': /* start standout */ 492 attributes |= STANDOUT; 493 break; 494 case 'B': /* start bold */ 495 attributes |= BOLD; 496 break; 497 case 'U': /* start underline */ 498 attributes |= UNDER; 499 break; 500 case 's': /* end standout */ 501 attributes &= ~STANDOUT; 502 break; 503 case 'b': /* end bold */ 504 attributes &= ~BOLD; 505 break; 506 case 'u': /* end underline */ 507 attributes &= ~UNDER; 508 break; 509 case 'L': 510 ClearToBottom(); 511 break; 512 513 case 'j': 514 { 515 Char buf[128], *ebuf, *q; 516 int njobs = -1; 517 struct process *pp; 518 for (pp = proclist.p_next; pp; pp = pp->p_next) 519 njobs++; 520 /* make sure we have space */ 521 ebuf = Itoa(njobs, buf, 1, attributes); 522 for (q = buf; q < ebuf; *p++ = *q++) 523 if (p >= ep) break; 524 break; 525 } 526 case '?': 527 if ((z = varval(STRstatus)) != STRNULL) 528 for (; *z; *p++ = attributes | *z++) 529 if (p >= ep) break; 530 break; 531 case '$': 532 sz = ep - p; 533 (void) expdollar(&p, &cp, &sz, attributes); 534 /* cp should point the last char of currnet % sequence */ 535 cp--; 536 break; 537 case '%': 538 *p++ = attributes | '%'; 539 break; 540 case '{': /* literal characters start */ 541#if LITERAL == 0 542 /* 543 * No literal capability, so skip all chars in the literal 544 * string 545 */ 546 while (*cp != '\0' && (*cp != '%' || cp[1] != '}')) 547 cp++; 548#endif /* LITERAL == 0 */ 549 attributes |= LITERAL; 550 break; 551 case '}': /* literal characters end */ 552 attributes &= ~LITERAL; 553 break; 554 default: 555#ifndef HAVENOUTMP 556 if (*cp == 'a' && what == FMT_WHO) { 557 cz = (unsigned char *) who_info(info, 'a', (char *) cbuff, 558 sizeof(cbuff)); 559 for (; cz && *cz; *p++ = attributes | *cz++) 560 if (p >= ep) break; 561 } 562 else 563#endif /* HAVENOUTMP */ 564 { 565 if (p >= ep - 3) break; 566 *p++ = attributes | '%'; 567 *p++ = attributes | *cp; 568 } 569 break; 570 } 571 } 572 else if (*cp == '\\' || *cp == '^') 573 *p++ = attributes | parseescape(&cp); 574 else if (*cp == HIST) { /* EGS: handle '!'s in prompts */ 575 if (what == FMT_HISTORY) 576 fmthist('h', info, (char *) cbuff, sizeof(cbuff)); 577 else 578 (void) xsnprintf((char *) cbuff, sizeof(cbuff), "%d", eventno + 1); 579 for (cz = cbuff; *cz; *p++ = attributes | *cz++) 580 if (p >= ep) break; 581 } 582 else 583 *p++ = attributes | *cp; /* normal character */ 584 } 585 *p = '\0'; 586} 587 588Char * 589expdollar(dstp, srcp, spp, attr) 590 Char **dstp; 591 const Char **srcp; 592 size_t *spp; 593 int attr; 594{ 595 struct varent *vp; 596 Char var[MAXVARLEN]; 597 const Char *src = *srcp; 598 Char *val; 599 Char *dst = *dstp; 600 int i, curly = 0; 601 602 /* found a variable, expand it */ 603 for (i = 0; i < MAXVARLEN; i++) { 604 var[i] = *++src & TRIM; 605 if (i == 0 && var[i] == '{') { 606 curly = 1; 607 var[i] = *++src & TRIM; 608 } 609 if (!alnum(var[i])) { 610 611 var[i] = '\0'; 612 break; 613 } 614 } 615 if (curly && (*src & TRIM) == '}') 616 src++; 617 618 vp = adrof(var); 619 val = (!vp) ? tgetenv(var) : NULL; 620 if (vp && vp->vec) { 621 for (i = 0; vp->vec[i] != NULL; i++) { 622 for (val = vp->vec[i]; *spp > 0 && *val; (*spp)--) 623 *dst++ = *val++ | attr; 624 if (vp->vec[i+1] && *spp > 0) { 625 *dst++ = ' ' | attr; 626 (*spp)--; 627 } 628 } 629 } 630 else if (val) { 631 for (; *spp > 0 && *val; (*spp)--) 632 *dst++ = *val++ | attr; 633 } 634 else { 635 **dstp = '\0'; 636 *srcp = src; 637 return NULL; 638 } 639 *dst = '\0'; 640 641 val = *dstp; 642 *srcp = src; 643 *dstp = dst; 644 645 return val; 646} 647