1 /* $NetBSD: history.c,v 1.63 2019/10/08 19:17:57 christos 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.63 2019/10/08 19:17:57 christos 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, elen, slen; 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 elen = Strlen(evp->str); 424 slen = Strlen(str); 425 len = elen + slen + 1; 426 s = h_malloc(len * sizeof(*s)); 427 if (s == NULL) { 428 he_seterrev(ev, _HE_MALLOC_FAILED); 429 return -1; 430 } 431 memcpy(s, evp->str, elen * sizeof(*s)); 432 memcpy(s + elen, str, slen * sizeof(*s)); 433 s[len - 1] = '\0'; 434 h_free(evp->str); 435 evp->str = s; 436 *ev = h->cursor->ev; 437 return 0; 438 } 439 440 441 static int 442 history_deldata_nth(history_t *h, TYPE(HistEvent) *ev, 443 int num, void **data) 444 { 445 if (history_set_nth(h, ev, num) != 0) 446 return -1; 447 /* magic value to skip delete (just set to n-th history) */ 448 if (data == (void **)-1) 449 return 0; 450 ev->str = Strdup(h->cursor->ev.str); 451 ev->num = h->cursor->ev.num; 452 if (data) 453 *data = h->cursor->data; 454 history_def_delete(h, ev, h->cursor); 455 return 0; 456 } 457 458 459 /* history_def_del(): 460 * Delete element hp of the h list 461 */ 462 /* ARGSUSED */ 463 static int 464 history_def_del(void *p, TYPE(HistEvent) *ev __attribute__((__unused__)), 465 const int num) 466 { 467 history_t *h = (history_t *) p; 468 if (history_def_set(h, ev, num) != 0) 469 return -1; 470 ev->str = Strdup(h->cursor->ev.str); 471 ev->num = h->cursor->ev.num; 472 history_def_delete(h, ev, h->cursor); 473 return 0; 474 } 475 476 477 /* history_def_delete(): 478 * Delete element hp of the h list 479 */ 480 /* ARGSUSED */ 481 static void 482 history_def_delete(history_t *h, 483 TYPE(HistEvent) *ev __attribute__((__unused__)), hentry_t *hp) 484 { 485 HistEventPrivate *evp = (void *)&hp->ev; 486 if (hp == &h->list) 487 abort(); 488 if (h->cursor == hp) { 489 h->cursor = hp->prev; 490 if (h->cursor == &h->list) 491 h->cursor = hp->next; 492 } 493 hp->prev->next = hp->next; 494 hp->next->prev = hp->prev; 495 h_free(evp->str); 496 h_free(hp); 497 h->cur--; 498 } 499 500 501 /* history_def_insert(): 502 * Insert element with string str in the h list 503 */ 504 static int 505 history_def_insert(history_t *h, TYPE(HistEvent) *ev, const Char *str) 506 { 507 hentry_t *c; 508 509 c = h_malloc(sizeof(*c)); 510 if (c == NULL) 511 goto oomem; 512 if ((c->ev.str = h_strdup(str)) == NULL) { 513 h_free(c); 514 goto oomem; 515 } 516 c->data = NULL; 517 c->ev.num = ++h->eventid; 518 c->next = h->list.next; 519 c->prev = &h->list; 520 h->list.next->prev = c; 521 h->list.next = c; 522 h->cur++; 523 h->cursor = c; 524 525 *ev = c->ev; 526 return 0; 527 oomem: 528 he_seterrev(ev, _HE_MALLOC_FAILED); 529 return -1; 530 } 531 532 533 /* history_def_enter(): 534 * Default function to enter an item in the history 535 */ 536 static int 537 history_def_enter(void *p, TYPE(HistEvent) *ev, const Char *str) 538 { 539 history_t *h = (history_t *) p; 540 541 if ((h->flags & H_UNIQUE) != 0 && h->list.next != &h->list && 542 Strcmp(h->list.next->ev.str, str) == 0) 543 return 0; 544 545 if (history_def_insert(h, ev, str) == -1) 546 return -1; /* error, keep error message */ 547 548 /* 549 * Always keep at least one entry. 550 * This way we don't have to check for the empty list. 551 */ 552 while (h->cur > h->max && h->cur > 0) 553 history_def_delete(h, ev, h->list.prev); 554 555 return 1; 556 } 557 558 559 /* history_def_init(): 560 * Default history initialization function 561 */ 562 /* ARGSUSED */ 563 static int 564 history_def_init(void **p, TYPE(HistEvent) *ev __attribute__((__unused__)), int n) 565 { 566 history_t *h = (history_t *) h_malloc(sizeof(*h)); 567 if (h == NULL) 568 return -1; 569 570 if (n <= 0) 571 n = 0; 572 h->eventid = 0; 573 h->cur = 0; 574 h->max = n; 575 h->list.next = h->list.prev = &h->list; 576 h->list.ev.str = NULL; 577 h->list.ev.num = 0; 578 h->cursor = &h->list; 579 h->flags = 0; 580 *p = h; 581 return 0; 582 } 583 584 585 /* history_def_clear(): 586 * Default history cleanup function 587 */ 588 static void 589 history_def_clear(void *p, TYPE(HistEvent) *ev) 590 { 591 history_t *h = (history_t *) p; 592 593 while (h->list.prev != &h->list) 594 history_def_delete(h, ev, h->list.prev); 595 h->cursor = &h->list; 596 h->eventid = 0; 597 h->cur = 0; 598 } 599 600 601 602 603 /************************************************************************/ 604 605 /* history_init(): 606 * Initialization function. 607 */ 608 TYPE(History) * 609 FUN(history,init)(void) 610 { 611 TYPE(HistEvent) ev; 612 TYPE(History) *h = (TYPE(History) *) h_malloc(sizeof(*h)); 613 if (h == NULL) 614 return NULL; 615 616 if (history_def_init(&h->h_ref, &ev, 0) == -1) { 617 h_free(h); 618 return NULL; 619 } 620 h->h_ent = -1; 621 h->h_next = history_def_next; 622 h->h_first = history_def_first; 623 h->h_last = history_def_last; 624 h->h_prev = history_def_prev; 625 h->h_curr = history_def_curr; 626 h->h_set = history_def_set; 627 h->h_clear = history_def_clear; 628 h->h_enter = history_def_enter; 629 h->h_add = history_def_add; 630 h->h_del = history_def_del; 631 632 return h; 633 } 634 635 636 /* history_end(): 637 * clean up history; 638 */ 639 void 640 FUN(history,end)(TYPE(History) *h) 641 { 642 TYPE(HistEvent) ev; 643 644 if (h->h_next == history_def_next) 645 history_def_clear(h->h_ref, &ev); 646 h_free(h->h_ref); 647 h_free(h); 648 } 649 650 651 652 /* history_setsize(): 653 * Set history number of events 654 */ 655 static int 656 history_setsize(TYPE(History) *h, TYPE(HistEvent) *ev, int num) 657 { 658 659 if (h->h_next != history_def_next) { 660 he_seterrev(ev, _HE_NOT_ALLOWED); 661 return -1; 662 } 663 if (num < 0) { 664 he_seterrev(ev, _HE_BAD_PARAM); 665 return -1; 666 } 667 history_def_setsize(h->h_ref, num); 668 return 0; 669 } 670 671 672 /* history_getsize(): 673 * Get number of events currently in history 674 */ 675 static int 676 history_getsize(TYPE(History) *h, TYPE(HistEvent) *ev) 677 { 678 if (h->h_next != history_def_next) { 679 he_seterrev(ev, _HE_NOT_ALLOWED); 680 return -1; 681 } 682 ev->num = history_def_getsize(h->h_ref); 683 if (ev->num < -1) { 684 he_seterrev(ev, _HE_SIZE_NEGATIVE); 685 return -1; 686 } 687 return 0; 688 } 689 690 691 /* history_setunique(): 692 * Set if adjacent equal events should not be entered in history. 693 */ 694 static int 695 history_setunique(TYPE(History) *h, TYPE(HistEvent) *ev, int uni) 696 { 697 698 if (h->h_next != history_def_next) { 699 he_seterrev(ev, _HE_NOT_ALLOWED); 700 return -1; 701 } 702 history_def_setunique(h->h_ref, uni); 703 return 0; 704 } 705 706 707 /* history_getunique(): 708 * Get if adjacent equal events should not be entered in history. 709 */ 710 static int 711 history_getunique(TYPE(History) *h, TYPE(HistEvent) *ev) 712 { 713 if (h->h_next != history_def_next) { 714 he_seterrev(ev, _HE_NOT_ALLOWED); 715 return -1; 716 } 717 ev->num = history_def_getunique(h->h_ref); 718 return 0; 719 } 720 721 722 /* history_set_fun(): 723 * Set history functions 724 */ 725 static int 726 history_set_fun(TYPE(History) *h, TYPE(History) *nh) 727 { 728 TYPE(HistEvent) ev; 729 730 if (nh->h_first == NULL || nh->h_next == NULL || nh->h_last == NULL || 731 nh->h_prev == NULL || nh->h_curr == NULL || nh->h_set == NULL || 732 nh->h_enter == NULL || nh->h_add == NULL || nh->h_clear == NULL || 733 nh->h_del == NULL || nh->h_ref == NULL) { 734 if (h->h_next != history_def_next) { 735 if (history_def_init(&h->h_ref, &ev, 0) == -1) 736 return -1; 737 h->h_first = history_def_first; 738 h->h_next = history_def_next; 739 h->h_last = history_def_last; 740 h->h_prev = history_def_prev; 741 h->h_curr = history_def_curr; 742 h->h_set = history_def_set; 743 h->h_clear = history_def_clear; 744 h->h_enter = history_def_enter; 745 h->h_add = history_def_add; 746 h->h_del = history_def_del; 747 } 748 return -1; 749 } 750 if (h->h_next == history_def_next) 751 history_def_clear(h->h_ref, &ev); 752 753 h->h_ent = -1; 754 h->h_first = nh->h_first; 755 h->h_next = nh->h_next; 756 h->h_last = nh->h_last; 757 h->h_prev = nh->h_prev; 758 h->h_curr = nh->h_curr; 759 h->h_set = nh->h_set; 760 h->h_clear = nh->h_clear; 761 h->h_enter = nh->h_enter; 762 h->h_add = nh->h_add; 763 h->h_del = nh->h_del; 764 765 return 0; 766 } 767 768 769 /* history_load(): 770 * TYPE(History) load function 771 */ 772 static int 773 history_load(TYPE(History) *h, const char *fname) 774 { 775 FILE *fp; 776 char *line; 777 size_t llen; 778 ssize_t sz; 779 size_t max_size; 780 char *ptr; 781 int i = -1; 782 TYPE(HistEvent) ev; 783 Char *decode_result; 784 #ifndef NARROWCHAR 785 static ct_buffer_t conv; 786 #endif 787 788 if ((fp = fopen(fname, "r")) == NULL) 789 return i; 790 791 line = NULL; 792 llen = 0; 793 if ((sz = getline(&line, &llen, fp)) == -1) 794 goto done; 795 796 if (strncmp(line, hist_cookie, (size_t)sz) != 0) 797 goto done; 798 799 ptr = h_malloc((max_size = 1024) * sizeof(*ptr)); 800 if (ptr == NULL) 801 goto done; 802 for (i = 0; (sz = getline(&line, &llen, fp)) != -1; i++) { 803 if (sz > 0 && line[sz - 1] == '\n') 804 line[--sz] = '\0'; 805 if (max_size < (size_t)sz) { 806 char *nptr; 807 max_size = ((size_t)sz + 1024) & (size_t)~1023; 808 nptr = h_realloc(ptr, max_size * sizeof(*ptr)); 809 if (nptr == NULL) { 810 i = -1; 811 goto oomem; 812 } 813 ptr = nptr; 814 } 815 (void) strunvis(ptr, line); 816 decode_result = ct_decode_string(ptr, &conv); 817 if (decode_result == NULL) 818 continue; 819 if (HENTER(h, &ev, decode_result) == -1) { 820 i = -1; 821 goto oomem; 822 } 823 } 824 oomem: 825 h_free(ptr); 826 done: 827 free(line); 828 (void) fclose(fp); 829 return i; 830 } 831 832 833 /* history_save_fp(): 834 * TYPE(History) save function 835 */ 836 static int 837 history_save_fp(TYPE(History) *h, size_t nelem, FILE *fp) 838 { 839 TYPE(HistEvent) ev; 840 int i = -1, retval; 841 size_t len, max_size; 842 char *ptr; 843 const char *str; 844 #ifndef NARROWCHAR 845 static ct_buffer_t conv; 846 #endif 847 848 if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) 849 goto done; 850 if (ftell(fp) == 0 && fputs(hist_cookie, fp) == EOF) 851 goto done; 852 ptr = h_malloc((max_size = 1024) * sizeof(*ptr)); 853 if (ptr == NULL) 854 goto done; 855 if (nelem != (size_t)-1) { 856 for (retval = HFIRST(h, &ev); retval != -1 && nelem-- > 0; 857 retval = HNEXT(h, &ev)) 858 continue; 859 } else 860 retval = -1; 861 862 if (retval == -1) 863 retval = HLAST(h, &ev); 864 865 for (i = 0; retval != -1; retval = HPREV(h, &ev), i++) { 866 str = ct_encode_string(ev.str, &conv); 867 len = strlen(str) * 4 + 1; 868 if (len > max_size) { 869 char *nptr; 870 max_size = (len + 1024) & (size_t)~1023; 871 nptr = h_realloc(ptr, max_size * sizeof(*ptr)); 872 if (nptr == NULL) { 873 i = -1; 874 goto oomem; 875 } 876 ptr = nptr; 877 } 878 (void) strvis(ptr, str, VIS_WHITE); 879 (void) fprintf(fp, "%s\n", ptr); 880 } 881 oomem: 882 h_free(ptr); 883 done: 884 return i; 885 } 886 887 888 /* history_save(): 889 * History save function 890 */ 891 static int 892 history_save(TYPE(History) *h, const char *fname) 893 { 894 FILE *fp; 895 int i; 896 897 if ((fp = fopen(fname, "w")) == NULL) 898 return -1; 899 900 i = history_save_fp(h, (size_t)-1, fp); 901 902 (void) fclose(fp); 903 return i; 904 } 905 906 907 /* history_prev_event(): 908 * Find the previous event, with number given 909 */ 910 static int 911 history_prev_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num) 912 { 913 int retval; 914 915 for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev)) 916 if (ev->num == num) 917 return 0; 918 919 he_seterrev(ev, _HE_NOT_FOUND); 920 return -1; 921 } 922 923 924 static int 925 history_next_evdata(TYPE(History) *h, TYPE(HistEvent) *ev, int num, void **d) 926 { 927 int retval; 928 929 for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev)) 930 if (ev->num == num) { 931 if (d) 932 *d = ((history_t *)h->h_ref)->cursor->data; 933 return 0; 934 } 935 936 he_seterrev(ev, _HE_NOT_FOUND); 937 return -1; 938 } 939 940 941 /* history_next_event(): 942 * Find the next event, with number given 943 */ 944 static int 945 history_next_event(TYPE(History) *h, TYPE(HistEvent) *ev, int num) 946 { 947 int retval; 948 949 for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev)) 950 if (ev->num == num) 951 return 0; 952 953 he_seterrev(ev, _HE_NOT_FOUND); 954 return -1; 955 } 956 957 958 /* history_prev_string(): 959 * Find the previous event beginning with string 960 */ 961 static int 962 history_prev_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str) 963 { 964 size_t len = Strlen(str); 965 int retval; 966 967 for (retval = HCURR(h, ev); retval != -1; retval = HNEXT(h, ev)) 968 if (Strncmp(str, ev->str, len) == 0) 969 return 0; 970 971 he_seterrev(ev, _HE_NOT_FOUND); 972 return -1; 973 } 974 975 976 /* history_next_string(): 977 * Find the next event beginning with string 978 */ 979 static int 980 history_next_string(TYPE(History) *h, TYPE(HistEvent) *ev, const Char *str) 981 { 982 size_t len = Strlen(str); 983 int retval; 984 985 for (retval = HCURR(h, ev); retval != -1; retval = HPREV(h, ev)) 986 if (Strncmp(str, ev->str, len) == 0) 987 return 0; 988 989 he_seterrev(ev, _HE_NOT_FOUND); 990 return -1; 991 } 992 993 994 /* history(): 995 * User interface to history functions. 996 */ 997 int 998 FUNW(history)(TYPE(History) *h, TYPE(HistEvent) *ev, int fun, ...) 999 { 1000 va_list va; 1001 const Char *str; 1002 int retval; 1003 1004 va_start(va, fun); 1005 1006 he_seterrev(ev, _HE_OK); 1007 1008 switch (fun) { 1009 case H_GETSIZE: 1010 retval = history_getsize(h, ev); 1011 break; 1012 1013 case H_SETSIZE: 1014 retval = history_setsize(h, ev, va_arg(va, int)); 1015 break; 1016 1017 case H_GETUNIQUE: 1018 retval = history_getunique(h, ev); 1019 break; 1020 1021 case H_SETUNIQUE: 1022 retval = history_setunique(h, ev, va_arg(va, int)); 1023 break; 1024 1025 case H_ADD: 1026 str = va_arg(va, const Char *); 1027 retval = HADD(h, ev, str); 1028 break; 1029 1030 case H_DEL: 1031 retval = HDEL(h, ev, va_arg(va, const int)); 1032 break; 1033 1034 case H_ENTER: 1035 str = va_arg(va, const Char *); 1036 if ((retval = HENTER(h, ev, str)) != -1) 1037 h->h_ent = ev->num; 1038 break; 1039 1040 case H_APPEND: 1041 str = va_arg(va, const Char *); 1042 if ((retval = HSET(h, ev, h->h_ent)) != -1) 1043 retval = HADD(h, ev, str); 1044 break; 1045 1046 case H_FIRST: 1047 retval = HFIRST(h, ev); 1048 break; 1049 1050 case H_NEXT: 1051 retval = HNEXT(h, ev); 1052 break; 1053 1054 case H_LAST: 1055 retval = HLAST(h, ev); 1056 break; 1057 1058 case H_PREV: 1059 retval = HPREV(h, ev); 1060 break; 1061 1062 case H_CURR: 1063 retval = HCURR(h, ev); 1064 break; 1065 1066 case H_SET: 1067 retval = HSET(h, ev, va_arg(va, const int)); 1068 break; 1069 1070 case H_CLEAR: 1071 HCLEAR(h, ev); 1072 retval = 0; 1073 break; 1074 1075 case H_LOAD: 1076 retval = history_load(h, va_arg(va, const char *)); 1077 if (retval == -1) 1078 he_seterrev(ev, _HE_HIST_READ); 1079 break; 1080 1081 case H_SAVE: 1082 retval = history_save(h, va_arg(va, const char *)); 1083 if (retval == -1) 1084 he_seterrev(ev, _HE_HIST_WRITE); 1085 break; 1086 1087 case H_SAVE_FP: 1088 retval = history_save_fp(h, (size_t)-1, va_arg(va, FILE *)); 1089 if (retval == -1) 1090 he_seterrev(ev, _HE_HIST_WRITE); 1091 break; 1092 1093 case H_NSAVE_FP: 1094 { 1095 size_t sz = va_arg(va, size_t); 1096 retval = history_save_fp(h, sz, va_arg(va, FILE *)); 1097 if (retval == -1) 1098 he_seterrev(ev, _HE_HIST_WRITE); 1099 break; 1100 } 1101 1102 case H_PREV_EVENT: 1103 retval = history_prev_event(h, ev, va_arg(va, int)); 1104 break; 1105 1106 case H_NEXT_EVENT: 1107 retval = history_next_event(h, ev, va_arg(va, int)); 1108 break; 1109 1110 case H_PREV_STR: 1111 retval = history_prev_string(h, ev, va_arg(va, const Char *)); 1112 break; 1113 1114 case H_NEXT_STR: 1115 retval = history_next_string(h, ev, va_arg(va, const Char *)); 1116 break; 1117 1118 case H_FUNC: 1119 { 1120 TYPE(History) hf; 1121 1122 hf.h_ref = va_arg(va, void *); 1123 h->h_ent = -1; 1124 hf.h_first = va_arg(va, history_gfun_t); 1125 hf.h_next = va_arg(va, history_gfun_t); 1126 hf.h_last = va_arg(va, history_gfun_t); 1127 hf.h_prev = va_arg(va, history_gfun_t); 1128 hf.h_curr = va_arg(va, history_gfun_t); 1129 hf.h_set = va_arg(va, history_sfun_t); 1130 hf.h_clear = va_arg(va, history_vfun_t); 1131 hf.h_enter = va_arg(va, history_efun_t); 1132 hf.h_add = va_arg(va, history_efun_t); 1133 hf.h_del = va_arg(va, history_sfun_t); 1134 1135 if ((retval = history_set_fun(h, &hf)) == -1) 1136 he_seterrev(ev, _HE_PARAM_MISSING); 1137 break; 1138 } 1139 1140 case H_END: 1141 FUN(history,end)(h); 1142 retval = 0; 1143 break; 1144 1145 case H_NEXT_EVDATA: 1146 { 1147 int num = va_arg(va, int); 1148 void **d = va_arg(va, void **); 1149 retval = history_next_evdata(h, ev, num, d); 1150 break; 1151 } 1152 1153 case H_DELDATA: 1154 { 1155 int num = va_arg(va, int); 1156 void **d = va_arg(va, void **); 1157 retval = history_deldata_nth((history_t *)h->h_ref, ev, num, d); 1158 break; 1159 } 1160 1161 case H_REPLACE: /* only use after H_NEXT_EVDATA */ 1162 { 1163 const Char *line = va_arg(va, const Char *); 1164 void *d = va_arg(va, void *); 1165 const Char *s; 1166 if(!line || !(s = Strdup(line))) { 1167 retval = -1; 1168 break; 1169 } 1170 ((history_t *)h->h_ref)->cursor->ev.str = s; 1171 ((history_t *)h->h_ref)->cursor->data = d; 1172 retval = 0; 1173 break; 1174 } 1175 1176 default: 1177 retval = -1; 1178 he_seterrev(ev, _HE_UNKNOWN); 1179 break; 1180 } 1181 va_end(va); 1182 return retval; 1183 } 1184