tonyb@daemon.UUCP (Tony Birnseth) (04/29/85)
Index: /usr/src/bin/csh/{sh.c,sh.hist.c,sh.lex.c} Description: The original problem was from the statement in the man page regarding relative history events: "A history reference may be given without an event specification e.g. '!$'. In this case the reference is to the previous command unless a previous history reference occurred on the same line in which case this form repeats the previous reference." Current implementation does not function that way. Relative history commands !{$,*,etc.} are always relative to the current command line. Repeat-By: % echo foo foo % cat /etc/printcap > /dev/null % !?foo?^ !$ echo /dev/null /dev/null Fix: Current behavior: The history reference is reset to the current event every time a history character is encountered. This prevents relative history characters from ever referencing anything but the previous command line. It became obvious, that to keep the aliasing mechanism functioning for substitution of "current command line arguments", Berkeley chose an implementation that forces the history to be relative to the current command. e.g. 'alias echo "/bin/echo \!*"' would echo its arguments. This is accomplished by pushing the history onto the history list, increment the event number, set the "last event" counter equal to the current event (which hasn't happened yet), then expand any history within aliases. (yuk!) Unfortunately, this breaks the relative nature of the history characters. (wouldn't it have been simpler to have a modifier that referenced the current line?) Psuedo Code (for comprehension) Old Version: Get a line parse into words expand any ! or $ if( any ! ) set last event = current event (relative referencing is ALWAYS relative to current event.) BUG! save the history increment the current event. BUG! if(error) break (actually longjump) expand aliasing if( any ! in alias itself ) set last event=current event. BUG! (relative reference is relative to next event, which hasn't happened yet.) (This effect must be maintained) execute the command line continue Needed changes: 1) Initialize the last event before any parsing occurs so that relative history references are truly relative if the history reference is reset. (ie !?foo?^ !$) 2) Save the history, but do not increment the current event until after the aliasing occurs. The current event is added to the history list. This allows '^' substitution on errors. 3) Increment the current event after aliasing occurs or if errors are encountered. Scenario now looks like: New version: get a line set last event = current event parse into words expand any ! or $ save history if(error) increment current event break expand aliases if(any ! in alias itself) expand it, maintain relativity by setting the next event in the history stack, but don't increment the event counter. execute the command line increment event number. continue Relative history is now relative. The aliasing behavior involving relative history is maintained. The changes were to: 1) Move initialization of lastev from getexcl() in sh.lex.c to process() in sh.c. 2) pass eventno + 1 as a parameter to enthist() from savehist() in sh.hist.c instead of ++eventno. 3) increment eventno after alias expansion has occurred in process() in sh.c, or if an error occurred during parsing. Tony Birnseth =============================================================================== | Real | Virtual | | ---- | ------- | | Small Systems Support Group | | | Computer Resource Dept. | USENET ../{ucbvax,decvax}!tektronix!tonyb| | Tektronix Inc. 19-333 | CSNET tonyb@tektronix.csnet | | P.O. Box 500 | ARPAnet tonyb%tektronix@csnet-relay.ARPA | | Beaverton, Or. 97077 | Ma Bell - (503) 627-5394 | =============================================================================== The Diffs: Line numbers will differ. ================================================================================ RCS file: RCS/sh.c,v Retrieving revision 1.2 diff -b -r1.2 sh.c 770a771,776 > * Initialize the last event here so that relative history > * accesses (ie !$ !*) remain relative. > */ > lastev = eventno; > > /* 801c807,813 < error(err); --- > /* > * It would be nice if we could bury eventno++ in > * error(). > * To many "uninteresting events" use error() to > * jump back here. > */ > eventno++, error(err); 808c820 < reset(); --- > eventno++, reset(); 817c829,839 < error(err); --- > eventno++, error(err); > > /* > * Increment the acutal event number here. > * If we waited till after execute(), interupted commands > * would not get their history counter incremented. > * We pad the eventno when savehist() above calls enthist() > * to place the current command in the history list. > */ > if ( t && intty && !whyles ) > eventno++; =================================================================== RCS file: RCS/sh.hist.c,v Retrieving revision 1.2 diff -b -r1.2 sh.hist.c 49c49 < enthist(++eventno, sp, 1); --- > enthist(eventno + 1, sp, 1); =================================================================== RCS file: RCS/sh.lex.c,v Retrieving revision 1.1 diff -b -r1.1 sh.lex.c 474c474 < lastev = eventno; --- > /* lastev = eventno; removed from here and done in process() in sh.c */