diff options
Diffstat (limited to 'cmdbuf.c')
-rw-r--r-- | cmdbuf.c | 300 |
1 files changed, 231 insertions, 69 deletions
@@ -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 */ } |