modified: SpatialOmicsCoord.py
[GalaxyCodeBases.git] / c_cpp / etc / calc / hist.c
blob62b4a670b8046f1c564cad2ee6c88084c4a0fdbd
1 /*
2 * hist - interactive readline module
4 * Copyright (C) 1999-2007 David I. Bell
6 * Calc is open software; you can redistribute it and/or modify it under
7 * the terms of the version 2.1 of the GNU Lesser General Public License
8 * as published by the Free Software Foundation.
10 * Calc is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
13 * Public License for more details.
15 * A copy of version 2.1 of the GNU Lesser General Public License is
16 * distributed with calc under the filename COPYING-LGPL. You should have
17 * received a copy with calc; if not, write to Free Software Foundation, Inc.
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * @(#) $Revision: 30.1 $
21 * @(#) $Id: hist.c,v 30.1 2007/03/16 11:09:46 chongo Exp $
22 * @(#) $Source: /usr/local/src/bin/calc/RCS/hist.c,v $
24 * Under source code control: 1993/05/02 20:09:19
25 * File existed as early as: 1993
27 * Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/
31 * Adapted from code written by Stephen Rothwell.
33 * GNU readline support added by Martin Buck <mbuck@debian.org>
35 * Interactive readline module. This is called to read lines of input,
36 * while using emacs-like editing commands within a command stack.
37 * The key bindings for the editing commands are (slightly) configurable.
41 #include <stdio.h>
42 #include <ctype.h>
43 #if !defined(_WIN32)
44 # include <pwd.h>
45 #endif
47 #include "have_unistd.h"
48 #if defined(HAVE_UNISTD_H)
49 #include <unistd.h>
50 #endif
52 #include "have_stdlib.h"
53 #if defined(HAVE_STDLIB_H)
54 #include <stdlib.h>
55 #endif
57 #include "calc.h"
58 #include "hist.h"
59 #include "have_string.h"
61 #include "have_strdup.h"
62 #if !defined(HAVE_STRDUP)
63 # define strdup(x) calc_strdup((CONST char *)(x))
64 #endif /* HAVE_STRDUP */
66 #ifdef HAVE_STRING_H
67 # include <string.h>
68 #endif
70 #include "have_unused.h"
72 #if !defined(USE_READLINE)
74 E_FUNC FILE *curstream(void);
76 #define STDIN 0
77 #define SAVE_SIZE 256 /* size of save buffer */
78 #define MAX_KEYS 60 /* number of key bindings */
81 #define CONTROL(x) ((char)(((int)(x)) & 0x1f))
83 STATIC struct {
84 char *prompt;
85 char *buf;
86 char *pos;
87 char *end;
88 char *mark;
89 int bufsize;
90 int linelen;
91 int histcount;
92 int curhist;
93 BOOL virgin_line; /* 1 => never typed chars, 0 => chars typed */
94 } HS;
97 typedef void (*FUNCPTR)();
99 typedef struct {
100 char *name;
101 FUNCPTR func;
102 } FUNC;
104 /* declare binding functions */
105 S_FUNC void flush_input(void);
106 S_FUNC void start_of_line(void);
107 S_FUNC void end_of_line(void);
108 S_FUNC void forward_char(void);
109 S_FUNC void backward_char(void);
110 S_FUNC void forward_word(void);
111 S_FUNC void backward_word(void);
112 S_FUNC void delete_char(void);
113 S_FUNC void forward_kill_char(void);
114 S_FUNC void backward_kill_char(void);
115 S_FUNC void forward_kill_word(void);
116 S_FUNC void kill_line(void);
117 S_FUNC void new_line(void);
118 S_FUNC void save_line(void);
119 S_FUNC void forward_history(void);
120 S_FUNC void backward_history(void);
121 S_FUNC void insert_char(int key);
122 S_FUNC void goto_line(void);
123 S_FUNC void list_history(void);
124 S_FUNC void refresh_line(void);
125 S_FUNC void swap_chars(void);
126 S_FUNC void set_mark(void);
127 S_FUNC void yank(void);
128 S_FUNC void save_region(void);
129 S_FUNC void kill_region(void);
130 S_FUNC void reverse_search(void);
131 S_FUNC void quote_char(void);
132 S_FUNC void uppercase_word(void);
133 S_FUNC void lowercase_word(void);
134 S_FUNC void ignore_char(void);
135 S_FUNC void arrow_key(void);
136 S_FUNC void quit_calc(void);
139 STATIC FUNC funcs[] =
141 {"ignore-char", ignore_char},
142 {"flush-input", flush_input},
143 {"start-of-line", start_of_line},
144 {"end-of-line", end_of_line},
145 {"forward-char", forward_char},
146 {"backward-char", backward_char},
147 {"forward-word", forward_word},
148 {"backward-word", backward_word},
149 {"delete-char", delete_char},
150 {"forward-kill-char", forward_kill_char},
151 {"backward-kill-char", backward_kill_char},
152 {"forward-kill-word", forward_kill_word},
153 {"uppercase-word", uppercase_word},
154 {"lowercase-word", lowercase_word},
155 {"kill-line", kill_line},
156 {"goto-line", goto_line},
157 {"new-line", new_line},
158 {"save-line", save_line},
159 {"forward-history", forward_history},
160 {"backward-history", backward_history},
161 {"insert-char", insert_char},
162 {"list-history", list_history},
163 {"refresh-line", refresh_line},
164 {"swap-chars", swap_chars},
165 {"set-mark", set_mark},
166 {"yank", yank},
167 {"save-region", save_region},
168 {"kill-region", kill_region},
169 {"reverse-search", reverse_search},
170 {"quote-char", quote_char},
171 {"arrow-key", arrow_key},
172 {"quit", quit_calc},
173 {NULL, NULL}
177 typedef struct key_ent KEY_ENT;
178 typedef struct key_map KEY_MAP;
180 struct key_ent {
181 FUNCPTR func;
182 KEY_MAP *next;
186 struct key_map {
187 char *name;
188 KEY_ENT default_ent;
189 KEY_ENT *map[256];
193 STATIC char base_map_name[] = "base-map";
194 STATIC char esc_map_name[] = "esc-map";
197 STATIC KEY_MAP maps[] = {
198 {base_map_name, {NULL, NULL}, {NULL, NULL}},
199 {esc_map_name, {NULL, NULL}, {NULL, NULL}},
203 #define INTROUND (sizeof(int) - 1)
204 #define HISTLEN(hp) ((((hp)->len + INTROUND) & ~INTROUND) + sizeof(int))
205 #define HISTOFFSET(hp) (((char *) (hp)) - histbuf)
206 #define FIRSTHIST ((HIST *) histbuf)
207 #define NEXTHIST(hp) ((HIST *) (((char *) (hp)) + HISTLEN(hp)))
210 typedef struct {
211 int len; /* length of data */
212 char data[1]; /* varying length data */
213 } HIST;
216 STATIC int inited;
217 STATIC int canedit;
218 STATIC int histused;
219 STATIC int key_count;
220 STATIC int save_len;
221 STATIC KEY_MAP *cur_map;
222 STATIC KEY_MAP *base_map;
223 STATIC KEY_ENT key_table[MAX_KEYS];
224 STATIC char histbuf[HIST_SIZE + 1];
225 STATIC char save_buffer[SAVE_SIZE];
227 /* declare other static functions */
228 S_FUNC FUNCPTR find_func(char *name);
229 S_FUNC HIST *get_event(int n);
230 S_FUNC HIST *find_event(char *pat, int len);
231 S_FUNC void read_key(void);
232 S_FUNC void erasechar(void);
233 S_FUNC void newline(void);
234 S_FUNC void backspace(void);
235 S_FUNC void beep(void);
236 S_FUNC void echo_char(int ch);
237 S_FUNC void echo_string(char *str, int len);
238 S_FUNC void savetext(char *str, int len);
239 S_FUNC void memrcpy(char *dest, char *src, int len);
240 S_FUNC int read_bindings(FILE *fp);
241 S_FUNC int in_word(int ch);
242 S_FUNC KEY_MAP *find_map(char *map);
243 S_FUNC void unbind_key(KEY_MAP *map, int key);
244 S_FUNC void raw_bind_key(KEY_MAP *map, int key,
245 FUNCPTR func, KEY_MAP *next_map);
246 S_FUNC KEY_MAP *do_map_line(char *line);
247 S_FUNC void do_default_line(KEY_MAP *map, char *line);
248 S_FUNC void do_bind_line(KEY_MAP *map, char *line);
249 S_FUNC void back_over_char(int ch);
250 S_FUNC void echo_rest_of_line(void);
251 S_FUNC void goto_start_of_line(void);
252 S_FUNC void goto_end_of_line(void);
253 S_FUNC void remove_char(int ch);
254 S_FUNC void decrement_end(int n);
255 S_FUNC void insert_string(char *str, int len);
259 * Read a line into the specified buffer. The line ends in a newline,
260 * and is NULL terminated. Returns the number of characters read, or
261 * zero on an end of file or error. The prompt is printed before reading
262 * the line.
264 size_t
265 hist_getline(char *prompt, char *buf, size_t len)
268 * initialize if we have not already done so
270 if (!inited)
271 (void) hist_init(calcbindings);
274 * establish the beginning of a line condition
276 HS.prompt = prompt;
277 HS.bufsize = len - 2;
278 HS.buf = buf;
279 HS.pos = buf;
280 HS.end = buf;
281 HS.mark = NULL;
282 HS.linelen = -1;
283 HS.virgin_line = TRUE;
286 * prep the I/O
288 fputs(prompt, stdout);
289 fflush(stdout);
292 * special case: non-interactive editing
294 if (!canedit) {
295 if (fgets(buf, len, stdin) == NULL)
296 return 0;
297 return strlen(buf);
301 * get the line
303 while (HS.linelen < 0) {
305 /* get the next char */
306 read_key();
308 /* chars typed, no longer virgin */
309 HS.virgin_line = FALSE;
313 * return the line
315 return HS.linelen;
320 * Initialize the module by reading in the key bindings from the specified
321 * filename, and then setting the terminal modes for noecho and cbreak mode.
322 * If the supplied filename is NULL, then a default filename will be used.
323 * We will search the CALCPATH for the file.
325 * Returns zero if successful, or a nonzero error code if unsuccessful.
326 * If this routine fails, hist_getline, hist_saveline, and hist_term can
327 * still be called but all fancy editing is disabled.
330 hist_init(char *filename)
333 * prevent multiple initializations
335 if (inited) {
336 if (conf->calc_debug & CALCDBG_TTY)
337 printf("hist_init: inited already set\n");
338 return HIST_INITED;
342 * setup
344 inited = 1;
345 canedit = 0;
346 if (conf->calc_debug & CALCDBG_TTY)
347 printf("hist_init: Set inited, cleared canedit\n");
350 * open the bindings file
352 if (filename == NULL)
353 filename = HIST_BINDING_FILE;
354 if (opensearchfile(filename, calcpath, NULL, FALSE) > 0)
355 return HIST_NOFILE;
358 * load the bindings
360 if (read_bindings(curstream()))
361 return HIST_NOFILE;
364 * close the bindings
366 closeinput();
369 * setup the calc TTY on STDIN
371 if (!calc_tty(STDIN)) {
372 return HIST_NOTTY;
375 canedit = 1;
376 if (conf->calc_debug & CALCDBG_TTY)
377 printf("hist_init: Set canedit\n");
379 return HIST_SUCCESS;
384 * Reset the terminal modes just before exiting.
386 void
387 hist_term(void)
389 if (!inited || !canedit) {
390 if (conf->calc_debug & CALCDBG_TTY) {
391 if (!inited)
392 printf("hist_term: inited already cleared\n");
393 if (!canedit)
394 printf("hist_term: canedit already cleared\n");
396 inited = 0;
397 if (conf->calc_debug & CALCDBG_TTY)
398 printf("hist_term: Cleared inited\n");
399 return;
403 * restore orignal tty state
405 (void) orig_tty(STDIN);
409 S_FUNC KEY_MAP *
410 find_map(char *map)
412 unsigned int i;
414 for (i = 0; i < sizeof(maps) / sizeof(maps[0]); i++) {
415 if (strcmp(map, maps[i].name) == 0)
416 return &maps[i];
418 return NULL;
422 S_FUNC void
423 unbind_key(KEY_MAP *map, int key)
425 map->map[key] = NULL;
429 S_FUNC void
430 raw_bind_key(KEY_MAP *map, int key, FUNCPTR func, KEY_MAP *next_map)
432 if (map->map[key] == NULL) {
433 if (key_count >= MAX_KEYS)
434 return;
435 map->map[key] = &key_table[key_count++];
437 map->map[key]->func = func;
438 map->map[key]->next = next_map;
442 S_FUNC KEY_MAP *
443 do_map_line(char *line)
445 char *cp;
446 char *map_name;
448 cp = line;
449 while (isspace((int)*cp))
450 cp++;
451 if (*cp == '\0')
452 return NULL;
453 map_name = cp;
454 while ((*cp != '\0') && !isspace((int)*cp))
455 cp++;
456 *cp = '\0';
457 return find_map(map_name);
461 S_FUNC void
462 do_bind_line(KEY_MAP *map, char *line)
464 char *cp;
465 char key;
466 char *func_name;
467 char *next_name;
468 KEY_MAP *next;
469 FUNCPTR func;
471 if (map == NULL)
472 return;
473 cp = line;
474 key = *cp++;
475 if (*cp == '\0') {
476 unbind_key(map, key);
477 return;
479 if (key == '^') {
480 if (*cp == '?') {
481 key = 0177;
482 cp++;
483 } else {
484 key = CONTROL(*cp++);
486 } else if (key == '\\') {
487 key = *cp++;
490 while (isspace((int)*cp))
491 cp++;
492 if (*cp == '\0') {
493 unbind_key(map, key);
494 return;
497 func_name = cp;
498 while ((*cp != '\0') && !isspace((int)*cp))
499 cp++;
500 if (*cp) {
501 *cp++ = '\0';
502 while (isspace((int)*cp))
503 cp++;
505 func = find_func(func_name);
506 if (func == NULL) {
507 fprintf(stderr, "Unknown function \"%s\"\n", func_name);
508 return;
511 if (*cp == '\0') {
512 next = map->default_ent.next;
513 if (next == NULL)
514 next = base_map;
515 } else {
516 next_name = cp;
517 while ((*cp != '\0') && !isspace((int)*cp))
518 cp++;
519 if (*cp) {
520 *cp++ = '\0';
521 while (isspace((int)*cp))
522 cp++;
524 next = find_map(next_name);
525 if (next == NULL)
526 return;
528 raw_bind_key(map, key, func, next);
532 S_FUNC void
533 do_default_line(KEY_MAP *map, char *line)
535 char *cp;
536 char *func_name;
537 char *next_name;
538 KEY_MAP *next;
539 FUNCPTR func;
541 if (map == NULL)
542 return;
543 cp = line;
544 while (isspace((int)*cp))
545 cp++;
546 if (*cp == '\0')
547 return;
549 func_name = cp;
550 while ((*cp != '\0') && !isspace((int)*cp))
551 cp++;
552 if (*cp != '\0') {
553 *cp++ = '\0';
554 while (isspace((int)*cp))
555 cp++;
557 func = find_func(func_name);
558 if (func == NULL)
559 return;
561 if (*cp == '\0') {
562 next = map;
563 } else {
564 next_name = cp;
565 while ((*cp != '\0') && !isspace((int)*cp))
566 cp++;
567 if (*cp != '\0') {
568 *cp++ = '\0';
569 while (isspace((int)*cp))
570 cp++;
572 next = find_map(next_name);
573 if (next == NULL)
574 return;
577 map->default_ent.func = func;
578 map->default_ent.next = next;
583 * Read bindings from specified open file.
585 * Returns nonzero on error.
587 S_FUNC int
588 read_bindings(FILE *fp)
590 char *cp;
591 KEY_MAP *input_map;
592 char line[BUFSIZ+1];
594 base_map = find_map(base_map_name);
595 cur_map = base_map;
596 input_map = base_map;
598 if (fp == NULL)
599 return 1;
601 while (fgets(line, sizeof(line) - 1, fp)) {
602 line[BUFSIZ] = '\0';
603 cp = line;
604 while (isspace((int)*cp))
605 cp++;
607 if ((*cp == '\0') || (*cp == '#') || (*cp == '\n'))
608 continue;
610 if (cp[strlen(cp) - 1] == '\n')
611 cp[strlen(cp) - 1] = '\0';
613 if (memcmp(cp, "map", 3) == 0)
614 input_map = do_map_line(&cp[3]);
615 else if (memcmp(cp, "default", 7) == 0)
616 do_default_line(input_map, &cp[7]);
617 else
618 do_bind_line(input_map, cp);
620 return 0;
624 S_FUNC void
625 read_key(void)
627 KEY_ENT *ent;
628 int key;
630 fflush(stdout);
631 key = fgetc(stdin);
632 if (key == EOF) {
633 HS.linelen = 0;
634 HS.buf[0] = '\0';
635 return;
638 ent = cur_map->map[key];
639 if (ent == NULL)
640 ent = &cur_map->default_ent;
641 if (ent->next)
642 cur_map = ent->next;
643 if (ent->func)
644 /* ignore Saber-C warning #65 - has 1 arg, expecting 0 */
645 /* ok to ignore in proc read_key */
646 (*ent->func)(key);
647 else
648 insert_char(key);
653 * Return the Nth history event, indexed from zero.
654 * Earlier history events are lower in number.
656 S_FUNC HIST *
657 get_event(int n)
659 register HIST * hp;
661 if ((n < 0) || (n >= HS.histcount))
662 return NULL;
663 hp = FIRSTHIST;
664 while (n-- > 0)
665 hp = NEXTHIST(hp);
666 return hp;
671 * Search the history list for the specified pattern.
672 * Returns the found history, or NULL.
674 S_FUNC HIST *
675 find_event(char *pat, int len)
677 register HIST * hp;
679 for (hp = FIRSTHIST; hp->len; hp = NEXTHIST(hp)) {
680 if ((hp->len == len) && (memcmp(hp->data, pat, len) == 0))
681 return hp;
683 return NULL;
688 * Insert a line into the end of the history table.
689 * If the line already appears in the table, then it is moved to the end.
690 * If the table is full, then the earliest commands are deleted as necessary.
691 * Warning: the incoming line cannot point into the history table.
693 void
694 hist_saveline(char *line, int len)
696 HIST * hp;
697 HIST * hp2;
698 int left;
700 if ((len > 0) && (line[len - 1] == '\n'))
701 len--;
702 if (len <= 0)
703 return;
706 * See if the line is already present in the history table.
707 * If so, and it is already at the end, then we are all done.
708 * Otherwise delete it since we will reinsert it at the end.
710 hp = find_event(line, len);
711 if (hp) {
712 hp2 = NEXTHIST(hp);
713 left = histused - HISTOFFSET(hp2);
714 if (left <= 0)
715 return;
716 histused -= HISTLEN(hp);
717 memcpy(hp, hp2, left + 1);
718 HS.histcount--;
722 * If there is not enough room left in the history buffer to add
723 * the new command, then repeatedly delete the earliest command
724 * as many times as necessary in order to make enough room.
726 while ((histused + len) >= HIST_SIZE) {
727 hp = (HIST *) histbuf;
728 hp2 = NEXTHIST(hp);
729 left = histused - HISTOFFSET(hp2);
730 histused -= HISTLEN(hp);
731 memcpy(hp, hp2, left + 1);
732 HS.histcount--;
736 * Add the line to the end of the history table.
738 hp = (HIST *) &histbuf[histused];
739 hp->len = len;
740 memcpy(hp->data, line, len);
741 histused += HISTLEN(hp);
742 histbuf[histused] = 0;
743 HS.curhist = ++HS.histcount;
748 * Find the function for a specified name.
750 S_FUNC FUNCPTR
751 find_func(char *name)
753 FUNC *fp;
755 for (fp = funcs; fp->name; fp++) {
756 if (strcmp(fp->name, name) == 0)
757 return fp->func;
759 return NULL;
763 S_FUNC void
764 arrow_key(void)
766 switch (fgetc(stdin)) {
767 case 'A':
768 backward_history();
769 break;
770 case 'B':
771 forward_history();
772 break;
773 case 'C':
774 forward_char();
775 break;
776 case 'D':
777 backward_char();
778 break;
783 S_FUNC void
784 back_over_char(int ch)
786 backspace();
787 if (!isprint(ch))
788 backspace();
792 S_FUNC void
793 remove_char(int ch)
795 erasechar();
796 if (!isprint(ch))
797 erasechar();
801 S_FUNC void
802 echo_rest_of_line(void)
804 echo_string(HS.pos, HS.end - HS.pos);
808 S_FUNC void
809 goto_start_of_line(void)
811 while (HS.pos > HS.buf)
812 back_over_char((int)(*--HS.pos));
816 S_FUNC void
817 goto_end_of_line(void)
819 echo_rest_of_line();
820 HS.pos = HS.end;
824 S_FUNC void
825 decrement_end(int n)
827 HS.end -= n;
828 if (HS.mark && (HS.mark > HS.end))
829 HS.mark = NULL;
833 S_FUNC void
834 ignore_char(void)
839 S_FUNC void
840 flush_input(void)
842 echo_rest_of_line();
843 while (HS.end > HS.buf)
844 remove_char((int)(*--HS.end));
845 HS.pos = HS.buf;
846 HS.mark = NULL;
850 S_FUNC void
851 start_of_line(void)
853 goto_start_of_line();
857 S_FUNC void
858 end_of_line(void)
860 goto_end_of_line();
864 S_FUNC void
865 forward_char(void)
867 if (HS.pos < HS.end)
868 echo_char(*HS.pos++);
872 S_FUNC void
873 backward_char(void)
875 if (HS.pos > HS.buf)
876 back_over_char((int)(*--HS.pos));
880 S_FUNC void
881 uppercase_word(void)
883 while ((HS.pos < HS.end) && !in_word((int)(*HS.pos)))
884 echo_char(*HS.pos++);
885 while ((HS.pos < HS.end) && in_word((int)(*HS.pos))) {
886 if ((*HS.pos >= 'a') && (*HS.pos <= 'z'))
887 *HS.pos += 'A' - 'a';
888 echo_char(*HS.pos++);
893 S_FUNC void
894 lowercase_word(void)
896 while ((HS.pos < HS.end) && !in_word((int)(*HS.pos)))
897 echo_char(*HS.pos++);
898 while ((HS.pos < HS.end) && in_word((int)(*HS.pos))) {
899 if ((*HS.pos >= 'A') && (*HS.pos <= 'Z'))
900 *HS.pos += 'a' - 'A';
901 echo_char(*HS.pos++);
906 S_FUNC void
907 forward_word(void)
909 while ((HS.pos < HS.end) && !in_word((int)(*HS.pos)))
910 echo_char(*HS.pos++);
911 while ((HS.pos < HS.end) && in_word((int)(*HS.pos)))
912 echo_char(*HS.pos++);
916 S_FUNC void
917 backward_word(void)
919 if ((HS.pos > HS.buf) && in_word((int)(*HS.pos)))
920 back_over_char((int)(*--HS.pos));
921 while ((HS.pos > HS.buf) && !in_word((int)(*HS.pos)))
922 back_over_char((int)(*--HS.pos));
923 while ((HS.pos > HS.buf) && in_word((int)(*HS.pos)))
924 back_over_char((int)(*--HS.pos));
925 if ((HS.pos < HS.end) && !in_word((int)(*HS.pos)))
926 echo_char(*HS.pos++);
930 S_FUNC void
931 forward_kill_char(void)
933 int rest;
934 char ch;
936 rest = HS.end - HS.pos;
937 if (rest-- <= 0)
938 return;
939 ch = *HS.pos;
940 if (rest > 0) {
941 memcpy(HS.pos, HS.pos + 1, rest);
942 *(HS.end - 1) = ch;
944 echo_rest_of_line();
945 remove_char((int)ch);
946 decrement_end(1);
947 while (rest > 0)
948 back_over_char((int)(HS.pos[--rest]));
952 S_FUNC void
953 delete_char(void)
956 * quit delete_char (usually ^D) is at start of line and we are allowed
958 * We exit of start of line and config("ctrl_d", "empty") or
959 * if config("ctrl_d", "virgin") and we have never typed on the line.
961 if ((HS.end == HS.buf) &&
962 (conf->ctrl_d == CTRL_D_EMPTY_EOF ||
963 (conf->ctrl_d == CTRL_D_VIRGIN_EOF && HS.virgin_line == TRUE))) {
964 quit_calc();
968 * normal case: just forward_kill_char
970 if (HS.end > HS.buf)
971 forward_kill_char();
975 S_FUNC void
976 backward_kill_char(void)
978 if (HS.pos > HS.buf) {
979 HS.pos--;
980 back_over_char((int)(*HS.pos));
981 forward_kill_char();
986 S_FUNC void
987 forward_kill_word(void)
989 char *cp;
991 if (HS.pos >= HS.end)
992 return;
993 echo_rest_of_line();
994 for (cp = HS.end; cp > HS.pos;)
995 remove_char((int)(*--cp));
996 cp = HS.pos;
997 while ((cp < HS.end) && !in_word((int)(*cp)))
998 cp++;
999 while ((cp < HS.end) && in_word((int)(*cp)))
1000 cp++;
1001 savetext(HS.pos, cp - HS.pos);
1002 memcpy(HS.pos, cp, HS.end - cp);
1003 decrement_end(cp - HS.pos);
1004 echo_rest_of_line();
1005 for (cp = HS.end; cp > HS.pos;)
1006 back_over_char((int)(*--cp));
1010 S_FUNC void
1011 kill_line(void)
1013 if (HS.end <= HS.pos)
1014 return;
1015 savetext(HS.pos, HS.end - HS.pos);
1016 echo_rest_of_line();
1017 while (HS.end > HS.pos)
1018 remove_char((int)(*--HS.end));
1019 decrement_end(0);
1024 * This is the function which completes a command line editing session.
1025 * The final line length is returned in the HS.linelen variable.
1026 * The line is NOT put into the edit history, so that the caller can
1027 * decide whether or not this should be done.
1029 S_FUNC void
1030 new_line(void)
1032 int len;
1034 newline();
1035 fflush(stdout);
1037 HS.mark = NULL;
1038 HS.end[0] = '\n';
1039 HS.end[1] = '\0';
1040 len = HS.end - HS.buf + 1;
1041 if (len <= 1) {
1042 HS.curhist = HS.histcount;
1043 HS.linelen = 1;
1044 return;
1046 HS.curhist = HS.histcount;
1047 HS.pos = HS.buf;
1048 HS.end = HS.buf;
1049 HS.linelen = len;
1053 S_FUNC void
1054 save_line(void)
1056 int len;
1058 len = HS.end - HS.buf;
1059 if (len > 0) {
1060 hist_saveline(HS.buf, len);
1061 flush_input();
1063 HS.curhist = HS.histcount;
1067 S_FUNC void
1068 goto_line(void)
1070 int num;
1071 char *cp;
1072 HIST *hp;
1074 num = 0;
1075 cp = HS.buf;
1076 while ((*cp >= '0') && (*cp <= '9') && (cp < HS.pos))
1077 num = num * 10 + (*cp++ - '0');
1078 if ((num <= 0) || (num > HS.histcount) || (cp != HS.pos)) {
1079 beep();
1080 return;
1082 flush_input();
1083 HS.curhist = HS.histcount - num;
1084 hp = get_event(HS.curhist);
1085 memcpy(HS.buf, hp->data, hp->len);
1086 HS.end = &HS.buf[hp->len];
1087 goto_end_of_line();
1091 S_FUNC void
1092 forward_history(void)
1094 HIST *hp;
1096 flush_input();
1097 if (++HS.curhist >= HS.histcount)
1098 HS.curhist = 0;
1099 hp = get_event(HS.curhist);
1100 if (hp) {
1101 memcpy(HS.buf, hp->data, hp->len);
1102 HS.end = &HS.buf[hp->len];
1104 goto_end_of_line();
1108 S_FUNC void
1109 backward_history(void)
1111 HIST *hp;
1113 flush_input();
1114 if (--HS.curhist < 0)
1115 HS.curhist = HS.histcount - 1;
1116 hp = get_event(HS.curhist);
1117 if (hp) {
1118 memcpy(HS.buf, hp->data, hp->len);
1119 HS.end = &HS.buf[hp->len];
1121 goto_end_of_line();
1125 S_FUNC void
1126 insert_char(int key)
1128 int len;
1129 int rest;
1131 len = HS.end - HS.buf;
1132 if (len >= HS.bufsize) {
1133 beep();
1134 return;
1136 rest = HS.end - HS.pos;
1137 if (rest > 0)
1138 memrcpy(HS.pos + 1, HS.pos, rest);
1139 HS.end++;
1140 *HS.pos++ = key;
1141 echo_char(key);
1142 echo_rest_of_line();
1143 while (rest > 0)
1144 back_over_char((int)(HS.pos[--rest]));
1148 S_FUNC void
1149 insert_string(char *str, int len)
1151 int rest;
1152 int totallen;
1154 if (len <= 0)
1155 return;
1156 totallen = (HS.end - HS.buf) + len;
1157 if (totallen > HS.bufsize) {
1158 beep();
1159 return;
1161 rest = HS.end - HS.pos;
1162 if (rest > 0)
1163 memrcpy(HS.pos + len, HS.pos, rest);
1164 HS.end += len;
1165 memcpy(HS.pos, str, len);
1166 HS.pos += len;
1167 echo_string(str, len);
1168 echo_rest_of_line();
1169 while (rest > 0)
1170 back_over_char((int)(HS.pos[--rest]));
1174 S_FUNC void
1175 list_history(void)
1177 HIST *hp;
1178 int hnum;
1180 for (hnum = 0; hnum < HS.histcount; hnum++) {
1181 hp = get_event(hnum);
1182 printf("\n%3d: ", HS.histcount - hnum);
1183 echo_string(hp->data, hp->len);
1185 refresh_line();
1189 S_FUNC void
1190 refresh_line(void)
1192 char *cp;
1194 newline();
1195 fputs(HS.prompt, stdout);
1196 if (HS.end > HS.buf) {
1197 echo_string(HS.buf, HS.end - HS.buf);
1198 cp = HS.end;
1199 while (cp > HS.pos)
1200 back_over_char((int)(*--cp));
1205 S_FUNC void
1206 swap_chars(void)
1208 char ch1;
1209 char ch2;
1211 if ((HS.pos <= HS.buf) || (HS.pos >= HS.end))
1212 return;
1213 ch1 = *HS.pos--;
1214 ch2 = *HS.pos;
1215 *HS.pos++ = ch1;
1216 *HS.pos = ch2;
1217 back_over_char((int)ch2);
1218 echo_char(ch1);
1219 echo_char(ch2);
1220 back_over_char((int)ch2);
1224 S_FUNC void
1225 set_mark(void)
1227 HS.mark = HS.pos;
1231 S_FUNC void
1232 save_region(void)
1234 int len;
1236 if (HS.mark == NULL)
1237 return;
1238 len = HS.mark - HS.pos;
1239 if (len > 0)
1240 savetext(HS.pos, len);
1241 if (len < 0)
1242 savetext(HS.mark, -len);
1246 S_FUNC void
1247 kill_region(void)
1249 char *cp;
1250 char *left;
1251 char *right;
1253 if ((HS.mark == NULL) || (HS.mark == HS.pos))
1254 return;
1256 echo_rest_of_line();
1257 if (HS.mark < HS.pos) {
1258 left = HS.mark;
1259 right = HS.pos;
1260 HS.pos = HS.mark;
1261 } else {
1262 left = HS.pos;
1263 right = HS.mark;
1264 HS.mark = HS.pos;
1266 savetext(left, right - left);
1267 for (cp = HS.end; cp > left;)
1268 remove_char((int)(*--cp));
1269 if (right < HS.end)
1270 memcpy(left, right, HS.end - right);
1271 decrement_end(right - left);
1272 echo_rest_of_line();
1273 for (cp = HS.end; cp > HS.pos;)
1274 back_over_char((int)(*--cp));
1278 S_FUNC void
1279 yank(void)
1281 insert_string(save_buffer, save_len);
1285 S_FUNC void
1286 reverse_search(void)
1288 int len;
1289 int count;
1290 int testhist;
1291 HIST *hp;
1292 char *save_pos;
1294 count = HS.histcount;
1295 len = HS.pos - HS.buf;
1296 if (len <= 0)
1297 count = 0;
1298 testhist = HS.curhist;
1299 do {
1300 if (--count < 0) {
1301 beep();
1302 return;
1304 if (--testhist < 0)
1305 testhist = HS.histcount - 1;
1306 hp = get_event(testhist);
1307 } while ((hp == NULL) || (hp->len < len) ||
1308 memcmp(hp->data, HS.buf, len));
1310 HS.curhist = testhist;
1311 save_pos = HS.pos;
1312 flush_input();
1313 memcpy(HS.buf, hp->data, hp->len);
1314 HS.end = &HS.buf[hp->len];
1315 goto_end_of_line();
1316 while (HS.pos > save_pos)
1317 back_over_char((int)(*--HS.pos));
1321 S_FUNC void
1322 quote_char(void)
1324 int ch;
1326 ch = fgetc(stdin);
1327 if (ch != EOF)
1328 insert_char(ch);
1333 * Save data in the save buffer.
1335 S_FUNC void
1336 savetext(char *str, int len)
1338 save_len = 0;
1339 if (len <= 0)
1340 return;
1341 if (len > SAVE_SIZE)
1342 len = SAVE_SIZE;
1343 memcpy(save_buffer, str, len);
1344 save_len = len;
1349 * Test whether a character is part of a word.
1351 S_FUNC int
1352 in_word(int ch)
1354 return (isalnum(ch) || (ch == '_'));
1358 S_FUNC void
1359 erasechar(void)
1361 fputs("\b \b", stdout);
1365 S_FUNC void
1366 newline(void)
1368 fputc('\n', stdout);
1372 S_FUNC void
1373 backspace(void)
1375 fputc('\b', stdout);
1379 S_FUNC void
1380 beep(void)
1382 fputc('\007', stdout);
1386 S_FUNC void
1387 echo_char(int ch)
1389 if (isprint(ch)) {
1390 putchar(ch);
1391 } else {
1392 putchar('^');
1393 putchar((ch + '@') & 0x7f);
1398 S_FUNC void
1399 echo_string(char *str, int len)
1401 while (len-- > 0)
1402 echo_char(*str++);
1406 S_FUNC void
1407 memrcpy(char *dest, char *src, int len)
1409 dest += len - 1;
1410 src += len - 1;
1411 while (len-- > 0)
1412 *dest-- = *src--;
1415 #endif /* !USE_READLINE */
1417 S_FUNC void
1418 quit_calc(void)
1420 hist_term();
1421 putchar('\n');
1422 libcalc_call_me_last();
1423 exit(0);
1426 #if defined(USE_READLINE)
1429 #define HISTORY_LEN (1024) /* number of entries to save */
1432 #include <readline/readline.h>
1433 #include <readline/history.h>
1437 * The readline/history libs do most of the dirty work for us, so we can
1438 * replace hist_init() and hist_term() with dummies when using readline.
1439 * For hist_getline() we have to add a newline that readline removed but
1440 * calc expects. For hist_saveline(), we have to undo this. hist_getline()
1441 * also has to cope with the different memory management schemes of calc and
1442 * readline.
1446 /* name of history file */
1447 char *my_calc_history = NULL;
1449 size_t
1450 hist_getline(char *prompt, char *buf, size_t len)
1452 char *line;
1454 buf[0] = '\0';
1455 line = readline(prompt);
1456 if (!line) {
1457 switch (conf->ctrl_d) {
1458 case CTRL_D_NEVER_EOF:
1459 return 0;
1460 case CTRL_D_VIRGIN_EOF:
1461 case CTRL_D_EMPTY_EOF:
1462 default:
1463 quit_calc();
1464 /*NOTREACHED*/
1467 strncpy(buf, line, len - 1);
1468 buf[len - 2] = '\0';
1469 len = strlen(buf);
1470 buf[len] = '\n';
1471 buf[len + 1] = '\0';
1472 free(line);
1473 return len + 1;
1477 void
1478 hist_term(void)
1483 S_FUNC void
1484 my_stifle_history (void)
1486 /* only save last number of entries */
1487 stifle_history(HISTORY_LEN);
1489 if (my_calc_history)
1490 write_history(my_calc_history);
1495 hist_init(char UNUSED *filename)
1497 /* used when parsing conditionals in ~/.inputrc */
1498 rl_readline_name = "calc";
1500 /* initialize interactive variables */
1501 using_history();
1503 /* name of history file */
1504 my_calc_history = tilde_expand("~/.calc_history");
1506 /* read previous history */
1507 read_history(my_calc_history);
1509 atexit(my_stifle_history);
1511 return HIST_SUCCESS;
1514 void
1515 hist_saveline(char *line, int len)
1517 STATIC char *prev = NULL;
1519 if (len <= 1)
1520 return;
1522 /* ignore if identical with previous line */
1523 if (prev != NULL && strcmp(prev, line) == 0)
1524 return;
1526 free(prev);
1528 /* fail silently */
1529 prev = strdup(line);
1531 line[len - 1] = '\0';
1532 add_history(line);
1533 line[len - 1] = '\n';
1537 #endif /* USE_READLINE */
1540 #if defined(HIST_TEST)
1543 * Main routine to test history.
1545 void
1546 main(int argc, char **argv)
1548 char *filename;
1549 int len;
1550 char buf[BUFSIZ+1];
1552 filename = NULL;
1553 if (argc > 1)
1554 filename = argv[1];
1556 switch (hist_init(filename)) {
1557 case HIST_SUCCESS:
1558 break;
1559 case HIST_NOFILE:
1560 fprintf(stderr, "Binding file was not found\n");
1561 break;
1562 case HIST_NOTTY:
1563 fprintf(stderr, "Cannot set terminal parameters\n");
1564 break;
1565 case HIST_INITED:
1566 fprintf(stderr, "Hist is already inited\n");
1567 break;
1568 default:
1569 fprintf(stderr, "Unknown error from hist_init\n");
1570 break;
1573 do {
1574 len = hist_getline("HIST> ", buf, sizeof(buf));
1575 hist_saveline(buf, len);
1576 } while (len && (buf[0] != 'q'));
1578 hist_term();
1579 exit(0);
1582 #endif /* HIST_TEST */