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