| File: | src/lib/libedit/history.c |
| Warning: | line 582, column 3 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: history.c,v 1.28 2016/04/11 21:17:29 schwarze Exp $ */ | |||
| 2 | /* $NetBSD: history.c,v 1.37 2010/01/03 18:27:10 christos Exp $ */ | |||
| 3 | ||||
| 4 | /*- | |||
| 5 | * Copyright (c) 1992, 1993 | |||
| 6 | * The Regents of the University of California. All rights reserved. | |||
| 7 | * | |||
| 8 | * This code is derived from software contributed to Berkeley by | |||
| 9 | * Christos Zoulas of Cornell University. | |||
| 10 | * | |||
| 11 | * Redistribution and use in source and binary forms, with or without | |||
| 12 | * modification, are permitted provided that the following conditions | |||
| 13 | * are met: | |||
| 14 | * 1. Redistributions of source code must retain the above copyright | |||
| 15 | * notice, this list of conditions and the following disclaimer. | |||
| 16 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 17 | * notice, this list of conditions and the following disclaimer in the | |||
| 18 | * documentation and/or other materials provided with the distribution. | |||
| 19 | * 3. Neither the name of the University nor the names of its contributors | |||
| 20 | * may be used to endorse or promote products derived from this software | |||
| 21 | * without specific prior written permission. | |||
| 22 | * | |||
| 23 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |||
| 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
| 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
| 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |||
| 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
| 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
| 29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
| 30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
| 31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
| 32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| 33 | * SUCH DAMAGE. | |||
| 34 | */ | |||
| 35 | ||||
| 36 | #include "config.h" | |||
| 37 | ||||
| 38 | /* | |||
| 39 | * hist.c: TYPE(History) access functions | |||
| 40 | */ | |||
| 41 | #include <sys/stat.h> | |||
| 42 | #include <stdarg.h> | |||
| 43 | #include <stdlib.h> | |||
| 44 | #include <string.h> | |||
| 45 | #ifdef HAVE_VIS_H1 | |||
| 46 | #include <vis.h> | |||
| 47 | #else | |||
| 48 | #include "np/vis.h" | |||
| 49 | #endif | |||
| 50 | ||||
| 51 | static const char hist_cookie[] = "_HiStOrY_V2_\n"; | |||
| 52 | ||||
| 53 | #include "histedit.h" | |||
| 54 | ||||
| 55 | ||||
| 56 | #ifdef NARROWCHAR | |||
| 57 | ||||
| 58 | #define Charwchar_t char | |||
| 59 | #define FUN(prefix, rest)prefix_wrest prefix ## _ ## rest | |||
| 60 | #define FUNW(type)type_w type | |||
| 61 | #define TYPE(type)typeW type | |||
| 62 | #define STR(x)Lx x | |||
| 63 | ||||
| 64 | #define Strlen(s)wcslen(s) strlen(s) | |||
| 65 | #define Strdup(s)wcsdup(s) strdup(s) | |||
| 66 | #define Strcmp(d, s)wcscmp(d, s) strcmp(d, s) | |||
| 67 | #define Strncmp(d, s, n)wcsncmp(d, s, n) strncmp(d, s, n) | |||
| 68 | #define Strncpy(d, s, n)wcsncpy(d, s, n) strncpy(d, s, n) | |||
| 69 | #define Strncat(d, s, n)wcsncat(d, s, n) strncat(d, s, n) | |||
| 70 | #define ct_decode_string(s, b) (s) | |||
| 71 | #define ct_encode_string(s, b) (s) | |||
| 72 | ||||
| 73 | #else | |||
| 74 | #include "chartype.h" | |||
| 75 | ||||
| 76 | #define Charwchar_t wchar_t | |||
| 77 | #define FUN(prefix, rest)prefix_wrest prefix ## _w ## rest | |||
| 78 | #define FUNW(type)type_w type ## _w | |||
| 79 | #define TYPE(type)typeW type ## W | |||
| 80 | #define STR(x)Lx L ## x | |||
| 81 | ||||
| 82 | #define Strlen(s)wcslen(s) wcslen(s) | |||
| 83 | #define Strdup(s)wcsdup(s) wcsdup(s) | |||
| 84 | #define Strcmp(d, s)wcscmp(d, s) wcscmp(d, s) | |||
| 85 | #define Strncmp(d, s, n)wcsncmp(d, s, n) wcsncmp(d, s, n) | |||
| 86 | #define Strncpy(d, s, n)wcsncpy(d, s, n) wcsncpy(d, s, n) | |||
| 87 | #define Strncat(d, s, n)wcsncat(d, s, n) wcsncat(d, s, n) | |||
| 88 | ||||
| 89 | #endif | |||
| 90 | ||||
| 91 | ||||
| 92 | typedef int (*history_gfun_t)(void *, TYPE(HistEvent)HistEventW *); | |||
| 93 | typedef int (*history_efun_t)(void *, TYPE(HistEvent)HistEventW *, const Charwchar_t *); | |||
| 94 | typedef void (*history_vfun_t)(void *, TYPE(HistEvent)HistEventW *); | |||
| 95 | typedef int (*history_sfun_t)(void *, TYPE(HistEvent)HistEventW *, const int); | |||
| 96 | ||||
| 97 | struct TYPE(history)historyW { | |||
| 98 | void *h_ref; /* Argument for history fcns */ | |||
| 99 | int h_ent; /* Last entry point for history */ | |||
| 100 | history_gfun_t h_first; /* Get the first element */ | |||
| 101 | history_gfun_t h_next; /* Get the next element */ | |||
| 102 | history_gfun_t h_last; /* Get the last element */ | |||
| 103 | history_gfun_t h_prev; /* Get the previous element */ | |||
| 104 | history_gfun_t h_curr; /* Get the current element */ | |||
| 105 | history_sfun_t h_set; /* Set the current element */ | |||
| 106 | history_sfun_t h_del; /* Set the given element */ | |||
| 107 | history_vfun_t h_clear; /* Clear the history list */ | |||
| 108 | history_efun_t h_enter; /* Add an element */ | |||
| 109 | history_efun_t h_add; /* Append to an element */ | |||
| 110 | }; | |||
| 111 | ||||
| 112 | #define HNEXT(h, ev)(*(h)->h_next)((h)->h_ref, ev) (*(h)->h_next)((h)->h_ref, ev) | |||
| 113 | #define HFIRST(h, ev)(*(h)->h_first)((h)->h_ref, ev) (*(h)->h_first)((h)->h_ref, ev) | |||
| 114 | #define HPREV(h, ev)(*(h)->h_prev)((h)->h_ref, ev) (*(h)->h_prev)((h)->h_ref, ev) | |||
| 115 | #define HLAST(h, ev)(*(h)->h_last)((h)->h_ref, ev) (*(h)->h_last)((h)->h_ref, ev) | |||
| 116 | #define HCURR(h, ev)(*(h)->h_curr)((h)->h_ref, ev) (*(h)->h_curr)((h)->h_ref, ev) | |||
| 117 | #define HSET(h, ev, n)(*(h)->h_set)((h)->h_ref, ev, n) (*(h)->h_set)((h)->h_ref, ev, n) | |||
| 118 | #define HCLEAR(h, ev)(*(h)->h_clear)((h)->h_ref, ev) (*(h)->h_clear)((h)->h_ref, ev) | |||
| 119 | #define HENTER(h, ev, str)(*(h)->h_enter)((h)->h_ref, ev, str) (*(h)->h_enter)((h)->h_ref, ev, str) | |||
| 120 | #define HADD(h, ev, str)(*(h)->h_add)((h)->h_ref, ev, str) (*(h)->h_add)((h)->h_ref, ev, str) | |||
| 121 | #define HDEL(h, ev, n)(*(h)->h_del)((h)->h_ref, ev, n) (*(h)->h_del)((h)->h_ref, ev, n) | |||
| 122 | ||||
| 123 | #define h_strdup(a)wcsdup(a) Strdup(a)wcsdup(a) | |||
| 124 | ||||
| 125 | typedef struct { | |||
| 126 | int num; | |||
| 127 | Charwchar_t *str; | |||
| 128 | } HistEventPrivate; | |||
| 129 | ||||
| 130 | ||||
| 131 | static int history_setsize(TYPE(History)HistoryW *, TYPE(HistEvent)HistEventW *, int); | |||
| 132 | static int history_getsize(TYPE(History)HistoryW *, TYPE(HistEvent)HistEventW *); | |||
| 133 | static int history_setunique(TYPE(History)HistoryW *, TYPE(HistEvent)HistEventW *, int); | |||
| 134 | static int history_getunique(TYPE(History)HistoryW *, TYPE(HistEvent)HistEventW *); | |||
| 135 | static int history_set_fun(TYPE(History)HistoryW *, TYPE(History)HistoryW *); | |||
| 136 | static int history_load(TYPE(History)HistoryW *, const char *); | |||
| 137 | static int history_save(TYPE(History)HistoryW *, const char *); | |||
| 138 | static int history_save_fp(TYPE(History)HistoryW *, FILE *); | |||
| 139 | static int history_prev_event(TYPE(History)HistoryW *, TYPE(HistEvent)HistEventW *, int); | |||
| 140 | static int history_next_event(TYPE(History)HistoryW *, TYPE(HistEvent)HistEventW *, int); | |||
| 141 | static int history_next_string(TYPE(History)HistoryW *, TYPE(HistEvent)HistEventW *, | |||
| 142 | const Charwchar_t *); | |||
| 143 | static int history_prev_string(TYPE(History)HistoryW *, TYPE(HistEvent)HistEventW *, | |||
| 144 | const Charwchar_t *); | |||
| 145 | ||||
| 146 | ||||
| 147 | /***********************************************************************/ | |||
| 148 | ||||
| 149 | /* | |||
| 150 | * Builtin- history implementation | |||
| 151 | */ | |||
| 152 | typedef struct hentry_t { | |||
| 153 | TYPE(HistEvent)HistEventW ev; /* What we return */ | |||
| 154 | void *data; /* data */ | |||
| 155 | struct hentry_t *next; /* Next entry */ | |||
| 156 | struct hentry_t *prev; /* Previous entry */ | |||
| 157 | } hentry_t; | |||
| 158 | ||||
| 159 | typedef struct history_t { | |||
| 160 | hentry_t list; /* Fake list header element */ | |||
| 161 | hentry_t *cursor; /* Current element in the list */ | |||
| 162 | int max; /* Maximum number of events */ | |||
| 163 | int cur; /* Current number of events */ | |||
| 164 | int eventid; /* For generation of unique event id */ | |||
| 165 | int flags; /* TYPE(History) flags */ | |||
| 166 | #define H_UNIQUE1 1 /* Store only unique elements */ | |||
| 167 | } history_t; | |||
| 168 | ||||
| 169 | static int history_def_next(void *, TYPE(HistEvent)HistEventW *); | |||
| 170 | static int history_def_first(void *, TYPE(HistEvent)HistEventW *); | |||
| 171 | static int history_def_prev(void *, TYPE(HistEvent)HistEventW *); | |||
| 172 | static int history_def_last(void *, TYPE(HistEvent)HistEventW *); | |||
| 173 | static int history_def_curr(void *, TYPE(HistEvent)HistEventW *); | |||
| 174 | static int history_def_set(void *, TYPE(HistEvent)HistEventW *, const int); | |||
| 175 | static void history_def_clear(void *, TYPE(HistEvent)HistEventW *); | |||
| 176 | static int history_def_enter(void *, TYPE(HistEvent)HistEventW *, const Charwchar_t *); | |||
| 177 | static int history_def_add(void *, TYPE(HistEvent)HistEventW *, const Charwchar_t *); | |||
| 178 | static int history_def_del(void *, TYPE(HistEvent)HistEventW *, const int); | |||
| 179 | ||||
| 180 | static int history_def_init(void **, TYPE(HistEvent)HistEventW *, int); | |||
| 181 | static int history_def_insert(history_t *, TYPE(HistEvent)HistEventW *, const Charwchar_t *); | |||
| 182 | static void history_def_delete(history_t *, TYPE(HistEvent)HistEventW *, hentry_t *); | |||
| 183 | ||||
| 184 | static int history_deldata_nth(history_t *, TYPE(HistEvent)HistEventW *, int, void **); | |||
| 185 | static int history_set_nth(void *, TYPE(HistEvent)HistEventW *, int); | |||
| 186 | ||||
| 187 | #define history_def_setsize(p, num)(void) (((history_t *)p)->max = (num))(void) (((history_t *)p)->max = (num)) | |||
| 188 | #define history_def_getsize(p)(((history_t *)p)->cur) (((history_t *)p)->cur) | |||
| 189 | #define history_def_getunique(p)(((((history_t *)p)->flags) & 1) != 0) (((((history_t *)p)->flags) & H_UNIQUE1) != 0) | |||
| 190 | #define history_def_setunique(p, uni)if (uni) (((history_t *)p)->flags) |= 1; else (((history_t *)p)->flags) &= ~1 \ | |||
| 191 | if (uni) \ | |||
| 192 | (((history_t *)p)->flags) |= H_UNIQUE1; \ | |||
| 193 | else \ | |||
| 194 | (((history_t *)p)->flags) &= ~H_UNIQUE1 | |||
| 195 | ||||
| 196 | #define he_strerror(code)he_errlist[code] he_errlist[code] | |||
| 197 | #define he_seterrev(evp, code){ evp->num = code; evp->str = he_errlist[code]; } {\ | |||
| 198 | evp->num = code;\ | |||
| 199 | evp->str = he_strerror(code)he_errlist[code];\ | |||
| 200 | } | |||
| 201 | ||||
| 202 | /* error messages */ | |||
| 203 | static const Charwchar_t *const he_errlist[] = { | |||
| 204 | STR("OK")L"OK", | |||
| 205 | STR("unknown error")L"unknown error", | |||
| 206 | STR("malloc() failed")L"malloc() failed", | |||
| 207 | STR("first event not found")L"first event not found", | |||
| 208 | STR("last event not found")L"last event not found", | |||
| 209 | STR("empty list")L"empty list", | |||
| 210 | STR("no next event")L"no next event", | |||
| 211 | STR("no previous event")L"no previous event", | |||
| 212 | STR("current event is invalid")L"current event is invalid", | |||
| 213 | STR("event not found")L"event not found", | |||
| 214 | STR("can't read history from file")L"can't read history from file", | |||
| 215 | STR("can't write history")L"can't write history", | |||
| 216 | STR("required parameter(s) not supplied")L"required parameter(s) not supplied", | |||
| 217 | STR("history size negative")L"history size negative", | |||
| 218 | STR("function not allowed with other history-functions-set the default")L"function not allowed with other history-functions-set the default", | |||
| 219 | STR("bad parameters")L"bad parameters" | |||
| 220 | }; | |||
| 221 | /* error codes */ | |||
| 222 | #define _HE_OK0 0 | |||
| 223 | #define _HE_UNKNOWN1 1 | |||
| 224 | #define _HE_MALLOC_FAILED2 2 | |||
| 225 | #define _HE_FIRST_NOTFOUND3 3 | |||
| 226 | #define _HE_LAST_NOTFOUND4 4 | |||
| 227 | #define _HE_EMPTY_LIST5 5 | |||
| 228 | #define _HE_END_REACHED6 6 | |||
| 229 | #define _HE_START_REACHED7 7 | |||
| 230 | #define _HE_CURR_INVALID8 8 | |||
| 231 | #define _HE_NOT_FOUND9 9 | |||
| 232 | #define _HE_HIST_READ10 10 | |||
| 233 | #define _HE_HIST_WRITE11 11 | |||
| 234 | #define _HE_PARAM_MISSING12 12 | |||
| 235 | #define _HE_SIZE_NEGATIVE13 13 | |||
| 236 | #define _HE_NOT_ALLOWED14 14 | |||
| 237 | #define _HE_BAD_PARAM15 15 | |||
| 238 | ||||
| 239 | /* history_def_first(): | |||
| 240 | * Default function to return the first event in the history. | |||
| 241 | */ | |||
| 242 | static int | |||
| 243 | history_def_first(void *p, TYPE(HistEvent)HistEventW *ev) | |||
| 244 | { | |||
| 245 | history_t *h = (history_t *) p; | |||
| 246 | ||||
| 247 | h->cursor = h->list.next; | |||
| 248 | if (h->cursor != &h->list) | |||
| 249 | *ev = h->cursor->ev; | |||
| 250 | else { | |||
| 251 | he_seterrev(ev, _HE_FIRST_NOTFOUND){ ev->num = 3; ev->str = he_errlist[3]; }; | |||
| 252 | return -1; | |||
| 253 | } | |||
| 254 | ||||
| 255 | return 0; | |||
| 256 | } | |||
| 257 | ||||
| 258 | ||||
| 259 | /* history_def_last(): | |||
| 260 | * Default function to return the last event in the history. | |||
| 261 | */ | |||
| 262 | static int | |||
| 263 | history_def_last(void *p, TYPE(HistEvent)HistEventW *ev) | |||
| 264 | { | |||
| 265 | history_t *h = (history_t *) p; | |||
| 266 | ||||
| 267 | h->cursor = h->list.prev; | |||
| 268 | if (h->cursor != &h->list) | |||
| 269 | *ev = h->cursor->ev; | |||
| 270 | else { | |||
| 271 | he_seterrev(ev, _HE_LAST_NOTFOUND){ ev->num = 4; ev->str = he_errlist[4]; }; | |||
| 272 | return -1; | |||
| 273 | } | |||
| 274 | ||||
| 275 | return 0; | |||
| 276 | } | |||
| 277 | ||||
| 278 | ||||
| 279 | /* history_def_next(): | |||
| 280 | * Default function to return the next event in the history. | |||
| 281 | */ | |||
| 282 | static int | |||
| 283 | history_def_next(void *p, TYPE(HistEvent)HistEventW *ev) | |||
| 284 | { | |||
| 285 | history_t *h = (history_t *) p; | |||
| 286 | ||||
| 287 | if (h->cursor == &h->list) { | |||
| 288 | he_seterrev(ev, _HE_EMPTY_LIST){ ev->num = 5; ev->str = he_errlist[5]; }; | |||
| 289 | return -1; | |||
| 290 | } | |||
| 291 | ||||
| 292 | if (h->cursor->next == &h->list) { | |||
| 293 | he_seterrev(ev, _HE_END_REACHED){ ev->num = 6; ev->str = he_errlist[6]; }; | |||
| 294 | return -1; | |||
| 295 | } | |||
| 296 | ||||
| 297 | h->cursor = h->cursor->next; | |||
| 298 | *ev = h->cursor->ev; | |||
| 299 | ||||
| 300 | return 0; | |||
| 301 | } | |||
| 302 | ||||
| 303 | ||||
| 304 | /* history_def_prev(): | |||
| 305 | * Default function to return the previous event in the history. | |||
| 306 | */ | |||
| 307 | static int | |||
| 308 | history_def_prev(void *p, TYPE(HistEvent)HistEventW *ev) | |||
| 309 | { | |||
| 310 | history_t *h = (history_t *) p; | |||
| 311 | ||||
| 312 | if (h->cursor == &h->list) { | |||
| 313 | he_seterrev(ev,{ ev->num = (h->cur > 0) ? 6 : 5; ev->str = he_errlist [(h->cur > 0) ? 6 : 5]; } | |||
| 314 | (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST){ ev->num = (h->cur > 0) ? 6 : 5; ev->str = he_errlist [(h->cur > 0) ? 6 : 5]; }; | |||
| 315 | return -1; | |||
| 316 | } | |||
| 317 | ||||
| 318 | if (h->cursor->prev == &h->list) { | |||
| 319 | he_seterrev(ev, _HE_START_REACHED){ ev->num = 7; ev->str = he_errlist[7]; }; | |||
| 320 | return -1; | |||
| 321 | } | |||
| 322 | ||||
| 323 | h->cursor = h->cursor->prev; | |||
| 324 | *ev = h->cursor->ev; | |||
| 325 | ||||
| 326 | return 0; | |||
| 327 | } | |||
| 328 | ||||
| 329 | ||||
| 330 | /* history_def_curr(): | |||
| 331 | * Default function to return the current event in the history. | |||
| 332 | */ | |||
| 333 | static int | |||
| 334 | history_def_curr(void *p, TYPE(HistEvent)HistEventW *ev) | |||
| 335 | { | |||
| 336 | history_t *h = (history_t *) p; | |||
| 337 | ||||
| 338 | if (h->cursor != &h->list) | |||
| 339 | *ev = h->cursor->ev; | |||
| 340 | else { | |||
| 341 | he_seterrev(ev,{ ev->num = (h->cur > 0) ? 8 : 5; ev->str = he_errlist [(h->cur > 0) ? 8 : 5]; } | |||
| 342 | (h->cur > 0) ? _HE_CURR_INVALID : _HE_EMPTY_LIST){ ev->num = (h->cur > 0) ? 8 : 5; ev->str = he_errlist [(h->cur > 0) ? 8 : 5]; }; | |||
| 343 | return -1; | |||
| 344 | } | |||
| 345 | ||||
| 346 | return 0; | |||
| 347 | } | |||
| 348 | ||||
| 349 | ||||
| 350 | /* history_def_set(): | |||
| 351 | * Default function to set the current event in the history to the | |||
| 352 | * given one. | |||
| 353 | */ | |||
| 354 | static int | |||
| 355 | history_def_set(void *p, TYPE(HistEvent)HistEventW *ev, const int n) | |||
| 356 | { | |||
| 357 | history_t *h = (history_t *) p; | |||
| 358 | ||||
| 359 | if (h->cur == 0) { | |||
| 360 | he_seterrev(ev, _HE_EMPTY_LIST){ ev->num = 5; ev->str = he_errlist[5]; }; | |||
| 361 | return -1; | |||
| 362 | } | |||
| 363 | if (h->cursor == &h->list || h->cursor->ev.num != n) { | |||
| 364 | for (h->cursor = h->list.next; h->cursor != &h->list; | |||
| 365 | h->cursor = h->cursor->next) | |||
| 366 | if (h->cursor->ev.num == n) | |||
| 367 | break; | |||
| 368 | } | |||
| 369 | if (h->cursor == &h->list) { | |||
| 370 | he_seterrev(ev, _HE_NOT_FOUND){ ev->num = 9; ev->str = he_errlist[9]; }; | |||
| 371 | return -1; | |||
| 372 | } | |||
| 373 | return 0; | |||
| 374 | } | |||
| 375 | ||||
| 376 | ||||
| 377 | /* history_set_nth(): | |||
| 378 | * Default function to set the current event in the history to the | |||
| 379 | * n-th one. | |||
| 380 | */ | |||
| 381 | static int | |||
| 382 | history_set_nth(void *p, TYPE(HistEvent)HistEventW *ev, int n) | |||
| 383 | { | |||
| 384 | history_t *h = (history_t *) p; | |||
| 385 | ||||
| 386 | if (h->cur == 0) { | |||
| 387 | he_seterrev(ev, _HE_EMPTY_LIST){ ev->num = 5; ev->str = he_errlist[5]; }; | |||
| 388 | return -1; | |||
| 389 | } | |||
| 390 | for (h->cursor = h->list.prev; h->cursor != &h->list; | |||
| 391 | h->cursor = h->cursor->prev) | |||
| 392 | if (n-- <= 0) | |||
| 393 | break; | |||
| 394 | if (h->cursor == &h->list) { | |||
| 395 | he_seterrev(ev, _HE_NOT_FOUND){ ev->num = 9; ev->str = he_errlist[9]; }; | |||
| 396 | return -1; | |||
| 397 | } | |||
| 398 | return 0; | |||
| 399 | } | |||
| 400 | ||||
| 401 | ||||
| 402 | /* history_def_add(): | |||
| 403 | * Append string to element | |||
| 404 | */ | |||
| 405 | static int | |||
| 406 | history_def_add(void *p, TYPE(HistEvent)HistEventW *ev, const Charwchar_t *str) | |||
| 407 | { | |||
| 408 | history_t *h = (history_t *) p; | |||
| 409 | size_t len; | |||
| 410 | Charwchar_t *s; | |||
| 411 | HistEventPrivate *evp = (void *)&h->cursor->ev; | |||
| 412 | ||||
| 413 | if (h->cursor == &h->list) | |||
| 414 | return history_def_enter(p, ev, str); | |||
| 415 | len = Strlen(evp->str)wcslen(evp->str) + Strlen(str)wcslen(str) + 1; | |||
| 416 | s = reallocarray(NULL((void *)0), len, sizeof(*s)); | |||
| 417 | if (s == NULL((void *)0)) { | |||
| 418 | he_seterrev(ev, _HE_MALLOC_FAILED){ ev->num = 2; ev->str = he_errlist[2]; }; | |||
| 419 | return -1; | |||
| 420 | } | |||
| 421 | (void) Strncpy(s, h->cursor->ev.str, len)wcsncpy(s, h->cursor->ev.str, len); | |||
| 422 | s[len - 1] = '\0'; | |||
| 423 | (void) Strncat(s, str, len - Strlen(s) - 1)wcsncat(s, str, len - wcslen(s) - 1); | |||
| 424 | free(evp->str); | |||
| 425 | evp->str = s; | |||
| 426 | *ev = h->cursor->ev; | |||
| 427 | return 0; | |||
| 428 | } | |||
| 429 | ||||
| 430 | ||||
| 431 | static int | |||
| 432 | history_deldata_nth(history_t *h, TYPE(HistEvent)HistEventW *ev, | |||
| 433 | int num, void **data) | |||
| 434 | { | |||
| 435 | if (history_set_nth(h, ev, num) != 0) | |||
| 436 | return -1; | |||
| 437 | /* magic value to skip delete (just set to n-th history) */ | |||
| 438 | if (data == (void **)-1) | |||
| 439 | return 0; | |||
| 440 | ev->str = Strdup(h->cursor->ev.str)wcsdup(h->cursor->ev.str); | |||
| 441 | ev->num = h->cursor->ev.num; | |||
| 442 | if (data) | |||
| 443 | *data = h->cursor->data; | |||
| 444 | history_def_delete(h, ev, h->cursor); | |||
| 445 | return 0; | |||
| 446 | } | |||
| 447 | ||||
| 448 | ||||
| 449 | /* history_def_del(): | |||
| 450 | * Delete element hp of the h list | |||
| 451 | */ | |||
| 452 | /* ARGSUSED */ | |||
| 453 | static int | |||
| 454 | history_def_del(void *p, TYPE(HistEvent)HistEventW *ev __attribute__((__unused__)), | |||
| 455 | const int num) | |||
| 456 | { | |||
| 457 | history_t *h = (history_t *) p; | |||
| 458 | if (history_def_set(h, ev, num) != 0) | |||
| 459 | return -1; | |||
| 460 | ev->str = Strdup(h->cursor->ev.str)wcsdup(h->cursor->ev.str); | |||
| 461 | ev->num = h->cursor->ev.num; | |||
| 462 | history_def_delete(h, ev, h->cursor); | |||
| 463 | return 0; | |||
| 464 | } | |||
| 465 | ||||
| 466 | ||||
| 467 | /* history_def_delete(): | |||
| 468 | * Delete element hp of the h list | |||
| 469 | */ | |||
| 470 | /* ARGSUSED */ | |||
| 471 | static void | |||
| 472 | history_def_delete(history_t *h, | |||
| 473 | TYPE(HistEvent)HistEventW *ev __attribute__((__unused__)), hentry_t *hp) | |||
| 474 | { | |||
| 475 | HistEventPrivate *evp = (void *)&hp->ev; | |||
| 476 | if (hp == &h->list) | |||
| 477 | abort(); | |||
| 478 | if (h->cursor == hp) { | |||
| 479 | h->cursor = hp->prev; | |||
| 480 | if (h->cursor == &h->list) | |||
| 481 | h->cursor = hp->next; | |||
| 482 | } | |||
| 483 | hp->prev->next = hp->next; | |||
| 484 | hp->next->prev = hp->prev; | |||
| 485 | free(evp->str); | |||
| 486 | free(hp); | |||
| 487 | h->cur--; | |||
| 488 | } | |||
| 489 | ||||
| 490 | ||||
| 491 | /* history_def_insert(): | |||
| 492 | * Insert element with string str in the h list | |||
| 493 | */ | |||
| 494 | static int | |||
| 495 | history_def_insert(history_t *h, TYPE(HistEvent)HistEventW *ev, const Charwchar_t *str) | |||
| 496 | { | |||
| 497 | ||||
| 498 | h->cursor = (hentry_t *) malloc(sizeof(hentry_t)); | |||
| 499 | if (h->cursor == NULL((void *)0)) | |||
| 500 | goto oomem; | |||
| 501 | if ((h->cursor->ev.str = h_strdup(str)wcsdup(str)) == NULL((void *)0)) { | |||
| 502 | free(h->cursor); | |||
| 503 | goto oomem; | |||
| 504 | } | |||
| 505 | h->cursor->data = NULL((void *)0); | |||
| 506 | h->cursor->ev.num = ++h->eventid; | |||
| 507 | h->cursor->next = h->list.next; | |||
| 508 | h->cursor->prev = &h->list; | |||
| 509 | h->list.next->prev = h->cursor; | |||
| 510 | h->list.next = h->cursor; | |||
| 511 | h->cur++; | |||
| 512 | ||||
| 513 | *ev = h->cursor->ev; | |||
| 514 | return 0; | |||
| 515 | oomem: | |||
| 516 | he_seterrev(ev, _HE_MALLOC_FAILED){ ev->num = 2; ev->str = he_errlist[2]; }; | |||
| 517 | return -1; | |||
| 518 | } | |||
| 519 | ||||
| 520 | ||||
| 521 | /* history_def_enter(): | |||
| 522 | * Default function to enter an item in the history | |||
| 523 | */ | |||
| 524 | static int | |||
| 525 | history_def_enter(void *p, TYPE(HistEvent)HistEventW *ev, const Charwchar_t *str) | |||
| 526 | { | |||
| 527 | history_t *h = (history_t *) p; | |||
| 528 | ||||
| 529 | if ((h->flags & H_UNIQUE1) != 0 && h->list.next != &h->list && | |||
| 530 | Strcmp(h->list.next->ev.str, str)wcscmp(h->list.next->ev.str, str) == 0) | |||
| 531 | return 0; | |||
| 532 | ||||
| 533 | if (history_def_insert(h, ev, str) == -1) | |||
| 534 | return -1; /* error, keep error message */ | |||
| 535 | ||||
| 536 | /* | |||
| 537 | * Always keep at least one entry. | |||
| 538 | * This way we don't have to check for the empty list. | |||
| 539 | */ | |||
| 540 | while (h->cur > h->max && h->cur > 0) | |||
| 541 | history_def_delete(h, ev, h->list.prev); | |||
| 542 | ||||
| 543 | return 1; | |||
| 544 | } | |||
| 545 | ||||
| 546 | ||||
| 547 | /* history_def_init(): | |||
| 548 | * Default history initialization function | |||
| 549 | */ | |||
| 550 | /* ARGSUSED */ | |||
| 551 | static int | |||
| 552 | history_def_init(void **p, TYPE(HistEvent)HistEventW *ev __attribute__((__unused__)), int n) | |||
| 553 | { | |||
| 554 | history_t *h = (history_t *) malloc(sizeof(history_t)); | |||
| 555 | if (h == NULL((void *)0)) | |||
| 556 | return -1; | |||
| 557 | ||||
| 558 | if (n <= 0) | |||
| 559 | n = 0; | |||
| 560 | h->eventid = 0; | |||
| 561 | h->cur = 0; | |||
| 562 | h->max = n; | |||
| 563 | h->list.next = h->list.prev = &h->list; | |||
| 564 | h->list.ev.str = NULL((void *)0); | |||
| 565 | h->list.ev.num = 0; | |||
| 566 | h->cursor = &h->list; | |||
| 567 | h->flags = 0; | |||
| 568 | *p = h; | |||
| 569 | return 0; | |||
| 570 | } | |||
| 571 | ||||
| 572 | ||||
| 573 | /* history_def_clear(): | |||
| 574 | * Default history cleanup function | |||
| 575 | */ | |||
| 576 | static void | |||
| 577 | history_def_clear(void *p, TYPE(HistEvent)HistEventW *ev) | |||
| 578 | { | |||
| 579 | history_t *h = (history_t *) p; | |||
| 580 | ||||
| 581 | while (h->list.prev != &h->list) | |||
| 582 | history_def_delete(h, ev, h->list.prev); | |||
| ||||
| 583 | h->eventid = 0; | |||
| 584 | h->cur = 0; | |||
| 585 | } | |||
| 586 | ||||
| 587 | ||||
| 588 | ||||
| 589 | ||||
| 590 | /************************************************************************/ | |||
| 591 | ||||
| 592 | /* history_init(): | |||
| 593 | * Initialization function. | |||
| 594 | */ | |||
| 595 | TYPE(History)HistoryW * | |||
| 596 | FUN(history,init)history_winit(void) | |||
| 597 | { | |||
| 598 | TYPE(HistEvent)HistEventW ev; | |||
| 599 | TYPE(History)HistoryW *h = (TYPE(History)HistoryW *) malloc(sizeof(TYPE(History)HistoryW)); | |||
| 600 | if (h == NULL((void *)0)) | |||
| 601 | return NULL((void *)0); | |||
| 602 | ||||
| 603 | if (history_def_init(&h->h_ref, &ev, 0) == -1) { | |||
| 604 | free(h); | |||
| 605 | return NULL((void *)0); | |||
| 606 | } | |||
| 607 | h->h_ent = -1; | |||
| 608 | h->h_next = history_def_next; | |||
| 609 | h->h_first = history_def_first; | |||
| 610 | h->h_last = history_def_last; | |||
| 611 | h->h_prev = history_def_prev; | |||
| 612 | h->h_curr = history_def_curr; | |||
| 613 | h->h_set = history_def_set; | |||
| 614 | h->h_clear = history_def_clear; | |||
| 615 | h->h_enter = history_def_enter; | |||
| 616 | h->h_add = history_def_add; | |||
| 617 | h->h_del = history_def_del; | |||
| 618 | ||||
| 619 | return h; | |||
| 620 | } | |||
| 621 | ||||
| 622 | ||||
| 623 | /* history_end(): | |||
| 624 | * clean up history; | |||
| 625 | */ | |||
| 626 | void | |||
| 627 | FUN(history,end)history_wend(TYPE(History)HistoryW *h) | |||
| 628 | { | |||
| 629 | TYPE(HistEvent)HistEventW ev; | |||
| 630 | ||||
| 631 | if (h->h_next == history_def_next) | |||
| 632 | history_def_clear(h->h_ref, &ev); | |||
| 633 | free(h->h_ref); | |||
| 634 | free(h); | |||
| 635 | } | |||
| 636 | ||||
| 637 | ||||
| 638 | ||||
| 639 | /* history_setsize(): | |||
| 640 | * Set history number of events | |||
| 641 | */ | |||
| 642 | static int | |||
| 643 | history_setsize(TYPE(History)HistoryW *h, TYPE(HistEvent)HistEventW *ev, int num) | |||
| 644 | { | |||
| 645 | ||||
| 646 | if (h->h_next != history_def_next) { | |||
| 647 | he_seterrev(ev, _HE_NOT_ALLOWED){ ev->num = 14; ev->str = he_errlist[14]; }; | |||
| 648 | return -1; | |||
| 649 | } | |||
| 650 | if (num < 0) { | |||
| 651 | he_seterrev(ev, _HE_BAD_PARAM){ ev->num = 15; ev->str = he_errlist[15]; }; | |||
| 652 | return -1; | |||
| 653 | } | |||
| 654 | history_def_setsize(h->h_ref, num)(void) (((history_t *)h->h_ref)->max = (num)); | |||
| 655 | return 0; | |||
| 656 | } | |||
| 657 | ||||
| 658 | ||||
| 659 | /* history_getsize(): | |||
| 660 | * Get number of events currently in history | |||
| 661 | */ | |||
| 662 | static int | |||
| 663 | history_getsize(TYPE(History)HistoryW *h, TYPE(HistEvent)HistEventW *ev) | |||
| 664 | { | |||
| 665 | if (h->h_next != history_def_next) { | |||
| 666 | he_seterrev(ev, _HE_NOT_ALLOWED){ ev->num = 14; ev->str = he_errlist[14]; }; | |||
| 667 | return -1; | |||
| 668 | } | |||
| 669 | ev->num = history_def_getsize(h->h_ref)(((history_t *)h->h_ref)->cur); | |||
| 670 | if (ev->num < -1) { | |||
| 671 | he_seterrev(ev, _HE_SIZE_NEGATIVE){ ev->num = 13; ev->str = he_errlist[13]; }; | |||
| 672 | return -1; | |||
| 673 | } | |||
| 674 | return 0; | |||
| 675 | } | |||
| 676 | ||||
| 677 | ||||
| 678 | /* history_setunique(): | |||
| 679 | * Set if adjacent equal events should not be entered in history. | |||
| 680 | */ | |||
| 681 | static int | |||
| 682 | history_setunique(TYPE(History)HistoryW *h, TYPE(HistEvent)HistEventW *ev, int uni) | |||
| 683 | { | |||
| 684 | ||||
| 685 | if (h->h_next != history_def_next) { | |||
| 686 | he_seterrev(ev, _HE_NOT_ALLOWED){ ev->num = 14; ev->str = he_errlist[14]; }; | |||
| 687 | return -1; | |||
| 688 | } | |||
| 689 | history_def_setunique(h->h_ref, uni)if (uni) (((history_t *)h->h_ref)->flags) |= 1; else (( (history_t *)h->h_ref)->flags) &= ~1; | |||
| 690 | return 0; | |||
| 691 | } | |||
| 692 | ||||
| 693 | ||||
| 694 | /* history_getunique(): | |||
| 695 | * Get if adjacent equal events should not be entered in history. | |||
| 696 | */ | |||
| 697 | static int | |||
| 698 | history_getunique(TYPE(History)HistoryW *h, TYPE(HistEvent)HistEventW *ev) | |||
| 699 | { | |||
| 700 | if (h->h_next != history_def_next) { | |||
| 701 | he_seterrev(ev, _HE_NOT_ALLOWED){ ev->num = 14; ev->str = he_errlist[14]; }; | |||
| 702 | return -1; | |||
| 703 | } | |||
| 704 | ev->num = history_def_getunique(h->h_ref)(((((history_t *)h->h_ref)->flags) & 1) != 0); | |||
| 705 | return 0; | |||
| 706 | } | |||
| 707 | ||||
| 708 | ||||
| 709 | /* history_set_fun(): | |||
| 710 | * Set history functions | |||
| 711 | */ | |||
| 712 | static int | |||
| 713 | history_set_fun(TYPE(History)HistoryW *h, TYPE(History)HistoryW *nh) | |||
| 714 | { | |||
| 715 | TYPE(HistEvent)HistEventW ev; | |||
| 716 | ||||
| 717 | if (nh->h_first == NULL((void *)0) || nh->h_next == NULL((void *)0) || nh->h_last == NULL((void *)0) || | |||
| 718 | nh->h_prev == NULL((void *)0) || nh->h_curr == NULL((void *)0) || nh->h_set == NULL((void *)0) || | |||
| 719 | nh->h_enter == NULL((void *)0) || nh->h_add == NULL((void *)0) || nh->h_clear == NULL((void *)0) || | |||
| 720 | nh->h_del == NULL((void *)0) || nh->h_ref == NULL((void *)0)) { | |||
| 721 | if (h->h_next != history_def_next) { | |||
| 722 | history_def_init(&h->h_ref, &ev, 0); | |||
| 723 | h->h_first = history_def_first; | |||
| 724 | h->h_next = history_def_next; | |||
| 725 | h->h_last = history_def_last; | |||
| 726 | h->h_prev = history_def_prev; | |||
| 727 | h->h_curr = history_def_curr; | |||
| 728 | h->h_set = history_def_set; | |||
| 729 | h->h_clear = history_def_clear; | |||
| 730 | h->h_enter = history_def_enter; | |||
| 731 | h->h_add = history_def_add; | |||
| 732 | h->h_del = history_def_del; | |||
| 733 | } | |||
| 734 | return -1; | |||
| 735 | } | |||
| 736 | if (h->h_next == history_def_next) | |||
| 737 | history_def_clear(h->h_ref, &ev); | |||
| 738 | ||||
| 739 | h->h_ent = -1; | |||
| 740 | h->h_first = nh->h_first; | |||
| 741 | h->h_next = nh->h_next; | |||
| 742 | h->h_last = nh->h_last; | |||
| 743 | h->h_prev = nh->h_prev; | |||
| 744 | h->h_curr = nh->h_curr; | |||
| 745 | h->h_set = nh->h_set; | |||
| 746 | h->h_clear = nh->h_clear; | |||
| 747 | h->h_enter = nh->h_enter; | |||
| 748 | h->h_add = nh->h_add; | |||
| 749 | h->h_del = nh->h_del; | |||
| 750 | ||||
| 751 | return 0; | |||
| 752 | } | |||
| 753 | ||||
| 754 | ||||
| 755 | /* history_load(): | |||
| 756 | * TYPE(History) load function | |||
| 757 | */ | |||
| 758 | static int | |||
| 759 | history_load(TYPE(History)HistoryW *h, const char *fname) | |||
| 760 | { | |||
| 761 | FILE *fp; | |||
| 762 | char *line; | |||
| 763 | size_t llen; | |||
| 764 | ssize_t sz; | |||
| 765 | size_t max_size; | |||
| 766 | char *ptr; | |||
| 767 | int i = -1; | |||
| 768 | TYPE(HistEvent)HistEventW ev; | |||
| 769 | #ifndef NARROWCHAR | |||
| 770 | static ct_buffer_t conv; | |||
| 771 | #endif | |||
| 772 | ||||
| 773 | if ((fp = fopen(fname, "r")) == NULL((void *)0)) | |||
| 774 | return i; | |||
| 775 | ||||
| 776 | line = NULL((void *)0); | |||
| 777 | llen = 0; | |||
| 778 | if ((sz = getline(&line, &llen, fp)) == -1) | |||
| 779 | goto done; | |||
| 780 | ||||
| 781 | if (strncmp(line, hist_cookie, sz) != 0) | |||
| 782 | goto done; | |||
| 783 | ||||
| 784 | ptr = malloc(max_size = 1024); | |||
| 785 | if (ptr == NULL((void *)0)) | |||
| 786 | goto done; | |||
| 787 | for (i = 0; (sz = getline(&line, &llen, fp)) != -1; i++) { | |||
| 788 | if (sz > 0 && line[sz - 1] == '\n') | |||
| 789 | line[--sz] = '\0'; | |||
| 790 | if (max_size < sz) { | |||
| 791 | char *nptr; | |||
| 792 | max_size = (sz + 1024) & ~1023; | |||
| 793 | nptr = realloc(ptr, max_size); | |||
| 794 | if (nptr == NULL((void *)0)) { | |||
| 795 | i = -1; | |||
| 796 | goto oomem; | |||
| 797 | } | |||
| 798 | ptr = nptr; | |||
| 799 | } | |||
| 800 | (void) strunvis(ptr, line); | |||
| 801 | if (HENTER(h, &ev, ct_decode_string(ptr, &conv))(*(h)->h_enter)((h)->h_ref, &ev, ct_decode_string(ptr , &conv)) == -1) { | |||
| 802 | i = -1; | |||
| 803 | goto oomem; | |||
| 804 | } | |||
| 805 | } | |||
| 806 | oomem: | |||
| 807 | free(ptr); | |||
| 808 | done: | |||
| 809 | free(line); | |||
| 810 | (void) fclose(fp); | |||
| 811 | return i; | |||
| 812 | } | |||
| 813 | ||||
| 814 | ||||
| 815 | /* history_save_fp(): | |||
| 816 | * TYPE(History) save function | |||
| 817 | */ | |||
| 818 | static int | |||
| 819 | history_save_fp(TYPE(History)HistoryW *h, FILE *fp) | |||
| 820 | { | |||
| 821 | TYPE(HistEvent)HistEventW ev; | |||
| 822 | int i = -1, retval; | |||
| 823 | size_t len, max_size; | |||
| 824 | char *ptr; | |||
| 825 | #ifndef NARROWCHAR | |||
| 826 | static ct_buffer_t conv; | |||
| 827 | #endif | |||
| 828 | ||||
| 829 | if (fchmod(fileno(fp)(!__isthreaded ? ((fp)->_file) : (fileno)(fp)), S_IRUSR0000400|S_IWUSR0000200) == -1) | |||
| 830 | goto done; | |||
| 831 | if (fputs(hist_cookie, fp) == EOF(-1)) | |||
| 832 | goto done; | |||
| 833 | ptr = malloc(max_size = 1024); | |||
| 834 | if (ptr == NULL((void *)0)) | |||
| 835 | goto done; | |||
| 836 | for (i = 0, retval = HLAST(h, &ev)(*(h)->h_last)((h)->h_ref, &ev); | |||
| 837 | retval != -1; | |||
| 838 | retval = HPREV(h, &ev)(*(h)->h_prev)((h)->h_ref, &ev), i++) { | |||
| 839 | len = Strlen(ev.str)wcslen(ev.str) * 4 + 1; | |||
| 840 | if (len > max_size) { | |||
| 841 | char *nptr; | |||
| 842 | max_size = (len + 1024) & ~1023; | |||
| 843 | nptr = realloc(ptr, max_size); | |||
| 844 | if (nptr == NULL((void *)0)) { | |||
| 845 | i = -1; | |||
| 846 | goto oomem; | |||
| 847 | } | |||
| 848 | ptr = nptr; | |||
| 849 | } | |||
| 850 | (void) strnvis(ptr, ct_encode_string(ev.str, &conv), max_size, | |||
| 851 | VIS_WHITE(0x04 | 0x08 | 0x10)); | |||
| 852 | (void) fprintf(fp, "%s\n", ptr); | |||
| 853 | } | |||
| 854 | oomem: | |||
| 855 | free(ptr); | |||
| 856 | done: | |||
| 857 | return i; | |||
| 858 | } | |||
| 859 | ||||
| 860 | ||||
| 861 | /* history_save(): | |||
| 862 | * History save function | |||
| 863 | */ | |||
| 864 | static int | |||
| 865 | history_save(TYPE(History)HistoryW *h, const char *fname) | |||
| 866 | { | |||
| 867 | FILE *fp; | |||
| 868 | int i; | |||
| 869 | ||||
| 870 | if ((fp = fopen(fname, "w")) == NULL((void *)0)) | |||
| 871 | return -1; | |||
| 872 | ||||
| 873 | i = history_save_fp(h, fp); | |||
| 874 | ||||
| 875 | (void) fclose(fp); | |||
| 876 | return i; | |||
| 877 | } | |||
| 878 | ||||
| 879 | ||||
| 880 | /* history_prev_event(): | |||
| 881 | * Find the previous event, with number given | |||
| 882 | */ | |||
| 883 | static int | |||
| 884 | history_prev_event(TYPE(History)HistoryW *h, TYPE(HistEvent)HistEventW *ev, int num) | |||
| 885 | { | |||
| 886 | int retval; | |||
| 887 | ||||
| 888 | for (retval = HCURR(h, ev)(*(h)->h_curr)((h)->h_ref, ev); retval != -1; retval = HPREV(h, ev)(*(h)->h_prev)((h)->h_ref, ev)) | |||
| 889 | if (ev->num == num) | |||
| 890 | return 0; | |||
| 891 | ||||
| 892 | he_seterrev(ev, _HE_NOT_FOUND){ ev->num = 9; ev->str = he_errlist[9]; }; | |||
| 893 | return -1; | |||
| 894 | } | |||
| 895 | ||||
| 896 | ||||
| 897 | static int | |||
| 898 | history_next_evdata(TYPE(History)HistoryW *h, TYPE(HistEvent)HistEventW *ev, int num, void **d) | |||
| 899 | { | |||
| 900 | int retval; | |||
| 901 | ||||
| 902 | for (retval = HCURR(h, ev)(*(h)->h_curr)((h)->h_ref, ev); retval != -1; retval = HPREV(h, ev)(*(h)->h_prev)((h)->h_ref, ev)) | |||
| 903 | if (ev->num == num) { | |||
| 904 | if (d) | |||
| 905 | *d = ((history_t *)h->h_ref)->cursor->data; | |||
| 906 | return 0; | |||
| 907 | } | |||
| 908 | ||||
| 909 | he_seterrev(ev, _HE_NOT_FOUND){ ev->num = 9; ev->str = he_errlist[9]; }; | |||
| 910 | return -1; | |||
| 911 | } | |||
| 912 | ||||
| 913 | ||||
| 914 | /* history_next_event(): | |||
| 915 | * Find the next event, with number given | |||
| 916 | */ | |||
| 917 | static int | |||
| 918 | history_next_event(TYPE(History)HistoryW *h, TYPE(HistEvent)HistEventW *ev, int num) | |||
| 919 | { | |||
| 920 | int retval; | |||
| 921 | ||||
| 922 | for (retval = HCURR(h, ev)(*(h)->h_curr)((h)->h_ref, ev); retval != -1; retval = HNEXT(h, ev)(*(h)->h_next)((h)->h_ref, ev)) | |||
| 923 | if (ev->num == num) | |||
| 924 | return 0; | |||
| 925 | ||||
| 926 | he_seterrev(ev, _HE_NOT_FOUND){ ev->num = 9; ev->str = he_errlist[9]; }; | |||
| 927 | return -1; | |||
| 928 | } | |||
| 929 | ||||
| 930 | ||||
| 931 | /* history_prev_string(): | |||
| 932 | * Find the previous event beginning with string | |||
| 933 | */ | |||
| 934 | static int | |||
| 935 | history_prev_string(TYPE(History)HistoryW *h, TYPE(HistEvent)HistEventW *ev, const Charwchar_t *str) | |||
| 936 | { | |||
| 937 | size_t len = Strlen(str)wcslen(str); | |||
| 938 | int retval; | |||
| 939 | ||||
| 940 | for (retval = HCURR(h, ev)(*(h)->h_curr)((h)->h_ref, ev); retval != -1; retval = HNEXT(h, ev)(*(h)->h_next)((h)->h_ref, ev)) | |||
| 941 | if (Strncmp(str, ev->str, len)wcsncmp(str, ev->str, len) == 0) | |||
| 942 | return 0; | |||
| 943 | ||||
| 944 | he_seterrev(ev, _HE_NOT_FOUND){ ev->num = 9; ev->str = he_errlist[9]; }; | |||
| 945 | return -1; | |||
| 946 | } | |||
| 947 | ||||
| 948 | ||||
| 949 | /* history_next_string(): | |||
| 950 | * Find the next event beginning with string | |||
| 951 | */ | |||
| 952 | static int | |||
| 953 | history_next_string(TYPE(History)HistoryW *h, TYPE(HistEvent)HistEventW *ev, const Charwchar_t *str) | |||
| 954 | { | |||
| 955 | size_t len = Strlen(str)wcslen(str); | |||
| 956 | int retval; | |||
| 957 | ||||
| 958 | for (retval = HCURR(h, ev)(*(h)->h_curr)((h)->h_ref, ev); retval != -1; retval = HPREV(h, ev)(*(h)->h_prev)((h)->h_ref, ev)) | |||
| 959 | if (Strncmp(str, ev->str, len)wcsncmp(str, ev->str, len) == 0) | |||
| 960 | return 0; | |||
| 961 | ||||
| 962 | he_seterrev(ev, _HE_NOT_FOUND){ ev->num = 9; ev->str = he_errlist[9]; }; | |||
| 963 | return -1; | |||
| 964 | } | |||
| 965 | ||||
| 966 | ||||
| 967 | /* history(): | |||
| 968 | * User interface to history functions. | |||
| 969 | */ | |||
| 970 | int | |||
| 971 | FUNW(history)history_w(TYPE(History)HistoryW *h, TYPE(HistEvent)HistEventW *ev, int fun, ...) | |||
| 972 | { | |||
| 973 | va_list va; | |||
| 974 | const Charwchar_t *str; | |||
| 975 | int retval; | |||
| 976 | ||||
| 977 | va_start(va, fun)__builtin_va_start(va, fun); | |||
| 978 | ||||
| 979 | he_seterrev(ev, _HE_OK){ ev->num = 0; ev->str = he_errlist[0]; }; | |||
| 980 | ||||
| 981 | switch (fun) { | |||
| ||||
| 982 | case H_GETSIZE2: | |||
| 983 | retval = history_getsize(h, ev); | |||
| 984 | break; | |||
| 985 | ||||
| 986 | case H_SETSIZE1: | |||
| 987 | retval = history_setsize(h, ev, va_arg(va, int)__builtin_va_arg(va, int)); | |||
| 988 | break; | |||
| 989 | ||||
| 990 | case H_GETUNIQUE21: | |||
| 991 | retval = history_getunique(h, ev); | |||
| 992 | break; | |||
| 993 | ||||
| 994 | case H_SETUNIQUE20: | |||
| 995 | retval = history_setunique(h, ev, va_arg(va, int)__builtin_va_arg(va, int)); | |||
| 996 | break; | |||
| 997 | ||||
| 998 | case H_ADD9: | |||
| 999 | str = va_arg(va, const Char *)__builtin_va_arg(va, const wchar_t *); | |||
| 1000 | retval = HADD(h, ev, str)(*(h)->h_add)((h)->h_ref, ev, str); | |||
| 1001 | break; | |||
| 1002 | ||||
| 1003 | case H_DEL22: | |||
| 1004 | retval = HDEL(h, ev, va_arg(va, const int))(*(h)->h_del)((h)->h_ref, ev, __builtin_va_arg(va, const int)); | |||
| 1005 | break; | |||
| 1006 | ||||
| 1007 | case H_ENTER10: | |||
| 1008 | str = va_arg(va, const Char *)__builtin_va_arg(va, const wchar_t *); | |||
| 1009 | if ((retval = HENTER(h, ev, str)(*(h)->h_enter)((h)->h_ref, ev, str)) != -1) | |||
| 1010 | h->h_ent = ev->num; | |||
| 1011 | break; | |||
| 1012 | ||||
| 1013 | case H_APPEND11: | |||
| 1014 | str = va_arg(va, const Char *)__builtin_va_arg(va, const wchar_t *); | |||
| 1015 | if ((retval = HSET(h, ev, h->h_ent)(*(h)->h_set)((h)->h_ref, ev, h->h_ent)) != -1) | |||
| 1016 | retval = HADD(h, ev, str)(*(h)->h_add)((h)->h_ref, ev, str); | |||
| 1017 | break; | |||
| 1018 | ||||
| 1019 | case H_FIRST3: | |||
| 1020 | retval = HFIRST(h, ev)(*(h)->h_first)((h)->h_ref, ev); | |||
| 1021 | break; | |||
| 1022 | ||||
| 1023 | case H_NEXT6: | |||
| 1024 | retval = HNEXT(h, ev)(*(h)->h_next)((h)->h_ref, ev); | |||
| 1025 | break; | |||
| 1026 | ||||
| 1027 | case H_LAST4: | |||
| 1028 | retval = HLAST(h, ev)(*(h)->h_last)((h)->h_ref, ev); | |||
| 1029 | break; | |||
| 1030 | ||||
| 1031 | case H_PREV5: | |||
| 1032 | retval = HPREV(h, ev)(*(h)->h_prev)((h)->h_ref, ev); | |||
| 1033 | break; | |||
| 1034 | ||||
| 1035 | case H_CURR8: | |||
| 1036 | retval = HCURR(h, ev)(*(h)->h_curr)((h)->h_ref, ev); | |||
| 1037 | break; | |||
| 1038 | ||||
| 1039 | case H_SET7: | |||
| 1040 | retval = HSET(h, ev, va_arg(va, const int))(*(h)->h_set)((h)->h_ref, ev, __builtin_va_arg(va, const int)); | |||
| 1041 | break; | |||
| 1042 | ||||
| 1043 | case H_CLEAR19: | |||
| 1044 | HCLEAR(h, ev)(*(h)->h_clear)((h)->h_ref, ev); | |||
| 1045 | retval = 0; | |||
| 1046 | break; | |||
| 1047 | ||||
| 1048 | case H_LOAD17: | |||
| 1049 | retval = history_load(h, va_arg(va, const char *)__builtin_va_arg(va, const char *)); | |||
| 1050 | if (retval == -1) | |||
| 1051 | he_seterrev(ev, _HE_HIST_READ){ ev->num = 10; ev->str = he_errlist[10]; }; | |||
| 1052 | break; | |||
| 1053 | ||||
| 1054 | case H_SAVE18: | |||
| 1055 | retval = history_save(h, va_arg(va, const char *)__builtin_va_arg(va, const char *)); | |||
| 1056 | if (retval == -1) | |||
| 1057 | he_seterrev(ev, _HE_HIST_WRITE){ ev->num = 11; ev->str = he_errlist[11]; }; | |||
| 1058 | break; | |||
| 1059 | ||||
| 1060 | case H_SAVE_FP26: | |||
| 1061 | retval = history_save_fp(h, va_arg(va, FILE *)__builtin_va_arg(va, FILE *)); | |||
| 1062 | if (retval == -1) | |||
| 1063 | he_seterrev(ev, _HE_HIST_WRITE){ ev->num = 11; ev->str = he_errlist[11]; }; | |||
| 1064 | break; | |||
| 1065 | ||||
| 1066 | case H_PREV_EVENT16: | |||
| 1067 | retval = history_prev_event(h, ev, va_arg(va, int)__builtin_va_arg(va, int)); | |||
| 1068 | break; | |||
| 1069 | ||||
| 1070 | case H_NEXT_EVENT15: | |||
| 1071 | retval = history_next_event(h, ev, va_arg(va, int)__builtin_va_arg(va, int)); | |||
| 1072 | break; | |||
| 1073 | ||||
| 1074 | case H_PREV_STR14: | |||
| 1075 | retval = history_prev_string(h, ev, va_arg(va, const Char *)__builtin_va_arg(va, const wchar_t *)); | |||
| 1076 | break; | |||
| 1077 | ||||
| 1078 | case H_NEXT_STR13: | |||
| 1079 | retval = history_next_string(h, ev, va_arg(va, const Char *)__builtin_va_arg(va, const wchar_t *)); | |||
| 1080 | break; | |||
| 1081 | ||||
| 1082 | case H_FUNC0: | |||
| 1083 | { | |||
| 1084 | TYPE(History)HistoryW hf; | |||
| 1085 | ||||
| 1086 | hf.h_ref = va_arg(va, void *)__builtin_va_arg(va, void *); | |||
| 1087 | h->h_ent = -1; | |||
| 1088 | hf.h_first = va_arg(va, history_gfun_t)__builtin_va_arg(va, history_gfun_t); | |||
| 1089 | hf.h_next = va_arg(va, history_gfun_t)__builtin_va_arg(va, history_gfun_t); | |||
| 1090 | hf.h_last = va_arg(va, history_gfun_t)__builtin_va_arg(va, history_gfun_t); | |||
| 1091 | hf.h_prev = va_arg(va, history_gfun_t)__builtin_va_arg(va, history_gfun_t); | |||
| 1092 | hf.h_curr = va_arg(va, history_gfun_t)__builtin_va_arg(va, history_gfun_t); | |||
| 1093 | hf.h_set = va_arg(va, history_sfun_t)__builtin_va_arg(va, history_sfun_t); | |||
| 1094 | hf.h_clear = va_arg(va, history_vfun_t)__builtin_va_arg(va, history_vfun_t); | |||
| 1095 | hf.h_enter = va_arg(va, history_efun_t)__builtin_va_arg(va, history_efun_t); | |||
| 1096 | hf.h_add = va_arg(va, history_efun_t)__builtin_va_arg(va, history_efun_t); | |||
| 1097 | hf.h_del = va_arg(va, history_sfun_t)__builtin_va_arg(va, history_sfun_t); | |||
| 1098 | ||||
| 1099 | if ((retval = history_set_fun(h, &hf)) == -1) | |||
| 1100 | he_seterrev(ev, _HE_PARAM_MISSING){ ev->num = 12; ev->str = he_errlist[12]; }; | |||
| 1101 | break; | |||
| 1102 | } | |||
| 1103 | ||||
| 1104 | case H_END12: | |||
| 1105 | FUN(history,end)history_wend(h); | |||
| 1106 | retval = 0; | |||
| 1107 | break; | |||
| 1108 | ||||
| 1109 | case H_NEXT_EVDATA23: | |||
| 1110 | { | |||
| 1111 | int num = va_arg(va, int)__builtin_va_arg(va, int); | |||
| 1112 | void **d = va_arg(va, void **)__builtin_va_arg(va, void **); | |||
| 1113 | retval = history_next_evdata(h, ev, num, d); | |||
| 1114 | break; | |||
| 1115 | } | |||
| 1116 | ||||
| 1117 | case H_DELDATA24: | |||
| 1118 | { | |||
| 1119 | int num = va_arg(va, int)__builtin_va_arg(va, int); | |||
| 1120 | void **d = va_arg(va, void **)__builtin_va_arg(va, void **); | |||
| 1121 | retval = history_deldata_nth((history_t *)h->h_ref, ev, num, d); | |||
| 1122 | break; | |||
| 1123 | } | |||
| 1124 | ||||
| 1125 | case H_REPLACE25: /* only use after H_NEXT_EVDATA */ | |||
| 1126 | { | |||
| 1127 | const Charwchar_t *line = va_arg(va, const Char *)__builtin_va_arg(va, const wchar_t *); | |||
| 1128 | void *d = va_arg(va, void *)__builtin_va_arg(va, void *); | |||
| 1129 | const Charwchar_t *s; | |||
| 1130 | if(!line || !(s = Strdup(line)wcsdup(line))) { | |||
| 1131 | retval = -1; | |||
| 1132 | break; | |||
| 1133 | } | |||
| 1134 | ((history_t *)h->h_ref)->cursor->ev.str = s; | |||
| 1135 | ((history_t *)h->h_ref)->cursor->data = d; | |||
| 1136 | retval = 0; | |||
| 1137 | break; | |||
| 1138 | } | |||
| 1139 | ||||
| 1140 | default: | |||
| 1141 | retval = -1; | |||
| 1142 | he_seterrev(ev, _HE_UNKNOWN){ ev->num = 1; ev->str = he_errlist[1]; }; | |||
| 1143 | break; | |||
| 1144 | } | |||
| 1145 | va_end(va)__builtin_va_end(va); | |||
| 1146 | return retval; | |||
| 1147 | } |