summaryrefslogtreecommitdiffstats
path: root/lib/libedit/history.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libedit/history.c')
-rw-r--r--lib/libedit/history.c258
1 files changed, 189 insertions, 69 deletions
diff --git a/lib/libedit/history.c b/lib/libedit/history.c
index f2e6aee..af4892a 100644
--- a/lib/libedit/history.c
+++ b/lib/libedit/history.c
@@ -13,11 +13,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
@@ -33,7 +29,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $NetBSD: history.c,v 1.16 2000/09/04 22:06:30 lukem Exp $
+ * $NetBSD: history.c,v 1.31 2005/08/01 14:34:06 christos Exp $
*/
#if !defined(lint) && !defined(SCCSID)
@@ -71,10 +67,12 @@ struct history {
history_gfun_t h_prev; /* Get the previous element */
history_gfun_t h_curr; /* Get the current element */
history_sfun_t h_set; /* Set the current element */
+ history_sfun_t h_del; /* Set the given element */
history_vfun_t h_clear; /* Clear the history list */
history_efun_t h_enter; /* Add an element */
history_efun_t h_add; /* Append to an element */
};
+
#define HNEXT(h, ev) (*(h)->h_next)((h)->h_ref, ev)
#define HFIRST(h, ev) (*(h)->h_first)((h)->h_ref, ev)
#define HPREV(h, ev) (*(h)->h_prev)((h)->h_ref, ev)
@@ -84,14 +82,24 @@ struct history {
#define HCLEAR(h, ev) (*(h)->h_clear)((h)->h_ref, ev)
#define HENTER(h, ev, str) (*(h)->h_enter)((h)->h_ref, ev, str)
#define HADD(h, ev, str) (*(h)->h_add)((h)->h_ref, ev, str)
+#define HDEL(h, ev, n) (*(h)->h_del)((h)->h_ref, ev, n)
+#define h_strdup(a) strdup(a)
#define h_malloc(a) malloc(a)
#define h_realloc(a, b) realloc((a), (b))
#define h_free(a) free(a)
+typedef struct {
+ int num;
+ char *str;
+} HistEventPrivate;
+
+
private int history_setsize(History *, HistEvent *, int);
private int history_getsize(History *, HistEvent *);
+private int history_setunique(History *, HistEvent *, int);
+private int history_getunique(History *, HistEvent *);
private int history_set_fun(History *, History *);
private int history_load(History *, const char *);
private int history_save(History *, const char *);
@@ -110,31 +118,41 @@ typedef struct hentry_t {
HistEvent ev; /* What we return */
struct hentry_t *next; /* Next entry */
struct hentry_t *prev; /* Previous entry */
-} hentry_t;
+} hentry_t;
typedef struct history_t {
- hentry_t list; /* Fake list header element */
- hentry_t *cursor; /* Current element in the list */
- int max; /* Maximum number of events */
- int cur; /* Current number of events */
+ hentry_t list; /* Fake list header element */
+ hentry_t *cursor; /* Current element in the list */
+ int max; /* Maximum number of events */
+ int cur; /* Current number of events */
int eventid; /* For generation of unique event id */
-} history_t;
+ int flags; /* History flags */
+#define H_UNIQUE 1 /* Store only unique elements */
+} history_t;
-private int history_def_first(ptr_t, HistEvent *);
-private int history_def_last(ptr_t, HistEvent *);
private int history_def_next(ptr_t, HistEvent *);
+private int history_def_first(ptr_t, HistEvent *);
private int history_def_prev(ptr_t, HistEvent *);
+private int history_def_last(ptr_t, HistEvent *);
private int history_def_curr(ptr_t, HistEvent *);
-private int history_def_set(ptr_t, HistEvent *, const int n);
+private int history_def_set(ptr_t, HistEvent *, const int);
+private void history_def_clear(ptr_t, HistEvent *);
private int history_def_enter(ptr_t, HistEvent *, const char *);
private int history_def_add(ptr_t, HistEvent *, const char *);
-private void history_def_init(ptr_t *, HistEvent *, int);
-private void history_def_clear(ptr_t, HistEvent *);
+private int history_def_del(ptr_t, HistEvent *, const int);
+
+private int history_def_init(ptr_t *, HistEvent *, int);
private int history_def_insert(history_t *, HistEvent *, const char *);
private void history_def_delete(history_t *, HistEvent *, hentry_t *);
-#define history_def_setsize(p, num)(void) (((history_t *) p)->max = (num))
-#define history_def_getsize(p) (((history_t *) p)->cur)
+#define history_def_setsize(p, num)(void) (((history_t *)p)->max = (num))
+#define history_def_getsize(p) (((history_t *)p)->cur)
+#define history_def_getunique(p) (((((history_t *)p)->flags) & H_UNIQUE) != 0)
+#define history_def_setunique(p, uni) \
+ if (uni) \
+ (((history_t *)p)->flags) |= H_UNIQUE; \
+ else \
+ (((history_t *)p)->flags) &= ~H_UNIQUE
#define he_strerror(code) he_errlist[code]
#define he_seterrev(evp, code) {\
@@ -227,20 +245,19 @@ history_def_next(ptr_t p, HistEvent *ev)
{
history_t *h = (history_t *) p;
- if (h->cursor != &h->list)
- h->cursor = h->cursor->next;
- else {
+ if (h->cursor == &h->list) {
he_seterrev(ev, _HE_EMPTY_LIST);
return (-1);
}
- if (h->cursor != &h->list)
- *ev = h->cursor->ev;
- else {
+ if (h->cursor->next == &h->list) {
he_seterrev(ev, _HE_END_REACHED);
return (-1);
}
+ h->cursor = h->cursor->next;
+ *ev = h->cursor->ev;
+
return (0);
}
@@ -253,21 +270,20 @@ history_def_prev(ptr_t p, HistEvent *ev)
{
history_t *h = (history_t *) p;
- if (h->cursor != &h->list)
- h->cursor = h->cursor->prev;
- else {
+ if (h->cursor == &h->list) {
he_seterrev(ev,
(h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
return (-1);
}
- if (h->cursor != &h->list)
- *ev = h->cursor->ev;
- else {
+ if (h->cursor->prev == &h->list) {
he_seterrev(ev, _HE_START_REACHED);
return (-1);
}
+ h->cursor = h->cursor->prev;
+ *ev = h->cursor->ev;
+
return (0);
}
@@ -328,39 +344,59 @@ history_def_add(ptr_t p, HistEvent *ev, const char *str)
history_t *h = (history_t *) p;
size_t len;
char *s;
+ HistEventPrivate *evp = (void *)&h->cursor->ev;
if (h->cursor == &h->list)
return (history_def_enter(p, ev, str));
- len = strlen(h->cursor->ev.str) + strlen(str) + 1;
+ len = strlen(evp->str) + strlen(str) + 1;
s = (char *) h_malloc(len);
- if (!s) {
+ if (s == NULL) {
he_seterrev(ev, _HE_MALLOC_FAILED);
return (-1);
}
(void) strlcpy(s, h->cursor->ev.str, len);
(void) strlcat(s, str, len);
- /* LINTED const cast */
- h_free((ptr_t) h->cursor->ev.str);
- h->cursor->ev.str = s;
+ h_free((ptr_t)evp->str);
+ evp->str = s;
*ev = h->cursor->ev;
return (0);
}
+/* history_def_del():
+ * Delete element hp of the h list
+ */
+/* ARGSUSED */
+private int
+history_def_del(ptr_t p, HistEvent *ev __unused,
+ const int num)
+{
+ history_t *h = (history_t *) p;
+ if (history_def_set(h, ev, num) != 0)
+ return (-1);
+ ev->str = strdup(h->cursor->ev.str);
+ ev->num = h->cursor->ev.num;
+ history_def_delete(h, ev, h->cursor);
+ return (0);
+}
+
+
/* history_def_delete():
* Delete element hp of the h list
*/
/* ARGSUSED */
private void
-history_def_delete(history_t *h, HistEvent *ev, hentry_t *hp)
+history_def_delete(history_t *h,
+ HistEvent *ev __unused, hentry_t *hp)
{
-
+ HistEventPrivate *evp = (void *)&hp->ev;
if (hp == &h->list)
abort();
+ if (h->cursor == hp)
+ h->cursor = hp->prev;
hp->prev->next = hp->next;
hp->next->prev = hp->prev;
- /* LINTED const cast */
- h_free((ptr_t) hp->ev.str);
+ h_free((ptr_t) evp->str);
h_free(hp);
h->cur--;
}
@@ -374,11 +410,11 @@ history_def_insert(history_t *h, HistEvent *ev, const char *str)
{
h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t));
- if (h->cursor)
- h->cursor->ev.str = strdup(str);
- if (!h->cursor || !h->cursor->ev.str) {
- he_seterrev(ev, _HE_MALLOC_FAILED);
- return (-1);
+ if (h->cursor == NULL)
+ goto oomem;
+ if ((h->cursor->ev.str = h_strdup(str)) == NULL) {
+ h_free((ptr_t)h->cursor);
+ goto oomem;
}
h->cursor->ev.num = ++h->eventid;
h->cursor->next = h->list.next;
@@ -389,6 +425,9 @@ history_def_insert(history_t *h, HistEvent *ev, const char *str)
*ev = h->cursor->ev;
return (0);
+oomem:
+ he_seterrev(ev, _HE_MALLOC_FAILED);
+ return (-1);
}
@@ -400,6 +439,10 @@ history_def_enter(ptr_t p, HistEvent *ev, const char *str)
{
history_t *h = (history_t *) p;
+ if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list &&
+ strcmp(h->list.next->ev.str, str) == 0)
+ return (0);
+
if (history_def_insert(h, ev, str) == -1)
return (-1); /* error, keep error message */
@@ -407,10 +450,10 @@ history_def_enter(ptr_t p, HistEvent *ev, const char *str)
* Always keep at least one entry.
* This way we don't have to check for the empty list.
*/
- while (h->cur - 1 > h->max)
+ while (h->cur > h->max && h->cur > 0)
history_def_delete(h, ev, h->list.prev);
- return (0);
+ return (1);
}
@@ -418,10 +461,12 @@ history_def_enter(ptr_t p, HistEvent *ev, const char *str)
* Default history initialization function
*/
/* ARGSUSED */
-private void
-history_def_init(ptr_t *p, HistEvent *ev, int n)
+private int
+history_def_init(ptr_t *p, HistEvent *ev __unused, int n)
{
history_t *h = (history_t *) h_malloc(sizeof(history_t));
+ if (h == NULL)
+ return -1;
if (n <= 0)
n = 0;
@@ -432,7 +477,9 @@ history_def_init(ptr_t *p, HistEvent *ev, int n)
h->list.ev.str = NULL;
h->list.ev.num = 0;
h->cursor = &h->list;
+ h->flags = 0;
*p = (ptr_t) h;
+ return 0;
}
@@ -461,10 +508,15 @@ history_def_clear(ptr_t p, HistEvent *ev)
public History *
history_init(void)
{
- History *h = (History *) h_malloc(sizeof(History));
HistEvent ev;
+ History *h = (History *) h_malloc(sizeof(History));
+ if (h == NULL)
+ return NULL;
- history_def_init(&h->h_ref, &ev, 0);
+ if (history_def_init(&h->h_ref, &ev, 0) == -1) {
+ h_free((ptr_t)h);
+ return NULL;
+ }
h->h_ent = -1;
h->h_next = history_def_next;
h->h_first = history_def_first;
@@ -475,6 +527,7 @@ history_init(void)
h->h_clear = history_def_clear;
h->h_enter = history_def_enter;
h->h_add = history_def_add;
+ h->h_del = history_def_del;
return (h);
}
@@ -490,6 +543,7 @@ history_end(History *h)
if (h->h_next == history_def_next)
history_def_clear(h->h_ref, &ev);
+ h_free(h);
}
@@ -520,18 +574,46 @@ history_setsize(History *h, HistEvent *ev, int num)
private int
history_getsize(History *h, HistEvent *ev)
{
- int retval = 0;
-
if (h->h_next != history_def_next) {
he_seterrev(ev, _HE_NOT_ALLOWED);
return (-1);
}
- retval = history_def_getsize(h->h_ref);
- if (retval < -1) {
+ ev->num = history_def_getsize(h->h_ref);
+ if (ev->num < -1) {
he_seterrev(ev, _HE_SIZE_NEGATIVE);
return (-1);
}
- ev->num = retval;
+ return (0);
+}
+
+
+/* history_setunique():
+ * Set if adjacent equal events should not be entered in history.
+ */
+private int
+history_setunique(History *h, HistEvent *ev, int uni)
+{
+
+ if (h->h_next != history_def_next) {
+ he_seterrev(ev, _HE_NOT_ALLOWED);
+ return (-1);
+ }
+ history_def_setunique(h->h_ref, uni);
+ return (0);
+}
+
+
+/* history_getunique():
+ * Get if adjacent equal events should not be entered in history.
+ */
+private int
+history_getunique(History *h, HistEvent *ev)
+{
+ if (h->h_next != history_def_next) {
+ he_seterrev(ev, _HE_NOT_ALLOWED);
+ return (-1);
+ }
+ ev->num = history_def_getunique(h->h_ref);
return (0);
}
@@ -547,7 +629,7 @@ history_set_fun(History *h, History *nh)
if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL ||
nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL ||
nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
- nh->h_ref == NULL) {
+ nh->h_del == NULL || nh->h_ref == NULL) {
if (h->h_next != history_def_next) {
history_def_init(&h->h_ref, &ev, 0);
h->h_first = history_def_first;
@@ -559,6 +641,7 @@ history_set_fun(History *h, History *nh)
h->h_clear = history_def_clear;
h->h_enter = history_def_enter;
h->h_add = history_def_add;
+ h->h_del = history_def_del;
}
return (-1);
}
@@ -575,6 +658,7 @@ history_set_fun(History *h, History *nh)
h->h_clear = nh->h_clear;
h->h_enter = nh->h_enter;
h->h_add = nh->h_add;
+ h->h_del = nh->h_del;
return (0);
}
@@ -603,6 +687,8 @@ history_load(History *h, const char *fname)
goto done;
ptr = h_malloc(max_size = 1024);
+ if (ptr == NULL)
+ goto done;
for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) {
char c = line[sz];
@@ -612,15 +698,24 @@ history_load(History *h, const char *fname)
line[sz] = '\0';
if (max_size < sz) {
- max_size = (sz + 1023) & ~1023;
- ptr = h_realloc(ptr, max_size);
+ char *nptr;
+ max_size = (sz + 1024) & ~1023;
+ nptr = h_realloc(ptr, max_size);
+ if (nptr == NULL) {
+ i = -1;
+ goto oomem;
+ }
+ ptr = nptr;
}
(void) strunvis(ptr, line);
line[sz] = c;
- HENTER(h, &ev, ptr);
+ if (HENTER(h, &ev, ptr) == -1) {
+ h_free((ptr_t)ptr);
+ return -1;
+ }
}
- h_free(ptr);
-
+oomem:
+ h_free((ptr_t)ptr);
done:
(void) fclose(fp);
return (i);
@@ -635,28 +730,40 @@ history_save(History *h, const char *fname)
{
FILE *fp;
HistEvent ev;
- int i = 0, retval;
+ int i = -1, retval;
size_t len, max_size;
char *ptr;
if ((fp = fopen(fname, "w")) == NULL)
return (-1);
- (void) fchmod(fileno(fp), S_IRUSR|S_IWUSR);
- (void) fputs(hist_cookie, fp);
+ if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1)
+ goto done;
+ if (fputs(hist_cookie, fp) == EOF)
+ goto done;
ptr = h_malloc(max_size = 1024);
- for (retval = HLAST(h, &ev);
+ if (ptr == NULL)
+ goto done;
+ for (i = 0, retval = HLAST(h, &ev);
retval != -1;
retval = HPREV(h, &ev), i++) {
len = strlen(ev.str) * 4;
if (len >= max_size) {
- max_size = (len + 1023) & 1023;
- ptr = h_realloc(ptr, max_size);
+ char *nptr;
+ max_size = (len + 1024) & ~1023;
+ nptr = h_realloc(ptr, max_size);
+ if (nptr == NULL) {
+ i = -1;
+ goto oomem;
+ }
+ ptr = nptr;
}
(void) strvis(ptr, ev.str, VIS_WHITE);
(void) fprintf(fp, "%s\n", ptr);
}
- h_free(ptr);
+oomem:
+ h_free((ptr_t)ptr);
+done:
(void) fclose(fp);
return (i);
}
@@ -755,11 +862,23 @@ history(History *h, HistEvent *ev, int fun, ...)
retval = history_setsize(h, ev, va_arg(va, int));
break;
+ case H_GETUNIQUE:
+ retval = history_getunique(h, ev);
+ break;
+
+ case H_SETUNIQUE:
+ retval = history_setunique(h, ev, va_arg(va, int));
+ break;
+
case H_ADD:
str = va_arg(va, const char *);
retval = HADD(h, ev, str);
break;
+ case H_DEL:
+ retval = HDEL(h, ev, va_arg(va, const int));
+ break;
+
case H_ENTER:
str = va_arg(va, const char *);
if ((retval = HENTER(h, ev, str)) != -1)
@@ -844,6 +963,7 @@ history(History *h, HistEvent *ev, int fun, ...)
hf.h_clear = va_arg(va, history_vfun_t);
hf.h_enter = va_arg(va, history_efun_t);
hf.h_add = va_arg(va, history_efun_t);
+ hf.h_del = va_arg(va, history_sfun_t);
if ((retval = history_set_fun(h, &hf)) == -1)
he_seterrev(ev, _HE_PARAM_MISSING);
OpenPOWER on IntegriCloud