Subject: lib/4257: editline: history() has no generic error handling and isn't reentrant
To: None <gnats-bugs@gnats.netbsd.org>
From: Jaromir Dolecek <dolecek@ics.muni.cz>
List: netbsd-bugs
Date: 10/10/1997 17:22:01
>Number: 4257
>Category: lib
>Synopsis: editline: history() has no generic error handling and isn't reentrant
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: lib-bug-people (Library Bug People)
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Fri Oct 10 08:35:01 1997
>Last-Modified:
>Originator: Jaromir Dolecek
>Organization:
ICS MU Brno, Czech Republic
>Release: 1.2G
>Environment:
System: NetBSD beleg.ics.muni.cz 1.2G NetBSD 1.2G
Architecture: i386
>Description:
history() returns pointer to HistEvent, which is not null
if the operation fails for any reason. However it's not possible
to find out the reason of error.
More importantly, the history() returns pointer leading to
static struct, which is (or can be) modified by next
history() call - this means, history is not reentrant. This
is the only point, where the implementation prevents it
from beeing reentrant, so it's wise to change it.
There are still non-reentrant termlib functions, but this
can change once there would be put some efford to make
thread-safe term library.
I've also noticed editline was not able to compile out of box;
it complains about not existent "help.h". make help.h
or adding help.h to AHDR in Makefile was enough to solve it.
However, following patch dosn't solve this.
>How-To-Repeat:
>Fix:
history() parameters were changed to:
int history(History *, HistEvent *, int, ...)
and it returns 0 if everything went okay, or -1 in case
of error. Structure ev is updated to contain error message
and (internal) error code in the latter case.
I haven't moved error code constants to histedit.h; I'm not
decided if it would be good thing or not, so I let Christos
to decide this.
The only problem is, apps using editline need to be updated;
I'm sending patches for ftp(1), sh(1) and fsdb(8) in separate
PRs.
Text added to manpage needs to be checked by some native
speaker; my english isn't very good, sorry ;-b
diff -c -r ../libedit_old/editline.3 ./editline.3
*** ../libedit_old/editline.3 Tue Oct 7 10:24:09 1997
--- ./editline.3 Thu Oct 9 18:24:17 1997
***************
*** 87,94 ****
.Fn history_init
.Ft void
.Fn history_end "History *h"
! .Ft HistEvent *
! .Fn history "History h" "int op" "..."
.Sh DESCRIPTION
The
.Nm
--- 87,94 ----
.Fn history_init
.Ft void
.Fn history_end "History *h"
! .Ft int
! .Fn history "History h" "HistEvent *ev" "int op" "..."
.Sh DESCRIPTION
The
.Nm
***************
*** 434,447 ****
.Fa op
on the history list, with optional arguments as needed by the
operation.
The following values for
.Fa op
are supported, along with the required argument list:
.Bl -tag -width 4n
! .It Dv H_EVENT , Fa "int size"
Set size of history to
.Fa size
elements.
.It Dv H_END
Cleans up and finishes with
.Fa h ,
--- 434,451 ----
.Fa op
on the history list, with optional arguments as needed by the
operation.
+ .Fa ev
+ is changed accordingly to operation.
The following values for
.Fa op
are supported, along with the required argument list:
.Bl -tag -width 4n
! .It Dv H_SETMAXSIZE , Fa "int size"
Set size of history to
.Fa size
elements.
+ .It Dv H_GETSIZE
+ Get number of events currently in history.
.It Dv H_END
Cleans up and finishes with
.Fa h ,
***************
*** 506,511 ****
--- 510,522 ----
.El
.\"XXX.Sh EXAMPLES
.\"XXX: provide some examples
+ .Sh RETURN VALUES
+ .Ft history
+ function returns 0 if the operation
+ .Ft op
+ succeeds, otherwise -1 is returned and
+ .Ft ev
+ is updated to contain more detailes about error.
.Sh SEE ALSO
.Xr editrc 5 ,
.Xr sh 1 ,
diff -c -r ../libedit_old/hist.c ./hist.c
*** ../libedit_old/hist.c Tue Oct 7 10:24:08 1997
--- ./hist.c Thu Oct 9 18:17:17 1997
***************
*** 172,177 ****
if (el->el_history.ref == NULL)
return -1;
for (str = HIST_LAST(el); str != NULL; str = HIST_PREV(el))
! (void) fprintf(el->el_outfile, "%d %s", el->el_history.ev->num, str);
return 0;
}
--- 172,177 ----
if (el->el_history.ref == NULL)
return -1;
for (str = HIST_LAST(el); str != NULL; str = HIST_PREV(el))
! (void) fprintf(el->el_outfile, "%d %s", el->el_history.ev.num, str);
return 0;
}
diff -c -r ../libedit_old/hist.h ./hist.h
*** ../libedit_old/hist.h Tue Oct 7 10:24:08 1997
--- ./hist.h Thu Oct 9 18:17:03 1997
***************
*** 46,52 ****
#include "histedit.h"
! typedef const HistEvent * (*hist_fun_t) __P((ptr_t, int, ...));
typedef struct el_history_t {
char *buf; /* The history buffer */
--- 46,52 ----
#include "histedit.h"
! typedef int (*hist_fun_t) __P((ptr_t, HistEvent *, int, ...));
typedef struct el_history_t {
char *buf; /* The history buffer */
***************
*** 54,66 ****
int eventno; /* Event we are looking for */
ptr_t ref; /* Argument for history fcns */
hist_fun_t fun; /* Event access */
! const HistEvent *ev; /* Event cookie */
} el_history_t;
#define HIST_FUN(el, fn, arg) \
! ((((el)->el_history.ev = \
! (*(el)->el_history.fun)((el)->el_history.ref, fn, arg)) == NULL) ? \
! NULL : (el)->el_history.ev->str)
#define HIST_NEXT(el) HIST_FUN(el, H_NEXT, NULL)
#define HIST_FIRST(el) HIST_FUN(el, H_FIRST, NULL)
--- 54,65 ----
int eventno; /* Event we are looking for */
ptr_t ref; /* Argument for history fcns */
hist_fun_t fun; /* Event access */
! HistEvent ev; /* Event cookie */
} el_history_t;
#define HIST_FUN(el, fn, arg) \
! ((( (*(el)->el_history.fun) ( (el)->el_history.ref, &(el)->el_history.ev,\
! fn, arg)) == -1) ? NULL : (el)->el_history.ev.str)
#define HIST_NEXT(el) HIST_FUN(el, H_NEXT, NULL)
#define HIST_FIRST(el) HIST_FUN(el, H_FIRST, NULL)
diff -c -r ../libedit_old/histedit.h ./histedit.h
*** ../libedit_old/histedit.h Tue Oct 7 10:24:08 1997
--- ./histedit.h Thu Oct 9 17:15:40 1997
***************
*** 145,178 ****
typedef struct history History;
typedef struct HistEvent {
! int num;
! const char *str;
} HistEvent;
/*
* History access functions.
*/
! History * history_init __P((void));
! void history_end __P((History *));
! const HistEvent * history __P((History *, int, ...));
#define H_FUNC 0 /* , UTSL */
! #define H_EVENT 1 /* , const int); */
! #define H_FIRST 2 /* , void); */
! #define H_LAST 3 /* , void); */
! #define H_PREV 4 /* , void); */
! #define H_NEXT 5 /* , void); */
! #define H_CURR 6 /* , void); */
! #define H_ADD 7 /* , const char*); */
! #define H_ENTER 8 /* , const char*); */
! #define H_END 9 /* , void); */
! #define H_NEXT_STR 10 /* , const char*); */
! #define H_PREV_STR 11 /* , const char*); */
! #define H_NEXT_EVENT 12 /* , const int); */
! #define H_PREV_EVENT 13 /* , const int); */
! #define H_LOAD 14 /* , const char *); */
! #define H_SAVE 15 /* , const char *); */
! #define H_CLEAR 16 /* , void); */
#endif /* _h_editline */
--- 145,179 ----
typedef struct history History;
typedef struct HistEvent {
! int num;
! const char *str;
} HistEvent;
/*
* History access functions.
*/
! History * history_init __P((void));
! void history_end __P((History *));
! int history __P((History *, HistEvent *, int, ...));
#define H_FUNC 0 /* , UTSL */
! #define H_SETMAXSIZE 1 /* , const int); */
! #define H_GETSIZE 2 /* , void); */
! #define H_FIRST 3 /* , void); */
! #define H_LAST 4 /* , void); */
! #define H_PREV 5 /* , void); */
! #define H_NEXT 6 /* , void); */
! #define H_CURR 7 /* , void); */
! #define H_ADD 8 /* , const char*); */
! #define H_ENTER 9 /* , const char*); */
! #define H_END 10 /* , void); */
! #define H_NEXT_STR 11 /* , const char*); */
! #define H_PREV_STR 12 /* , const char*); */
! #define H_NEXT_EVENT 13 /* , const int); */
! #define H_PREV_EVENT 14 /* , const int); */
! #define H_LOAD 15 /* , const char *); */
! #define H_SAVE 16 /* , const char *); */
! #define H_CLEAR 17 /* , void); */
#endif /* _h_editline */
diff -c -r ../libedit_old/history.c ./history.c
*** ../libedit_old/history.c Tue Oct 7 10:24:08 1997
--- ./history.c Thu Oct 9 18:43:44 1997
***************
*** 62,70 ****
#include "histedit.h"
! typedef const HistEvent * (*history_gfun_t) __P((ptr_t));
! typedef const HistEvent * (*history_efun_t) __P((ptr_t, const char *));
! typedef void (*history_vfun_t) __P((ptr_t));
struct history {
ptr_t h_ref; /* Argument for history fcns */
--- 62,70 ----
#include "histedit.h"
! typedef int (*history_gfun_t) __P((ptr_t, HistEvent *));
! typedef int (*history_efun_t) __P((ptr_t, HistEvent *, const char *));
! typedef void (*history_vfun_t) __P((ptr_t, HistEvent *));
struct history {
ptr_t h_ref; /* Argument for history fcns */
***************
*** 78,104 ****
history_efun_t h_add; /* Append to an element */
};
! #define HNEXT(h) (*(h)->h_next)((h)->h_ref)
! #define HFIRST(h) (*(h)->h_first)((h)->h_ref)
! #define HPREV(h) (*(h)->h_prev)((h)->h_ref)
! #define HLAST(h) (*(h)->h_last)((h)->h_ref)
! #define HCURR(h) (*(h)->h_curr)((h)->h_ref)
! #define HCLEAR(h) (*(h)->h_clear)((h)->h_ref)
! #define HENTER(h, str) (*(h)->h_enter)((h)->h_ref, str)
! #define HADD(h, str) (*(h)->h_add)((h)->h_ref, str)
#define h_malloc(a) malloc(a)
#define h_free(a) free(a)
! private int history_set_num __P((History *, int));
! private int history_set_fun __P((History *, History *));
! private int history_load __P((History *, const char *));
! private int history_save __P((History *, const char *));
! private const HistEvent *history_prev_event __P((History *, int));
! private const HistEvent *history_next_event __P((History *, int));
! private const HistEvent *history_next_string __P((History *, const char *));
! private const HistEvent *history_prev_string __P((History *, const char *));
/***********************************************************************/
--- 78,105 ----
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)
! #define HLAST(h, ev) (*(h)->h_last)((h)->h_ref, ev)
! #define HCURR(h, ev) (*(h)->h_curr)((h)->h_ref, ev)
! #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 h_malloc(a) malloc(a)
#define h_free(a) free(a)
! private int history_set_num __P((History *, HistEvent *, int));
! private int history_get_size __P((History *, HistEvent *));
! private int history_set_fun __P((History *, History *));
! private int history_load __P((History *, const char *));
! private int history_save __P((History *, const char *));
! private int history_prev_event __P((History *, HistEvent *, int));
! private int history_next_event __P((History *, HistEvent *, int));
! private int history_next_string __P((History *, HistEvent *, const char *));
! private int history_prev_string __P((History *, HistEvent *, const char *));
/***********************************************************************/
***************
*** 117,233 ****
hentry_t *cursor; /* Current element in the list */
int max; /* Maximum number of events */
int cur; /* Current number of events */
! int eventno; /* Current event number */
} history_t;
! private const HistEvent *history_def_first __P((ptr_t));
! private const HistEvent *history_def_last __P((ptr_t));
! private const HistEvent *history_def_next __P((ptr_t));
! private const HistEvent *history_def_prev __P((ptr_t));
! private const HistEvent *history_def_curr __P((ptr_t));
! private const HistEvent *history_def_enter __P((ptr_t, const char *));
! private const HistEvent *history_def_add __P((ptr_t, const char *));
! private void history_def_init __P((ptr_t *, int));
! private void history_def_clear __P((ptr_t));
! private const HistEvent *history_def_insert __P((history_t *, const char *));
! private void history_def_delete __P((history_t *, hentry_t *));
#define history_def_set(p, num) (void) (((history_t *) p)->max = (num))
/* history_def_first():
* Default function to return the first event in the history.
*/
! private const HistEvent *
! history_def_first(p)
ptr_t p;
{
history_t *h = (history_t *) p;
h->cursor = h->list.next;
if (h->cursor != &h->list)
! return &h->cursor->ev;
! else
! return NULL;
}
/* history_def_last():
* Default function to return the last event in the history.
*/
! private const HistEvent *
! history_def_last(p)
ptr_t p;
{
history_t *h = (history_t *) p;
h->cursor = h->list.prev;
if (h->cursor != &h->list)
! return &h->cursor->ev;
! else
! return NULL;
}
/* history_def_next():
* Default function to return the next event in the history.
*/
! private const HistEvent *
! history_def_next(p)
ptr_t p;
{
history_t *h = (history_t *) p;
if (h->cursor != &h->list)
h->cursor = h->cursor->next;
! else
! return NULL;
if (h->cursor != &h->list)
! return &h->cursor->ev;
! else
! return NULL;
}
/* history_def_prev():
* Default function to return the previous event in the history.
*/
! private const HistEvent *
! history_def_prev(p)
ptr_t p;
{
history_t *h = (history_t *) p;
if (h->cursor != &h->list)
h->cursor = h->cursor->prev;
! else
! return NULL;
if (h->cursor != &h->list)
! return &h->cursor->ev;
! else
! return NULL;
}
/* history_def_curr():
* Default function to return the current event in the history.
*/
! private const HistEvent *
! history_def_curr(p)
ptr_t p;
{
history_t *h = (history_t *) p;
if (h->cursor != &h->list)
! return &h->cursor->ev;
! else
! return NULL;
}
/* history_def_add():
* Append string to element
*/
! private const HistEvent *
! history_def_add(p, str)
ptr_t p;
const char *str;
{
history_t *h = (history_t *) p;
--- 118,322 ----
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;
! private int history_def_first __P((ptr_t, HistEvent *));
! private int history_def_last __P((ptr_t, HistEvent *));
! private int history_def_next __P((ptr_t, HistEvent *));
! private int history_def_prev __P((ptr_t, HistEvent *));
! private int history_def_curr __P((ptr_t, HistEvent *));
! private int history_def_enter __P((ptr_t, HistEvent *, const char *));
! private int history_def_add __P((ptr_t, HistEvent *, const char *));
! private void history_def_init __P((ptr_t *, HistEvent *, int));
! private void history_def_clear __P((ptr_t, HistEvent *));
! private int history_def_insert __P((history_t *, HistEvent *,const char *));
! private void history_def_delete __P((history_t *, HistEvent *, hentry_t *));
! private int history_def_size __P((history_t *, HistEvent *));
#define history_def_set(p, num) (void) (((history_t *) p)->max = (num))
+ #define history_def_getsize(p) (((history_t *) p)->cur)
+ #define he_strerror(code) err_msg[code]
+ #define he_seterrev(evp, code) {\
+ evp->num = code;\
+ evp->str = he_strerror(code);\
+ }
+
+ /* error messages */
+ static const char *err_msg[] = {
+ "OK",
+ "malloc() failed",
+ "first event not found",
+ "last event not found",
+ "empty list",
+ "no next event",
+ "no previous event",
+ "current event is invalid",
+ "event not found",
+ "can't read history from file",
+ "can't write history",
+ "required parameter(s) not supplied",
+ "history size negative",
+ "function not allowed with other history-functions-set tha default",
+ "bad parameters",
+ };
+
+ /* error codes */
+ #define _HE_OK 0
+ #define _HE_UNKNOWN 1
+ #define _HE_MALLOC_FAILED 2
+ #define _HE_FIRST_NOTFOUND 3
+ #define _HE_LAST_NOTFOUND 4
+ #define _HE_EMPTY_LIST 5
+ #define _HE_END_REACHED 6
+ #define _HE_START_REACHED 7
+ #define _HE_CURR_INVALID 8
+ #define _HE_NOT_FOUND 9
+ #define _HE_HIST_READ 10
+ #define _HE_HIST_WRITE 11
+ #define _HE_PARAM_MISSING 12
+ #define _HE_SIZE_NEGATIVE 13
+ #define _HE_NOT_ALLOWED 14
+ #define _HE_BAD_PARAM 15
+
+ /* he_cpy():
+ * copy contents of one HistEvent to another
+ */
+ private int
+ he_cpy(tev, sev)
+ HistEvent *tev;
+ const HistEvent *sev;
+ {
+ tev->num = sev->num;
+ tev->str = sev->str;
+ }
/* history_def_first():
* Default function to return the first event in the history.
*/
! private int
! history_def_first(p, ev)
ptr_t p;
+ HistEvent *ev;
{
history_t *h = (history_t *) p;
+
h->cursor = h->list.next;
if (h->cursor != &h->list)
! he_cpy(ev, &h->cursor->ev);
! else {
! he_seterrev(ev, _HE_FIRST_NOTFOUND);
! return -1;
! }
!
! return 0;
}
/* history_def_last():
* Default function to return the last event in the history.
*/
! private int
! history_def_last(p, ev)
ptr_t p;
+ HistEvent *ev;
{
history_t *h = (history_t *) p;
+
h->cursor = h->list.prev;
if (h->cursor != &h->list)
! he_cpy(ev, &h->cursor->ev);
! else {
! he_seterrev(ev, _HE_LAST_NOTFOUND);
! return -1;
! }
!
! return 0;
}
/* history_def_next():
* Default function to return the next event in the history.
*/
! private int
! history_def_next(p, ev)
ptr_t p;
+ HistEvent *ev;
{
history_t *h = (history_t *) p;
if (h->cursor != &h->list)
h->cursor = h->cursor->next;
! else {
! he_seterrev(ev, _HE_EMPTY_LIST);
! return -1;
! }
if (h->cursor != &h->list)
! he_cpy(ev, &h->cursor->ev);
! else {
! he_seterrev(ev, _HE_END_REACHED);
! return -1;
! }
!
! return 0;
}
/* history_def_prev():
* Default function to return the previous event in the history.
*/
! private int
! history_def_prev(p, ev)
ptr_t p;
+ HistEvent *ev;
{
history_t *h = (history_t *) p;
if (h->cursor != &h->list)
h->cursor = h->cursor->prev;
! else {
! he_seterrev(ev, (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST);
! return -1;
! }
if (h->cursor != &h->list)
! he_cpy(ev, &h->cursor->ev);
! else {
! he_seterrev(ev, _HE_START_REACHED);
! return -1;
! }
!
! return 0;
}
/* history_def_curr():
* Default function to return the current event in the history.
*/
! private int
! history_def_curr(p, ev)
ptr_t p;
+ HistEvent *ev;
{
history_t *h = (history_t *) p;
if (h->cursor != &h->list)
! he_cpy(ev, &h->cursor->ev);
! else {
! he_seterrev(ev, (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST);
! return -1;
! }
!
! return 0;
}
/* history_def_add():
* Append string to element
*/
! private int
! history_def_add(p, ev, str)
ptr_t p;
+ HistEvent *ev;
const char *str;
{
history_t *h = (history_t *) p;
***************
*** 235,248 ****
char *s;
if (h->cursor == &h->list)
! return (history_def_enter(p, str));
len = strlen(h->cursor->ev.str) + strlen(str) + 1;
s = (char *) h_malloc(len);
! (void)strcpy(s, h->cursor->ev.str); /* XXX strcpy is safe */
(void)strcat(s, str); /* XXX strcat is safe */
h_free((ptr_t) h->cursor->ev.str);
h->cursor->ev.str = s;
! return &h->cursor->ev;
}
--- 324,342 ----
char *s;
if (h->cursor == &h->list)
! return (history_def_enter(p, ev, str));
len = strlen(h->cursor->ev.str) + strlen(str) + 1;
s = (char *) h_malloc(len);
! if (!s) {
! he_seterrev(ev, _HE_MALLOC_FAILED);
! return -1;
! }
! (void)strcpy(s, h->cursor->ev.str); /* XXX strcpy is safe */
(void)strcat(s, str); /* XXX strcat is safe */
h_free((ptr_t) h->cursor->ev.str);
h->cursor->ev.str = s;
! he_cpy(ev, &h->cursor->ev);
! return 0;
}
***************
*** 250,257 ****
* Delete element hp of the h list
*/
private void
! history_def_delete(h, hp)
history_t *h;
hentry_t *hp;
{
if (hp == &h->list)
--- 344,352 ----
* Delete element hp of the h list
*/
private void
! history_def_delete(h, ev, hp)
history_t *h;
+ HistEvent *ev;
hentry_t *hp;
{
if (hp == &h->list)
***************
*** 267,311 ****
/* history_def_insert():
* Insert element with string str in the h list
*/
! private const HistEvent *
! history_def_insert(h, str)
history_t *h;
const char *str;
{
h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t));
! h->cursor->ev.str = strdup(str);
h->cursor->next = h->list.next;
h->cursor->prev = &h->list;
h->list.next->prev = h->cursor;
h->list.next = h->cursor;
h->cur++;
! return &h->cursor->ev;
}
/* history_def_enter():
* Default function to enter an item in the history
*/
! private const HistEvent *
! history_def_enter(p, str)
ptr_t p;
const char *str;
{
history_t *h = (history_t *) p;
- const HistEvent *ev;
-
! ev = history_def_insert(h, str);
! ((HistEvent*) ev)->num = ++h->eventno;
/*
* Always keep at least one entry.
* This way we don't have to check for the empty list.
*/
! while (h->cur > h->max + 1)
! history_def_delete(h, h->list.prev);
! return ev;
}
--- 362,414 ----
/* history_def_insert():
* Insert element with string str in the h list
*/
! private int
! history_def_insert(h, ev, str)
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;
! }
! h->cursor->ev.num = ++h->eventid;
h->cursor->next = h->list.next;
h->cursor->prev = &h->list;
h->list.next->prev = h->cursor;
h->list.next = h->cursor;
h->cur++;
! he_cpy(ev, &h->cursor->ev);
! return 0;
}
/* history_def_enter():
* Default function to enter an item in the history
*/
! private int
! history_def_enter(p, ev, str)
ptr_t p;
+ HistEvent *ev;
const char *str;
{
history_t *h = (history_t *) p;
! if (history_def_insert(h, ev, str) == -1)
! return -1; /* error, keep error message */
/*
* Always keep at least one entry.
* This way we don't have to check for the empty list.
*/
! while (h->cur - 1 > h->max)
! history_def_delete(h, ev, h->list.prev);
!
! return 0;
}
***************
*** 313,326 ****
* Default history initialization function
*/
private void
! history_def_init(p, n)
ptr_t *p;
int n;
{
history_t *h = (history_t *) h_malloc(sizeof(history_t));
if (n <= 0)
n = 0;
! h->eventno = 0;
h->cur = 0;
h->max = n;
h->list.next = h->list.prev = &h->list;
--- 416,430 ----
* Default history initialization function
*/
private void
! history_def_init(p, ev, n)
ptr_t *p;
+ HistEvent *ev;
int n;
{
history_t *h = (history_t *) h_malloc(sizeof(history_t));
if (n <= 0)
n = 0;
! h->eventid = 0;
h->cur = 0;
h->max = n;
h->list.next = h->list.prev = &h->list;
***************
*** 335,348 ****
* Default history cleanup function
*/
private void
! history_def_clear(p)
ptr_t p;
{
history_t *h = (history_t *) p;
while (h->list.prev != &h->list)
! history_def_delete(h, h->list.prev);
! h->eventno = 0;
h->cur = 0;
}
--- 439,453 ----
* Default history cleanup function
*/
private void
! history_def_clear(p, ev)
ptr_t p;
+ HistEvent *ev;
{
history_t *h = (history_t *) p;
while (h->list.prev != &h->list)
! history_def_delete(h, ev, h->list.prev);
! h->eventid = 0;
h->cur = 0;
}
***************
*** 358,365 ****
history_init()
{
History *h = (History *) h_malloc(sizeof(History));
! history_def_init(&h->h_ref, 0);
h->h_next = history_def_next;
h->h_first = history_def_first;
--- 463,471 ----
history_init()
{
History *h = (History *) h_malloc(sizeof(History));
+ HistEvent ev;
! history_def_init(&h->h_ref, &ev, 0);
h->h_next = history_def_next;
h->h_first = history_def_first;
***************
*** 381,388 ****
history_end(h)
History *h;
{
if (h->h_next == history_def_next)
! history_def_clear(h->h_ref);
}
--- 487,495 ----
history_end(h)
History *h;
{
+ HistEvent ev;
if (h->h_next == history_def_next)
! history_def_clear(h->h_ref, &ev);
}
***************
*** 391,420 ****
* Set history number of events
*/
private int
! history_set_num(h, num)
History *h;
int num;
{
! if (h->h_next != history_def_next || num < 0)
return -1;
history_def_set(h->h_ref, num);
return 0;
}
/* history_set_fun():
* Set history functions
*/
private int
history_set_fun(h, nh)
! History *h, *nh;
{
if (nh->h_first == NULL || nh->h_next == NULL ||
nh->h_last == NULL || nh->h_prev == NULL || nh->h_curr == NULL ||
nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL ||
nh->h_ref == NULL) {
if (h->h_next != history_def_next) {
! history_def_init(&h->h_ref, 0);
h->h_first = history_def_first;
h->h_next = history_def_next;
h->h_last = history_def_last;
--- 498,562 ----
* Set history number of events
*/
private int
! history_set_num(h, ev, num)
History *h;
+ HistEvent *ev;
int num;
{
! if (h->h_next != history_def_next) {
! he_seterrev(ev, _HE_NOT_ALLOWED);
! return -1;
! }
!
! if (num < 0) {
! he_seterrev(ev, _HE_BAD_PARAM);
return -1;
+ }
+
history_def_set(h->h_ref, num);
return 0;
}
+ /* history_get_size():
+ * Get number of events currently in history
+ */
+ private int
+ history_get_size(h, ev)
+ 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) {
+ he_seterrev(ev, _HE_SIZE_NEGATIVE);
+ return -1;
+ }
+
+ ev->num = retval;
+ return 0;
+ }
/* history_set_fun():
* Set history functions
*/
private int
history_set_fun(h, nh)
! History *h;
! History *nh;
{
+ HistEvent ev;
+
if (nh->h_first == NULL || nh->h_next == NULL ||
nh->h_last == NULL || nh->h_prev == NULL || nh->h_curr == NULL ||
nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == 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;
h->h_next = history_def_next;
h->h_last = history_def_last;
***************
*** 428,434 ****
}
if (h->h_next == history_def_next)
! history_def_clear(h->h_ref);
h->h_first = nh->h_first;
h->h_next = nh->h_next;
--- 570,576 ----
}
if (h->h_next == history_def_next)
! history_def_clear(h->h_ref, &ev);
h->h_first = nh->h_first;
h->h_next = nh->h_next;
***************
*** 455,460 ****
--- 597,603 ----
char *line;
size_t sz;
int i = -1;
+ HistEvent ev;
if ((fp = fopen(fname, "r")) == NULL)
return i;
***************
*** 468,474 ****
for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) {
char c = line[sz];
line[sz] = '\0';
! HENTER(h, line);
line[sz] = c;
}
--- 611,617 ----
for (i = 0; (line = fgetln(fp, &sz)) != NULL; i++) {
char c = line[sz];
line[sz] = '\0';
! HENTER(h, &ev, line);
line[sz] = c;
}
***************
*** 487,501 ****
const char *fname;
{
FILE *fp;
! const HistEvent *ev;
! int i = 0;
if ((fp = fopen(fname, "w")) == NULL)
return -1;
(void) fputs(hist_cookie, fp);
! for (ev = HLAST(h); ev != NULL; ev = HPREV(h), i++)
! (void) fprintf(fp, "%s", ev->str);
(void) fclose(fp);
return i;
}
--- 630,644 ----
const char *fname;
{
FILE *fp;
! HistEvent ev;
! int i = 0, retval;
if ((fp = fopen(fname, "w")) == NULL)
return -1;
(void) fputs(hist_cookie, fp);
! for (retval = HLAST(h, &ev); retval != -1; retval = HPREV(h, &ev), i++)
! (void) fprintf(fp, "%s", ev.str);
(void) fclose(fp);
return i;
}
***************
*** 504,534 ****
/* history_prev_event():
* Find the previous event, with number given
*/
! private const HistEvent *
! history_prev_event(h, num)
History *h;
int num;
{
! const HistEvent *ev;
! for (ev = HCURR(h); ev != NULL; ev = HPREV(h))
if (ev->num == num)
! return ev;
! return NULL;
}
/* history_next_event():
* Find the next event, with number given
*/
! private const HistEvent *
! history_next_event(h, num)
History *h;
int num;
{
! const HistEvent *ev;
! for (ev = HCURR(h); ev != NULL; ev = HNEXT(h))
if (ev->num == num)
! return ev;
return NULL;
}
--- 647,683 ----
/* history_prev_event():
* Find the previous event, with number given
*/
! private int
! history_prev_event(h, ev, num)
History *h;
+ HistEvent *ev;
int num;
{
! int retval;
! for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
if (ev->num == num)
! return 0;
!
! he_seterrev(ev, _HE_NOT_FOUND);
! return -1;
}
/* history_next_event():
* Find the next event, with number given
*/
! private int
! history_next_event(h, ev, num)
History *h;
+ HistEvent *ev;
int num;
{
! int retval;
! for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
if (ev->num == num)
! return 0;
!
! he_seterrev(ev, _HE_NOT_FOUND);
return NULL;
}
***************
*** 536,553 ****
/* history_prev_string():
* Find the previous event beginning with string
*/
! private const HistEvent *
! history_prev_string(h, str)
History *h;
const char* str;
{
- const HistEvent *ev;
size_t len = strlen(str);
! for (ev = HCURR(h); ev != NULL; ev = HNEXT(h))
if (strncmp(str, ev->str, len) == 0)
! return ev;
! return NULL;
}
--- 685,705 ----
/* history_prev_string():
* Find the previous event beginning with string
*/
! private int
! history_prev_string(h, ev, str)
History *h;
+ HistEvent *ev;
const char* str;
{
size_t len = strlen(str);
+ int retval;
! for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev))
if (strncmp(str, ev->str, len) == 0)
! return 0;
!
! he_seterrev(ev, _HE_NOT_FOUND);
! return -1;
}
***************
*** 556,668 ****
/* history_next_string():
* Find the next event beginning with string
*/
! private const HistEvent *
! history_next_string(h, str)
History *h;
const char* str;
{
- const HistEvent *ev;
size_t len = strlen(str);
! for (ev = HCURR(h); ev != NULL; ev = HPREV(h))
if (strncmp(str, ev->str, len) == 0)
! return ev;
! return NULL;
}
/* history():
* User interface to history functions.
*/
! const HistEvent *
#ifdef __STDC__
! history(History *h, int fun, ...)
#else
history(va_alist)
va_dcl
#endif
{
va_list va;
- const HistEvent *ev = NULL;
const char *str;
! static HistEvent sev = { 0, "" };
#ifdef __STDC__
va_start(va, fun);
#else
History *h;
int fun;
va_start(va);
h = va_arg(va, History *);
fun = va_arg(va, int);
#endif
switch (fun) {
case H_ADD:
str = va_arg(va, const char *);
! ev = HADD(h, str);
break;
case H_ENTER:
str = va_arg(va, const char *);
! ev = HENTER(h, str);
break;
case H_FIRST:
! ev = HFIRST(h);
break;
case H_NEXT:
! ev = HNEXT(h);
break;
case H_LAST:
! ev = HLAST(h);
break;
case H_PREV:
! ev = HPREV(h);
break;
case H_CURR:
! ev = HCURR(h);
break;
case H_CLEAR:
! HCLEAR(h);
break;
case H_LOAD:
! sev.num = history_load(h, va_arg(va, const char *));
! ev = &sev;
break;
case H_SAVE:
! sev.num = history_save(h, va_arg(va, const char *));
! ev = &sev;
break;
case H_PREV_EVENT:
! ev = history_prev_event(h, va_arg(va, int));
break;
case H_NEXT_EVENT:
! ev = history_next_event(h, va_arg(va, int));
break;
case H_PREV_STR:
! ev = history_prev_string(h, va_arg(va, const char*));
break;
case H_NEXT_STR:
! ev = history_next_string(h, va_arg(va, const char*));
break;
! case H_EVENT:
! if (history_set_num(h, va_arg(va, int)) == 0) {
! sev.num = -1;
! ev = &sev;
! }
break;
case H_FUNC:
--- 708,826 ----
/* history_next_string():
* Find the next event beginning with string
*/
! private int
! history_next_string(h, ev, str)
History *h;
+ HistEvent *ev;
const char* str;
{
size_t len = strlen(str);
+ int retval;
! for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev))
if (strncmp(str, ev->str, len) == 0)
! return 0;
!
! he_seterrev(ev, _HE_NOT_FOUND);
! return -1;
}
/* history():
* User interface to history functions.
*/
! int
#ifdef __STDC__
! history(History *h, HistEvent *ev, int fun, ...)
#else
history(va_alist)
va_dcl
#endif
{
va_list va;
const char *str;
! int retval;
#ifdef __STDC__
va_start(va, fun);
#else
History *h;
+ HistEvent *ev;
int fun;
va_start(va);
h = va_arg(va, History *);
+ ev = va_arg(va, HistEvent *);
fun = va_arg(va, int);
#endif
+ he_seterrev(ev, _HE_OK);
+
switch (fun) {
case H_ADD:
str = va_arg(va, const char *);
! retval = HADD(h, ev, str);
break;
case H_ENTER:
str = va_arg(va, const char *);
! retval = HENTER(h, ev, str);
break;
case H_FIRST:
! retval = HFIRST(h, ev);
break;
case H_NEXT:
! retval = HNEXT(h, ev);
break;
case H_LAST:
! retval = HLAST(h, ev);
break;
case H_PREV:
! retval = HPREV(h, ev);
break;
case H_CURR:
! retval = HCURR(h, ev);
break;
case H_CLEAR:
! HCLEAR(h, ev);
! retval = 0;
break;
case H_LOAD:
! retval = history_load(h, va_arg(va, const char *));
! if (retval == -1)
! he_seterrev(ev, _HE_HIST_READ);
break;
case H_SAVE:
! retval = history_save(h, va_arg(va, const char *));
! if (retval == -1)
! he_seterrev(ev, _HE_HIST_WRITE);
break;
case H_PREV_EVENT:
! retval = history_prev_event(h, ev, va_arg(va, int));
break;
case H_NEXT_EVENT:
! retval = history_next_event(h, ev, va_arg(va, int));
break;
case H_PREV_STR:
! retval = history_prev_string(h, ev, va_arg(va, const char*));
break;
case H_NEXT_STR:
! retval = history_next_string(h, ev, va_arg(va, const char*));
break;
! case H_SETMAXSIZE:
! retval = history_set_num(h, ev, va_arg(va, int));
break;
case H_FUNC:
***************
*** 678,697 ****
hf.h_enter = va_arg(va, history_efun_t);
hf.h_add = va_arg(va, history_efun_t);
! if (history_set_fun(h, &hf) == 0) {
! sev.num = -1;
! ev = &sev;
}
}
break;
case H_END:
history_end(h);
break;
default:
break;
}
va_end(va);
! return ev;
}
--- 836,862 ----
hf.h_enter = va_arg(va, history_efun_t);
hf.h_add = va_arg(va, history_efun_t);
! if (history_set_fun(h, &hf) == -1) {
! he_seterrev(ev, _HE_PARAM_MISSING);
! retval = -1;
}
}
break;
case H_END:
history_end(h);
+ retval = 0;
+ break;
+
+ case H_GETSIZE:
+ retval = history_get_size(h, ev);
break;
default:
+ retval = -1;
+ he_seterrev(ev, _HE_UNKNOWN);
break;
}
va_end(va);
! return retval;
}
>Audit-Trail:
>Unformatted: