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