#include <sys/stat.h>
#include "less.h"
static int fd0 = 0;
extern int new_file;
extern int errmsgs;
extern char *every_first_cmd;
extern int any_display;
extern int force_open;
extern int is_tty;
extern IFILE curr_ifile;
extern IFILE old_ifile;
extern struct scrpos initial_scrpos;
extern void *ml_examine;
extern char openquote;
extern char closequote;
extern int less_is_more;
extern int logfile;
extern int force_logfile;
extern char *namelogfile;
dev_t curr_dev;
ino_t curr_ino;
void
init_textlist(struct textlist *tlist, char *str)
{
char *s;
int meta_quoted = 0;
int delim_quoted = 0;
char *esc = get_meta_escape();
int esclen = strlen(esc);
tlist->string = skipsp(str);
tlist->endstring = tlist->string + strlen(tlist->string);
for (s = str; s < tlist->endstring; s++) {
if (meta_quoted) {
meta_quoted = 0;
} else if (esclen > 0 && s + esclen < tlist->endstring &&
strncmp(s, esc, esclen) == 0) {
meta_quoted = 1;
s += esclen - 1;
} else if (delim_quoted) {
if (*s == closequote)
delim_quoted = 0;
} else {
if (*s == openquote)
delim_quoted = 1;
else if (*s == ' ')
*s = '\0';
}
}
}
char *
forw_textlist(struct textlist *tlist, char *prev)
{
char *s;
if (prev == NULL)
s = tlist->string;
else
s = prev + strlen(prev);
if (s >= tlist->endstring)
return (NULL);
while (*s == '\0')
s++;
if (s >= tlist->endstring)
return (NULL);
return (s);
}
char *
back_textlist(struct textlist *tlist, char *prev)
{
char *s;
if (prev == NULL)
s = tlist->endstring;
else if (prev <= tlist->string)
return (NULL);
else
s = prev - 1;
while (*s == '\0')
s--;
if (s <= tlist->string)
return (NULL);
while (s[-1] != '\0' && s > tlist->string)
s--;
return (s);
}
static void
close_file(void)
{
struct scrpos scrpos;
if (curr_ifile == NULL)
return;
get_scrpos(&scrpos);
if (scrpos.pos != -1) {
store_pos(curr_ifile, &scrpos);
lastmark();
}
ch_close();
curr_ifile = NULL;
curr_ino = curr_dev = 0;
}
int
edit(char *filename)
{
if (filename == NULL)
return (edit_ifile(NULL));
return (edit_ifile(get_ifile(filename, curr_ifile)));
}
int
edit_ifile(IFILE ifile)
{
int f;
int answer;
int no_display;
int chflags;
char *filename;
char *qopen_filename;
IFILE was_curr_ifile;
PARG parg;
if (ifile == curr_ifile) {
return (0);
}
end_logfile();
was_curr_ifile = save_curr_ifile();
if (curr_ifile != NULL) {
chflags = ch_getflags();
close_file();
if ((chflags & CH_HELPFILE) &&
held_ifile(was_curr_ifile) <= 1) {
del_ifile(was_curr_ifile);
was_curr_ifile = old_ifile;
}
}
if (ifile == NULL) {
unsave_ifile(was_curr_ifile);
return (0);
}
filename = estrdup(get_filename(ifile));
qopen_filename = shell_unquote(filename);
chflags = 0;
if (strcmp(filename, helpfile()) == 0)
chflags |= CH_HELPFILE;
if (strcmp(filename, "-") == 0) {
f = fd0;
chflags |= CH_KEEPOPEN;
} else if (strcmp(filename, FAKE_EMPTYFILE) == 0) {
f = -1;
chflags |= CH_NODATA;
} else if ((parg.p_string = bad_file(filename)) != NULL) {
error("%s", &parg);
free(parg.p_string);
err1:
del_ifile(ifile);
free(qopen_filename);
free(filename);
if (was_curr_ifile == ifile) {
quit(QUIT_ERROR);
}
reedit_ifile(was_curr_ifile);
return (1);
} else if ((f = open(qopen_filename, O_RDONLY)) == -1) {
parg.p_string = errno_message(filename);
error("%s", &parg);
free(parg.p_string);
goto err1;
} else {
chflags |= CH_CANSEEK;
if (!force_open && !opened(ifile) && bin_file(f)) {
parg.p_string = filename;
answer = query("\"%s\" may be a binary file. "
"See it anyway? ", &parg);
if (answer != 'y' && answer != 'Y') {
(void) close(f);
goto err1;
}
}
}
if (was_curr_ifile != NULL) {
old_ifile = was_curr_ifile;
unsave_ifile(was_curr_ifile);
}
curr_ifile = ifile;
set_open(curr_ifile);
get_pos(curr_ifile, &initial_scrpos);
new_file = TRUE;
ch_init(f, chflags);
if (!(chflags & CH_HELPFILE)) {
struct stat statbuf;
int r;
if (namelogfile != NULL && is_tty)
use_logfile(namelogfile);
r = stat(qopen_filename, &statbuf);
if (r == 0) {
curr_ino = statbuf.st_ino;
curr_dev = statbuf.st_dev;
}
if (every_first_cmd != NULL)
ungetsc(every_first_cmd);
}
free(qopen_filename);
no_display = !any_display;
flush(0);
any_display = TRUE;
if (is_tty) {
pos_clear();
clr_linenum();
clr_hilite();
cmd_addhist(ml_examine, filename);
if (no_display && errmsgs > 0) {
parg.p_string = filename;
error("%s", &parg);
}
}
free(filename);
return (0);
}
int
edit_list(char *filelist)
{
IFILE save_ifile;
char *good_filename;
char *filename;
char *gfilelist;
char *gfilename;
struct textlist tl_files;
struct textlist tl_gfiles;
save_ifile = save_curr_ifile();
good_filename = NULL;
init_textlist(&tl_files, filelist);
filename = NULL;
while ((filename = forw_textlist(&tl_files, filename)) != NULL) {
gfilelist = lglob(filename);
init_textlist(&tl_gfiles, gfilelist);
gfilename = NULL;
while ((gfilename = forw_textlist(&tl_gfiles, gfilename)) !=
NULL) {
if (edit(gfilename) == 0 && good_filename == NULL)
good_filename = get_filename(curr_ifile);
}
free(gfilelist);
}
if (good_filename == NULL) {
unsave_ifile(save_ifile);
return (1);
}
if (get_ifile(good_filename, curr_ifile) == curr_ifile) {
unsave_ifile(save_ifile);
return (0);
}
reedit_ifile(save_ifile);
return (edit(good_filename));
}
int
edit_first(void)
{
curr_ifile = NULL;
return (edit_next(1));
}
int
edit_last(void)
{
curr_ifile = NULL;
return (edit_prev(1));
}
static int
edit_istep(IFILE h, int n, int dir)
{
IFILE next;
for (;;) {
next = (dir > 0) ? next_ifile(h) : prev_ifile(h);
if (--n < 0) {
if (edit_ifile(h) == 0)
break;
}
if (next == NULL) {
return (1);
}
if (abort_sigs()) {
return (1);
}
h = next;
}
return (0);
}
static int
edit_inext(IFILE h, int n)
{
return (edit_istep(h, n, +1));
}
int
edit_next(int n)
{
return (edit_istep(curr_ifile, n, +1));
}
static int
edit_iprev(IFILE h, int n)
{
return (edit_istep(h, n, -1));
}
int
edit_prev(int n)
{
return (edit_istep(curr_ifile, n, -1));
}
int
edit_index(int n)
{
IFILE h;
h = NULL;
do {
if ((h = next_ifile(h)) == NULL) {
return (1);
}
} while (get_index(h) != n);
return (edit_ifile(h));
}
IFILE
save_curr_ifile(void)
{
if (curr_ifile != NULL)
hold_ifile(curr_ifile, 1);
return (curr_ifile);
}
void
unsave_ifile(IFILE save_ifile)
{
if (save_ifile != NULL)
hold_ifile(save_ifile, -1);
}
void
reedit_ifile(IFILE save_ifile)
{
IFILE next;
IFILE prev;
unsave_ifile(save_ifile);
next = next_ifile(save_ifile);
prev = prev_ifile(save_ifile);
if (edit_ifile(save_ifile) == 0)
return;
if (next != NULL && edit_inext(next, 0) == 0)
return;
if (prev != NULL && edit_iprev(prev, 0) == 0)
return;
quit(QUIT_ERROR);
}
void
reopen_curr_ifile(void)
{
IFILE save_ifile = save_curr_ifile();
close_file();
reedit_ifile(save_ifile);
}
int
edit_stdin(void)
{
if (isatty(fd0)) {
if (less_is_more) {
error("Missing filename (\"more -h\" for help)",
NULL);
} else {
error("Missing filename (\"less --help\" for help)",
NULL);
}
quit(QUIT_OK);
}
return (edit("-"));
}
void
cat_file(void)
{
int c;
while ((c = ch_forw_get()) != EOI)
putchr(c);
flush(0);
}
void
use_logfile(char *filename)
{
int exists;
int answer;
PARG parg;
if (ch_getflags() & CH_CANSEEK)
return;
filename = shell_unquote(filename);
exists = open(filename, O_RDONLY);
close(exists);
exists = (exists >= 0);
if (!exists || force_logfile) {
answer = 'O';
} else {
parg.p_string = filename;
answer = query("Warning: \"%s\" exists; "
"Overwrite, Append or Don't log? ", &parg);
}
loop:
switch (answer) {
case 'O': case 'o':
logfile = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0644);
break;
case 'A': case 'a':
logfile = open(filename, O_WRONLY | O_APPEND);
if (lseek(logfile, (off_t)0, SEEK_END) == (off_t)-1) {
close(logfile);
logfile = -1;
}
break;
case 'D': case 'd':
free(filename);
return;
case 'q':
quit(QUIT_OK);
default:
answer = query("Overwrite, Append, or Don't log? "
"(Type \"O\", \"A\", \"D\" or \"q\") ", NULL);
goto loop;
}
if (logfile < 0) {
parg.p_string = filename;
error("Cannot write to \"%s\"", &parg);
free(filename);
return;
}
free(filename);
}