The libedit implementation of history_get() also differs from the GNU
implementation: libedit goes to the entry with the given number stored in the HistEvent structure, while GNU subtracts history_base, then advances that many entries from the oldest one. If entries were removed in between, GNU advances further than libedit. The call sequence H_CURR, H_DELDATA, H_CURR, H_NEXT_EVDATA looks weird, as if part of that must somehow be redundant. But actually, the user interface is so counter-intuitive that every single step is really required. - The first H_CURR is needed to be able to go back after an error. - The H_DELDATA is needed to move the cursor. Even though it takes a pointer to ev, that structure is not filled in when the call succeeds. H_DELDATA only moves the cursor, it doesn't tell us the new event number. - Consequently, the second H_CURR is required to get ev.num filled in. But it doesn't return the data because ev has no field for that. - So even though the cursor is already positioned correctly, H_NEXT_EVDATA is needed as the final step merely to get the data. (Ingo Schwarze)
This commit is contained in:
parent
8a99e51de9
commit
05b61ce72a
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: readline.c,v 1.130 2016/05/08 20:15:00 christos Exp $ */
|
||||
/* $NetBSD: readline.c,v 1.131 2016/05/09 21:25:11 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1997 The NetBSD Foundation, Inc.
|
||||
|
@ -31,7 +31,7 @@
|
|||
|
||||
#include "config.h"
|
||||
#if !defined(lint) && !defined(SCCSID)
|
||||
__RCSID("$NetBSD: readline.c,v 1.130 2016/05/08 20:15:00 christos Exp $");
|
||||
__RCSID("$NetBSD: readline.c,v 1.131 2016/05/09 21:25:11 christos Exp $");
|
||||
#endif /* not lint && not SCCSID */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
@ -1400,25 +1400,37 @@ history_get(int num)
|
|||
if (h == NULL || e == NULL)
|
||||
rl_initialize();
|
||||
|
||||
if (num < history_base)
|
||||
return NULL;
|
||||
|
||||
/* save current position */
|
||||
if (history(h, &ev, H_CURR) != 0)
|
||||
return NULL;
|
||||
curr_num = ev.num;
|
||||
|
||||
/* start from the oldest */
|
||||
if (history(h, &ev, H_LAST) != 0)
|
||||
return NULL; /* error */
|
||||
|
||||
/* look forwards for event matching specified offset */
|
||||
if (history(h, &ev, H_NEXT_EVDATA, num, &she.data))
|
||||
return NULL;
|
||||
/*
|
||||
* use H_DELDATA to set to nth history (without delete) by passing
|
||||
* (void **)-1 -- as in history_set_pos
|
||||
*/
|
||||
if (history(h, &ev, H_DELDATA, num - history_base, (void **)-1) != 0)
|
||||
goto out;
|
||||
|
||||
/* get current entry */
|
||||
if (history(h, &ev, H_CURR) != 0)
|
||||
goto out;
|
||||
if (history(h, &ev, H_NEXT_EVDATA, ev.num, &she.data) != 0)
|
||||
goto out;
|
||||
she.line = ev.str;
|
||||
|
||||
/* restore pointer to where it was */
|
||||
(void)history(h, &ev, H_SET, curr_num);
|
||||
|
||||
return &she;
|
||||
|
||||
out:
|
||||
/* restore pointer to where it was */
|
||||
(void)history(h, &ev, H_SET, curr_num);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue