1/* 2 * hist.c - history expansion 3 * 4 * This file is part of zsh, the Z shell. 5 * 6 * Copyright (c) 1992-1997 Paul Falstad 7 * All rights reserved. 8 * 9 * Permission is hereby granted, without written agreement and without 10 * license or royalty fees, to use, copy, modify, and distribute this 11 * software and to distribute modified versions of this software for any 12 * purpose, provided that the above copyright notice and the following 13 * two paragraphs appear in all copies of this software. 14 * 15 * In no event shall Paul Falstad or the Zsh Development Group be liable 16 * to any party for direct, indirect, special, incidental, or consequential 17 * damages arising out of the use of this software and its documentation, 18 * even if Paul Falstad and the Zsh Development Group have been advised of 19 * the possibility of such damage. 20 * 21 * Paul Falstad and the Zsh Development Group specifically disclaim any 22 * warranties, including, but not limited to, the implied warranties of 23 * merchantability and fitness for a particular purpose. The software 24 * provided hereunder is on an "as is" basis, and Paul Falstad and the 25 * Zsh Development Group have no obligation to provide maintenance, 26 * support, updates, enhancements, or modifications. 27 * 28 */ 29 30#include "zsh.mdh" 31#include "hist.pro" 32 33/* Functions to call for getting/ungetting a character and for history 34 * word control. */ 35 36/**/ 37mod_export int (*hgetc) _((void)); 38 39/**/ 40void (*hungetc) _((int)); 41 42/**/ 43void (*hwaddc) _((int)); 44 45/**/ 46void (*hwbegin) _((int)); 47 48/**/ 49void (*hwend) _((void)); 50 51/**/ 52void (*addtoline) _((int)); 53 54/* != 0 means history substitution is turned off */ 55 56/**/ 57mod_export int stophist; 58 59/* if != 0, we are expanding the current line */ 60 61/**/ 62mod_export int expanding; 63 64/* these are used to modify the cursor position during expansion */ 65 66/**/ 67mod_export int excs, exlast; 68 69/* 70 * Current history event number 71 * 72 * Note on curhist: with history inactive, this points to the 73 * last line actually added to the history list. With history active, 74 * the line does not get added to the list until hend(), if at all. 75 * However, curhist is incremented to reflect the current line anyway 76 * and a temporary history entry is inserted while the user is editing. 77 * If the resulting line was not added to the list, a flag is set so 78 * that curhist will be decremented in hbegin(). 79 */ 80 81/**/ 82mod_export zlong curhist; 83 84/**/ 85struct histent curline; 86 87/* current line count of allocated history entries */ 88 89/**/ 90zlong histlinect; 91 92/* The history lines are kept in a hash, and also doubly-linked in a ring */ 93 94/**/ 95HashTable histtab; 96/**/ 97mod_export Histent hist_ring; 98 99/* capacity of history lists */ 100 101/**/ 102zlong histsiz; 103 104/* desired history-file size (in lines) */ 105 106/**/ 107zlong savehistsiz; 108 109/* if = 1, we have performed history substitution on the current line * 110 * if = 2, we have used the 'p' modifier */ 111 112/**/ 113int histdone; 114 115/* state of the history mechanism */ 116 117/**/ 118int histactive; 119 120/* Current setting of the associated option, but sometimes also includes 121 * the setting of the HIST_SAVE_NO_DUPS option. */ 122 123/**/ 124int hist_ignore_all_dups; 125 126/* What flags (if any) we should skip when moving through the history */ 127 128/**/ 129mod_export int hist_skip_flags; 130 131/* Bits of histactive variable */ 132#define HA_ACTIVE (1<<0) /* History mechanism is active */ 133#define HA_NOINC (1<<1) /* Don't store, curhist not incremented */ 134 135/* Array of word beginnings and endings in current history line. */ 136 137/**/ 138short *chwords; 139 140/* Max, actual position in chwords. 141 * nwords = chwordpos/2 because we record beginning and end of words. 142 */ 143 144/**/ 145int chwordlen, chwordpos; 146 147/* the last l for s/l/r/ history substitution */ 148 149/**/ 150char *hsubl; 151 152/* the last r for s/l/r/ history substitution */ 153 154/**/ 155char *hsubr; 156 157/* pointer into the history line */ 158 159/**/ 160mod_export char *hptr; 161 162/* the current history line */ 163 164/**/ 165mod_export char *chline; 166 167/* 168 * The current history line as seen by ZLE. 169 * We modify chline for use in other contexts while ZLE may 170 * still be running; ZLE should see only the top-level value. 171 * 172 * To avoid having to modify this every time we modify chline, 173 * we set it when we push the stack, and unset it when we pop 174 * the appropriate value off the stack. As it's never modified 175 * on the stack this is the only maintainance we ever do on it. 176 * In return, ZLE has to check both zle_chline and (if that's 177 * NULL) chline to get the current value. 178 */ 179 180/**/ 181mod_export char *zle_chline; 182 183/* true if the last character returned by hgetc was an escaped bangchar * 184 * if it is set and NOBANGHIST is unset hwaddc escapes bangchars */ 185 186/**/ 187int qbang; 188 189/* max size of histline */ 190 191/**/ 192int hlinesz; 193 194/* default event (usually curhist-1, that is, "!!") */ 195 196static zlong defev; 197 198/* Remember the last line in the history file so we can find it again. */ 199static struct histfile_stats { 200 char *text; 201 time_t stim, mtim; 202 off_t fpos, fsiz; 203 zlong next_write_ev; 204} lasthist; 205 206static struct histsave { 207 struct histfile_stats lasthist; 208 char *histfile; 209 HashTable histtab; 210 Histent hist_ring; 211 zlong curhist; 212 zlong histlinect; 213 zlong histsiz; 214 zlong savehistsiz; 215 int locallevel; 216} *histsave_stack; 217static int histsave_stack_size = 0; 218static int histsave_stack_pos = 0; 219 220static zlong histfile_linect; 221 222/* add a character to the current history word */ 223 224static void 225ihwaddc(int c) 226{ 227 /* Only if history line exists and lexing has not finished. */ 228 if (chline && !(errflag || lexstop)) { 229 /* Quote un-expanded bangs in the history line. */ 230 if (c == bangchar && stophist < 2 && qbang) 231 /* If qbang is not set, we do not escape this bangchar as it's * 232 * not necessary (e.g. it's a bang in !=, or it is followed * 233 * by a space). Roughly speaking, qbang is zero only if the * 234 * history interpreter has already digested this bang and * 235 * found that it is not necessary to escape it. */ 236 hwaddc('\\'); 237 *hptr++ = c; 238 239 /* Resize history line if necessary */ 240 if (hptr - chline >= hlinesz) { 241 int oldsiz = hlinesz; 242 243 chline = realloc(chline, hlinesz = oldsiz + 64); 244 hptr = chline + oldsiz; 245 } 246 } 247} 248 249/* This function adds a character to the zle input line. It is used when * 250 * zsh expands history (see doexpandhist() in zle_tricky.c). It also * 251 * calculates the new cursor position after the expansion. It is called * 252 * from hgetc() and from gettok() in lex.c for characters in comments. */ 253 254/**/ 255void 256iaddtoline(int c) 257{ 258 if (!expanding || lexstop) 259 return; 260 if (qbang && c == bangchar && stophist < 2) { 261 exlast--; 262 zleentry(ZLE_CMD_ADD_TO_LINE, '\\'); 263 } 264 if (excs > zlemetacs) { 265 excs += 1 + inbufct - exlast; 266 if (excs < zlemetacs) 267 /* this case could be handled better but it is * 268 * so rare that it does not worth it */ 269 excs = zlemetacs; 270 } 271 exlast = inbufct; 272 zleentry(ZLE_CMD_ADD_TO_LINE, itok(c) ? ztokens[c - Pound] : c); 273} 274 275 276static int 277ihgetc(void) 278{ 279 int c = ingetc(); 280 281 qbang = 0; 282 if (!stophist && !(inbufflags & INP_ALIAS)) { 283 /* If necessary, expand history characters. */ 284 c = histsubchar(c); 285 if (c < 0) { 286 /* bad expansion */ 287 errflag = lexstop = 1; 288 return ' '; 289 } 290 } 291 if ((inbufflags & INP_HIST) && !stophist) { 292 /* the current character c came from a history expansion * 293 * (inbufflags & INP_HIST) and history is not disabled * 294 * (e.g. we are not inside single quotes). In that case, \! * 295 * should be treated as ! (since this \! came from a previous * 296 * history line where \ was used to escape the bang). So if * 297 * c == '\\' we fetch one more character to see if it's a bang, * 298 * and if it is not, we unget it and reset c back to '\\' */ 299 qbang = 0; 300 if (c == '\\' && !(qbang = (c = ingetc()) == bangchar)) 301 safeinungetc(c), c = '\\'; 302 } else if (stophist || (inbufflags & INP_ALIAS)) 303 /* If the result is a bangchar which came from history or alias * 304 * expansion, we treat it as an escaped bangchar, unless history * 305 * is disabled. If stophist == 1 it only means that history is * 306 * temporarily disabled by a !" which won't appear in the * 307 * history, so we still have an escaped bang. stophist > 1 if * 308 * history is disabled with NOBANGHIST or by someone else (e.g. * 309 * when the lexer scans single quoted text). */ 310 qbang = c == bangchar && (stophist < 2); 311 hwaddc(c); 312 addtoline(c); 313 314 return c; 315} 316 317/**/ 318static void 319safeinungetc(int c) 320{ 321 if (lexstop) 322 lexstop = 0; 323 else 324 inungetc(c); 325} 326 327/**/ 328void 329herrflush(void) 330{ 331 inpopalias(); 332 333 while (!lexstop && inbufct && !strin) 334 hwaddc(ingetc()); 335} 336 337/* 338 * Extract :s/foo/bar/ delimiters and arguments 339 * 340 * The first character expected is the first delimiter. 341 * The arguments are stored in the hsubl and hsubr variables. 342 * 343 * subline is the part of the command line to be matched. 344 * 345 * If a ':' was found but was not followed by a 'G', 346 * *cflagp is set to 1 and the input is backed up to the 347 * character following the colon. 348 */ 349 350/**/ 351static int 352getsubsargs(char *subline, int *gbalp, int *cflagp) 353{ 354 int del, follow; 355 char *ptr1, *ptr2; 356 357 del = ingetc(); 358 ptr1 = hdynread2(del); 359 if (!ptr1) 360 return 1; 361 ptr2 = hdynread2(del); 362 if (strlen(ptr1)) { 363 zsfree(hsubl); 364 hsubl = ptr1; 365 } else if (!hsubl) { /* fail silently on this */ 366 zsfree(ptr2); 367 return 0; 368 } 369 zsfree(hsubr); 370 hsubr = ptr2; 371 follow = ingetc(); 372 if (follow == ':') { 373 follow = ingetc(); 374 if (follow == 'G') 375 *gbalp = 1; 376 else { 377 inungetc(follow); 378 *cflagp = 1; 379 } 380 } else 381 inungetc(follow); 382 return 0; 383} 384 385/* Get the maximum no. of words for a history entry. */ 386 387/**/ 388static int 389getargc(Histent ehist) 390{ 391 return ehist->nwords ? ehist->nwords-1 : 0; 392} 393 394/**/ 395static int 396substfailed(void) 397{ 398 herrflush(); 399 zerr("substitution failed"); 400 return -1; 401} 402 403/* Perform history substitution, returning the next character afterwards. */ 404 405/**/ 406static int 407histsubchar(int c) 408{ 409 int farg, evset = -1, larg, argc, cflag = 0, bflag = 0; 410 zlong ev; 411 static int marg = -1; 412 static zlong mev = -1; 413 char *buf, *ptr; 414 char *sline; 415 Histent ehist; 416 size_t buflen; 417 418 /* look, no goto's */ 419 if (isfirstch && c == hatchar) { 420 int gbal = 0; 421 422 /* Line begins ^foo^bar */ 423 isfirstch = 0; 424 inungetc(hatchar); 425 if (!(ehist = gethist(defev)) 426 || !(sline = getargs(ehist, 0, getargc(ehist)))) 427 return -1; 428 429 if (getsubsargs(sline, &gbal, &cflag)) 430 return substfailed(); 431 if (!hsubl) 432 return -1; 433 if (subst(&sline, hsubl, hsubr, gbal)) 434 return substfailed(); 435 } else { 436 /* Line doesn't begin ^foo^bar */ 437 if (c != ' ') 438 isfirstch = 0; 439 if (c == '\\') { 440 int g = ingetc(); 441 442 if (g != bangchar) 443 safeinungetc(g); 444 else { 445 qbang = 1; 446 return bangchar; 447 } 448 } 449 if (c != bangchar) 450 return c; 451 *hptr = '\0'; 452 if ((c = ingetc()) == '{') { 453 bflag = cflag = 1; 454 c = ingetc(); 455 } 456 if (c == '\"') { 457 stophist = 1; 458 return ingetc(); 459 } 460 if ((!cflag && inblank(c)) || c == '=' || c == '(' || lexstop) { 461 safeinungetc(c); 462 return bangchar; 463 } 464 cflag = 0; 465 ptr = buf = zhalloc(buflen = 265); 466 467 /* get event number */ 468 469 queue_signals(); 470 if (c == '?') { 471 for (;;) { 472 c = ingetc(); 473 if (c == '?' || c == '\n' || lexstop) 474 break; 475 else { 476 *ptr++ = c; 477 if (ptr == buf + buflen) { 478 buf = hrealloc(buf, buflen, 2 * buflen); 479 ptr = buf + buflen; 480 buflen *= 2; 481 } 482 } 483 } 484 if (c != '\n' && !lexstop) 485 c = ingetc(); 486 *ptr = '\0'; 487 mev = ev = hconsearch(hsubl = ztrdup(buf), &marg); 488 evset = 0; 489 if (ev == -1) { 490 herrflush(); 491 unqueue_signals(); 492 zerr("no such event: %s", buf); 493 return -1; 494 } 495 } else { 496 zlong t0; 497 498 for (;;) { 499 if (inblank(c) || c == ';' || c == ':' || c == '^' || 500 c == '$' || c == '*' || c == '%' || c == '}' || 501 c == '\'' || c == '"' || c == '`' || lexstop) 502 break; 503 if (ptr != buf) { 504 if (c == '-') 505 break; 506 if ((idigit(buf[0]) || buf[0] == '-') && !idigit(c)) 507 break; 508 } 509 *ptr++ = c; 510 if (ptr == buf + buflen) { 511 buf = hrealloc(buf, buflen, 2 * buflen); 512 ptr = buf + buflen; 513 buflen *= 2; 514 } 515 if (c == '#' || c == bangchar) { 516 c = ingetc(); 517 break; 518 } 519 c = ingetc(); 520 } 521 *ptr = 0; 522 if (!*buf) { 523 if (c != '%') { 524 if (isset(CSHJUNKIEHISTORY)) 525 ev = addhistnum(curhist,-1,HIST_FOREIGN); 526 else 527 ev = defev; 528 if (c == ':' && evset == -1) 529 evset = 0; 530 else 531 evset = 1; 532 } else { 533 if (marg != -1) 534 ev = mev; 535 else 536 ev = defev; 537 evset = 0; 538 } 539 } else if ((t0 = zstrtol(buf, NULL, 10))) { 540 ev = (t0 < 0) ? addhistnum(curhist,t0,HIST_FOREIGN) : t0; 541 evset = 1; 542 } else if ((unsigned)*buf == bangchar) { 543 ev = addhistnum(curhist,-1,HIST_FOREIGN); 544 evset = 1; 545 } else if (*buf == '#') { 546 ev = curhist; 547 evset = 1; 548 } else if ((ev = hcomsearch(buf)) == -1) { 549 herrflush(); 550 unqueue_signals(); 551 zerr("event not found: %s", buf); 552 return -1; 553 } else 554 evset = 1; 555 } 556 557 /* get the event */ 558 559 if (!(ehist = gethist(defev = ev))) { 560 unqueue_signals(); 561 return -1; 562 } 563 /* extract the relevant arguments */ 564 565 argc = getargc(ehist); 566 if (c == ':') { 567 cflag = 1; 568 c = ingetc(); 569 if (c == '%' && marg != -1) { 570 if (!evset) { 571 ehist = gethist(defev = mev); 572 argc = getargc(ehist); 573 } else { 574 herrflush(); 575 unqueue_signals(); 576 zerr("ambiguous history reference"); 577 return -1; 578 } 579 580 } 581 } 582 if (c == '*') { 583 farg = 1; 584 larg = argc; 585 cflag = 0; 586 } else { 587 inungetc(c); 588 larg = farg = getargspec(argc, marg, evset); 589 if (larg == -2) { 590 unqueue_signals(); 591 return -1; 592 } 593 if (farg != -1) 594 cflag = 0; 595 c = ingetc(); 596 if (c == '*') { 597 cflag = 0; 598 larg = argc; 599 } else if (c == '-') { 600 cflag = 0; 601 larg = getargspec(argc, marg, evset); 602 if (larg == -2) { 603 unqueue_signals(); 604 return -1; 605 } 606 if (larg == -1) 607 larg = argc - 1; 608 } else 609 inungetc(c); 610 } 611 if (farg == -1) 612 farg = 0; 613 if (larg == -1) 614 larg = argc; 615 if (!(sline = getargs(ehist, farg, larg))) { 616 unqueue_signals(); 617 return -1; 618 } 619 unqueue_signals(); 620 } 621 622 /* do the modifiers */ 623 624 for (;;) { 625 c = (cflag) ? ':' : ingetc(); 626 cflag = 0; 627 if (c == ':') { 628 int gbal = 0; 629 630 if ((c = ingetc()) == 'g') { 631 gbal = 1; 632 c = ingetc(); 633 if (c != 's' && c != '&') { 634 zerr("'s' or '&' modifier expected after 'g'"); 635 return -1; 636 } 637 } 638 switch (c) { 639 case 'p': 640 histdone = HISTFLAG_DONE | HISTFLAG_NOEXEC; 641 break; 642 case 'a': 643 if (!chabspath(&sline)) { 644 herrflush(); 645 zerr("modifier failed: a"); 646 return -1; 647 } 648 break; 649 650 case 'A': 651 if (!chrealpath(&sline)) { 652 herrflush(); 653 zerr("modifier failed: A"); 654 return -1; 655 } 656 break; 657 case 'c': 658 if (!(sline = equalsubstr(sline, 0, 0))) { 659 herrflush(); 660 zerr("modifier failed: c"); 661 return -1; 662 } 663 break; 664 case 'h': 665 if (!remtpath(&sline)) { 666 herrflush(); 667 zerr("modifier failed: h"); 668 return -1; 669 } 670 break; 671 case 'e': 672 if (!rembutext(&sline)) { 673 herrflush(); 674 zerr("modifier failed: e"); 675 return -1; 676 } 677 break; 678 case 'r': 679 if (!remtext(&sline)) { 680 herrflush(); 681 zerr("modifier failed: r"); 682 return -1; 683 } 684 break; 685 case 't': 686 if (!remlpaths(&sline)) { 687 herrflush(); 688 zerr("modifier failed: t"); 689 return -1; 690 } 691 break; 692 case 's': 693 if (getsubsargs(sline, &gbal, &cflag)) 694 return -1; /* fall through */ 695 case '&': 696 if (hsubl && hsubr) { 697 if (subst(&sline, hsubl, hsubr, gbal)) 698 return substfailed(); 699 } else { 700 herrflush(); 701 zerr("no previous substitution"); 702 return -1; 703 } 704 break; 705 case 'q': 706 quote(&sline); 707 break; 708 case 'Q': 709 { 710 int one = noerrs, oef = errflag; 711 712 noerrs = 1; 713 parse_subst_string(sline); 714 noerrs = one; 715 errflag = oef; 716 remnulargs(sline); 717 untokenize(sline); 718 } 719 break; 720 case 'x': 721 quotebreak(&sline); 722 break; 723 case 'l': 724 sline = casemodify(sline, CASMOD_LOWER); 725 break; 726 case 'u': 727 sline = casemodify(sline, CASMOD_UPPER); 728 break; 729 default: 730 herrflush(); 731 zerr("illegal modifier: %c", c); 732 return -1; 733 } 734 } else { 735 if (c != '}' || !bflag) 736 inungetc(c); 737 if (c != '}' && bflag) { 738 zerr("'}' expected"); 739 return -1; 740 } 741 break; 742 } 743 } 744 745 /* 746 * Push the expanded value onto the input stack, 747 * marking this as a history word for purposes of the alias stack. 748 */ 749 750 lexstop = 0; 751 /* this function is called only called from hgetc and only if * 752 * !(inbufflags & INP_ALIAS). History expansion should never be * 753 * done with INP_ALIAS (to prevent recursive history expansion and * 754 * histoty expansion of aliases). Escapes are not removed here. * 755 * This is now handled in hgetc. */ 756 inpush(sline, INP_HIST, NULL); /* sline from heap, don't free */ 757 histdone |= HISTFLAG_DONE; 758 if (isset(HISTVERIFY)) 759 histdone |= HISTFLAG_NOEXEC | HISTFLAG_RECALL; 760 761 /* Don't try and re-expand line. */ 762 return ingetc(); 763} 764 765/* unget a char and remove it from chline. It can only be used * 766 * to unget a character returned by hgetc. */ 767 768static void 769ihungetc(int c) 770{ 771 int doit = 1; 772 773 while (!lexstop && !errflag) { 774 if (hptr[-1] != (char) c && stophist < 4 && 775 hptr > chline + 1 && hptr[-1] == '\n' && hptr[-2] == '\\') 776 hungetc('\n'), hungetc('\\'); 777 778 if (expanding) { 779 zlemetacs--; 780 zlemetall--; 781 exlast++; 782 } 783 DPUTS(hptr <= chline, "BUG: hungetc attempted at buffer start"); 784 hptr--; 785 DPUTS(*hptr != (char) c, "BUG: wrong character in hungetc() "); 786 qbang = (c == bangchar && stophist < 2 && 787 hptr > chline && hptr[-1] == '\\'); 788 if (doit) 789 inungetc(c); 790 if (!qbang) 791 return; 792 doit = !stophist && ((inbufflags & INP_HIST) || 793 !(inbufflags & INP_ALIAS)); 794 c = '\\'; 795 } 796} 797 798/* begin reading a string */ 799 800/**/ 801mod_export void 802strinbeg(int dohist) 803{ 804 strin++; 805 hbegin(dohist); 806 lexinit(); 807} 808 809/* done reading a string */ 810 811/**/ 812mod_export void 813strinend(void) 814{ 815 hend(NULL); 816 DPUTS(!strin, "BUG: strinend() called without strinbeg()"); 817 strin--; 818 isfirstch = 1; 819 histdone = 0; 820} 821 822/* dummy functions to use instead of hwaddc(), hwbegin(), and hwend() when 823 * they aren't needed */ 824 825static void 826nohw(UNUSED(int c)) 827{ 828} 829 830static void 831nohwe(void) 832{ 833} 834 835/* these functions handle adding/removing curline to/from the hist_ring */ 836 837static void 838linkcurline(void) 839{ 840 if (!hist_ring) 841 hist_ring = curline.up = curline.down = &curline; 842 else { 843 curline.up = hist_ring; 844 curline.down = hist_ring->down; 845 hist_ring->down = hist_ring->down->up = &curline; 846 hist_ring = &curline; 847 } 848 curline.histnum = ++curhist; 849} 850 851static void 852unlinkcurline(void) 853{ 854 curline.up->down = curline.down; 855 curline.down->up = curline.up; 856 if (hist_ring == &curline) { 857 if (!histlinect) 858 hist_ring = NULL; 859 else 860 hist_ring = curline.up; 861 } 862 curhist--; 863} 864 865/* initialize the history mechanism */ 866 867/**/ 868mod_export void 869hbegin(int dohist) 870{ 871 isfirstln = isfirstch = 1; 872 errflag = histdone = 0; 873 if (!dohist) 874 stophist = 2; 875 else if (dohist != 2) 876 stophist = (!interact || unset(SHINSTDIN)) ? 2 : 0; 877 else 878 stophist = 0; 879 /* 880 * pws: We used to test for "|| (inbufflags & INP_ALIAS)" 881 * in this test, but at this point we don't have input 882 * set up up so this can trigger unnecessarily. 883 * I don't see how the test at this point could ever be 884 * useful, since we only get here when we're initialising 885 * the history mechanism, before we've done any input. 886 * 887 * (I also don't see any point where this function is called with 888 * dohist=0.) 889 */ 890 if (stophist == 2) { 891 chline = hptr = NULL; 892 hlinesz = 0; 893 chwords = NULL; 894 chwordlen = 0; 895 hgetc = ingetc; 896 hungetc = inungetc; 897 hwaddc = nohw; 898 hwbegin = nohw; 899 hwend = nohwe; 900 addtoline = nohw; 901 } else { 902 chline = hptr = zshcalloc(hlinesz = 64); 903 chwords = zalloc((chwordlen = 64) * sizeof(short)); 904 hgetc = ihgetc; 905 hungetc = ihungetc; 906 hwaddc = ihwaddc; 907 hwbegin = ihwbegin; 908 hwend = ihwend; 909 addtoline = iaddtoline; 910 if (!isset(BANGHIST)) 911 stophist = 4; 912 } 913 chwordpos = 0; 914 915 if (hist_ring && !hist_ring->ftim && !strin) 916 hist_ring->ftim = time(NULL); 917 if ((dohist == 2 || (interact && isset(SHINSTDIN))) && !strin) { 918 histactive = HA_ACTIVE; 919 attachtty(mypgrp); 920 linkcurline(); 921 defev = addhistnum(curhist, -1, HIST_FOREIGN); 922 } else 923 histactive = HA_ACTIVE | HA_NOINC; 924} 925 926/**/ 927void 928histreduceblanks(void) 929{ 930 int i, len, pos, needblank, spacecount = 0; 931 932 if (isset(HISTIGNORESPACE)) 933 while (chline[spacecount] == ' ') spacecount++; 934 935 for (i = 0, len = spacecount; i < chwordpos; i += 2) { 936 len += chwords[i+1] - chwords[i] 937 + (i > 0 && chwords[i] > chwords[i-1]); 938 } 939 if (chline[len] == '\0') 940 return; 941 942 for (i = 0, pos = spacecount; i < chwordpos; i += 2) { 943 len = chwords[i+1] - chwords[i]; 944 needblank = (i < chwordpos-2 && chwords[i+2] > chwords[i+1]); 945 if (pos != chwords[i]) { 946 memcpy(chline + pos, chline + chwords[i], len + needblank); 947 chwords[i] = pos; 948 chwords[i+1] = chwords[i] + len; 949 } 950 pos += len + needblank; 951 } 952 chline[pos] = '\0'; 953} 954 955/**/ 956void 957histremovedups(void) 958{ 959 Histent he, next; 960 for (he = hist_ring; he; he = next) { 961 next = up_histent(he); 962 if (he->node.flags & HIST_DUP) 963 freehistnode(&he->node); 964 } 965} 966 967/**/ 968mod_export zlong 969addhistnum(zlong hl, int n, int xflags) 970{ 971 int dir = n < 0? -1 : n > 0? 1 : 0; 972 Histent he = gethistent(hl, dir); 973 974 if (!he) 975 return 0; 976 if (he->histnum != hl) 977 n -= dir; 978 if (n) 979 he = movehistent(he, n, xflags); 980 if (!he) 981 return dir < 0? firsthist() - 1 : curhist + 1; 982 return he->histnum; 983} 984 985/**/ 986mod_export Histent 987movehistent(Histent he, int n, int xflags) 988{ 989 while (n < 0) { 990 if (!(he = up_histent(he))) 991 return NULL; 992 if (!(he->node.flags & xflags)) 993 n++; 994 } 995 while (n > 0) { 996 if (!(he = down_histent(he))) 997 return NULL; 998 if (!(he->node.flags & xflags)) 999 n--; 1000 } 1001 checkcurline(he); 1002 return he; 1003} 1004 1005/**/ 1006mod_export Histent 1007up_histent(Histent he) 1008{ 1009 return !he || he->up == hist_ring? NULL : he->up; 1010} 1011 1012/**/ 1013mod_export Histent 1014down_histent(Histent he) 1015{ 1016 return he == hist_ring? NULL : he->down; 1017} 1018 1019/**/ 1020mod_export Histent 1021gethistent(zlong ev, int nearmatch) 1022{ 1023 Histent he; 1024 1025 if (!hist_ring) 1026 return NULL; 1027 1028 if (ev - hist_ring->down->histnum < hist_ring->histnum - ev) { 1029 for (he = hist_ring->down; he->histnum < ev; he = he->down) ; 1030 if (he->histnum != ev) { 1031 if (nearmatch == 0 1032 || (nearmatch < 0 && (he = up_histent(he)) == NULL)) 1033 return NULL; 1034 } 1035 } 1036 else { 1037 for (he = hist_ring; he->histnum > ev; he = he->up) ; 1038 if (he->histnum != ev) { 1039 if (nearmatch == 0 1040 || (nearmatch > 0 && (he = down_histent(he)) == NULL)) 1041 return NULL; 1042 } 1043 } 1044 1045 checkcurline(he); 1046 return he; 1047} 1048 1049static void 1050putoldhistentryontop(short keep_going) 1051{ 1052 static Histent next = NULL; 1053 Histent he = keep_going? next : hist_ring->down; 1054 next = he->down; 1055 if (isset(HISTEXPIREDUPSFIRST) && !(he->node.flags & HIST_DUP)) { 1056 static zlong max_unique_ct = 0; 1057 if (!keep_going) 1058 max_unique_ct = savehistsiz; 1059 do { 1060 if (max_unique_ct-- <= 0 || he == hist_ring) { 1061 max_unique_ct = 0; 1062 he = hist_ring->down; 1063 next = hist_ring; 1064 break; 1065 } 1066 he = next; 1067 next = he->down; 1068 } while (!(he->node.flags & HIST_DUP)); 1069 } 1070 if (he != hist_ring->down) { 1071 he->up->down = he->down; 1072 he->down->up = he->up; 1073 he->up = hist_ring; 1074 he->down = hist_ring->down; 1075 hist_ring->down = he->down->up = he; 1076 } 1077 hist_ring = he; 1078} 1079 1080/**/ 1081Histent 1082prepnexthistent(void) 1083{ 1084 Histent he; 1085 int curline_in_ring = hist_ring == &curline; 1086 1087 if (curline_in_ring) 1088 unlinkcurline(); 1089 if (hist_ring && hist_ring->node.flags & HIST_TMPSTORE) { 1090 curhist--; 1091 freehistnode(&hist_ring->node); 1092 } 1093 1094 if (histlinect < histsiz) { 1095 he = (Histent)zshcalloc(sizeof *he); 1096 if (!hist_ring) 1097 hist_ring = he->up = he->down = he; 1098 else { 1099 he->up = hist_ring; 1100 he->down = hist_ring->down; 1101 hist_ring->down = he->down->up = he; 1102 hist_ring = he; 1103 } 1104 histlinect++; 1105 } 1106 else { 1107 putoldhistentryontop(0); 1108 freehistdata(hist_ring, 0); 1109 he = hist_ring; 1110 } 1111 he->histnum = ++curhist; 1112 if (curline_in_ring) 1113 linkcurline(); 1114 return he; 1115} 1116 1117/* A helper function for hend() */ 1118 1119static int 1120should_ignore_line(Eprog prog) 1121{ 1122 if (isset(HISTIGNORESPACE)) { 1123 if (*chline == ' ' || aliasspaceflag) 1124 return 1; 1125 } 1126 1127 if (!prog) 1128 return 0; 1129 1130 if (isset(HISTNOFUNCTIONS)) { 1131 Wordcode pc = prog->prog; 1132 wordcode code = *pc; 1133 if (wc_code(code) == WC_LIST && WC_LIST_TYPE(code) & Z_SIMPLE 1134 && wc_code(pc[2]) == WC_FUNCDEF) 1135 return 1; 1136 } 1137 1138 if (isset(HISTNOSTORE)) { 1139 char *b = getjobtext(prog, NULL); 1140 int saw_builtin; 1141 if (*b == 'b' && strncmp(b,"builtin ",8) == 0) { 1142 b += 8; 1143 saw_builtin = 1; 1144 } else 1145 saw_builtin = 0; 1146 if (*b == 'h' && strncmp(b,"history",7) == 0 && (!b[7] || b[7] == ' ') 1147 && (saw_builtin || !shfunctab->getnode(shfunctab,"history"))) 1148 return 1; 1149 if (*b == 'r' && (!b[1] || b[1] == ' ') 1150 && (saw_builtin || !shfunctab->getnode(shfunctab,"r"))) 1151 return 1; 1152 if (*b == 'f' && b[1] == 'c' && b[2] == ' ' && b[3] == '-' 1153 && (saw_builtin || !shfunctab->getnode(shfunctab,"fc"))) { 1154 b += 3; 1155 do { 1156 if (*++b == 'l') 1157 return 1; 1158 } while (ialpha(*b)); 1159 } 1160 } 1161 1162 return 0; 1163} 1164 1165/* say we're done using the history mechanism */ 1166 1167/**/ 1168mod_export int 1169hend(Eprog prog) 1170{ 1171 LinkList hookargs = newlinklist(); 1172 int flag, save = 1, hookret, stack_pos = histsave_stack_pos; 1173 char *hf; 1174 1175 DPUTS(stophist != 2 && !(inbufflags & INP_ALIAS) && !chline, 1176 "BUG: chline is NULL in hend()"); 1177 queue_signals(); 1178 if (histdone & HISTFLAG_SETTY) 1179 settyinfo(&shttyinfo); 1180 if (!(histactive & HA_NOINC)) 1181 unlinkcurline(); 1182 if (histactive & HA_NOINC) { 1183 zfree(chline, hlinesz); 1184 zfree(chwords, chwordlen*sizeof(short)); 1185 chline = hptr = NULL; 1186 chwords = NULL; 1187 histactive = 0; 1188 unqueue_signals(); 1189 return 1; 1190 } 1191 if (hist_ignore_all_dups != isset(HISTIGNOREALLDUPS) 1192 && (hist_ignore_all_dups = isset(HISTIGNOREALLDUPS)) != 0) 1193 histremovedups(); 1194 1195 if (hptr) { 1196 /* 1197 * Added the following in case the test "hptr < chline + 1" 1198 * is more than just paranoia. 1199 */ 1200 DPUTS(hptr < chline, "History end pointer off start of line"); 1201 *hptr = '\0'; 1202 } 1203 addlinknode(hookargs, "zshaddhistory"); 1204 addlinknode(hookargs, chline); 1205 callhookfunc("zshaddhistory", hookargs, 1, &hookret); 1206 /* For history sharing, lock history file once for both read and write */ 1207 hf = getsparam("HISTFILE"); 1208 if (isset(SHAREHISTORY) && !lockhistfile(hf, 0)) { 1209 readhistfile(hf, 0, HFILE_USE_OPTIONS | HFILE_FAST); 1210 curline.histnum = curhist+1; 1211 } 1212 flag = histdone; 1213 histdone = 0; 1214 if (hptr < chline + 1) 1215 save = 0; 1216 else { 1217 if (hptr[-1] == '\n') { 1218 if (chline[1]) { 1219 *--hptr = '\0'; 1220 } else 1221 save = 0; 1222 } 1223 if (chwordpos <= 2) 1224 save = 0; 1225 else if (hookret || should_ignore_line(prog)) 1226 save = -1; 1227 } 1228 if (flag & (HISTFLAG_DONE | HISTFLAG_RECALL)) { 1229 char *ptr; 1230 1231 ptr = ztrdup(chline); 1232 if ((flag & (HISTFLAG_DONE | HISTFLAG_RECALL)) == HISTFLAG_DONE) { 1233 zputs(ptr, shout); 1234 fputc('\n', shout); 1235 fflush(shout); 1236 } 1237 if (flag & HISTFLAG_RECALL) { 1238 zpushnode(bufstack, ptr); 1239 save = 0; 1240 } else 1241 zsfree(ptr); 1242 } 1243 if (save || *chline == ' ') { 1244 Histent he; 1245 for (he = hist_ring; he && he->node.flags & HIST_FOREIGN; 1246 he = up_histent(he)) ; 1247 if (he && he->node.flags & HIST_TMPSTORE) { 1248 if (he == hist_ring) 1249 curline.histnum = curhist--; 1250 freehistnode(&he->node); 1251 } 1252 } 1253 if (save) { 1254 Histent he; 1255 int newflags; 1256 1257#ifdef DEBUG 1258 /* debugging only */ 1259 if (chwordpos%2) { 1260 hwend(); 1261 DPUTS(1, "BUG: uncompleted line in history"); 1262 } 1263#endif 1264 /* get rid of pesky \n which we've already nulled out */ 1265 if (chwordpos > 1 && !chline[chwords[chwordpos-2]]) { 1266 chwordpos -= 2; 1267 /* strip superfluous blanks, if desired */ 1268 if (isset(HISTREDUCEBLANKS)) 1269 histreduceblanks(); 1270 } 1271 newflags = save > 0? 0 : HIST_TMPSTORE; 1272 if ((isset(HISTIGNOREDUPS) || isset(HISTIGNOREALLDUPS)) && save > 0 1273 && hist_ring && histstrcmp(chline, hist_ring->node.nam) == 0) { 1274 /* This history entry compares the same as the previous. 1275 * In case minor changes were made, we overwrite the 1276 * previous one with the current one. This also gets the 1277 * timestamp right. Perhaps, preserve the HIST_OLD flag. 1278 */ 1279 he = hist_ring; 1280 newflags |= he->node.flags & HIST_OLD; /* Avoid re-saving */ 1281 freehistdata(he, 0); 1282 curline.histnum = curhist; 1283 } else 1284 he = prepnexthistent(); 1285 1286 he->node.nam = ztrdup(chline); 1287 he->stim = time(NULL); 1288 he->ftim = 0L; 1289 he->node.flags = newflags; 1290 1291 if ((he->nwords = chwordpos/2)) { 1292 he->words = (short *)zalloc(chwordpos * sizeof(short)); 1293 memcpy(he->words, chwords, chwordpos * sizeof(short)); 1294 } 1295 if (!(newflags & HIST_TMPSTORE)) 1296 addhistnode(histtab, he->node.nam, he); 1297 } 1298 zfree(chline, hlinesz); 1299 zfree(chwords, chwordlen*sizeof(short)); 1300 chline = hptr = NULL; 1301 chwords = NULL; 1302 histactive = 0; 1303 if (isset(SHAREHISTORY)? histfileIsLocked() : isset(INCAPPENDHISTORY)) 1304 savehistfile(hf, 0, HFILE_USE_OPTIONS | HFILE_FAST); 1305 unlockhistfile(hf); /* It's OK to call this even if we aren't locked */ 1306 /* 1307 * No good reason for the user to push the history more than once, but 1308 * it's easy to be tidy... 1309 */ 1310 while (histsave_stack_pos > stack_pos) 1311 pophiststack(); 1312 unqueue_signals(); 1313 return !(flag & HISTFLAG_NOEXEC || errflag); 1314} 1315 1316/* Gives current expansion word if not last word before chwordpos. */ 1317 1318/**/ 1319int hwgetword = -1; 1320 1321/* begin a word */ 1322 1323/**/ 1324void 1325ihwbegin(int offset) 1326{ 1327 if (stophist == 2) 1328 return; 1329 if (chwordpos%2) 1330 chwordpos--; /* make sure we're on a word start, not end */ 1331 /* If we're expanding an alias, we should overwrite the expansion 1332 * in the history. 1333 */ 1334 if ((inbufflags & INP_ALIAS) && !(inbufflags & INP_HIST)) 1335 hwgetword = chwordpos; 1336 else 1337 hwgetword = -1; 1338 chwords[chwordpos++] = hptr - chline + offset; 1339} 1340 1341/* add a word to the history List */ 1342 1343/**/ 1344void 1345ihwend(void) 1346{ 1347 if (stophist == 2) 1348 return; 1349 if (chwordpos%2 && chline) { 1350 /* end of word reached and we've already begun a word */ 1351 if (hptr > chline + chwords[chwordpos-1]) { 1352 chwords[chwordpos++] = hptr - chline; 1353 if (chwordpos >= chwordlen) { 1354 chwords = (short *) realloc(chwords, 1355 (chwordlen += 32) * 1356 sizeof(short)); 1357 } 1358 if (hwgetword > -1 && 1359 (inbufflags & INP_ALIAS) && !(inbufflags & INP_HIST)) { 1360 /* We want to reuse the current word position */ 1361 chwordpos = hwgetword; 1362 /* Start from where previous word ended, if possible */ 1363 hptr = chline + chwords[chwordpos ? chwordpos - 1 : 0]; 1364 } 1365 } else { 1366 /* scrub that last word, it doesn't exist */ 1367 chwordpos--; 1368 } 1369 } 1370} 1371 1372/* Go back to immediately after the last word, skipping space. */ 1373 1374/**/ 1375void 1376histbackword(void) 1377{ 1378 if (!(chwordpos%2) && chwordpos) 1379 hptr = chline + chwords[chwordpos-1]; 1380} 1381 1382/* Get the start and end point of the current history word */ 1383 1384/**/ 1385static void 1386hwget(char **startptr) 1387{ 1388 int pos = hwgetword > -1 ? hwgetword : chwordpos - 2; 1389 1390#ifdef DEBUG 1391 /* debugging only */ 1392 if (hwgetword == -1 && !chwordpos) { 1393 /* no words available */ 1394 DPUTS(1, "BUG: hwget() called with no words"); 1395 *startptr = ""; 1396 return; 1397 } 1398 else if (hwgetword == -1 && chwordpos%2) { 1399 DPUTS(1, "BUG: hwget() called in middle of word"); 1400 *startptr = ""; 1401 return; 1402 } 1403#endif 1404 1405 *startptr = chline + chwords[pos]; 1406 chline[chwords[++pos]] = '\0'; 1407} 1408 1409/* Replace the current history word with rep, if different */ 1410 1411/**/ 1412void 1413hwrep(char *rep) 1414{ 1415 char *start; 1416 hwget(&start); 1417 1418 if (!strcmp(rep, start)) 1419 return; 1420 1421 hptr = start; 1422 chwordpos = (hwgetword > -1) ? hwgetword : chwordpos - 2; 1423 hwbegin(0); 1424 qbang = 1; 1425 while (*rep) 1426 hwaddc(*rep++); 1427 hwend(); 1428} 1429 1430/* Get the entire current line, deleting it in the history. */ 1431 1432/**/ 1433mod_export char * 1434hgetline(void) 1435{ 1436 /* Currently only used by pushlineoredit(). 1437 * It's necessary to prevent that from getting too pally with 1438 * the history code. 1439 */ 1440 char *ret; 1441 1442 if (!chline || hptr == chline) 1443 return NULL; 1444 *hptr = '\0'; 1445 ret = dupstring(chline); 1446 1447 /* reset line */ 1448 hptr = chline; 1449 chwordpos = 0; 1450 hwgetword = -1; 1451 1452 return ret; 1453} 1454 1455/* get an argument specification */ 1456 1457/**/ 1458static int 1459getargspec(int argc, int marg, int evset) 1460{ 1461 int c, ret = -1; 1462 1463 if ((c = ingetc()) == '0') 1464 return 0; 1465 if (idigit(c)) { 1466 ret = 0; 1467 while (idigit(c)) { 1468 ret = ret * 10 + c - '0'; 1469 c = ingetc(); 1470 } 1471 inungetc(c); 1472 } else if (c == '^') 1473 ret = 1; 1474 else if (c == '$') 1475 ret = argc; 1476 else if (c == '%') { 1477 if (evset) { 1478 herrflush(); 1479 zerr("Ambiguous history reference"); 1480 return -2; 1481 } 1482 if (marg == -1) { 1483 herrflush(); 1484 zerr("%% with no previous word matched"); 1485 return -2; 1486 } 1487 ret = marg; 1488 } else 1489 inungetc(c); 1490 return ret; 1491} 1492 1493/* do ?foo? search */ 1494 1495/**/ 1496static zlong 1497hconsearch(char *str, int *marg) 1498{ 1499 int t1 = 0; 1500 char *s; 1501 Histent he; 1502 1503 for (he = up_histent(hist_ring); he; he = up_histent(he)) { 1504 if (he->node.flags & HIST_FOREIGN) 1505 continue; 1506 if ((s = strstr(he->node.nam, str))) { 1507 int pos = s - he->node.nam; 1508 while (t1 < he->nwords && he->words[2*t1] <= pos) 1509 t1++; 1510 *marg = t1 - 1; 1511 return he->histnum; 1512 } 1513 } 1514 return -1; 1515} 1516 1517/* do !foo search */ 1518 1519/**/ 1520zlong 1521hcomsearch(char *str) 1522{ 1523 Histent he; 1524 int len = strlen(str); 1525 1526 for (he = up_histent(hist_ring); he; he = up_histent(he)) { 1527 if (he->node.flags & HIST_FOREIGN) 1528 continue; 1529 if (strncmp(he->node.nam, str, len) == 0) 1530 return he->histnum; 1531 } 1532 return -1; 1533} 1534 1535/* various utilities for : modifiers */ 1536 1537/**/ 1538int 1539chabspath(char **junkptr) 1540{ 1541 char *current, *dest; 1542 1543 if (!**junkptr) 1544 return 1; 1545 1546 if (**junkptr != '/') { 1547 *junkptr = zhtricat(metafy(zgetcwd(), -1, META_HEAPDUP), "/", *junkptr); 1548 } 1549 1550 current = *junkptr; 1551 dest = *junkptr; 1552 1553#ifdef HAVE_SUPERROOT 1554 while (*current == '/' && current[1] == '.' && current[2] == '.' && 1555 (!current[3] || current[3] == '/')) { 1556 *dest++ = '/'; 1557 *dest++ = '.'; 1558 *dest++ = '.'; 1559 current += 3; 1560 } 1561#endif 1562 1563 for (;;) { 1564 if (*current == '/') { 1565#ifdef __CYGWIN__ 1566 if (current == *junkptr && current[1] == '/') 1567 *dest++ = *current++; 1568#endif 1569 *dest++ = *current++; 1570 while (*current == '/') 1571 current++; 1572 } else if (!*current) { 1573 while (dest > *junkptr + 1 && dest[-1] == '/') 1574 dest--; 1575 *dest = '\0'; 1576 break; 1577 } else if (current[0] == '.' && current[1] == '.' && 1578 (!current[2] || current[2] == '/')) { 1579 if (current == *junkptr || dest == *junkptr) { 1580 *dest++ = '.'; 1581 *dest++ = '.'; 1582 current += 2; 1583 } else if (dest > *junkptr + 2 && 1584 !strncmp(dest - 3, "../", 3)) { 1585 *dest++ = '.'; 1586 *dest++ = '.'; 1587 current += 2; 1588 } else if (dest > *junkptr + 1) { 1589 *dest = '\0'; 1590 for (dest--; 1591 dest > *junkptr + 1 && dest[-1] != '/'; 1592 dest--); 1593 if (dest[-1] != '/') 1594 dest--; 1595 current += 2; 1596 if (*current == '/') 1597 current++; 1598 } else if (dest == *junkptr + 1) { 1599 /* This might break with Cygwin's leading double slashes? */ 1600 current += 2; 1601 } else { 1602 return 0; 1603 } 1604 } else if (current[0] == '.' && (current[1] == '/' || !current[1])) { 1605 while (*++current == '/'); 1606 } else { 1607 while (*current != '/' && *current != '\0') 1608 if ((*dest++ = *current++) == Meta) 1609 *dest++ = *current++; 1610 } 1611 } 1612 return 1; 1613} 1614 1615/**/ 1616int 1617chrealpath(char **junkptr) 1618{ 1619 char *str; 1620#ifdef HAVE_CANONICALIZE_FILE_NAME 1621 char *lastpos, *nonreal, *real; 1622#else 1623# ifdef HAVE_REALPATH 1624 char *lastpos, *nonreal, real[PATH_MAX]; 1625# endif 1626#endif 1627 1628 if (!**junkptr) 1629 return 1; 1630 1631 /* Notice that this means ..'s are applied before symlinks are resolved! */ 1632 if (!chabspath(junkptr)) 1633 return 0; 1634 1635#if !defined(HAVE_REALPATH) && !defined(HAVE_CANONICALIZE_FILE_NAME) 1636 return 1; 1637#else 1638 /* 1639 * Notice that this means you cannot pass relative paths into this 1640 * function! 1641 */ 1642 if (**junkptr != '/') 1643 return 0; 1644 1645 unmetafy(*junkptr, NULL); 1646 1647 lastpos = strend(*junkptr); 1648 nonreal = lastpos + 1; 1649 1650 while (! 1651#ifdef HAVE_CANONICALIZE_FILE_NAME 1652 /* 1653 * This is a GNU extension to realpath(); it's the 1654 * same as calling realpath() with a NULL second argument 1655 * which uses malloc() to get memory. The alternative 1656 * interface is easier to test for, however. 1657 */ 1658 (real = canonicalize_file_name(*junkptr)) 1659#else 1660 realpath(*junkptr, real) 1661#endif 1662 ) { 1663 if (errno == EINVAL || errno == ELOOP || 1664 errno == ENAMETOOLONG || errno == ENOMEM) 1665 return 0; 1666 1667#ifdef HAVE_CANONICALIZE_FILE_NAME 1668 if (!real) 1669 return 0; 1670#endif 1671 1672 if (nonreal == *junkptr) { 1673 *real = '\0'; 1674 break; 1675 } 1676 1677 while (*nonreal != '/' && nonreal >= *junkptr) 1678 nonreal--; 1679 *nonreal = '\0'; 1680 } 1681 1682 str = nonreal; 1683 while (str <= lastpos) { 1684 if (*str == '\0') 1685 *str = '/'; 1686 str++; 1687 } 1688 1689 *junkptr = metafy(bicat(real, nonreal), -1, META_HEAPDUP); 1690#ifdef HAVE_CANONICALIZE_FILE_NAME 1691 free(real); 1692#endif 1693#endif 1694 1695 return 1; 1696} 1697 1698/**/ 1699int 1700remtpath(char **junkptr) 1701{ 1702 char *str = strend(*junkptr); 1703 1704 /* ignore trailing slashes */ 1705 while (str >= *junkptr && IS_DIRSEP(*str)) 1706 --str; 1707 /* skip filename */ 1708 while (str >= *junkptr && !IS_DIRSEP(*str)) 1709 --str; 1710 if (str < *junkptr) { 1711 if (IS_DIRSEP(**junkptr)) 1712 *junkptr = dupstring ("/"); 1713 else 1714 *junkptr = dupstring ("."); 1715 1716 return 0; 1717 } 1718 /* repeated slashes are considered like a single slash */ 1719 while (str > *junkptr && IS_DIRSEP(str[-1])) 1720 --str; 1721 /* never erase the root slash */ 1722 if (str == *junkptr) { 1723 ++str; 1724 /* Leading doubled slashes (`//') have a special meaning on cygwin 1725 and some old flavor of UNIX, so we do not assimilate them to 1726 a single slash. However a greater number is ok to squeeze. */ 1727 if (IS_DIRSEP(*str) && !IS_DIRSEP(str[1])) 1728 ++str; 1729 } 1730 *str = '\0'; 1731 return 1; 1732} 1733 1734/**/ 1735int 1736remtext(char **junkptr) 1737{ 1738 char *str; 1739 1740 for (str = strend(*junkptr); str >= *junkptr && !IS_DIRSEP(*str); --str) 1741 if (*str == '.') { 1742 *str = '\0'; 1743 return 1; 1744 } 1745 return 0; 1746} 1747 1748/**/ 1749int 1750rembutext(char **junkptr) 1751{ 1752 char *str; 1753 1754 for (str = strend(*junkptr); str >= *junkptr && !IS_DIRSEP(*str); --str) 1755 if (*str == '.') { 1756 *junkptr = dupstring(str + 1); /* .xx or xx? */ 1757 return 1; 1758 } 1759 /* no extension */ 1760 *junkptr = dupstring (""); 1761 return 0; 1762} 1763 1764/**/ 1765mod_export int 1766remlpaths(char **junkptr) 1767{ 1768 char *str = strend(*junkptr); 1769 1770 if (IS_DIRSEP(*str)) { 1771 /* remove trailing slashes */ 1772 while (str >= *junkptr && IS_DIRSEP(*str)) 1773 --str; 1774 str[1] = '\0'; 1775 } 1776 for (; str >= *junkptr; --str) 1777 if (IS_DIRSEP(*str)) { 1778 *str = '\0'; 1779 *junkptr = dupstring(str + 1); 1780 return 1; 1781 } 1782 return 0; 1783} 1784 1785/* 1786 * Return modified version of str from the heap with modification 1787 * according to one of the CASMOD_* types defined in zsh.h; CASMOD_NONE 1788 * is not handled, for obvious reasons. 1789 */ 1790 1791/**/ 1792char * 1793casemodify(char *str, int how) 1794{ 1795 char *str2 = zhalloc(2 * strlen(str) + 1); 1796 char *ptr2 = str2; 1797 int nextupper = 1; 1798 1799#ifdef MULTIBYTE_SUPPORT 1800 if (isset(MULTIBYTE)) { 1801 VARARR(char, mbstr, MB_CUR_MAX); 1802 mbstate_t ps; 1803 1804 mb_metacharinit(); 1805 memset(&ps, 0, sizeof(ps)); 1806 while (*str) { 1807 wint_t wc; 1808 int len = mb_metacharlenconv(str, &wc), mod = 0, len2; 1809 /* 1810 * wc is set to WEOF if the start of str couldn't be 1811 * converted. Presumably WEOF doesn't match iswlower(), but 1812 * better be safe. 1813 */ 1814 if (wc == WEOF) { 1815 while (len--) 1816 *ptr2++ = *str++; 1817 /* not alphanumeric */ 1818 nextupper = 1; 1819 continue; 1820 } 1821 switch (how) { 1822 case CASMOD_LOWER: 1823 if (iswupper(wc)) { 1824 wc = towlower(wc); 1825 mod = 1; 1826 } 1827 break; 1828 1829 case CASMOD_UPPER: 1830 if (iswlower(wc)) { 1831 wc = towupper(wc); 1832 mod = 1; 1833 } 1834 break; 1835 1836 case CASMOD_CAPS: 1837 default: /* shuts up compiler */ 1838 if (IS_COMBINING(wc)) 1839 break; 1840 if (!iswalnum(wc)) 1841 nextupper = 1; 1842 else if (nextupper) { 1843 if (iswlower(wc)) { 1844 wc = towupper(wc); 1845 mod = 1; 1846 } 1847 nextupper = 0; 1848 } else if (iswupper(wc)) { 1849 wc = towlower(wc); 1850 mod = 1; 1851 } 1852 break; 1853 } 1854 if (mod && (len2 = wcrtomb(mbstr, wc, &ps)) > 0) { 1855 char *mbptr; 1856 1857 for (mbptr = mbstr; mbptr < mbstr + len2; mbptr++) { 1858 if (imeta(STOUC(*mbptr))) { 1859 *ptr2++ = Meta; 1860 *ptr2++ = *mbptr ^ 32; 1861 } else 1862 *ptr2++ = *mbptr; 1863 } 1864 str += len; 1865 } else { 1866 while (len--) 1867 *ptr2++ = *str++; 1868 } 1869 } 1870 } 1871 else 1872#endif 1873 while (*str) { 1874 int c; 1875 if (*str == Meta) { 1876 c = str[1] ^ 32; 1877 str += 2; 1878 } else 1879 c = *str++; 1880 switch (how) { 1881 case CASMOD_LOWER: 1882 if (isupper(c)) 1883 c = tolower(c); 1884 break; 1885 1886 case CASMOD_UPPER: 1887 if (islower(c)) 1888 c = toupper(c); 1889 break; 1890 1891 case CASMOD_CAPS: 1892 default: /* shuts up compiler */ 1893 if (!ialnum(c)) 1894 nextupper = 1; 1895 else if (nextupper) { 1896 if (islower(c)) 1897 c = toupper(c); 1898 nextupper = 0; 1899 } else if (isupper(c)) 1900 c = tolower(c); 1901 break; 1902 } 1903 if (imeta(c)) { 1904 *ptr2++ = Meta; 1905 *ptr2++ = c ^ 32; 1906 } else 1907 *ptr2++ = c; 1908 } 1909 *ptr2 = '\0'; 1910 return str2; 1911} 1912 1913 1914/* 1915 * Substitute "in" for "out" in "*strptr" and update "*strptr". 1916 * If "gbal", do global substitution. 1917 * 1918 * This returns a result from the heap. There seems to have 1919 * been some confusion on this point. 1920 */ 1921 1922/**/ 1923int 1924subst(char **strptr, char *in, char *out, int gbal) 1925{ 1926 char *str = *strptr, *substcut, *sptr; 1927 int off, inlen, outlen; 1928 1929 if (!*in) 1930 in = str, gbal = 0; 1931 1932 if (isset(HISTSUBSTPATTERN)) { 1933 int fl = SUB_LONG|SUB_REST|SUB_RETFAIL; 1934 char *oldin = in; 1935 if (gbal) 1936 fl |= SUB_GLOBAL; 1937 if (*in == '#' || *in == Pound) { 1938 /* anchor at head, flag needed if SUB_END is also set */ 1939 fl |= SUB_START; 1940 in++; 1941 } 1942 if (*in == '%') { 1943 /* anchor at tail */ 1944 in++; 1945 fl |= SUB_END; 1946 } 1947 if (in == oldin) { 1948 /* no anchor, substring match */ 1949 fl |= SUB_SUBSTR; 1950 } 1951 if (in == str) 1952 in = dupstring(in); 1953 if (parse_subst_string(in) || errflag) 1954 return 1; 1955 if (parse_subst_string(out) || errflag) 1956 return 1; 1957 singsub(&in); 1958 if (getmatch(strptr, in, fl, 1, out)) 1959 return 0; 1960 } else { 1961 if ((substcut = (char *)strstr(str, in))) { 1962 inlen = strlen(in); 1963 sptr = convamps(out, in, inlen); 1964 outlen = strlen(sptr); 1965 1966 do { 1967 *substcut = '\0'; 1968 off = substcut - *strptr + outlen; 1969 substcut += inlen; 1970 *strptr = zhtricat(*strptr, sptr, substcut); 1971 str = (char *)*strptr + off; 1972 } while (gbal && (substcut = (char *)strstr(str, in))); 1973 1974 return 0; 1975 } 1976 } 1977 1978 return 1; 1979} 1980 1981/**/ 1982static char * 1983convamps(char *out, char *in, int inlen) 1984{ 1985 char *ptr, *ret, *pp; 1986 int slen, sdup = 0; 1987 1988 for (ptr = out, slen = 0; *ptr; ptr++, slen++) 1989 if (*ptr == '\\') 1990 ptr++, sdup = 1; 1991 else if (*ptr == '&') 1992 slen += inlen - 1, sdup = 1; 1993 if (!sdup) 1994 return out; 1995 ret = pp = (char *) zhalloc(slen + 1); 1996 for (ptr = out; *ptr; ptr++) 1997 if (*ptr == '\\') 1998 *pp++ = *++ptr; 1999 else if (*ptr == '&') { 2000 strcpy(pp, in); 2001 pp += inlen; 2002 } else 2003 *pp++ = *ptr; 2004 *pp = '\0'; 2005 return ret; 2006} 2007 2008/**/ 2009mod_export void 2010checkcurline(Histent he) 2011{ 2012 if (he->histnum == curhist && (histactive & HA_ACTIVE)) { 2013 curline.node.nam = chline; 2014 curline.nwords = chwordpos/2; 2015 curline.words = chwords; 2016 } 2017} 2018 2019/**/ 2020mod_export Histent 2021quietgethist(int ev) 2022{ 2023 return gethistent(ev, GETHIST_EXACT); 2024} 2025 2026/**/ 2027static Histent 2028gethist(int ev) 2029{ 2030 Histent ret; 2031 2032 ret = quietgethist(ev); 2033 if (!ret) { 2034 herrflush(); 2035 zerr("no such event: %d", ev); 2036 } 2037 return ret; 2038} 2039 2040/**/ 2041static char * 2042getargs(Histent elist, int arg1, int arg2) 2043{ 2044 short *words = elist->words; 2045 int pos1, nwords = elist->nwords; 2046 2047 if (arg2 < arg1 || arg1 >= nwords || arg2 >= nwords) { 2048 /* remember, argN is indexed from 0, nwords is total no. of words */ 2049 herrflush(); 2050 zerr("no such word in event"); 2051 return NULL; 2052 } 2053 2054 pos1 = words[2*arg1]; 2055 return dupstrpfx(elist->node.nam + pos1, words[2*arg2+1] - pos1); 2056} 2057 2058/**/ 2059int 2060quote(char **tr) 2061{ 2062 char *ptr, *rptr, **str = (char **)tr; 2063 int len = 3; 2064 int inquotes = 0; 2065 2066 for (ptr = *str; *ptr; ptr++, len++) 2067 if (*ptr == '\'') { 2068 len += 3; 2069 if (!inquotes) 2070 inquotes = 1; 2071 else 2072 inquotes = 0; 2073 } else if (inblank(*ptr) && !inquotes && ptr[-1] != '\\') 2074 len += 2; 2075 ptr = *str; 2076 *str = rptr = (char *) zhalloc(len); 2077 *rptr++ = '\''; 2078 for (; *ptr; ptr++) 2079 if (*ptr == '\'') { 2080 if (!inquotes) 2081 inquotes = 1; 2082 else 2083 inquotes = 0; 2084 *rptr++ = '\''; 2085 *rptr++ = '\\'; 2086 *rptr++ = '\''; 2087 *rptr++ = '\''; 2088 } else if (inblank(*ptr) && !inquotes && ptr[-1] != '\\') { 2089 *rptr++ = '\''; 2090 *rptr++ = *ptr; 2091 *rptr++ = '\''; 2092 } else 2093 *rptr++ = *ptr; 2094 *rptr++ = '\''; 2095 *rptr++ = 0; 2096 str[1] = NULL; 2097 return 0; 2098} 2099 2100/**/ 2101static int 2102quotebreak(char **tr) 2103{ 2104 char *ptr, *rptr, **str = (char **)tr; 2105 int len = 3; 2106 2107 for (ptr = *str; *ptr; ptr++, len++) 2108 if (*ptr == '\'') 2109 len += 3; 2110 else if (inblank(*ptr)) 2111 len += 2; 2112 ptr = *str; 2113 *str = rptr = (char *) zhalloc(len); 2114 *rptr++ = '\''; 2115 for (; *ptr;) 2116 if (*ptr == '\'') { 2117 *rptr++ = '\''; 2118 *rptr++ = '\\'; 2119 *rptr++ = '\''; 2120 *rptr++ = '\''; 2121 ptr++; 2122 } else if (inblank(*ptr)) { 2123 *rptr++ = '\''; 2124 *rptr++ = *ptr++; 2125 *rptr++ = '\''; 2126 } else 2127 *rptr++ = *ptr++; 2128 *rptr++ = '\''; 2129 *rptr++ = '\0'; 2130 return 0; 2131} 2132 2133/* read an arbitrary amount of data into a buffer until stop is found */ 2134 2135#if 0 /**/ 2136char * 2137hdynread(int stop) 2138{ 2139 int bsiz = 256, ct = 0, c; 2140 char *buf = (char *)zalloc(bsiz), *ptr; 2141 2142 ptr = buf; 2143 while ((c = ingetc()) != stop && c != '\n' && !lexstop) { 2144 if (c == '\\') 2145 c = ingetc(); 2146 *ptr++ = c; 2147 if (++ct == bsiz) { 2148 buf = realloc(buf, bsiz *= 2); 2149 ptr = buf + ct; 2150 } 2151 } 2152 *ptr = 0; 2153 if (c == '\n') { 2154 inungetc('\n'); 2155 zerr("delimiter expected"); 2156 zfree(buf, bsiz); 2157 return NULL; 2158 } 2159 return buf; 2160} 2161#endif 2162 2163/**/ 2164static char * 2165hdynread2(int stop) 2166{ 2167 int bsiz = 256, ct = 0, c; 2168 char *buf = (char *)zalloc(bsiz), *ptr; 2169 2170 ptr = buf; 2171 while ((c = ingetc()) != stop && c != '\n' && !lexstop) { 2172 if (c == '\\') 2173 c = ingetc(); 2174 *ptr++ = c; 2175 if (++ct == bsiz) { 2176 buf = realloc(buf, bsiz *= 2); 2177 ptr = buf + ct; 2178 } 2179 } 2180 *ptr = 0; 2181 if (c == '\n') 2182 inungetc('\n'); 2183 return buf; 2184} 2185 2186/**/ 2187void 2188inithist(void) 2189{ 2190 createhisttable(); 2191} 2192 2193/**/ 2194void 2195resizehistents(void) 2196{ 2197 if (histlinect > histsiz) { 2198 /* The reason we don't just call freehistnode(hist_ring->down) is 2199 * so that we can honor the HISTEXPIREDUPSFIRST setting. */ 2200 putoldhistentryontop(0); 2201 freehistnode(&hist_ring->node); 2202 while (histlinect > histsiz) { 2203 putoldhistentryontop(1); 2204 freehistnode(&hist_ring->node); 2205 } 2206 } 2207} 2208 2209static int 2210readhistline(int start, char **bufp, int *bufsiz, FILE *in) 2211{ 2212 char *buf = *bufp; 2213 if (fgets(buf + start, *bufsiz - start, in)) { 2214 int len = start + strlen(buf + start); 2215 if (len == start) 2216 return -1; 2217 if (buf[len - 1] != '\n') { 2218 if (!feof(in)) { 2219 if (len < (*bufsiz) - 1) 2220 return -1; 2221 *bufp = zrealloc(buf, 2 * (*bufsiz)); 2222 *bufsiz = 2 * (*bufsiz); 2223 return readhistline(len, bufp, bufsiz, in); 2224 } 2225 } 2226 else { 2227 buf[len - 1] = '\0'; 2228 if (len > 1 && buf[len - 2] == '\\' && 2229 (len < 3 || buf[len - 3] != '\\')) { 2230 buf[--len - 1] = '\n'; 2231 if (!feof(in)) 2232 return readhistline(len, bufp, bufsiz, in); 2233 } 2234 } 2235 return len; 2236 } 2237 return 0; 2238} 2239 2240/**/ 2241void 2242readhistfile(char *fn, int err, int readflags) 2243{ 2244 char *buf, *start = NULL; 2245 FILE *in; 2246 Histent he; 2247 time_t stim, ftim, tim = time(NULL); 2248 off_t fpos; 2249 short *words; 2250 struct stat sb; 2251 int nwordpos, nwords, bufsiz; 2252 int searching, newflags, l, ret, uselex; 2253 2254 if (!fn && !(fn = getsparam("HISTFILE"))) 2255 return; 2256 if (stat(unmeta(fn), &sb) < 0 || 2257 sb.st_size == 0) 2258 return; 2259 if (readflags & HFILE_FAST) { 2260 if ((lasthist.fsiz == sb.st_size && lasthist.mtim == sb.st_mtime) 2261 || lockhistfile(fn, 0)) 2262 return; 2263 lasthist.fsiz = sb.st_size; 2264 lasthist.mtim = sb.st_mtime; 2265 } else if ((ret = lockhistfile(fn, 1))) { 2266 if (ret == 2) { 2267 zwarn("locking failed for %s: %e: reading anyway", fn, errno); 2268 } else { 2269 zerr("locking failed for %s: %e", fn, errno); 2270 return; 2271 } 2272 } 2273 if ((in = fopen(unmeta(fn), "r"))) { 2274 nwords = 64; 2275 words = (short *)zalloc(nwords*sizeof(short)); 2276 bufsiz = 1024; 2277 buf = zalloc(bufsiz); 2278 2279 pushheap(); 2280 if (readflags & HFILE_FAST && lasthist.text) { 2281 if (lasthist.fpos < lasthist.fsiz) { 2282 fseek(in, lasthist.fpos, 0); 2283 searching = 1; 2284 } 2285 else { 2286 histfile_linect = 0; 2287 searching = -1; 2288 } 2289 } else 2290 searching = 0; 2291 2292 newflags = HIST_OLD | HIST_READ; 2293 if (readflags & HFILE_FAST) 2294 newflags |= HIST_FOREIGN; 2295 if (readflags & HFILE_SKIPOLD 2296 || (hist_ignore_all_dups && newflags & hist_skip_flags)) 2297 newflags |= HIST_MAKEUNIQUE; 2298 while (fpos = ftell(in), (l = readhistline(0, &buf, &bufsiz, in))) { 2299 char *pt = buf; 2300 2301 if (l < 0) { 2302 zerr("corrupt history file %s", fn); 2303 break; 2304 } 2305 if (*pt == ':') { 2306 pt++; 2307 stim = zstrtol(pt, NULL, 0); 2308 for (; *pt != ':' && *pt; pt++); 2309 if (*pt) { 2310 pt++; 2311 ftim = zstrtol(pt, NULL, 0); 2312 for (; *pt != ';' && *pt; pt++); 2313 if (*pt) 2314 pt++; 2315 } else 2316 ftim = stim; 2317 } else { 2318 if (*pt == '\\' && pt[1] == ':') 2319 pt++; 2320 stim = ftim = 0; 2321 } 2322 2323 if (searching) { 2324 if (searching > 0) { 2325 if (stim == lasthist.stim 2326 && histstrcmp(pt, lasthist.text) == 0) 2327 searching = 0; 2328 else { 2329 fseek(in, 0, 0); 2330 histfile_linect = 0; 2331 searching = -1; 2332 } 2333 continue; 2334 } 2335 else if (stim < lasthist.stim) { 2336 histfile_linect++; 2337 continue; 2338 } 2339 searching = 0; 2340 } 2341 2342 if (readflags & HFILE_USE_OPTIONS) { 2343 histfile_linect++; 2344 lasthist.fpos = fpos; 2345 lasthist.stim = stim; 2346 } 2347 2348 he = prepnexthistent(); 2349 he->node.nam = ztrdup(pt); 2350 he->node.flags = newflags; 2351 if ((he->stim = stim) == 0) 2352 he->stim = he->ftim = tim; 2353 else if (ftim < stim) 2354 he->ftim = stim + ftim; 2355 else 2356 he->ftim = ftim; 2357 2358 /* 2359 * Divide up the words. 2360 */ 2361 start = pt; 2362 uselex = isset(HISTLEXWORDS) && !(readflags & HFILE_FAST); 2363 histsplitwords(pt, &words, &nwords, &nwordpos, uselex); 2364 if (uselex) 2365 freeheap(); 2366 2367 he->nwords = nwordpos/2; 2368 if (he->nwords) { 2369 he->words = (short *)zalloc(nwordpos*sizeof(short)); 2370 memcpy(he->words, words, nwordpos*sizeof(short)); 2371 } else 2372 he->words = (short *)NULL; 2373 addhistnode(histtab, he->node.nam, he); 2374 if (he->node.flags & HIST_DUP) { 2375 freehistnode(&he->node); 2376 curhist--; 2377 } 2378 } 2379 if (start && readflags & HFILE_USE_OPTIONS) { 2380 zsfree(lasthist.text); 2381 lasthist.text = ztrdup(start); 2382 } 2383 zfree(words, nwords*sizeof(short)); 2384 zfree(buf, bufsiz); 2385 2386 popheap(); 2387 fclose(in); 2388 } else if (err) 2389 zerr("can't read history file %s", fn); 2390 2391 unlockhistfile(fn); 2392} 2393 2394#ifdef HAVE_FCNTL_H 2395static int flock_fd = -1; 2396 2397/* 2398 * Lock file using fcntl(). Return 0 on success, 1 on failure of 2399 * locking mechanism, 2 on permanent failure (e.g. permission). 2400 */ 2401 2402static int 2403flockhistfile(char *fn, int keep_trying) 2404{ 2405 struct flock lck; 2406 int ctr = keep_trying ? 9 : 0; 2407 2408 if ((flock_fd = open(unmeta(fn), O_RDWR | O_NOCTTY)) < 0) 2409 return errno == ENOENT ? 0 : 2; /* "successfully" locked missing file */ 2410 2411 lck.l_type = F_WRLCK; 2412 lck.l_whence = SEEK_SET; 2413 lck.l_start = 0; 2414 lck.l_len = 0; /* lock the whole file */ 2415 2416 while (fcntl(flock_fd, F_SETLKW, &lck) == -1) { 2417 if (--ctr < 0) { 2418 close(flock_fd); 2419 flock_fd = -1; 2420 return 1; 2421 } 2422 sleep(1); 2423 } 2424 2425 return 0; 2426} 2427#endif 2428 2429/**/ 2430void 2431savehistfile(char *fn, int err, int writeflags) 2432{ 2433 char *t, *tmpfile, *start = NULL; 2434 FILE *out; 2435 Histent he; 2436 zlong xcurhist = curhist - !!(histactive & HA_ACTIVE); 2437 int extended_history = isset(EXTENDEDHISTORY); 2438 int ret; 2439 2440 if (!interact || savehistsiz <= 0 || !hist_ring 2441 || (!fn && !(fn = getsparam("HISTFILE")))) 2442 return; 2443 if (writeflags & HFILE_FAST) { 2444 he = gethistent(lasthist.next_write_ev, GETHIST_DOWNWARD); 2445 while (he && he->node.flags & HIST_OLD) { 2446 lasthist.next_write_ev = he->histnum + 1; 2447 he = down_histent(he); 2448 } 2449 if (!he || lockhistfile(fn, 0)) 2450 return; 2451 if (histfile_linect > savehistsiz + savehistsiz / 5) 2452 writeflags &= ~HFILE_FAST; 2453 } 2454 else { 2455 if (lockhistfile(fn, 1)) { 2456 zerr("locking failed for %s: %e", fn, errno); 2457 return; 2458 } 2459 he = hist_ring->down; 2460 } 2461 if (writeflags & HFILE_USE_OPTIONS) { 2462 if (isset(APPENDHISTORY) || isset(INCAPPENDHISTORY) 2463 || isset(SHAREHISTORY)) 2464 writeflags |= HFILE_APPEND | HFILE_SKIPOLD; 2465 else 2466 histfile_linect = 0; 2467 if (isset(HISTSAVENODUPS)) 2468 writeflags |= HFILE_SKIPDUPS; 2469 if (isset(SHAREHISTORY)) 2470 extended_history = 1; 2471 } 2472 errno = 0; 2473 if (writeflags & HFILE_APPEND) { 2474 int fd = open(unmeta(fn), O_CREAT | O_WRONLY | O_APPEND | O_NOCTTY, 0600); 2475 tmpfile = NULL; 2476 out = fd >= 0 ? fdopen(fd, "a") : NULL; 2477 } else if (!isset(HISTSAVEBYCOPY)) { 2478 int fd = open(unmeta(fn), O_CREAT | O_WRONLY | O_TRUNC | O_NOCTTY, 0600); 2479 tmpfile = NULL; 2480 out = fd >= 0 ? fdopen(fd, "w") : NULL; 2481 } else { 2482 tmpfile = bicat(unmeta(fn), ".new"); 2483 if (unlink(tmpfile) < 0 && errno != ENOENT) 2484 out = NULL; 2485 else { 2486 struct stat sb; 2487 int old_exists = stat(unmeta(fn), &sb) == 0; 2488 uid_t euid = geteuid(); 2489 2490 if (old_exists 2491#if defined HAVE_FCHMOD && defined HAVE_FCHOWN 2492 && euid 2493#endif 2494 && sb.st_uid != euid) { 2495 free(tmpfile); 2496 tmpfile = NULL; 2497 if (err) { 2498 if (isset(APPENDHISTORY) || isset(INCAPPENDHISTORY) 2499 || isset(SHAREHISTORY)) 2500 zerr("rewriting %s would change its ownership -- skipped", fn); 2501 else 2502 zerr("rewriting %s would change its ownership -- history not saved", fn); 2503 err = 0; /* Don't report a generic error below. */ 2504 } 2505 out = NULL; 2506 } else { 2507 int fd = open(tmpfile, O_CREAT | O_WRONLY | O_EXCL, 0600); 2508 out = fd >= 0 ? fdopen(fd, "w") : NULL; 2509 } 2510 2511#ifdef HAVE_FCHMOD 2512 if (old_exists && out) { 2513#ifdef HAVE_FCHOWN 2514 if (fchown(fileno(out), sb.st_uid, sb.st_gid) < 0) {} /* IGNORE FAILURE */ 2515#endif 2516 if (fchmod(fileno(out), sb.st_mode) < 0) {} /* IGNORE FAILURE */ 2517 } 2518#endif 2519 } 2520 } 2521 if (out) { 2522 ret = 0; 2523 for (; he && he->histnum <= xcurhist; he = down_histent(he)) { 2524 if ((writeflags & HFILE_SKIPDUPS && he->node.flags & HIST_DUP) 2525 || (writeflags & HFILE_SKIPFOREIGN && he->node.flags & HIST_FOREIGN) 2526 || he->node.flags & HIST_TMPSTORE) 2527 continue; 2528 if (writeflags & HFILE_SKIPOLD) { 2529 if (he->node.flags & HIST_OLD) 2530 continue; 2531 he->node.flags |= HIST_OLD; 2532 if (writeflags & HFILE_USE_OPTIONS) 2533 lasthist.next_write_ev = he->histnum + 1; 2534 } 2535 if (writeflags & HFILE_USE_OPTIONS) { 2536 lasthist.fpos = ftell(out); 2537 lasthist.stim = he->stim; 2538 histfile_linect++; 2539 } 2540 t = start = he->node.nam; 2541 if (extended_history) { 2542 ret = fprintf(out, ": %ld:%ld;", (long)he->stim, 2543 he->ftim? (long)(he->ftim - he->stim) : 0L); 2544 } else if (*t == ':') 2545 ret = fputc('\\', out); 2546 2547 for (; ret >= 0 && *t; t++) { 2548 if (*t == '\n') 2549 if ((ret = fputc('\\', out)) < 0) 2550 break; 2551 if ((ret = fputc(*t, out)) < 0) 2552 break; 2553 } 2554 if (ret < 0 || (ret = fputc('\n', out)) < 0) 2555 break; 2556 } 2557 if (ret >= 0 && start && writeflags & HFILE_USE_OPTIONS) { 2558 struct stat sb; 2559 if ((ret = fflush(out)) >= 0) { 2560 if (fstat(fileno(out), &sb) == 0) { 2561 lasthist.fsiz = sb.st_size; 2562 lasthist.mtim = sb.st_mtime; 2563 } 2564 zsfree(lasthist.text); 2565 lasthist.text = ztrdup(start); 2566 } 2567 } 2568 if (fclose(out) < 0 && ret >= 0) 2569 ret = -1; 2570 if (ret >= 0) { 2571 if (tmpfile) { 2572 if (rename(tmpfile, unmeta(fn)) < 0) { 2573 zerr("can't rename %s.new to $HISTFILE", fn); 2574 ret = -1; 2575 err = 0; 2576#ifdef HAVE_FCNTL_H 2577 } else { 2578 /* We renamed over the locked HISTFILE, so close fd. 2579 * If we do more writing, we'll get a lock then. */ 2580 if (flock_fd >= 0) { 2581 close(flock_fd); 2582 flock_fd = -1; 2583 } 2584#endif 2585 } 2586 } 2587 2588 if (ret >= 0 && writeflags & HFILE_SKIPOLD 2589 && !(writeflags & (HFILE_FAST | HFILE_NO_REWRITE))) { 2590 int remember_histactive = histactive; 2591 2592 /* Zeroing histactive avoids unnecessary munging of curline. */ 2593 histactive = 0; 2594 /* The NULL leaves HISTFILE alone, preserving fn's value. */ 2595 pushhiststack(NULL, savehistsiz, savehistsiz, -1); 2596 2597 hist_ignore_all_dups |= isset(HISTSAVENODUPS); 2598 readhistfile(fn, err, 0); 2599 hist_ignore_all_dups = isset(HISTIGNOREALLDUPS); 2600 if (histlinect) 2601 savehistfile(fn, err, 0); 2602 2603 pophiststack(); 2604 histactive = remember_histactive; 2605 } 2606 } 2607 } else 2608 ret = -1; 2609 2610 if (ret < 0 && err) { 2611 if (tmpfile) 2612 zerr("failed to write history file %s.new: %e", fn, errno); 2613 else 2614 zerr("failed to write history file %s: %e", fn, errno); 2615 } 2616 if (tmpfile) 2617 free(tmpfile); 2618 2619 unlockhistfile(fn); 2620} 2621 2622static int lockhistct; 2623 2624/* 2625 * Lock history file. Return 0 on success, 1 on failure to lock this 2626 * time, 2 on permanent failure (e.g. permission). 2627 */ 2628 2629/**/ 2630int 2631lockhistfile(char *fn, int keep_trying) 2632{ 2633 int ct = lockhistct; 2634 int ret = 0; 2635 2636 if (!fn && !(fn = getsparam("HISTFILE"))) 2637 return 1; 2638 2639#ifdef HAVE_FCNTL_H 2640 if (isset(HISTFCNTLLOCK) && flock_fd < 0) { 2641 ret = flockhistfile(fn, keep_trying); 2642 if (ret) 2643 return ret; 2644 } 2645#endif 2646 2647 if (!lockhistct++) { 2648 struct stat sb; 2649 int fd; 2650 char *lockfile; 2651#ifdef HAVE_LINK 2652# ifdef HAVE_SYMLINK 2653 char pidbuf[32], *lnk; 2654# else 2655 char *tmpfile; 2656# endif 2657#endif 2658 2659 lockfile = bicat(unmeta(fn), ".LOCK"); 2660 /* NOTE: only use symlink locking on a link()-having host in order to 2661 * avoid a change from open()-based locking to symlink()-based. */ 2662#ifdef HAVE_LINK 2663# ifdef HAVE_SYMLINK 2664 sprintf(pidbuf, "/pid-%ld/host-", (long)mypid); 2665 lnk = bicat(pidbuf, getsparam("HOST")); 2666 /* We'll abuse fd as our success flag. */ 2667 while ((fd = symlink(lnk, lockfile)) < 0) { 2668 if (errno != EEXIST) { 2669 ret = 2; 2670 break; 2671 } else if (!keep_trying) { 2672 ret = 1; 2673 break; 2674 } 2675 if (lstat(lockfile, &sb) < 0) { 2676 if (errno == ENOENT) 2677 continue; 2678 break; 2679 } 2680 if (time(NULL) - sb.st_mtime < 10) 2681 sleep(1); 2682 else 2683 unlink(lockfile); 2684 } 2685 if (fd < 0) 2686 lockhistct--; 2687 free(lnk); 2688# else /* not HAVE_SYMLINK */ 2689 if ((fd = gettempfile(fn, 0, &tmpfile)) >= 0) { 2690 FILE *out = fdopen(fd, "w"); 2691 if (out) { 2692 fprintf(out, "%ld %s\n", (long)getpid(), getsparam("HOST")); 2693 fclose(out); 2694 } else 2695 close(fd); 2696 while (link(tmpfile, lockfile) < 0) { 2697 if (errno != EEXIST) { 2698 ret = 2; 2699 break; 2700 } else if (!keep_trying) { 2701 ret = 1; 2702 break; 2703 } else if (lstat(lockfile, &sb) < 0) { 2704 if (errno == ENOENT) 2705 continue; 2706 ret = 2; 2707 } else { 2708 if (time(NULL) - sb.st_mtime < 10) 2709 sleep(1); 2710 else 2711 unlink(lockfile); 2712 continue; 2713 } 2714 lockhistct--; 2715 break; 2716 } 2717 unlink(tmpfile); 2718 free(tmpfile); 2719 } 2720# endif /* not HAVE_SYMLINK */ 2721#else /* not HAVE_LINK */ 2722 while ((fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL, 0644)) < 0) { 2723 if (errno != EEXIST) { 2724 ret = 2; 2725 break; 2726 } else if (!keep_trying) { 2727 ret = 1; 2728 break; 2729 } 2730 if (lstat(lockfile, &sb) < 0) { 2731 if (errno == ENOENT) 2732 continue; 2733 ret = 2; 2734 break; 2735 } 2736 if (time(NULL) - sb.st_mtime < 10) 2737 sleep(1); 2738 else 2739 unlink(lockfile); 2740 } 2741 if (fd < 0) 2742 lockhistct--; 2743 else { 2744 FILE *out = fdopen(fd, "w"); 2745 if (out) { 2746 fprintf(out, "%ld %s\n", (long)mypid, getsparam("HOST")); 2747 fclose(out); 2748 } else 2749 close(fd); 2750 } 2751#endif /* not HAVE_LINK */ 2752 free(lockfile); 2753 } 2754 2755 if (ct == lockhistct) { 2756#ifdef HAVE_FCNTL_H 2757 if (flock_fd >= 0) { 2758 close(flock_fd); 2759 flock_fd = -1; 2760 } 2761#endif 2762 DPUTS(ret == 0, "BUG: return value non-zero on locking error"); 2763 return ret; 2764 } 2765 return 0; 2766} 2767 2768/* Unlock the history file if this corresponds to the last nested lock 2769 * request. If we don't have the file locked, just return. 2770 */ 2771 2772/**/ 2773void 2774unlockhistfile(char *fn) 2775{ 2776 if (!fn && !(fn = getsparam("HISTFILE"))) 2777 return; 2778 if (--lockhistct) { 2779 if (lockhistct < 0) 2780 lockhistct = 0; 2781 } 2782 else { 2783 char *lockfile; 2784 fn = unmeta(fn); 2785 lockfile = zalloc(strlen(fn) + 5 + 1); 2786 sprintf(lockfile, "%s.LOCK", fn); 2787 unlink(lockfile); 2788 free(lockfile); 2789#ifdef HAVE_FCNTL_H 2790 if (flock_fd >= 0) { 2791 close(flock_fd); 2792 flock_fd = -1; 2793 } 2794#endif 2795 } 2796} 2797 2798/**/ 2799int 2800histfileIsLocked(void) 2801{ 2802 return lockhistct > 0; 2803} 2804 2805/* 2806 * Get the words in the current buffer. Using the lexer. 2807 * 2808 * As far as I can make out, this is a gross hack based on a gross hack. 2809 * When analysing lines from within zle, we tweak the metafied line 2810 * positions (zlemetall and zlemetacs) directly in the lexer. That's 2811 * bad enough, but this function appears to be designed to be called 2812 * from outside zle, pretending to be in zle and calling out, so 2813 * we set zlemetall and zlemetacs locally and copy the current zle line, 2814 * which may not even be valid at this point. 2815 * 2816 * However, I'm so confused it could simply be baking Bakewell tarts. 2817 * 2818 * list may be an existing linked list (off the heap), in which case 2819 * it will be appended to; otherwise it will be created. 2820 * 2821 * If buf is set we will take input from that string, else we will 2822 * attempt to use ZLE directly in a way they tell you not to do on all 2823 * programming courses. 2824 * 2825 * If index is non-NULL, and input is from a string in ZLE, *index 2826 * is set to the position of the end of the current editor word. 2827 * 2828 * flags is passed directly to lexflags, see lex.c, except that 2829 * we 'or' in the bit LEXFLAGS_ACTIVE to make sure the variable 2830 * is set. 2831 */ 2832 2833/**/ 2834mod_export LinkList 2835bufferwords(LinkList list, char *buf, int *index, int flags) 2836{ 2837 int num = 0, cur = -1, got = 0, ne = noerrs; 2838 int owb = wb, owe = we, oadx = addedx, onc = nocomments; 2839 int ona = noaliases, ocs = zlemetacs, oll = zlemetall; 2840 int forloop = 0, rcquotes = opts[RCQUOTES]; 2841 char *p, *addedspaceptr; 2842 2843 if (!list) 2844 list = newlinklist(); 2845 2846 /* 2847 * With RC_QUOTES, 'foo '' bar' comes back as 'foo ' bar'. That's 2848 * not very useful. As nothing in here requires the fully processed 2849 * string expression, we just turn the option off for this function. 2850 */ 2851 opts[RCQUOTES] = 0; 2852 addedx = 0; 2853 noerrs = 1; 2854 lexsave(); 2855 lexflags = flags | LEXFLAGS_ACTIVE; 2856 /* 2857 * Are we handling comments? 2858 */ 2859 nocomments = !(flags & (LEXFLAGS_COMMENTS_KEEP| 2860 LEXFLAGS_COMMENTS_STRIP)); 2861 if (buf) { 2862 int l = strlen(buf); 2863 2864 p = (char *) zhalloc(l + 2); 2865 memcpy(p, buf, l); 2866 /* 2867 * I'm sure this space is here for a reason, but it's 2868 * a pain in the neck: when we get back a string that's 2869 * not finished it's very hard to tell if a space at the 2870 * end is this one or not. We use two tricks below to 2871 * work around this. 2872 */ 2873 addedspaceptr = p + l; 2874 *addedspaceptr = ' '; 2875 addedspaceptr[1] = '\0'; 2876 inpush(p, 0, NULL); 2877 zlemetall = strlen(p) ; 2878 zlemetacs = zlemetall + 1; 2879 } else { 2880 int ll, cs; 2881 char *linein; 2882 2883 linein = zleentry(ZLE_CMD_GET_LINE, &ll, &cs); 2884 zlemetall = ll + 1; /* length of line plus space added below */ 2885 zlemetacs = cs; 2886 2887 if (!isfirstln && chline) { 2888 p = (char *) zhalloc(hptr - chline + ll + 2); 2889 memcpy(p, chline, hptr - chline); 2890 memcpy(p + (hptr - chline), linein, ll); 2891 addedspaceptr = p + (hptr - chline) + ll; 2892 *addedspaceptr = ' '; 2893 addedspaceptr[1] = '\0'; 2894 inpush(p, 0, NULL); 2895 2896 /* 2897 * advance line length and character position over 2898 * prepended string. 2899 */ 2900 zlemetall += hptr - chline; 2901 zlemetacs += hptr - chline; 2902 } else { 2903 p = (char *) zhalloc(ll + 2); 2904 memcpy(p, linein, ll); 2905 addedspaceptr = p + ll; 2906 *addedspaceptr = ' '; 2907 p[zlemetall] = '\0'; 2908 inpush(p, 0, NULL); 2909 } 2910 zsfree(linein); 2911 } 2912 if (zlemetacs) 2913 zlemetacs--; 2914 strinbeg(0); 2915 noaliases = 1; 2916 do { 2917 if (incond) 2918 incond = 1 + (tok != DINBRACK && tok != INPAR && 2919 tok != DBAR && tok != DAMPER && 2920 tok != BANG); 2921 ctxtlex(); 2922 if (tok == ENDINPUT || tok == LEXERR) 2923 break; 2924 if (tok == FOR) { 2925 /* 2926 * The way for (( expr1 ; expr2; expr3 )) is parsed is: 2927 * - a FOR tok 2928 * - a DINPAR with no tokstr 2929 * - two DINPARS with tokstr's expr1, expr2. 2930 * - a DOUTPAR with tokstr expr3. 2931 * 2932 * We'll decrement the variable forloop as we verify 2933 * the various stages. 2934 * 2935 * Don't ask me, ma'am, I'm just the programmer. 2936 */ 2937 forloop = 5; 2938 } else { 2939 switch (forloop) { 2940 case 1: 2941 if (tok != DOUTPAR) 2942 forloop = 0; 2943 break; 2944 2945 case 2: 2946 case 3: 2947 case 4: 2948 if (tok != DINPAR) 2949 forloop = 0; 2950 break; 2951 2952 default: 2953 /* nothing to do */ 2954 break; 2955 } 2956 } 2957 if (tokstr) { 2958 switch (tok) { 2959 case ENVARRAY: 2960 p = dyncat(tokstr, "=("); 2961 break; 2962 2963 case DINPAR: 2964 if (forloop) { 2965 /* See above. */ 2966 p = dyncat(tokstr, ";"); 2967 } else { 2968 /* 2969 * Mathematical expressions analysed as a single 2970 * word. That's correct because it behaves like 2971 * double quotes. Whitespace in the middle is 2972 * similarly retained, so just add the parentheses back. 2973 */ 2974 p = tricat("((", tokstr, "))"); 2975 } 2976 break; 2977 2978 default: 2979 p = dupstring(tokstr); 2980 break; 2981 } 2982 if (*p) { 2983 untokenize(p); 2984 if (ingetptr() == addedspaceptr + 1) { 2985 /* 2986 * Whoops, we've read past the space we added, probably 2987 * because we were expecting a terminator but when 2988 * it didn't turn up we shrugged our shoulders thinking 2989 * it might as well be a complete string anyway. 2990 * So remove the space. C.f. below for the case 2991 * where the missing terminator caused a lex error. 2992 * We use the same paranoid test. 2993 */ 2994 int plen = strlen(p); 2995 if (plen && p[plen-1] == ' ' && 2996 (plen == 1 || p[plen-2] != Meta)) 2997 p[plen-1] = '\0'; 2998 } 2999 addlinknode(list, p); 3000 num++; 3001 } 3002 } else if (buf) { 3003 if (IS_REDIROP(tok) && tokfd >= 0) { 3004 char b[20]; 3005 3006 sprintf(b, "%d%s", tokfd, tokstrings[tok]); 3007 addlinknode(list, dupstring(b)); 3008 num++; 3009 } else if (tok != NEWLIN) { 3010 addlinknode(list, dupstring(tokstrings[tok])); 3011 num++; 3012 } 3013 } 3014 if (forloop) { 3015 if (forloop == 1) { 3016 /* 3017 * Final "))" of for loop to match opening, 3018 * since we've just added the preceding element. 3019 */ 3020 addlinknode(list, dupstring("))")); 3021 } 3022 forloop--; 3023 } 3024 if (!got && !lexflags) { 3025 got = 1; 3026 cur = num - 1; 3027 } 3028 } while (tok != ENDINPUT && tok != LEXERR); 3029 if (buf && tok == LEXERR && tokstr && *tokstr) { 3030 int plen; 3031 untokenize((p = dupstring(tokstr))); 3032 plen = strlen(p); 3033 /* 3034 * Strip the space we added for lexing but which won't have 3035 * been swallowed by the lexer because we aborted early. 3036 * The test is paranoia. 3037 */ 3038 if (plen && p[plen-1] == ' ' && (plen == 1 || p[plen-2] != Meta)) 3039 p[plen - 1] = '\0'; 3040 addlinknode(list, p); 3041 num++; 3042 } 3043 if (cur < 0 && num) 3044 cur = num - 1; 3045 noaliases = ona; 3046 strinend(); 3047 inpop(); 3048 errflag = 0; 3049 nocomments = onc; 3050 noerrs = ne; 3051 lexrestore(); 3052 zlemetacs = ocs; 3053 zlemetall = oll; 3054 wb = owb; 3055 we = owe; 3056 addedx = oadx; 3057 opts[RCQUOTES] = rcquotes; 3058 3059 if (index) 3060 *index = cur; 3061 3062 return list; 3063} 3064 3065/* 3066 * Split up a line into words for use in a history file. 3067 * 3068 * lineptr is the line to be split. 3069 * 3070 * *wordsp and *nwordsp are an array already allocated to hold words 3071 * and its length. The array holds both start and end positions, 3072 * so *nwordsp actually counts twice the number of words in the 3073 * original string. *nwordsp may be zero in which case the array 3074 * will be allocated. 3075 * 3076 * *nwordposp returns the used length of *wordsp in the same units as 3077 * *nwordsp, i.e. twice the number of words in the input line. 3078 * 3079 * If uselex is 1, attempt to do this using the lexical analyser. 3080 * This is more accurate, but slower; for reading history files it's 3081 * controlled by the option HISTLEXWORDS. If this failed (which 3082 * indicates a bug in the shell) it falls back to whitespace-separated 3083 * strings, printing a message if in debug mode. 3084 * 3085 * If uselex is 0, just look for whitespace-separated words; the only 3086 * special handling is for a backslash-newline combination as used 3087 * by the history file format to save multiline buffers. 3088 */ 3089/**/ 3090mod_export void 3091histsplitwords(char *lineptr, short **wordsp, int *nwordsp, int *nwordposp, 3092 int uselex) 3093{ 3094 int nwords = *nwordsp, nwordpos = 0; 3095 short *words = *wordsp; 3096 char *start = lineptr; 3097 3098 if (uselex) { 3099 LinkList wordlist = bufferwords(NULL, lineptr, NULL, 3100 LEXFLAGS_COMMENTS_KEEP); 3101 LinkNode wordnode; 3102 int nwords_max; 3103 3104 nwords_max = 2 * countlinknodes(wordlist); 3105 if (nwords_max > nwords) { 3106 *nwordsp = nwords = nwords_max; 3107 *wordsp = words = (short *)zrealloc(words, nwords*sizeof(short)); 3108 } 3109 for (wordnode = firstnode(wordlist); 3110 wordnode; 3111 incnode(wordnode)) { 3112 char *word = getdata(wordnode); 3113 char *lptr, *wptr = word; 3114 int loop_next = 0, skipping; 3115 3116 /* Skip stuff at the start of the word */ 3117 for (;;) { 3118 /* 3119 * Not really an oddity: "\\\n" is 3120 * removed from input as if whitespace. 3121 */ 3122 if (inblank(*lineptr)) 3123 lineptr++; 3124 else if (lineptr[0] == '\\' && lineptr[1] == '\n') { 3125 /* 3126 * Optimisation: we handle this in the loop below, 3127 * too. 3128 */ 3129 lineptr += 2; 3130 } else 3131 break; 3132 } 3133 lptr = lineptr; 3134 /* 3135 * Skip chunks of word with possible intervening 3136 * backslash-newline. 3137 * 3138 * To get round C's annoying lack of ability to 3139 * reference the outer loop, we'll break from this 3140 * one with 3141 * loop_next = 0: carry on as normal 3142 * loop_next = 1: break from outer loop 3143 * loop_next = 2: continue round outer loop. 3144 */ 3145 do { 3146 skipping = 0; 3147 if (strpfx(wptr, lptr)) { 3148 /* 3149 * Normal case: word from lexer matches start of 3150 * string from line. Just advance over it. 3151 */ 3152 int len; 3153 if (!strcmp(wptr, ";") && strpfx(";;", lptr)) { 3154 /* 3155 * Don't get confused between a semicolon that's 3156 * probably really a newline and a double 3157 * semicolon that's terminating a case. 3158 */ 3159 loop_next = 2; 3160 break; 3161 } 3162 len = strlen(wptr); 3163 lptr += len; 3164 wptr += len; 3165 } else { 3166 /* 3167 * Didn't get to the end of the word. 3168 * See what's amiss. 3169 */ 3170 int bad = 0; 3171 /* 3172 * Oddity 1: newlines turn into semicolons. 3173 */ 3174 if (!strcmp(wptr, ";")) 3175 { 3176 loop_next = 2; 3177 break; 3178 } 3179 while (*lptr) { 3180 if (!*wptr) { 3181 /* 3182 * End of the word before the end of the 3183 * line: not good. 3184 */ 3185 bad = 1; 3186 loop_next = 1; 3187 break; 3188 } 3189 /* 3190 * Oddity 2: !'s turn into |'s. 3191 */ 3192 if (*lptr == *wptr || 3193 (*lptr == '!' && *wptr == '|')) { 3194 lptr++; 3195 wptr++; 3196 } else if (lptr[0] == '\\' && 3197 lptr[1] == '\n') { 3198 /* 3199 * \\\n can occur in the middle of a word; 3200 * wptr is already pointing at this, we 3201 * just need to skip over the break 3202 * in lptr and look at the next chunk. 3203 */ 3204 lptr += 2; 3205 skipping = 1; 3206 break; 3207 } else { 3208 bad = 1; 3209 loop_next = 1; 3210 break; 3211 } 3212 } 3213 if (bad) { 3214#ifdef DEBUG 3215 dputs(ERRMSG("bad wordsplit reading history: " 3216 "%s\nat: %s\nword: %s"), 3217 start, lineptr, word); 3218#endif 3219 lineptr = start; 3220 nwordpos = 0; 3221 uselex = 0; 3222 loop_next = 1; 3223 } 3224 } 3225 } while (skipping); 3226 if (loop_next) { 3227 if (loop_next == 1) 3228 break; 3229 continue; 3230 } 3231 /* Record position of current word... */ 3232 words[nwordpos++] = lineptr - start; 3233 words[nwordpos++] = lptr - start; 3234 3235 /* ready for start of next word. */ 3236 lineptr = lptr; 3237 } 3238 } 3239 if (!uselex) { 3240 do { 3241 for (;;) { 3242 if (inblank(*lineptr)) 3243 lineptr++; 3244 else if (lineptr[0] == '\\' && lineptr[1] == '\n') 3245 lineptr += 2; 3246 else 3247 break; 3248 } 3249 if (*lineptr) { 3250 if (nwordpos >= nwords) { 3251 *nwordsp = nwords = nwords + 64; 3252 *wordsp = words = (short *) 3253 zrealloc(words, nwords*sizeof(*words)); 3254 } 3255 words[nwordpos++] = lineptr - start; 3256 while (*lineptr && !inblank(*lineptr)) 3257 lineptr++; 3258 words[nwordpos++] = lineptr - start; 3259 } 3260 } while (*lineptr); 3261 } 3262 3263 *nwordposp = nwordpos; 3264} 3265 3266/* Move the current history list out of the way and prepare a fresh history 3267 * list using hf for HISTFILE, hs for HISTSIZE, and shs for SAVEHIST. If 3268 * the hf value is an empty string, HISTFILE will be unset from the new 3269 * environment; if it is NULL, HISTFILE will not be changed, not even by the 3270 * pop function (this functionality is used internally to rewrite the current 3271 * history file without affecting pointers into the environment). 3272 */ 3273 3274/**/ 3275int 3276pushhiststack(char *hf, zlong hs, zlong shs, int level) 3277{ 3278 struct histsave *h; 3279 int curline_in_ring = (histactive & HA_ACTIVE) && hist_ring == &curline; 3280 3281 if (histsave_stack_pos == histsave_stack_size) { 3282 histsave_stack_size += 5; 3283 histsave_stack = zrealloc(histsave_stack, 3284 histsave_stack_size * sizeof (struct histsave)); 3285 } 3286 3287 if (curline_in_ring) 3288 unlinkcurline(); 3289 3290 h = &histsave_stack[histsave_stack_pos++]; 3291 3292 h->lasthist = lasthist; 3293 if (hf) { 3294 if ((h->histfile = getsparam("HISTFILE")) != NULL && *h->histfile) 3295 h->histfile = ztrdup(h->histfile); 3296 else 3297 h->histfile = ""; 3298 } else 3299 h->histfile = NULL; 3300 h->histtab = histtab; 3301 h->hist_ring = hist_ring; 3302 h->curhist = curhist; 3303 h->histlinect = histlinect; 3304 h->histsiz = histsiz; 3305 h->savehistsiz = savehistsiz; 3306 h->locallevel = level; 3307 3308 memset(&lasthist, 0, sizeof lasthist); 3309 if (hf) { 3310 if (*hf) 3311 setsparam("HISTFILE", ztrdup(hf)); 3312 else 3313 unsetparam("HISTFILE"); 3314 } 3315 hist_ring = NULL; 3316 curhist = histlinect = 0; 3317 histsiz = hs; 3318 savehistsiz = shs; 3319 inithist(); /* sets histtab */ 3320 3321 if (curline_in_ring) 3322 linkcurline(); 3323 3324 return histsave_stack_pos; 3325} 3326 3327 3328/**/ 3329int 3330pophiststack(void) 3331{ 3332 struct histsave *h; 3333 int curline_in_ring = (histactive & HA_ACTIVE) && hist_ring == &curline; 3334 3335 if (histsave_stack_pos == 0) 3336 return 0; 3337 3338 if (curline_in_ring) 3339 unlinkcurline(); 3340 3341 deletehashtable(histtab); 3342 zsfree(lasthist.text); 3343 3344 h = &histsave_stack[--histsave_stack_pos]; 3345 3346 lasthist = h->lasthist; 3347 if (h->histfile) { 3348 if (*h->histfile) 3349 setsparam("HISTFILE", h->histfile); 3350 else 3351 unsetparam("HISTFILE"); 3352 } 3353 histtab = h->histtab; 3354 hist_ring = h->hist_ring; 3355 curhist = h->curhist; 3356 histlinect = h->histlinect; 3357 histsiz = h->histsiz; 3358 savehistsiz = h->savehistsiz; 3359 3360 if (curline_in_ring) 3361 linkcurline(); 3362 3363 return histsave_stack_pos + 1; 3364} 3365 3366/* If pop_through > 0, pop all array items >= the 1-relative index value. 3367 * If pop_through <= 0, pop (-1)*pop_through levels off the stack. 3368 * If the (new) top of stack is from a higher locallevel, auto-pop until 3369 * it is not. 3370 */ 3371 3372/**/ 3373int 3374saveandpophiststack(int pop_through, int writeflags) 3375{ 3376 if (pop_through <= 0) { 3377 pop_through += histsave_stack_pos + 1; 3378 if (pop_through <= 0) 3379 pop_through = 1; 3380 } 3381 while (pop_through > 1 3382 && histsave_stack[pop_through-2].locallevel > locallevel) 3383 pop_through--; 3384 if (histsave_stack_pos < pop_through) 3385 return 0; 3386 do { 3387 if (!nohistsave) 3388 savehistfile(NULL, 1, writeflags); 3389 pophiststack(); 3390 } while (histsave_stack_pos >= pop_through); 3391 return 1; 3392} 3393