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.
47 #include "have_unistd.h"
48 #if defined(HAVE_UNISTD_H)
52 #include "have_stdlib.h"
53 #if defined(HAVE_STDLIB_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 */
70 #include "have_unused.h"
72 #if !defined(USE_READLINE)
74 E_FUNC
FILE *curstream(void);
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))
93 BOOL virgin_line
; /* 1 => never typed chars, 0 => chars typed */
97 typedef void (*FUNCPTR
)();
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
},
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
},
177 typedef struct key_ent KEY_ENT
;
178 typedef struct key_map KEY_MAP
;
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)))
211 int len
; /* length of data */
212 char data
[1]; /* varying length data */
219 STATIC
int key_count
;
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
265 hist_getline(char *prompt
, char *buf
, size_t len
)
268 * initialize if we have not already done so
271 (void) hist_init(calcbindings
);
274 * establish the beginning of a line condition
277 HS
.bufsize
= len
- 2;
283 HS
.virgin_line
= TRUE
;
288 fputs(prompt
, stdout
);
292 * special case: non-interactive editing
295 if (fgets(buf
, len
, stdin
) == NULL
)
303 while (HS
.linelen
< 0) {
305 /* get the next char */
308 /* chars typed, no longer virgin */
309 HS
.virgin_line
= FALSE
;
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
336 if (conf
->calc_debug
& CALCDBG_TTY
)
337 printf("hist_init: inited already set\n");
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)
360 if (read_bindings(curstream()))
369 * setup the calc TTY on STDIN
371 if (!calc_tty(STDIN
)) {
376 if (conf
->calc_debug
& CALCDBG_TTY
)
377 printf("hist_init: Set canedit\n");
384 * Reset the terminal modes just before exiting.
389 if (!inited
|| !canedit
) {
390 if (conf
->calc_debug
& CALCDBG_TTY
) {
392 printf("hist_term: inited already cleared\n");
394 printf("hist_term: canedit already cleared\n");
397 if (conf
->calc_debug
& CALCDBG_TTY
)
398 printf("hist_term: Cleared inited\n");
403 * restore orignal tty state
405 (void) orig_tty(STDIN
);
414 for (i
= 0; i
< sizeof(maps
) / sizeof(maps
[0]); i
++) {
415 if (strcmp(map
, maps
[i
].name
) == 0)
423 unbind_key(KEY_MAP
*map
, int key
)
425 map
->map
[key
] = NULL
;
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
)
435 map
->map
[key
] = &key_table
[key_count
++];
437 map
->map
[key
]->func
= func
;
438 map
->map
[key
]->next
= next_map
;
443 do_map_line(char *line
)
449 while (isspace((int)*cp
))
454 while ((*cp
!= '\0') && !isspace((int)*cp
))
457 return find_map(map_name
);
462 do_bind_line(KEY_MAP
*map
, char *line
)
476 unbind_key(map
, key
);
484 key
= CONTROL(*cp
++);
486 } else if (key
== '\\') {
490 while (isspace((int)*cp
))
493 unbind_key(map
, key
);
498 while ((*cp
!= '\0') && !isspace((int)*cp
))
502 while (isspace((int)*cp
))
505 func
= find_func(func_name
);
507 fprintf(stderr
, "Unknown function \"%s\"\n", func_name
);
512 next
= map
->default_ent
.next
;
517 while ((*cp
!= '\0') && !isspace((int)*cp
))
521 while (isspace((int)*cp
))
524 next
= find_map(next_name
);
528 raw_bind_key(map
, key
, func
, next
);
533 do_default_line(KEY_MAP
*map
, char *line
)
544 while (isspace((int)*cp
))
550 while ((*cp
!= '\0') && !isspace((int)*cp
))
554 while (isspace((int)*cp
))
557 func
= find_func(func_name
);
565 while ((*cp
!= '\0') && !isspace((int)*cp
))
569 while (isspace((int)*cp
))
572 next
= find_map(next_name
);
577 map
->default_ent
.func
= func
;
578 map
->default_ent
.next
= next
;
583 * Read bindings from specified open file.
585 * Returns nonzero on error.
588 read_bindings(FILE *fp
)
594 base_map
= find_map(base_map_name
);
596 input_map
= base_map
;
601 while (fgets(line
, sizeof(line
) - 1, fp
)) {
604 while (isspace((int)*cp
))
607 if ((*cp
== '\0') || (*cp
== '#') || (*cp
== '\n'))
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]);
618 do_bind_line(input_map
, cp
);
638 ent
= cur_map
->map
[key
];
640 ent
= &cur_map
->default_ent
;
644 /* ignore Saber-C warning #65 - has 1 arg, expecting 0 */
645 /* ok to ignore in proc read_key */
653 * Return the Nth history event, indexed from zero.
654 * Earlier history events are lower in number.
661 if ((n
< 0) || (n
>= HS
.histcount
))
671 * Search the history list for the specified pattern.
672 * Returns the found history, or NULL.
675 find_event(char *pat
, int len
)
679 for (hp
= FIRSTHIST
; hp
->len
; hp
= NEXTHIST(hp
)) {
680 if ((hp
->len
== len
) && (memcmp(hp
->data
, pat
, len
) == 0))
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.
694 hist_saveline(char *line
, int len
)
700 if ((len
> 0) && (line
[len
- 1] == '\n'))
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
);
713 left
= histused
- HISTOFFSET(hp2
);
716 histused
-= HISTLEN(hp
);
717 memcpy(hp
, hp2
, left
+ 1);
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
;
729 left
= histused
- HISTOFFSET(hp2
);
730 histused
-= HISTLEN(hp
);
731 memcpy(hp
, hp2
, left
+ 1);
736 * Add the line to the end of the history table.
738 hp
= (HIST
*) &histbuf
[histused
];
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.
751 find_func(char *name
)
755 for (fp
= funcs
; fp
->name
; fp
++) {
756 if (strcmp(fp
->name
, name
) == 0)
766 switch (fgetc(stdin
)) {
784 back_over_char(int ch
)
802 echo_rest_of_line(void)
804 echo_string(HS
.pos
, HS
.end
- HS
.pos
);
809 goto_start_of_line(void)
811 while (HS
.pos
> HS
.buf
)
812 back_over_char((int)(*--HS
.pos
));
817 goto_end_of_line(void)
828 if (HS
.mark
&& (HS
.mark
> HS
.end
))
843 while (HS
.end
> HS
.buf
)
844 remove_char((int)(*--HS
.end
));
853 goto_start_of_line();
868 echo_char(*HS
.pos
++);
876 back_over_char((int)(*--HS
.pos
));
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
++);
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
++);
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
++);
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
++);
931 forward_kill_char(void)
936 rest
= HS
.end
- HS
.pos
;
941 memcpy(HS
.pos
, HS
.pos
+ 1, rest
);
945 remove_char((int)ch
);
948 back_over_char((int)(HS
.pos
[--rest
]));
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
))) {
968 * normal case: just forward_kill_char
976 backward_kill_char(void)
978 if (HS
.pos
> HS
.buf
) {
980 back_over_char((int)(*HS
.pos
));
987 forward_kill_word(void)
991 if (HS
.pos
>= HS
.end
)
994 for (cp
= HS
.end
; cp
> HS
.pos
;)
995 remove_char((int)(*--cp
));
997 while ((cp
< HS
.end
) && !in_word((int)(*cp
)))
999 while ((cp
< HS
.end
) && in_word((int)(*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
));
1013 if (HS
.end
<= HS
.pos
)
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
));
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.
1040 len
= HS
.end
- HS
.buf
+ 1;
1042 HS
.curhist
= HS
.histcount
;
1046 HS
.curhist
= HS
.histcount
;
1058 len
= HS
.end
- HS
.buf
;
1060 hist_saveline(HS
.buf
, len
);
1063 HS
.curhist
= HS
.histcount
;
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
)) {
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
];
1092 forward_history(void)
1097 if (++HS
.curhist
>= HS
.histcount
)
1099 hp
= get_event(HS
.curhist
);
1101 memcpy(HS
.buf
, hp
->data
, hp
->len
);
1102 HS
.end
= &HS
.buf
[hp
->len
];
1109 backward_history(void)
1114 if (--HS
.curhist
< 0)
1115 HS
.curhist
= HS
.histcount
- 1;
1116 hp
= get_event(HS
.curhist
);
1118 memcpy(HS
.buf
, hp
->data
, hp
->len
);
1119 HS
.end
= &HS
.buf
[hp
->len
];
1126 insert_char(int key
)
1131 len
= HS
.end
- HS
.buf
;
1132 if (len
>= HS
.bufsize
) {
1136 rest
= HS
.end
- HS
.pos
;
1138 memrcpy(HS
.pos
+ 1, HS
.pos
, rest
);
1142 echo_rest_of_line();
1144 back_over_char((int)(HS
.pos
[--rest
]));
1149 insert_string(char *str
, int len
)
1156 totallen
= (HS
.end
- HS
.buf
) + len
;
1157 if (totallen
> HS
.bufsize
) {
1161 rest
= HS
.end
- HS
.pos
;
1163 memrcpy(HS
.pos
+ len
, HS
.pos
, rest
);
1165 memcpy(HS
.pos
, str
, len
);
1167 echo_string(str
, len
);
1168 echo_rest_of_line();
1170 back_over_char((int)(HS
.pos
[--rest
]));
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
);
1195 fputs(HS
.prompt
, stdout
);
1196 if (HS
.end
> HS
.buf
) {
1197 echo_string(HS
.buf
, HS
.end
- HS
.buf
);
1200 back_over_char((int)(*--cp
));
1211 if ((HS
.pos
<= HS
.buf
) || (HS
.pos
>= HS
.end
))
1217 back_over_char((int)ch2
);
1220 back_over_char((int)ch2
);
1236 if (HS
.mark
== NULL
)
1238 len
= HS
.mark
- HS
.pos
;
1240 savetext(HS
.pos
, len
);
1242 savetext(HS
.mark
, -len
);
1253 if ((HS
.mark
== NULL
) || (HS
.mark
== HS
.pos
))
1256 echo_rest_of_line();
1257 if (HS
.mark
< HS
.pos
) {
1266 savetext(left
, right
- left
);
1267 for (cp
= HS
.end
; cp
> left
;)
1268 remove_char((int)(*--cp
));
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
));
1281 insert_string(save_buffer
, save_len
);
1286 reverse_search(void)
1294 count
= HS
.histcount
;
1295 len
= HS
.pos
- HS
.buf
;
1298 testhist
= HS
.curhist
;
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
;
1313 memcpy(HS
.buf
, hp
->data
, hp
->len
);
1314 HS
.end
= &HS
.buf
[hp
->len
];
1316 while (HS
.pos
> save_pos
)
1317 back_over_char((int)(*--HS
.pos
));
1333 * Save data in the save buffer.
1336 savetext(char *str
, int len
)
1341 if (len
> SAVE_SIZE
)
1343 memcpy(save_buffer
, str
, len
);
1349 * Test whether a character is part of a word.
1354 return (isalnum(ch
) || (ch
== '_'));
1361 fputs("\b \b", stdout
);
1368 fputc('\n', stdout
);
1375 fputc('\b', stdout
);
1382 fputc('\007', stdout
);
1393 putchar((ch
+ '@') & 0x7f);
1399 echo_string(char *str
, int len
)
1407 memrcpy(char *dest
, char *src
, int len
)
1415 #endif /* !USE_READLINE */
1422 libcalc_call_me_last();
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
1446 /* name of history file */
1447 char *my_calc_history
= NULL
;
1450 hist_getline(char *prompt
, char *buf
, size_t len
)
1455 line
= readline(prompt
);
1457 switch (conf
->ctrl_d
) {
1458 case CTRL_D_NEVER_EOF
:
1460 case CTRL_D_VIRGIN_EOF
:
1461 case CTRL_D_EMPTY_EOF
:
1467 strncpy(buf
, line
, len
- 1);
1468 buf
[len
- 2] = '\0';
1471 buf
[len
+ 1] = '\0';
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 */
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
;
1515 hist_saveline(char *line
, int len
)
1517 STATIC
char *prev
= NULL
;
1522 /* ignore if identical with previous line */
1523 if (prev
!= NULL
&& strcmp(prev
, line
) == 0)
1529 prev
= strdup(line
);
1531 line
[len
- 1] = '\0';
1533 line
[len
- 1] = '\n';
1537 #endif /* USE_READLINE */
1540 #if defined(HIST_TEST)
1543 * Main routine to test history.
1546 main(int argc
, char **argv
)
1556 switch (hist_init(filename
)) {
1560 fprintf(stderr
, "Binding file was not found\n");
1563 fprintf(stderr
, "Cannot set terminal parameters\n");
1566 fprintf(stderr
, "Hist is already inited\n");
1569 fprintf(stderr
, "Unknown error from hist_init\n");
1574 len
= hist_getline("HIST> ", buf
, sizeof(buf
));
1575 hist_saveline(buf
, len
);
1576 } while (len
&& (buf
[0] != 'q'));
1582 #endif /* HIST_TEST */