summaryrefslogtreecommitdiffstats
path: root/cmdbuf.c
diff options
context:
space:
mode:
Diffstat (limited to 'cmdbuf.c')
-rw-r--r--cmdbuf.c300
1 files changed, 231 insertions, 69 deletions
diff --git a/cmdbuf.c b/cmdbuf.c
index e387ccc..69d7414 100644
--- a/cmdbuf.c
+++ b/cmdbuf.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1984-2012 Mark Nudelman
+ * Copyright (C) 1984-2015 Mark Nudelman
*
* You may distribute under the terms of either the GNU General Public
* License or the Less License, as specified in the README file.
@@ -203,7 +203,7 @@ cmd_step_common(p, ch, len, pwidth, bswidth)
pr = prchar((int) ch);
if (pwidth != NULL || bswidth != NULL)
{
- int len = strlen(pr);
+ int len = (int) strlen(pr);
if (pwidth != NULL)
*pwidth = len;
if (bswidth != NULL)
@@ -222,7 +222,7 @@ cmd_step_common(p, ch, len, pwidth, bswidth)
*bswidth = 0;
} else if (is_ubin_char(ch))
{
- int len = strlen(pr);
+ int len = (int) strlen(pr);
if (pwidth != NULL)
*pwidth = len;
if (bswidth != NULL)
@@ -375,7 +375,7 @@ cmd_lshift()
s = ns;
}
- cmd_offset = s - cmdbuf;
+ cmd_offset = (int) (s - cmdbuf);
save_cp = cp;
cmd_home();
cmd_repaint(save_cp);
@@ -405,7 +405,7 @@ cmd_rshift()
cols += width;
}
- cmd_offset = s - cmdbuf;
+ cmd_offset = (int) (s - cmdbuf);
save_cp = cp;
cmd_home();
cmd_repaint(save_cp);
@@ -535,7 +535,7 @@ cmd_erase()
*/
s = cp;
cmd_left();
- clen = s - cp;
+ clen = (int) (s - cp);
/*
* Remove the char from the buffer (shift the buffer left).
@@ -701,7 +701,7 @@ cmd_updown(action)
if (updown_match < 0)
{
- updown_match = cp - cmdbuf;
+ updown_match = (int) (cp - cmdbuf);
}
/*
@@ -744,12 +744,13 @@ cmd_updown(action)
#endif
/*
- * Add a string to a history list.
+ * Add a string to an mlist.
*/
public void
-cmd_addhist(mlist, cmd)
+cmd_addhist(mlist, cmd, modified)
struct mlist *mlist;
char *cmd;
+ int modified;
{
#if CMD_HISTORY
struct mlist *ml;
@@ -773,6 +774,7 @@ cmd_addhist(mlist, cmd)
*/
ml = (struct mlist *) ecalloc(1, sizeof(struct mlist));
ml->string = save(cmd);
+ ml->modified = modified;
ml->next = mlist;
ml->prev = mlist->prev;
mlist->prev->next = ml;
@@ -799,7 +801,7 @@ cmd_accept()
*/
if (curr_mlist == NULL)
return;
- cmd_addhist(curr_mlist, cmdbuf);
+ cmd_addhist(curr_mlist, cmdbuf, 1);
curr_mlist->modified = 1;
#endif
}
@@ -965,7 +967,7 @@ delimit_word()
int delim_quoted = 0;
int meta_quoted = 0;
char *esc = get_meta_escape();
- int esclen = strlen(esc);
+ int esclen = (int) strlen(esc);
#endif
/*
@@ -1262,7 +1264,7 @@ cmd_char(c)
cmd_mbc_buf[cmd_mbc_buf_index++] = c;
if (cmd_mbc_buf_index < cmd_mbc_buf_len)
return (CC_OK);
- if (!is_utf8_well_formed(cmd_mbc_buf))
+ if (!is_utf8_well_formed(cmd_mbc_buf, cmd_mbc_buf_index))
{
/* complete, but not well formed (non-shortest form), sequence */
cmd_mbc_buf_len = 0;
@@ -1359,6 +1361,18 @@ cmd_lastpattern()
#if CMD_HISTORY
/*
+ */
+ static int
+mlist_size(ml)
+ struct mlist *ml;
+{
+ int size = 0;
+ for (ml = ml->next; ml->string != NULL; ml = ml->next)
+ ++size;
+ return size;
+}
+
+/*
* Get the name of the history file.
*/
static char *
@@ -1378,6 +1392,10 @@ histfile_name()
return (save(name));
}
+ /* See if history file is disabled in the build. */
+ if (strcmp(LESSHISTFILE, "") == 0 || strcmp(LESSHISTFILE, "-") == 0)
+ return (NULL);
+
/* Otherwise, file is in $HOME. */
home = lgetenv("HOME");
if (home == NULL || *home == '\0')
@@ -1388,25 +1406,28 @@ histfile_name()
#endif
return (NULL);
}
- len = strlen(home) + strlen(LESSHISTFILE) + 2;
+ len = (int) (strlen(home) + strlen(LESSHISTFILE) + 2);
name = (char *) ecalloc(len, sizeof(char));
SNPRINTF2(name, len, "%s/%s", home, LESSHISTFILE);
return (name);
}
-#endif /* CMD_HISTORY */
/*
- * Initialize history from a .lesshist file.
+ * Read a .lesshst file and call a callback for each line in the file.
*/
- public void
-init_cmdhist()
+ static void
+read_cmdhist2(action, uparam, skip_search, skip_shell)
+ void (*action)(void*,struct mlist*,char*);
+ void *uparam;
+ int skip_search;
+ int skip_shell;
{
-#if CMD_HISTORY
struct mlist *ml = NULL;
char line[CMDBUF_SIZE];
char *filename;
FILE *f;
char *p;
+ int *skip = NULL;
filename = histfile_name();
if (filename == NULL)
@@ -1432,84 +1453,170 @@ init_cmdhist()
}
}
if (strcmp(line, HISTFILE_SEARCH_SECTION) == 0)
+ {
ml = &mlist_search;
- else if (strcmp(line, HISTFILE_SHELL_SECTION) == 0)
+ skip = &skip_search;
+ } else if (strcmp(line, HISTFILE_SHELL_SECTION) == 0)
{
#if SHELL_ESCAPE || PIPEC
ml = &mlist_shell;
+ skip = &skip_shell;
#else
ml = NULL;
+ skip = NULL;
#endif
} else if (*line == '"')
{
if (ml != NULL)
- cmd_addhist(ml, line+1);
+ {
+ if (skip != NULL && *skip > 0)
+ --(*skip);
+ else
+ (*action)(uparam, ml, line+1);
+ }
}
}
fclose(f);
+}
+
+ static void
+read_cmdhist(action, uparam, skip_search, skip_shell)
+ void (*action)(void*,struct mlist*,char*);
+ void *uparam;
+ int skip_search;
+ int skip_shell;
+{
+ read_cmdhist2(action, uparam, skip_search, skip_shell);
+ (*action)(uparam, NULL, NULL); /* signal end of file */
+}
+
+ static void
+addhist_init(void *uparam, struct mlist *ml, char *string)
+{
+ if (ml == NULL || string == NULL)
+ return;
+ cmd_addhist(ml, string, 0);
+}
+#endif /* CMD_HISTORY */
+
+/*
+ * Initialize history from a .lesshist file.
+ */
+ public void
+init_cmdhist()
+{
+#if CMD_HISTORY
+ read_cmdhist(&addhist_init, NULL, 0, 0);
#endif /* CMD_HISTORY */
}
/*
- *
+ * Write the header for a section of the history file.
*/
#if CMD_HISTORY
static void
-save_mlist(ml, f)
+write_mlist_header(ml, f)
struct mlist *ml;
FILE *f;
{
- int histsize = 0;
- int n;
- char *s;
-
- s = lgetenv("LESSHISTSIZE");
- if (s != NULL)
- histsize = atoi(s);
- if (histsize == 0)
- histsize = 100;
+ if (ml == &mlist_search)
+ fprintf(f, "%s\n", HISTFILE_SEARCH_SECTION);
+#if SHELL_ESCAPE || PIPEC
+ else if (ml == &mlist_shell)
+ fprintf(f, "%s\n", HISTFILE_SHELL_SECTION);
+#endif
+}
- ml = ml->prev;
- for (n = 0; n < histsize; n++)
- {
- if (ml->string == NULL)
- break;
- ml = ml->prev;
- }
+/*
+ * Write all modified entries in an mlist to the history file.
+ */
+ static void
+write_mlist(ml, f)
+ struct mlist *ml;
+ FILE *f;
+{
for (ml = ml->next; ml->string != NULL; ml = ml->next)
+ {
+ if (!ml->modified)
+ continue;
fprintf(f, "\"%s\n", ml->string);
+ ml->modified = 0;
+ }
+ ml->modified = 0; /* entire mlist is now unmodified */
}
-#endif /* CMD_HISTORY */
/*
- *
+ * Make a temp name in the same directory as filename.
*/
- public void
-save_cmdhist()
-{
-#if CMD_HISTORY
+ static char *
+make_tempname(filename)
char *filename;
- FILE *f;
- int modified = 0;
+{
+ char lastch;
+ char *tempname = ecalloc(1, strlen(filename)+1);
+ strcpy(tempname, filename);
+ lastch = tempname[strlen(tempname)-1];
+ tempname[strlen(tempname)-1] = (lastch == 'Q') ? 'Z' : 'Q';
+ return tempname;
+}
- if (mlist_search.modified)
- modified = 1;
+struct save_ctx
+{
+ struct mlist *mlist;
+ FILE *fout;
+};
+
+/*
+ * Copy entries from the saved history file to a new file.
+ * At the end of each mlist, append any new entries
+ * created during this session.
+ */
+ static void
+copy_hist(void *uparam, struct mlist *ml, char *string)
+{
+ struct save_ctx *ctx = (struct save_ctx *) uparam;
+
+ if (ml != ctx->mlist) {
+ /* We're changing mlists. */
+ if (ctx->mlist)
+ /* Append any new entries to the end of the current mlist. */
+ write_mlist(ctx->mlist, ctx->fout);
+ /* Write the header for the new mlist. */
+ ctx->mlist = ml;
+ write_mlist_header(ctx->mlist, ctx->fout);
+ }
+ if (string != NULL)
+ {
+ /* Copy the entry. */
+ fprintf(ctx->fout, "\"%s\n", string);
+ }
+ if (ml == NULL) /* End of file */
+ {
+ /* Write any sections that were not in the original file. */
+ if (mlist_search.modified)
+ {
+ write_mlist_header(&mlist_search, ctx->fout);
+ write_mlist(&mlist_search, ctx->fout);
+ }
#if SHELL_ESCAPE || PIPEC
- if (mlist_shell.modified)
- modified = 1;
+ if (mlist_shell.modified)
+ {
+ write_mlist_header(&mlist_shell, ctx->fout);
+ write_mlist(&mlist_shell, ctx->fout);
+ }
#endif
- if (!modified)
- return;
- filename = histfile_name();
- if (filename == NULL)
- return;
- f = fopen(filename, "w");
- free(filename);
- if (f == NULL)
- return;
-#if HAVE_FCHMOD
+ }
+}
+#endif /* CMD_HISTORY */
+
+/*
+ * Make a file readable only by its owner.
+ */
+ static void
+make_file_private(f)
+ FILE *f;
{
- /* Make history file readable only by owner. */
+#if HAVE_FCHMOD
int do_chmod = 1;
#if HAVE_STAT
struct stat statbuf;
@@ -1520,19 +1627,74 @@ save_cmdhist()
#endif
if (do_chmod)
fchmod(fileno(f), 0600);
-}
#endif
+}
- fprintf(f, "%s\n", HISTFILE_FIRST_LINE);
+/*
+ * Does the history file need to be updated?
+ */
+ static int
+histfile_modified()
+{
+ if (mlist_search.modified)
+ return 1;
+#if SHELL_ESCAPE || PIPEC
+ if (mlist_shell.modified)
+ return 1;
+#endif
+ return 0;
+}
- fprintf(f, "%s\n", HISTFILE_SEARCH_SECTION);
- save_mlist(&mlist_search, f);
+/*
+ * Update the .lesshst file.
+ */
+ public void
+save_cmdhist()
+{
+#if CMD_HISTORY
+ char *histname;
+ char *tempname;
+ int skip_search;
+ int skip_shell;
+ struct save_ctx ctx;
+ char *s;
+ FILE *fout = NULL;
+ int histsize = 0;
+ if (!histfile_modified())
+ return;
+ histname = histfile_name();
+ if (histname == NULL)
+ return;
+ tempname = make_tempname(histname);
+ fout = fopen(tempname, "w");
+ if (fout != NULL)
+ {
+ make_file_private(fout);
+ s = lgetenv("LESSHISTSIZE");
+ if (s != NULL)
+ histsize = atoi(s);
+ if (histsize <= 0)
+ histsize = 100;
+ skip_search = mlist_size(&mlist_search) - histsize;
#if SHELL_ESCAPE || PIPEC
- fprintf(f, "%s\n", HISTFILE_SHELL_SECTION);
- save_mlist(&mlist_shell, f);
+ skip_shell = mlist_size(&mlist_shell) - histsize;
#endif
-
- fclose(f);
+ fprintf(fout, "%s\n", HISTFILE_FIRST_LINE);
+ ctx.fout = fout;
+ ctx.mlist = NULL;
+ read_cmdhist(copy_hist, &ctx, skip_search, skip_shell);
+ fclose(fout);
+#if MSDOS_COMPILER==WIN32C
+ /*
+ * Windows rename doesn't remove an existing file,
+ * making it useless for atomic operations. Sigh.
+ */
+ remove(histname);
+#endif
+ rename(tempname, histname);
+ }
+ free(tempname);
+ free(histname);
#endif /* CMD_HISTORY */
}
OpenPOWER on IntegriCloud