patch-readline.c   [plain text]


--- src/readline.c.orig	2008-07-12 01:38:05.000000000 -0700
+++ src/readline.c	2008-08-07 13:10:58.000000000 -0700
@@ -89,6 +89,7 @@
 /* readline compatibility stuff - look at readline sources/documentation */
 /* to see what these variables mean */
 const char *rl_library_version = "EditLine wrapper";
+int rl_readline_version = RL_READLINE_VERSION;
 static char empty[] = { '\0' };
 static char expand_chars[] = { ' ', '\t', '\n', '=', '(', '\0' };
 static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '$',
@@ -137,6 +138,7 @@
 VFunction *rl_completion_display_matches_hook = NULL;
 VFunction *rl_prep_term_function = (VFunction *)rl_prep_terminal;
 VFunction *rl_deprep_term_function = (VFunction *)rl_deprep_terminal;
+KEYMAP_ENTRY_ARRAY emacs_meta_keymap;
 
 /*
  * The current prompt string.
@@ -233,6 +235,22 @@
 	return 1;
 }
 
+static const char _dothistory[] = "/.history";
+
+static const char *
+_default_history_file(void)
+{
+	struct passwd *p;
+	static char path[PATH_MAX];
+
+	if (*path)
+		return path;
+	if ((p = getpwuid(getuid())) == NULL)
+		return NULL;
+	strlcpy(path, p->pw_dir, PATH_MAX);
+	strlcat(path, _dothistory, PATH_MAX);
+	return path;
+}
 
 /*
  * READLINE compatibility stuff
@@ -1127,6 +1145,139 @@
 	return (max_input_history != INT_MAX);
 }
 
+static const char _history_tmp_template[] = "/tmp/.historyXXXXXX";
+
+int
+history_truncate_file (const char *filename, int nlines)
+{
+	int ret = 0;
+	FILE *fp, *tp;
+	char template[sizeof(_history_tmp_template)];
+	char buf[4096];
+
+	if (filename == NULL && (filename = _default_history_file()) == NULL)
+		return errno;
+	if ((fp = fopen(filename, "r+")) == NULL)
+		return errno;
+	do {
+		int fd;
+
+		strcpy(template, _history_tmp_template);
+		if ((fd = mkstemp(template)) < 0) {
+			ret = errno;
+			break;
+		}
+		do {
+			char *cp;
+
+			if ((tp = fdopen(fd, "r+")) == NULL) {
+				close(fd);
+				ret = errno;
+				break;
+			}
+			do {
+				off_t off;
+				int count = 0, left = 0;
+
+				for(;;) {
+					if (fread(buf, sizeof(buf), 1, fp) != 1) {
+						if (ferror(fp)) {
+							ret = errno;
+							break;
+						}
+						if (fseeko(fp, (off_t)sizeof(buf) * count, SEEK_SET) < 0) {
+							ret = errno;
+							break;
+						}
+						left = fread(buf, 1, sizeof(buf), fp);
+						if (ferror(fp)) {
+							ret = errno;
+							break;
+						}
+						if (left == 0) {
+							count--;
+							left = sizeof(buf);
+						} else if (fwrite(buf, left, 1, tp) != 1) {
+							ret = errno;
+							break;
+						}
+						fflush(tp);
+						break;
+					}
+					if (fwrite(buf, sizeof(buf), 1, tp) != 1) {
+						ret = errno;
+						break;
+					}
+					count++;
+				}
+				if (ret)
+					break;
+				cp = buf + left - 1;
+				if(*cp != '\n')
+					cp++;
+				for(;;) {
+					while (--cp >= buf) {
+						if (*cp == '\n') {
+							if (--nlines == 0) {
+								if (++cp >= buf + sizeof(buf)) {
+									count++;
+									cp = buf;
+								}
+								break;
+							}
+						}
+					}
+					if (nlines <= 0 || count == 0)
+						break;
+					count--;
+					if (fseeko(tp, (off_t)sizeof(buf) * count, SEEK_SET) < 0) {
+						ret = errno;
+						break;
+					}
+					if (fread(buf, sizeof(buf), 1, tp) != 1) {
+						if (ferror(tp)) {
+							ret = errno;
+							break;
+						}
+						ret = EAGAIN;
+						break;
+					}
+					cp = buf + sizeof(buf);
+				}
+				if (ret || nlines > 0)
+					break;
+				if (fseeko(fp, 0, SEEK_SET) < 0) {
+					ret = errno;
+					break;
+				}
+				if (fseeko(tp, (off_t)sizeof(buf) * count + (cp - buf), SEEK_SET) < 0) {
+					ret = errno;
+					break;
+				}
+				for(;;) {
+					if ((left = fread(buf, 1, sizeof(buf), tp)) == 0) {
+						if (ferror(fp))
+							ret = errno;
+						break;
+					}
+					if (fwrite(buf, left, 1, fp) != 1) {
+						ret = errno;
+						break;
+					}
+				}
+				fflush(fp);
+				if((off = ftello(fp)) > 0)
+					ftruncate(fileno(fp), off);
+			} while(0);
+			fclose(tp);
+		} while(0);
+		unlink(template);
+	} while(0);
+	fclose(fp);
+
+	return ret;
+}
+
 
 /*
  * read history from a file given
@@ -1138,7 +1289,9 @@
 
 	if (h == NULL || e == NULL)
 		rl_initialize();
-	return (history(h, &ev, H_LOAD, filename) == -1);
+	if (filename == NULL && (filename = _default_history_file()) == NULL)
+		return errno;
+	return (history(h, &ev, H_LOAD, filename) == -1 ? (errno ? errno : EINVAL) : 0);
 }
 
 
@@ -1152,7 +1305,9 @@
 
 	if (h == NULL || e == NULL)
 		rl_initialize();
-	return (history(h, &ev, H_SAVE, filename) == -1);
+	if (filename == NULL && (filename = _default_history_file()) == NULL)
+		return errno;
+	return (history(h, &ev, H_SAVE, filename) == -1 ? (errno ? errno : EINVAL) : 0);
 }
 
 
@@ -1176,16 +1331,15 @@
 		return (NULL);
 	curr_num = ev.num;
 
-	/* start from most recent */
-	if (history(h, &ev, H_FIRST) != 0)
+	/* start from the oldest */
+	if (history(h, &ev, H_LAST) != 0)
 		return (NULL);	/* error */
 
-	/* look backwards for event matching specified offset */
-	if (history(h, &ev, H_NEXT_EVENT, num + 1))
+	/* look forward for event matching specified offset */
+	if (history(h, &ev, H_NEXT_EVDATA, num, &she.data))
 		return (NULL);
 
 	she.line = ev.str;
-	she.data = NULL;
 
 	/* restore pointer to where it was */
 	(void)history(h, &ev, H_SET, curr_num);
@@ -1225,20 +1379,64 @@
 	if (h == NULL || e == NULL)
 		rl_initialize();
 
-	if (history(h, &ev, H_DEL, num) != 0)
+	if ((she = malloc(sizeof(*she))) == NULL)
 		return NULL;
 
-	if ((she = malloc(sizeof(*she))) == NULL)
+	if (history(h, &ev, H_DELDATA, num, &she->data) != 0) {
+		free(she);
 		return NULL;
+	}
 
 	she->line = ev.str;
-	she->data = NULL;
+	if (history(h, &ev, H_GETSIZE) == 0)
+		history_length = ev.num;
 
 	return she;
 }
 
 
 /*
+ * replace the line and data of the num-th entry
+ */
+HIST_ENTRY *
+replace_history_entry(int num, const char *line, histdata_t data)
+{
+	HIST_ENTRY *he;
+	HistEvent ev;
+	int curr_num;
+
+	if (h == NULL || e == NULL)
+		rl_initialize();
+
+	/* save current position */
+	if (history(h, &ev, H_CURR) != 0)
+		return (NULL);
+	curr_num = ev.num;
+
+	/* start from the oldest */
+	if (history(h, &ev, H_LAST) != 0)
+		return (NULL);	/* error */
+
+	if ((he = (HIST_ENTRY *)malloc(sizeof(HIST_ENTRY))) == NULL)
+		return NULL;
+
+	/* look forwards for event matching specified offset */
+	if (history(h, &ev, H_NEXT_EVDATA, num, &he->data)) {
+		free(he);
+		return (NULL);
+	}
+
+	he->line = strdup(ev.str);
+	history(h, &ev, H_REPLACE, line, data);
+
+	/* restore pointer to where it was */
+	(void)history(h, &ev, H_SET, curr_num);
+
+	return (he);
+}
+
+
+/*
  * clear the history list - delete all entries
  */
 void
@@ -1247,6 +1445,7 @@
 	HistEvent ev;
 
 	history(h, &ev, H_CLEAR);
+	history_length = 0;
 }
 
 
@@ -1318,13 +1517,17 @@
 	HistEvent ev;
 	int curr_num;
 
-	if (pos > history_length || pos < 0)
+	if (pos >= history_length || pos < 0)
 		return (-1);
 
 	history(h, &ev, H_CURR);
 	curr_num = ev.num;
 
-	if (history(h, &ev, H_SET, pos)) {
+	/*
+	 * use H_DELDATA to set to nth history (without delete) by passing
+	 * (void **)-1
+	 */
+	if (history(h, &ev, H_DELDATA, pos, (void **)-1)) {
 		history(h, &ev, H_SET, curr_num);
 		return(-1);
 	}
@@ -1554,7 +1757,7 @@
  * bind key c to readline-type function func
  */
 int
-rl_bind_key(int c, int func(int, int))
+rl_bind_key(int c, rl_command_func_t *func)
 {
 	int retval = -1;
 
@@ -1621,6 +1824,20 @@
 	return (0);
 }
 
+int
+rl_insert_text(const char *text)
+{
+	if (!text || *text == 0)
+		return (0);
+
+	if (h == NULL || e == NULL)
+		rl_initialize();
+
+	if (el_insertstr(e, text) < 0)
+		return (0);
+	return (strlen(text));
+}
+
 /*ARGSUSED*/
 int
 rl_newline(int count, int c)
@@ -1684,7 +1901,7 @@
 		} else
 			wbuf = NULL;
 		(*(void (*)(const char *))rl_linefunc)(wbuf);
-		el_set(e, EL_UNBUFFERED, 1);
+		//el_set(e, EL_UNBUFFERED, 1);
 	}
 }
 
@@ -1966,7 +2183,30 @@
 
 int
 /*ARGSUSED*/
-rl_bind_key_in_map(int key, Function *fun, Keymap k)
+rl_bind_key_in_map(int key, rl_command_func_t *fun, Keymap k)
 {
 	return 0;
 }
+
+HISTORY_STATE *
+history_get_history_state(void)
+{
+	HISTORY_STATE *hs;
+	HistEvent ev;
+
+	if ((hs = malloc(sizeof(HISTORY_STATE))) == NULL)
+		return (NULL);
+	hs->length = history_length;
+	return (hs);
+}
+
+/* unsupported, but needed by python */
+void
+rl_cleanup_after_signal(void)
+{
+}
+
+void
+rl_free_line_state(void)
+{
+}