version 1.1.1.2, 2003/04/13 18:21:21 |
version 1.1.1.3, 2011/09/16 17:47:01 |
|
|
/* |
/* |
* Copyright (C) 1984-2002 Mark Nudelman |
* Copyright (C) 1984-2011 Mark Nudelman |
* |
* |
* You may distribute under the terms of either the GNU General Public |
* You may distribute under the terms of either the GNU General Public |
* License or the Less License, as specified in the README file. |
* License or the Less License, as specified in the README file. |
|
|
|
|
#include "less.h" |
#include "less.h" |
#include "cmd.h" |
#include "cmd.h" |
|
#include "charset.h" |
|
#if HAVE_STAT |
|
#include <sys/stat.h> |
|
#endif |
|
|
extern int sc_width; |
extern int sc_width; |
|
extern int utf_mode; |
|
|
static char cmdbuf[CMDBUF_SIZE]; /* Buffer for holding a multi-char command */ |
static char cmdbuf[CMDBUF_SIZE]; /* Buffer for holding a multi-char command */ |
static int cmd_col; /* Current column of the cursor */ |
static int cmd_col; /* Current column of the cursor */ |
|
|
#endif |
#endif |
|
|
#if CMD_HISTORY |
#if CMD_HISTORY |
|
|
|
/* History file */ |
|
#define HISTFILE_FIRST_LINE ".less-history-file:" |
|
#define HISTFILE_SEARCH_SECTION ".search" |
|
#define HISTFILE_SHELL_SECTION ".shell" |
|
|
/* |
/* |
* A mlist structure represents a command history. |
* A mlist structure represents a command history. |
*/ |
*/ |
|
|
struct mlist *prev; |
struct mlist *prev; |
struct mlist *curr_mp; |
struct mlist *curr_mp; |
char *string; |
char *string; |
|
int modified; |
}; |
}; |
|
|
/* |
/* |
* These are the various command histories that exist. |
* These are the various command histories that exist. |
*/ |
*/ |
struct mlist mlist_search = |
struct mlist mlist_search = |
{ &mlist_search, &mlist_search, &mlist_search, NULL }; |
{ &mlist_search, &mlist_search, &mlist_search, NULL, 0 }; |
public void * constant ml_search = (void *) &mlist_search; |
public void * constant ml_search = (void *) &mlist_search; |
|
|
struct mlist mlist_examine = |
struct mlist mlist_examine = |
{ &mlist_examine, &mlist_examine, &mlist_examine, NULL }; |
{ &mlist_examine, &mlist_examine, &mlist_examine, NULL, 0 }; |
public void * constant ml_examine = (void *) &mlist_examine; |
public void * constant ml_examine = (void *) &mlist_examine; |
|
|
#if SHELL_ESCAPE || PIPEC |
#if SHELL_ESCAPE || PIPEC |
struct mlist mlist_shell = |
struct mlist mlist_shell = |
{ &mlist_shell, &mlist_shell, &mlist_shell, NULL }; |
{ &mlist_shell, &mlist_shell, &mlist_shell, NULL, 0 }; |
public void * constant ml_shell = (void *) &mlist_shell; |
public void * constant ml_shell = (void *) &mlist_shell; |
#endif |
#endif |
|
|
|
|
static struct mlist *curr_mlist = NULL; |
static struct mlist *curr_mlist = NULL; |
static int curr_cmdflags; |
static int curr_cmdflags; |
|
|
|
static char cmd_mbc_buf[MAX_UTF_CHAR_LEN]; |
|
static int cmd_mbc_buf_len; |
|
static int cmd_mbc_buf_index; |
|
|
|
|
/* |
/* |
* Reset command buffer (to empty). |
* Reset command buffer (to empty). |
*/ |
*/ |
|
|
cmd_col = 0; |
cmd_col = 0; |
cmd_offset = 0; |
cmd_offset = 0; |
literal = 0; |
literal = 0; |
|
cmd_mbc_buf_len = 0; |
} |
} |
|
|
/* |
/* |
* Clear command line on display. |
* Clear command line. |
*/ |
*/ |
public void |
public void |
clear_cmd() |
clear_cmd() |
{ |
{ |
clear_bot(); |
|
cmd_col = prompt_col = 0; |
cmd_col = prompt_col = 0; |
|
cmd_mbc_buf_len = 0; |
} |
} |
|
|
/* |
/* |
|
|
cmd_putstr(s) |
cmd_putstr(s) |
char *s; |
char *s; |
{ |
{ |
putstr(s); |
LWCHAR prev_ch = 0; |
cmd_col += strlen(s); |
LWCHAR ch; |
prompt_col += strlen(s); |
char *endline = s + strlen(s); |
|
while (*s != '\0') |
|
{ |
|
char *ns = s; |
|
ch = step_char(&ns, +1, endline); |
|
while (s < ns) |
|
putchr(*s++); |
|
if (!utf_mode) |
|
{ |
|
cmd_col++; |
|
prompt_col++; |
|
} else if (!is_composing_char(ch) && |
|
!is_combining_char(prev_ch, ch)) |
|
{ |
|
int width = is_wide_char(ch) ? 2 : 1; |
|
cmd_col += width; |
|
prompt_col += width; |
|
} |
|
prev_ch = ch; |
|
} |
} |
} |
|
|
/* |
/* |
|
|
public int |
public int |
len_cmdbuf() |
len_cmdbuf() |
{ |
{ |
return (strlen(cmdbuf)); |
char *s = cmdbuf; |
|
char *endline = s + strlen(s); |
|
int len = 0; |
|
|
|
while (*s != '\0') |
|
{ |
|
step_char(&s, +1, endline); |
|
len++; |
|
} |
|
return (len); |
} |
} |
|
|
/* |
/* |
|
* Common part of cmd_step_right() and cmd_step_left(). |
|
*/ |
|
static char * |
|
cmd_step_common(p, ch, len, pwidth, bswidth) |
|
char *p; |
|
LWCHAR ch; |
|
int len; |
|
int *pwidth; |
|
int *bswidth; |
|
{ |
|
char *pr; |
|
|
|
if (len == 1) |
|
{ |
|
pr = prchar((int) ch); |
|
if (pwidth != NULL || bswidth != NULL) |
|
{ |
|
int len = strlen(pr); |
|
if (pwidth != NULL) |
|
*pwidth = len; |
|
if (bswidth != NULL) |
|
*bswidth = len; |
|
} |
|
} else |
|
{ |
|
pr = prutfchar(ch); |
|
if (pwidth != NULL || bswidth != NULL) |
|
{ |
|
if (is_composing_char(ch)) |
|
{ |
|
if (pwidth != NULL) |
|
*pwidth = 0; |
|
if (bswidth != NULL) |
|
*bswidth = 0; |
|
} else if (is_ubin_char(ch)) |
|
{ |
|
int len = strlen(pr); |
|
if (pwidth != NULL) |
|
*pwidth = len; |
|
if (bswidth != NULL) |
|
*bswidth = len; |
|
} else |
|
{ |
|
LWCHAR prev_ch = step_char(&p, -1, cmdbuf); |
|
if (is_combining_char(prev_ch, ch)) |
|
{ |
|
if (pwidth != NULL) |
|
*pwidth = 0; |
|
if (bswidth != NULL) |
|
*bswidth = 0; |
|
} else |
|
{ |
|
if (pwidth != NULL) |
|
*pwidth = is_wide_char(ch) |
|
? 2 |
|
: 1; |
|
if (bswidth != NULL) |
|
*bswidth = 1; |
|
} |
|
} |
|
} |
|
} |
|
|
|
return (pr); |
|
} |
|
|
|
/* |
|
* Step a pointer one character right in the command buffer. |
|
*/ |
|
static char * |
|
cmd_step_right(pp, pwidth, bswidth) |
|
char **pp; |
|
int *pwidth; |
|
int *bswidth; |
|
{ |
|
char *p = *pp; |
|
LWCHAR ch = step_char(pp, +1, p + strlen(p)); |
|
|
|
return cmd_step_common(p, ch, *pp - p, pwidth, bswidth); |
|
} |
|
|
|
/* |
|
* Step a pointer one character left in the command buffer. |
|
*/ |
|
static char * |
|
cmd_step_left(pp, pwidth, bswidth) |
|
char **pp; |
|
int *pwidth; |
|
int *bswidth; |
|
{ |
|
char *p = *pp; |
|
LWCHAR ch = step_char(pp, -1, cmdbuf); |
|
|
|
return cmd_step_common(*pp, ch, p - *pp, pwidth, bswidth); |
|
} |
|
|
|
/* |
* Repaint the line from cp onwards. |
* Repaint the line from cp onwards. |
* Then position the cursor just after the char old_cp (a pointer into cmdbuf). |
* Then position the cursor just after the char old_cp (a pointer into cmdbuf). |
*/ |
*/ |
|
|
cmd_repaint(old_cp) |
cmd_repaint(old_cp) |
char *old_cp; |
char *old_cp; |
{ |
{ |
char *p; |
|
|
|
/* |
/* |
* Repaint the line from the current position. |
* Repaint the line from the current position. |
*/ |
*/ |
clear_eol(); |
clear_eol(); |
for ( ; *cp != '\0'; cp++) |
while (*cp != '\0') |
{ |
{ |
p = prchar(*cp); |
char *np = cp; |
if (cmd_col + (int)strlen(p) >= sc_width) |
int width; |
|
char *pr = cmd_step_right(&np, &width, NULL); |
|
if (cmd_col + width >= sc_width) |
break; |
break; |
putstr(p); |
cp = np; |
cmd_col += strlen(p); |
putstr(pr); |
|
cmd_col += width; |
} |
} |
|
while (*cp != '\0') |
|
{ |
|
char *np = cp; |
|
int width; |
|
char *pr = cmd_step_right(&np, &width, NULL); |
|
if (width > 0) |
|
break; |
|
cp = np; |
|
putstr(pr); |
|
} |
|
|
/* |
/* |
* Back up the cursor to the correct position. |
* Back up the cursor to the correct position. |
|
|
{ |
{ |
while (cmd_col > prompt_col) |
while (cmd_col > prompt_col) |
{ |
{ |
putbs(); |
int width, bswidth; |
cmd_col--; |
|
|
cmd_step_left(&cp, &width, &bswidth); |
|
while (bswidth-- > 0) |
|
putbs(); |
|
cmd_col -= width; |
} |
} |
|
|
cp = &cmdbuf[cmd_offset]; |
cp = &cmdbuf[cmd_offset]; |
|
|
s = cmdbuf + cmd_offset; |
s = cmdbuf + cmd_offset; |
cols = 0; |
cols = 0; |
while (cols < (sc_width - prompt_col) / 2 && *s != '\0') |
while (cols < (sc_width - prompt_col) / 2 && *s != '\0') |
cols += strlen(prchar(*s++)); |
{ |
|
int width; |
|
cmd_step_right(&s, &width, NULL); |
|
cols += width; |
|
} |
|
while (*s != '\0') |
|
{ |
|
int width; |
|
char *ns = s; |
|
cmd_step_right(&ns, &width, NULL); |
|
if (width > 0) |
|
break; |
|
s = ns; |
|
} |
|
|
cmd_offset = s - cmdbuf; |
cmd_offset = s - cmdbuf; |
save_cp = cp; |
save_cp = cp; |
|
|
cmd_rshift() |
cmd_rshift() |
{ |
{ |
char *s; |
char *s; |
char *p; |
|
char *save_cp; |
char *save_cp; |
int cols; |
int cols; |
|
|
|
|
cols = 0; |
cols = 0; |
while (cols < (sc_width - prompt_col) / 2 && s > cmdbuf) |
while (cols < (sc_width - prompt_col) / 2 && s > cmdbuf) |
{ |
{ |
p = prchar(*--s); |
int width; |
cols += strlen(p); |
cmd_step_left(&s, &width, NULL); |
|
cols += width; |
} |
} |
|
|
cmd_offset = s - cmdbuf; |
cmd_offset = s - cmdbuf; |
|
|
static int |
static int |
cmd_right() |
cmd_right() |
{ |
{ |
char *p; |
char *pr; |
|
char *ncp; |
|
int width; |
|
|
if (*cp == '\0') |
if (*cp == '\0') |
{ |
{ |
/* |
/* Already at the end of the line. */ |
* Already at the end of the line. |
|
*/ |
|
return (CC_OK); |
return (CC_OK); |
} |
} |
p = prchar(*cp); |
ncp = cp; |
if (cmd_col + (int)strlen(p) >= sc_width) |
pr = cmd_step_right(&ncp, &width, NULL); |
|
if (cmd_col + width >= sc_width) |
cmd_lshift(); |
cmd_lshift(); |
else if (cmd_col + (int)strlen(p) == sc_width - 1 && cp[1] != '\0') |
else if (cmd_col + width == sc_width - 1 && cp[1] != '\0') |
cmd_lshift(); |
cmd_lshift(); |
cp++; |
cp = ncp; |
putstr(p); |
cmd_col += width; |
cmd_col += strlen(p); |
putstr(pr); |
|
while (*cp != '\0') |
|
{ |
|
pr = cmd_step_right(&ncp, &width, NULL); |
|
if (width > 0) |
|
break; |
|
putstr(pr); |
|
cp = ncp; |
|
} |
return (CC_OK); |
return (CC_OK); |
} |
} |
|
|
|
|
static int |
static int |
cmd_left() |
cmd_left() |
{ |
{ |
char *p; |
char *ncp; |
|
int width, bswidth; |
|
|
if (cp <= cmdbuf) |
if (cp <= cmdbuf) |
{ |
{ |
/* Already at the beginning of the line */ |
/* Already at the beginning of the line */ |
return (CC_OK); |
return (CC_OK); |
} |
} |
p = prchar(cp[-1]); |
ncp = cp; |
if (cmd_col < prompt_col + (int)strlen(p)) |
while (ncp > cmdbuf) |
|
{ |
|
cmd_step_left(&ncp, &width, &bswidth); |
|
if (width > 0) |
|
break; |
|
} |
|
if (cmd_col < prompt_col + width) |
cmd_rshift(); |
cmd_rshift(); |
cp--; |
cp = ncp; |
cmd_col -= strlen(p); |
cmd_col -= width; |
while (*p++ != '\0') |
while (bswidth-- > 0) |
putbs(); |
putbs(); |
return (CC_OK); |
return (CC_OK); |
} |
} |
|
|
* Insert a char into the command buffer, at the current position. |
* Insert a char into the command buffer, at the current position. |
*/ |
*/ |
static int |
static int |
cmd_ichar(c) |
cmd_ichar(cs, clen) |
int c; |
char *cs; |
|
int clen; |
{ |
{ |
char *s; |
char *s; |
|
|
if (strlen(cmdbuf) >= sizeof(cmdbuf)-2) |
if (strlen(cmdbuf) + clen >= sizeof(cmdbuf)-1) |
{ |
{ |
/* |
/* No room in the command buffer for another char. */ |
* No room in the command buffer for another char. |
|
*/ |
|
bell(); |
bell(); |
return (CC_ERROR); |
return (CC_ERROR); |
} |
} |
|
|
/* |
/* |
* Insert the character into the buffer. |
* Make room for the new character (shift the tail of the buffer right). |
*/ |
*/ |
for (s = &cmdbuf[strlen(cmdbuf)]; s >= cp; s--) |
for (s = &cmdbuf[strlen(cmdbuf)]; s >= cp; s--) |
s[1] = s[0]; |
s[clen] = s[0]; |
*cp = c; |
|
/* |
/* |
|
* Insert the character into the buffer. |
|
*/ |
|
for (s = cp; s < cp + clen; s++) |
|
*s = *cs++; |
|
/* |
* Reprint the tail of the line from the inserted char. |
* Reprint the tail of the line from the inserted char. |
*/ |
*/ |
cmd_repaint(cp); |
cmd_repaint(cp); |
|
|
cmd_erase() |
cmd_erase() |
{ |
{ |
register char *s; |
register char *s; |
|
int clen; |
|
|
if (cp == cmdbuf) |
if (cp == cmdbuf) |
{ |
{ |
|
|
/* |
/* |
* Move cursor left (to the char being erased). |
* Move cursor left (to the char being erased). |
*/ |
*/ |
|
s = cp; |
cmd_left(); |
cmd_left(); |
|
clen = s - cp; |
|
|
/* |
/* |
* Remove the char from the buffer (shift the buffer left). |
* Remove the char from the buffer (shift the buffer left). |
*/ |
*/ |
for (s = cp; *s != '\0'; s++) |
for (s = cp; ; s++) |
s[0] = s[1]; |
{ |
|
s[0] = s[clen]; |
|
if (s[0] == '\0') |
|
break; |
|
} |
|
|
/* |
/* |
* Repaint the buffer after the erased char. |
* Repaint the buffer after the erased char. |
*/ |
*/ |
|
|
{ |
{ |
if (*cp == '\0') |
if (*cp == '\0') |
{ |
{ |
/* |
/* At end of string; there is no char under the cursor. */ |
* At end of string; there is no char under the cursor. |
|
*/ |
|
return (CC_OK); |
return (CC_OK); |
} |
} |
/* |
/* |
|
|
{ |
{ |
if (cmdbuf[0] == '\0') |
if (cmdbuf[0] == '\0') |
{ |
{ |
/* |
/* Buffer is already empty; abort the current command. */ |
* Buffer is already empty; abort the current command. |
|
*/ |
|
return (CC_QUIT); |
return (CC_QUIT); |
} |
} |
cmd_offset = 0; |
cmd_offset = 0; |
|
|
void *mlist; |
void *mlist; |
int cmdflags; |
int cmdflags; |
{ |
{ |
|
#if CMD_HISTORY |
curr_mlist = (struct mlist *) mlist; |
curr_mlist = (struct mlist *) mlist; |
curr_cmdflags = cmdflags; |
curr_cmdflags = cmdflags; |
|
|
|
/* Make sure the next up-arrow moves to the last string in the mlist. */ |
|
if (curr_mlist != NULL) |
|
curr_mlist->curr_mp = curr_mlist; |
|
#endif |
} |
} |
|
|
#if CMD_HISTORY |
#if CMD_HISTORY |
|
|
s = curr_mlist->curr_mp->string; |
s = curr_mlist->curr_mp->string; |
if (s == NULL) |
if (s == NULL) |
s = ""; |
s = ""; |
for (cp = cmdbuf; *s != '\0'; s++) |
strcpy(cmdbuf, s); |
{ |
for (cp = cmdbuf; *cp != '\0'; ) |
*cp = *s; |
|
cmd_right(); |
cmd_right(); |
} |
|
*cp = '\0'; |
|
return (CC_OK); |
return (CC_OK); |
} |
} |
#endif |
#endif |
|
|
*/ |
*/ |
if (strlen(cmd) == 0) |
if (strlen(cmd) == 0) |
return; |
return; |
|
|
/* |
/* |
* Don't save if a duplicate of a command which is already |
* Save the command unless it's a duplicate of the |
* in the history. |
* last command in the history. |
* But select the one already in the history to be current. |
|
*/ |
*/ |
for (ml = mlist->next; ml != mlist; ml = ml->next) |
ml = mlist->prev; |
|
if (ml == mlist || strcmp(ml->string, cmd) != 0) |
{ |
{ |
if (strcmp(ml->string, cmd) == 0) |
|
break; |
|
} |
|
if (ml == mlist) |
|
{ |
|
/* |
/* |
* Did not find command in history. |
* Did not find command in history. |
* Save the command and put it at the end of the history list. |
* Save the command and put it at the end of the history list. |
|
|
if (curr_mlist == NULL) |
if (curr_mlist == NULL) |
return; |
return; |
cmd_addhist(curr_mlist, cmdbuf); |
cmd_addhist(curr_mlist, cmdbuf); |
|
curr_mlist->modified = 1; |
#endif |
#endif |
} |
} |
|
|
|
|
case EC_LINEKILL: |
case EC_LINEKILL: |
not_in_completion(); |
not_in_completion(); |
return (cmd_kill()); |
return (cmd_kill()); |
|
case EC_ABORT: |
|
not_in_completion(); |
|
(void) cmd_kill(); |
|
return (CC_QUIT); |
case EC_W_BACKSPACE: |
case EC_W_BACKSPACE: |
not_in_completion(); |
not_in_completion(); |
return (cmd_werase()); |
return (cmd_werase()); |
|
|
{ |
{ |
char *s; |
char *s; |
int action; |
int action; |
|
char *endline = str + strlen(str); |
|
|
for (s = str; *s != '\0'; s++) |
for (s = str; *s != '\0'; ) |
{ |
{ |
action = cmd_ichar(*s); |
char *os = s; |
|
step_char(&s, +1, endline); |
|
action = cmd_ichar(os, s - os); |
if (action != CC_OK) |
if (action != CC_OK) |
{ |
{ |
bell(); |
bell(); |
|
|
int c; |
int c; |
{ |
{ |
int action; |
int action; |
|
int len; |
|
|
|
if (!utf_mode) |
|
{ |
|
cmd_mbc_buf[0] = c; |
|
len = 1; |
|
} else |
|
{ |
|
/* Perform strict validation in all possible cases. */ |
|
if (cmd_mbc_buf_len == 0) |
|
{ |
|
retry: |
|
cmd_mbc_buf_index = 1; |
|
*cmd_mbc_buf = c; |
|
if (IS_ASCII_OCTET(c)) |
|
cmd_mbc_buf_len = 1; |
|
else if (IS_UTF8_LEAD(c)) |
|
{ |
|
cmd_mbc_buf_len = utf_len(c); |
|
return (CC_OK); |
|
} else |
|
{ |
|
/* UTF8_INVALID or stray UTF8_TRAIL */ |
|
bell(); |
|
return (CC_ERROR); |
|
} |
|
} else if (IS_UTF8_TRAIL(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)) |
|
{ |
|
/* complete, but not well formed (non-shortest form), sequence */ |
|
cmd_mbc_buf_len = 0; |
|
bell(); |
|
return (CC_ERROR); |
|
} |
|
} else |
|
{ |
|
/* Flush incomplete (truncated) sequence. */ |
|
cmd_mbc_buf_len = 0; |
|
bell(); |
|
/* Handle new char. */ |
|
goto retry; |
|
} |
|
|
|
len = cmd_mbc_buf_len; |
|
cmd_mbc_buf_len = 0; |
|
} |
|
|
if (literal) |
if (literal) |
{ |
{ |
/* |
/* |
* Insert the char, even if it is a line-editing char. |
* Insert the char, even if it is a line-editing char. |
*/ |
*/ |
literal = 0; |
literal = 0; |
return (cmd_ichar(c)); |
return (cmd_ichar(cmd_mbc_buf, len)); |
} |
} |
|
|
/* |
/* |
* See if it is a special line-editing character. |
* See if it is a line-editing character. |
*/ |
*/ |
if (in_mca()) |
if (in_mca() && len == 1) |
{ |
{ |
action = cmd_edit(c); |
action = cmd_edit(c); |
switch (action) |
switch (action) |
|
|
/* |
/* |
* Insert the char into the command buffer. |
* Insert the char into the command buffer. |
*/ |
*/ |
return (cmd_ichar(c)); |
return (cmd_ichar(cmd_mbc_buf, len)); |
} |
} |
|
|
/* |
/* |
* Return the number currently in the command buffer. |
* Return the number currently in the command buffer. |
*/ |
*/ |
public LINENUM |
public LINENUM |
cmd_int() |
cmd_int(frac) |
|
long *frac; |
{ |
{ |
register char *p; |
char *p; |
LINENUM n = 0; |
LINENUM n = 0; |
|
int err; |
|
|
for (p = cmdbuf; *p != '\0'; p++) |
for (p = cmdbuf; *p >= '0' && *p <= '9'; p++) |
n = (10 * n) + (*p - '0'); |
n = (n * 10) + (*p - '0'); |
|
*frac = 0; |
|
if (*p++ == '.') |
|
{ |
|
*frac = getfraction(&p, NULL, &err); |
|
/* {{ do something if err is set? }} */ |
|
} |
return (n); |
return (n); |
} |
} |
|
|
|
|
get_cmdbuf() |
get_cmdbuf() |
{ |
{ |
return (cmdbuf); |
return (cmdbuf); |
|
} |
|
|
|
#if CMD_HISTORY |
|
/* |
|
* Return the last (most recent) string in the current command history. |
|
*/ |
|
public char * |
|
cmd_lastpattern() |
|
{ |
|
if (curr_mlist == NULL) |
|
return (NULL); |
|
return (curr_mlist->curr_mp->prev->string); |
|
} |
|
#endif |
|
|
|
#if CMD_HISTORY |
|
/* |
|
* Get the name of the history file. |
|
*/ |
|
static char * |
|
histfile_name() |
|
{ |
|
char *home; |
|
char *name; |
|
int len; |
|
|
|
/* See if filename is explicitly specified by $LESSHISTFILE. */ |
|
name = lgetenv("LESSHISTFILE"); |
|
if (name != NULL && *name != '\0') |
|
{ |
|
if (strcmp(name, "-") == 0 || strcmp(name, "/dev/null") == 0) |
|
/* $LESSHISTFILE == "-" means don't use a history file. */ |
|
return (NULL); |
|
return (save(name)); |
|
} |
|
|
|
/* Otherwise, file is in $HOME. */ |
|
home = lgetenv("HOME"); |
|
if (home == NULL || *home == '\0') |
|
{ |
|
#if OS2 |
|
home = lgetenv("INIT"); |
|
if (home == NULL || *home == '\0') |
|
#endif |
|
return (NULL); |
|
} |
|
len = 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. |
|
*/ |
|
public void |
|
init_cmdhist() |
|
{ |
|
#if CMD_HISTORY |
|
struct mlist *ml = NULL; |
|
char line[CMDBUF_SIZE]; |
|
char *filename; |
|
FILE *f; |
|
char *p; |
|
|
|
filename = histfile_name(); |
|
if (filename == NULL) |
|
return; |
|
f = fopen(filename, "r"); |
|
free(filename); |
|
if (f == NULL) |
|
return; |
|
if (fgets(line, sizeof(line), f) == NULL || |
|
strncmp(line, HISTFILE_FIRST_LINE, strlen(HISTFILE_FIRST_LINE)) != 0) |
|
{ |
|
fclose(f); |
|
return; |
|
} |
|
while (fgets(line, sizeof(line), f) != NULL) |
|
{ |
|
for (p = line; *p != '\0'; p++) |
|
{ |
|
if (*p == '\n' || *p == '\r') |
|
{ |
|
*p = '\0'; |
|
break; |
|
} |
|
} |
|
if (strcmp(line, HISTFILE_SEARCH_SECTION) == 0) |
|
ml = &mlist_search; |
|
else if (strcmp(line, HISTFILE_SHELL_SECTION) == 0) |
|
{ |
|
#if SHELL_ESCAPE || PIPEC |
|
ml = &mlist_shell; |
|
#else |
|
ml = NULL; |
|
#endif |
|
} else if (*line == '"') |
|
{ |
|
if (ml != NULL) |
|
cmd_addhist(ml, line+1); |
|
} |
|
} |
|
fclose(f); |
|
#endif /* CMD_HISTORY */ |
|
} |
|
|
|
/* |
|
* |
|
*/ |
|
#if CMD_HISTORY |
|
static void |
|
save_mlist(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; |
|
|
|
ml = ml->prev; |
|
for (n = 0; n < histsize; n++) |
|
{ |
|
if (ml->string == NULL) |
|
break; |
|
ml = ml->prev; |
|
} |
|
for (ml = ml->next; ml->string != NULL; ml = ml->next) |
|
fprintf(f, "\"%s\n", ml->string); |
|
} |
|
#endif /* CMD_HISTORY */ |
|
|
|
/* |
|
* |
|
*/ |
|
public void |
|
save_cmdhist() |
|
{ |
|
#if CMD_HISTORY |
|
char *filename; |
|
FILE *f; |
|
int modified = 0; |
|
|
|
filename = histfile_name(); |
|
if (filename == NULL) |
|
return; |
|
if (mlist_search.modified) |
|
modified = 1; |
|
#if SHELL_ESCAPE || PIPEC |
|
if (mlist_shell.modified) |
|
modified = 1; |
|
#endif |
|
if (!modified) |
|
return; |
|
f = fopen(filename, "w"); |
|
free(filename); |
|
if (f == NULL) |
|
return; |
|
#if HAVE_FCHMOD |
|
{ |
|
/* Make history file readable only by owner. */ |
|
int do_chmod = 1; |
|
#if HAVE_STAT |
|
struct stat statbuf; |
|
int r = fstat(fileno(f), &statbuf); |
|
if (r < 0 || !S_ISREG(statbuf.st_mode)) |
|
/* Don't chmod if not a regular file. */ |
|
do_chmod = 0; |
|
#endif |
|
if (do_chmod) |
|
fchmod(fileno(f), 0600); |
|
} |
|
#endif |
|
|
|
fprintf(f, "%s\n", HISTFILE_FIRST_LINE); |
|
|
|
fprintf(f, "%s\n", HISTFILE_SEARCH_SECTION); |
|
save_mlist(&mlist_search, f); |
|
|
|
#if SHELL_ESCAPE || PIPEC |
|
fprintf(f, "%s\n", HISTFILE_SHELL_SECTION); |
|
save_mlist(&mlist_shell, f); |
|
#endif |
|
|
|
fclose(f); |
|
#endif /* CMD_HISTORY */ |
} |
} |