diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2016-07-12 12:41:15 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2016-07-12 14:34:16 +0300 |
commit | 89f200b55b309aa67c1fbfc11d4de211725348f4 (patch) | |
tree | 39e2e43f29766cbebbdf61f160b5d062ea63c996 /src/lex.l | |
parent | e8cad816f36b1cad11bb67c96f0ce878cf30844e (diff) | |
download | gdbm-89f200b55b309aa67c1fbfc11d4de211725348f4.tar.gz gdbm-89f200b55b309aa67c1fbfc11d4de211725348f4.tar.bz2 |
Line-editing support in gdbmtool
* configure.ac: Check if GNU Readline is available.
* src/Makefile.am: Add new files.
* src/input-rl.c: New file.
* src/input-std.c: New file.
* src/gdbmtool.c (handler_param): Move declaration to
the header file.
(quit_handler): Call input_done.
(command_tab): Add the "history" command.
(command_generator): New function.
(slist_new_s, slist_new_l)
(slist_insert): New functions.
(main): Call input_init and input_done.
* src/gdbmtool.h: New protos.
* src/gram.y: Use slist_insert to construct string lists.
* src/lex.l (read_input): Remove. Use input_read instead.
(print_prompt_at_bol): New function.
(print_prompt): Remove.
(make_prompt): New function.
* NEWS: Document changes.
* README: Document readline support.
* doc/gdbm.texi: Document line editing in gdbmtool.
* doc/gdbmtool.1: Likewise.
Diffstat (limited to 'src/lex.l')
-rw-r--r-- | src/lex.l | 134 |
1 files changed, 80 insertions, 54 deletions
@@ -46,7 +46,7 @@ advance_line () | |||
46 | #define YY_INPUT(buf,result,max_size) \ | 46 | #define YY_INPUT(buf,result,max_size) \ |
47 | do \ | 47 | do \ |
48 | { \ | 48 | { \ |
49 | result = read_input (buf, max_size); \ | 49 | result = input_read (yyin, buf, max_size); \ |
50 | } \ | 50 | } \ |
51 | while (0); | 51 | while (0); |
52 | 52 | ||
@@ -56,8 +56,6 @@ void string_addc (int c); | |||
56 | char *string_end (void); | 56 | char *string_end (void); |
57 | int unescape (int c); | 57 | int unescape (int c); |
58 | 58 | ||
59 | static ssize_t read_input (char *buf, size_t size); | ||
60 | |||
61 | struct context /* Input context */ | 59 | struct context /* Input context */ |
62 | { | 60 | { |
63 | struct context *parent; /* Pointer to the parent context */ | 61 | struct context *parent; /* Pointer to the parent context */ |
@@ -315,18 +313,16 @@ end_def (void) | |||
315 | BEGIN (INITIAL); | 313 | BEGIN (INITIAL); |
316 | } | 314 | } |
317 | 315 | ||
318 | static ssize_t | 316 | void |
319 | read_input (char *buf, size_t size) | 317 | print_prompt_at_bol (void) |
320 | { | 318 | { |
321 | if (interactive) | 319 | if (YY_AT_BOL ()) |
322 | { | 320 | { |
323 | if (YY_AT_BOL ()) | 321 | char *s = make_prompt (); |
324 | print_prompt (); | 322 | fputs (s, stdout); |
325 | if (fgets (buf, size, yyin) == NULL) | 323 | fflush (stdout); |
326 | return 0; | 324 | free (s); |
327 | return strlen (buf); | ||
328 | } | 325 | } |
329 | return fread (buf, 1, size, yyin); | ||
330 | } | 326 | } |
331 | 327 | ||
332 | 328 | ||
@@ -453,44 +449,40 @@ lerror (struct locus *loc, const char *fmt, ...) | |||
453 | } | 449 | } |
454 | 450 | ||
455 | 451 | ||
456 | struct prompt_exp; | 452 | static struct slist * |
457 | 453 | pe_file_name (void) | |
458 | void | ||
459 | pe_file_name (struct prompt_exp *p) | ||
460 | { | 454 | { |
461 | if (file_name) | 455 | return file_name ? slist_new (file_name) : NULL; |
462 | fwrite (file_name, strlen (file_name), 1, stdout); | ||
463 | } | 456 | } |
464 | 457 | ||
465 | void | 458 | static struct slist * |
466 | pe_program_name (struct prompt_exp *p) | 459 | pe_program_name (void) |
467 | { | 460 | { |
468 | fwrite (progname, strlen (progname), 1, stdout); | 461 | return slist_new (progname); |
469 | } | 462 | } |
470 | 463 | ||
471 | void | 464 | static struct slist * |
472 | pe_package_name (struct prompt_exp *p) | 465 | pe_package_name (void) |
473 | { | 466 | { |
474 | fwrite (PACKAGE_NAME, sizeof (PACKAGE_NAME) - 1, 1, stdout); | 467 | return slist_new (PACKAGE_NAME); |
475 | } | 468 | } |
476 | 469 | ||
477 | void | 470 | static struct slist * |
478 | pe_program_version (struct prompt_exp *p) | 471 | pe_program_version (void) |
479 | { | 472 | { |
480 | fwrite (PACKAGE_VERSION, sizeof (PACKAGE_VERSION) - 1, 1, stdout); | 473 | return slist_new (PACKAGE_VERSION); |
481 | } | 474 | } |
482 | 475 | ||
483 | void | 476 | static struct slist * |
484 | pe_space (struct prompt_exp *p) | 477 | pe_space (void) |
485 | { | 478 | { |
486 | fwrite (" ", 1, 1, stdout); | 479 | return slist_new (" "); |
487 | } | 480 | } |
488 | 481 | ||
489 | struct prompt_exp | 482 | struct prompt_exp |
490 | { | 483 | { |
491 | int ch; | 484 | int ch; |
492 | void (*fun) (struct prompt_exp *); | 485 | struct slist *(*fun) (void); |
493 | char *cache; | ||
494 | }; | 486 | }; |
495 | 487 | ||
496 | struct prompt_exp prompt_exp[] = { | 488 | struct prompt_exp prompt_exp[] = { |
@@ -502,8 +494,8 @@ struct prompt_exp prompt_exp[] = { | |||
502 | { 0 } | 494 | { 0 } |
503 | }; | 495 | }; |
504 | 496 | ||
505 | static void | 497 | static int |
506 | expand_char (int c) | 498 | expand_char (int c, struct slist **tailp) |
507 | { | 499 | { |
508 | struct prompt_exp *p; | 500 | struct prompt_exp *p; |
509 | 501 | ||
@@ -513,58 +505,92 @@ expand_char (int c) | |||
513 | { | 505 | { |
514 | if (c == p->ch) | 506 | if (c == p->ch) |
515 | { | 507 | { |
516 | if (p->cache) | 508 | struct slist *s = p->fun (); |
517 | free (p->cache); | 509 | if (s) |
518 | p->fun (p); | 510 | slist_insert (tailp, s); |
519 | return; | 511 | return 0; |
520 | } | 512 | } |
521 | } | 513 | } |
522 | } | 514 | } |
523 | putchar ('%'); | 515 | return 1; |
524 | putchar (c); | ||
525 | } | 516 | } |
526 | 517 | ||
527 | char const * | 518 | char const * |
528 | psname () | 519 | psname (void) |
529 | { | 520 | { |
530 | if (YYSTATE == DEF || YYSTATE == MLSTR) | 521 | if (YYSTATE == DEF || YYSTATE == MLSTR) |
531 | return "ps2"; | 522 | return "ps2"; |
532 | return "ps1"; | 523 | return "ps1"; |
533 | } | 524 | } |
534 | 525 | ||
535 | void | 526 | char * |
536 | print_prompt () | 527 | make_prompt (void) |
537 | { | 528 | { |
538 | const char *s; | 529 | const char *s; |
539 | const char *prompt; | 530 | const char *prompt; |
540 | 531 | struct slist *head = NULL, *tail = NULL, *p; | |
532 | char *ret, *end; | ||
533 | size_t len; | ||
534 | |||
541 | switch (variable_get (psname (), VART_STRING, (void *) &prompt)) | 535 | switch (variable_get (psname (), VART_STRING, (void *) &prompt)) |
542 | { | 536 | { |
543 | case VAR_OK: | 537 | case VAR_OK: |
544 | break; | 538 | break; |
545 | 539 | ||
546 | case VAR_ERR_NOTSET: | 540 | case VAR_ERR_NOTSET: |
547 | return; | 541 | return NULL; |
548 | 542 | ||
549 | default: | 543 | default: |
550 | abort (); | 544 | abort (); |
551 | } | 545 | } |
552 | 546 | ||
553 | for (s = prompt; *s; s++) | 547 | for (s = prompt; *s; ) |
554 | { | 548 | { |
555 | if (*s == '%') | 549 | if (*s == '%' && s[1]) |
556 | { | 550 | { |
557 | if (!*++s) | 551 | if (s > prompt) |
552 | { | ||
553 | slist_insert (&tail, slist_new_l (prompt, s - prompt)); | ||
554 | if (!head) | ||
555 | head = tail; | ||
556 | } | ||
557 | if (expand_char (s[1], &tail) == 0) | ||
558 | { | 558 | { |
559 | putchar ('%'); | 559 | if (!head) |
560 | break; | 560 | head = tail; |
561 | prompt = s + 2; | ||
561 | } | 562 | } |
562 | expand_char (*s); | 563 | else |
564 | prompt = s; | ||
565 | s += 2; | ||
563 | } | 566 | } |
564 | else | 567 | else |
565 | putchar (*s); | 568 | ++s; |
569 | } | ||
570 | |||
571 | if (s > prompt) | ||
572 | { | ||
573 | slist_insert (&tail, slist_new_l (prompt, s - prompt)); | ||
574 | if (!head) | ||
575 | head = tail; | ||
566 | } | 576 | } |
567 | 577 | ||
568 | fflush (stdout); | 578 | len = 0; |
579 | for (p = head; p; p = p->next) | ||
580 | len += strlen (p->str); | ||
581 | |||
582 | ret = emalloc (len + 1); | ||
583 | end = ret; | ||
584 | for (p = head; p; p = p->next) | ||
585 | { | ||
586 | s = p->str; | ||
587 | while (*s) | ||
588 | *end++ = *s++; | ||
589 | } | ||
590 | *end = 0; | ||