version 1.1.1.1, 1996/09/21 05:39:42 |
version 1.1.1.2, 2003/04/13 18:21:21 |
|
|
/* |
/* |
* Copyright (c) 1984,1985,1989,1994,1995 Mark Nudelman |
* Copyright (C) 1984-2002 Mark Nudelman |
* All rights reserved. |
|
* |
* |
* Redistribution and use in source and binary forms, with or without |
* You may distribute under the terms of either the GNU General Public |
* modification, are permitted provided that the following conditions |
* License or the Less License, as specified in the README file. |
* are met: |
|
* 1. Redistributions of source code must retain the above copyright |
|
* notice, this list of conditions and the following disclaimer. |
|
* 2. Redistributions in binary form must reproduce the above copyright |
|
* notice in the documentation and/or other materials provided with |
|
* the distribution. |
|
* |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY |
* For more information about less, or for information on how to |
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* contact the author, see the README file. |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
|
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
*/ |
*/ |
|
|
|
|
|
|
|
|
extern int new_file; |
extern int new_file; |
extern int errmsgs; |
extern int errmsgs; |
extern int quit_at_eof; |
|
extern int cbufs; |
extern int cbufs; |
extern char *every_first_cmd; |
extern char *every_first_cmd; |
extern int any_display; |
extern int any_display; |
extern int force_open; |
extern int force_open; |
extern int is_tty; |
extern int is_tty; |
|
extern int sigs; |
extern IFILE curr_ifile; |
extern IFILE curr_ifile; |
extern IFILE old_ifile; |
extern IFILE old_ifile; |
extern struct scrpos initial_scrpos; |
extern struct scrpos initial_scrpos; |
|
extern void constant *ml_examine; |
|
#if SPACES_IN_FILENAMES |
|
extern char openquote; |
|
extern char closequote; |
|
#endif |
|
|
#if LOGFILE |
#if LOGFILE |
extern int logfile; |
extern int logfile; |
|
|
char *str; |
char *str; |
{ |
{ |
char *s; |
char *s; |
|
#if SPACES_IN_FILENAMES |
|
int meta_quoted = 0; |
|
int delim_quoted = 0; |
|
char *esc = get_meta_escape(); |
|
int esclen = strlen(esc); |
|
#endif |
|
|
tlist->string = skipsp(str); |
tlist->string = skipsp(str); |
tlist->endstring = tlist->string + strlen(tlist->string); |
tlist->endstring = tlist->string + strlen(tlist->string); |
for (s = str; s < tlist->endstring; s++) |
for (s = str; s < tlist->endstring; s++) |
{ |
{ |
|
#if SPACES_IN_FILENAMES |
|
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 /* (!delim_quoted) */ |
|
{ |
|
if (*s == openquote) |
|
delim_quoted = 1; |
|
else if (*s == ' ') |
|
*s = '\0'; |
|
} |
|
#else |
if (*s == ' ') |
if (*s == ' ') |
*s = '\0'; |
*s = '\0'; |
|
#endif |
} |
} |
} |
} |
|
|
|
|
|
|
if (curr_ifile == NULL_IFILE) |
if (curr_ifile == NULL_IFILE) |
return; |
return; |
|
|
/* |
/* |
* Save the current position so that we can return to |
* Save the current position so that we can return to |
* the same position if we edit this file again. |
* the same position if we edit this file again. |
|
|
if (curr_altfilename != NULL) |
if (curr_altfilename != NULL) |
{ |
{ |
close_altfile(curr_altfilename, get_filename(curr_ifile), |
close_altfile(curr_altfilename, get_filename(curr_ifile), |
curr_altpipe); |
curr_altpipe); |
free(curr_altfilename); |
free(curr_altfilename); |
curr_altfilename = NULL; |
curr_altfilename = NULL; |
} |
} |
|
|
int chflags; |
int chflags; |
char *filename; |
char *filename; |
char *open_filename; |
char *open_filename; |
|
char *qopen_filename; |
char *alt_filename; |
char *alt_filename; |
void *alt_pipe; |
void *alt_pipe; |
IFILE was_curr_ifile; |
IFILE was_curr_ifile; |
|
|
#if LOGFILE |
#if LOGFILE |
end_logfile(); |
end_logfile(); |
#endif |
#endif |
was_curr_ifile = curr_ifile; |
was_curr_ifile = save_curr_ifile(); |
if (curr_ifile != NULL_IFILE) |
if (curr_ifile != NULL_IFILE) |
{ |
{ |
|
chflags = ch_getflags(); |
close_file(); |
close_file(); |
|
if ((chflags & CH_HELPFILE) && held_ifile(was_curr_ifile) <= 1) |
|
{ |
|
/* |
|
* Don't keep the help file in the ifile list. |
|
*/ |
|
del_ifile(was_curr_ifile); |
|
was_curr_ifile = old_ifile; |
|
} |
} |
} |
|
|
if (ifile == NULL_IFILE) |
if (ifile == NULL_IFILE) |
|
|
* you're supposed to have saved curr_ifile yourself, |
* you're supposed to have saved curr_ifile yourself, |
* and you'll restore it if necessary.) |
* and you'll restore it if necessary.) |
*/ |
*/ |
|
unsave_ifile(was_curr_ifile); |
return (0); |
return (0); |
} |
} |
|
|
filename = get_filename(ifile); |
filename = save(get_filename(ifile)); |
/* |
/* |
* See if LESSOPEN specifies an "alternate" file to open. |
* See if LESSOPEN specifies an "alternate" file to open. |
*/ |
*/ |
alt_pipe = NULL; |
alt_pipe = NULL; |
alt_filename = open_altfile(filename, &f, &alt_pipe); |
alt_filename = open_altfile(filename, &f, &alt_pipe); |
open_filename = (alt_filename != NULL) ? alt_filename : filename; |
open_filename = (alt_filename != NULL) ? alt_filename : filename; |
|
qopen_filename = shell_unquote(open_filename); |
|
|
chflags = 0; |
chflags = 0; |
if (alt_pipe != NULL) |
if (alt_pipe != NULL) |
|
|
*/ |
*/ |
f = fd0; |
f = fd0; |
chflags |= CH_KEEPOPEN; |
chflags |= CH_KEEPOPEN; |
|
/* |
|
* Must switch stdin to BINARY mode. |
|
*/ |
|
SET_BINARY(f); |
|
#if MSDOS_COMPILER==DJGPPC |
|
/* |
|
* Setting stdin to binary by default causes |
|
* Ctrl-C to not raise SIGINT. We must undo |
|
* that side-effect. |
|
*/ |
|
__djgpp_set_ctrl_c(1); |
|
#endif |
|
} else if (strcmp(open_filename, FAKE_HELPFILE) == 0) |
|
{ |
|
f = -1; |
|
chflags |= CH_HELPFILE; |
} else if ((parg.p_string = bad_file(open_filename)) != NULL) |
} else if ((parg.p_string = bad_file(open_filename)) != NULL) |
{ |
{ |
/* |
/* |
|
|
free(alt_filename); |
free(alt_filename); |
} |
} |
del_ifile(ifile); |
del_ifile(ifile); |
|
free(qopen_filename); |
|
free(filename); |
/* |
/* |
* Re-open the current file. |
* Re-open the current file. |
*/ |
*/ |
(void) edit_ifile(was_curr_ifile); |
reedit_ifile(was_curr_ifile); |
return (1); |
return (1); |
} else if ((f = open(open_filename, OPEN_READ)) < 0) |
} else if ((f = open(qopen_filename, OPEN_READ)) < 0) |
{ |
{ |
/* |
/* |
* Got an error trying to open it. |
* Got an error trying to open it. |
|
|
error("%s", &parg); |
error("%s", &parg); |
free(parg.p_string); |
free(parg.p_string); |
goto err1; |
goto err1; |
} else if (!force_open && !opened(ifile) && bin_file(f)) |
} else |
{ |
{ |
/* |
chflags |= CH_CANSEEK; |
* Looks like a binary file. Ask user if we should proceed. |
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') |
|
{ |
{ |
close(f); |
/* |
goto err1; |
* Looks like a binary file. |
|
* Ask user if we should proceed. |
|
*/ |
|
parg.p_string = filename; |
|
answer = query("\"%s\" may be a binary file. See it anyway? ", |
|
&parg); |
|
if (answer != 'y' && answer != 'Y') |
|
{ |
|
close(f); |
|
goto err1; |
|
} |
} |
} |
} |
} |
|
free(qopen_filename); |
|
|
/* |
/* |
* Get the new ifile. |
* Get the new ifile. |
* Get the saved position for the file. |
* Get the saved position for the file. |
*/ |
*/ |
if (was_curr_ifile != NULL_IFILE) |
if (was_curr_ifile != NULL_IFILE) |
|
{ |
old_ifile = was_curr_ifile; |
old_ifile = was_curr_ifile; |
|
unsave_ifile(was_curr_ifile); |
|
} |
curr_ifile = ifile; |
curr_ifile = ifile; |
curr_altfilename = alt_filename; |
curr_altfilename = alt_filename; |
curr_altpipe = alt_pipe; |
curr_altpipe = alt_pipe; |
|
|
get_pos(curr_ifile, &initial_scrpos); |
get_pos(curr_ifile, &initial_scrpos); |
new_file = TRUE; |
new_file = TRUE; |
ch_init(f, chflags); |
ch_init(f, chflags); |
|
|
|
if (!(chflags & CH_HELPFILE)) |
|
{ |
#if LOGFILE |
#if LOGFILE |
if (namelogfile != NULL && is_tty) |
if (namelogfile != NULL && is_tty) |
use_logfile(namelogfile); |
use_logfile(namelogfile); |
#endif |
#endif |
|
if (every_first_cmd != NULL) |
|
ungetsc(every_first_cmd); |
|
} |
|
|
if (every_first_cmd != NULL) |
|
ungetsc(every_first_cmd); |
|
|
|
no_display = !any_display; |
no_display = !any_display; |
flush(); |
flush(); |
any_display = TRUE; |
any_display = TRUE; |
|
|
#if HILITE_SEARCH |
#if HILITE_SEARCH |
clr_hilite(); |
clr_hilite(); |
#endif |
#endif |
|
cmd_addhist(ml_examine, filename); |
if (no_display && errmsgs > 0) |
if (no_display && errmsgs > 0) |
{ |
{ |
/* |
/* |
|
|
error("%s", &parg); |
error("%s", &parg); |
} |
} |
} |
} |
|
free(filename); |
return (0); |
return (0); |
} |
} |
|
|
|
|
edit_list(filelist) |
edit_list(filelist) |
char *filelist; |
char *filelist; |
{ |
{ |
IFILE save_curr_ifile; |
IFILE save_ifile; |
char *good_filename; |
char *good_filename; |
char *filename; |
char *filename; |
char *gfilelist; |
char *gfilelist; |
|
|
struct textlist tl_files; |
struct textlist tl_files; |
struct textlist tl_gfiles; |
struct textlist tl_gfiles; |
|
|
save_curr_ifile = curr_ifile; |
save_ifile = save_curr_ifile(); |
good_filename = NULL; |
good_filename = NULL; |
|
|
/* |
/* |
|
|
filename = NULL; |
filename = NULL; |
while ((filename = forw_textlist(&tl_files, filename)) != NULL) |
while ((filename = forw_textlist(&tl_files, filename)) != NULL) |
{ |
{ |
gfilelist = glob(filename); |
gfilelist = lglob(filename); |
init_textlist(&tl_gfiles, gfilelist); |
init_textlist(&tl_gfiles, gfilelist); |
gfilename = NULL; |
gfilename = NULL; |
while ((gfilename = forw_textlist(&tl_gfiles, gfilename)) != NULL) |
while ((gfilename = forw_textlist(&tl_gfiles, gfilename)) != NULL) |
|
|
* Edit the first valid filename in the list. |
* Edit the first valid filename in the list. |
*/ |
*/ |
if (good_filename == NULL) |
if (good_filename == NULL) |
|
{ |
|
unsave_ifile(save_ifile); |
return (1); |
return (1); |
|
} |
if (get_ifile(good_filename, curr_ifile) == curr_ifile) |
if (get_ifile(good_filename, curr_ifile) == curr_ifile) |
|
{ |
/* |
/* |
* Trying to edit the current file; don't reopen it. |
* Trying to edit the current file; don't reopen it. |
*/ |
*/ |
|
unsave_ifile(save_ifile); |
return (0); |
return (0); |
if (edit_ifile(save_curr_ifile)) |
} |
quit(QUIT_ERROR); |
reedit_ifile(save_ifile); |
return (edit(good_filename)); |
return (edit(good_filename)); |
} |
} |
|
|
|
|
|
|
|
|
/* |
/* |
* Edit the next file in the command line (ifile) list. |
* Edit the next or previous file in the command line (ifile) list. |
*/ |
*/ |
public int |
static int |
edit_next(n) |
edit_istep(h, n, dir) |
|
IFILE h; |
int n; |
int n; |
|
int dir; |
{ |
{ |
IFILE h; |
|
IFILE next; |
IFILE next; |
|
|
h = curr_ifile; |
|
/* |
/* |
* Skip n filenames, then try to edit each filename. |
* Skip n filenames, then try to edit each filename. |
*/ |
*/ |
for (;;) |
for (;;) |
{ |
{ |
next = next_ifile(h); |
next = (dir > 0) ? next_ifile(h) : prev_ifile(h); |
if (--n < 0) |
if (--n < 0) |
{ |
{ |
if (edit_ifile(h) == 0) |
if (edit_ifile(h) == 0) |
|
|
*/ |
*/ |
return (1); |
return (1); |
} |
} |
|
if (ABORT_SIGS()) |
|
{ |
|
/* |
|
* Interrupt breaks out, if we're in a long |
|
* list of files that can't be opened. |
|
*/ |
|
return (1); |
|
} |
h = next; |
h = next; |
} |
} |
/* |
/* |
|
|
return (0); |
return (0); |
} |
} |
|
|
/* |
static int |
* Edit the previous file in the command line list. |
edit_inext(h, n) |
*/ |
IFILE h; |
|
int n; |
|
{ |
|
return (edit_istep(h, n, 1)); |
|
} |
|
|
public int |
public int |
edit_prev(n) |
edit_next(n) |
int n; |
int n; |
{ |
{ |
|
return edit_istep(curr_ifile, n, 1); |
|
} |
|
|
|
static int |
|
edit_iprev(h, n) |
IFILE h; |
IFILE h; |
IFILE next; |
int n; |
|
{ |
|
return (edit_istep(h, n, -1)); |
|
} |
|
|
h = curr_ifile; |
public int |
/* |
edit_prev(n) |
* Skip n filenames, then try to edit each filename. |
int n; |
*/ |
{ |
for (;;) |
return edit_istep(curr_ifile, n, -1); |
{ |
|
next = prev_ifile(h); |
|
if (--n < 0) |
|
{ |
|
if (edit_ifile(h) == 0) |
|
break; |
|
} |
|
if (next == NULL_IFILE) |
|
{ |
|
/* |
|
* Reached beginning of the ifile list. |
|
*/ |
|
return (1); |
|
} |
|
h = next; |
|
} |
|
/* |
|
* Found a file that we can edit. |
|
*/ |
|
return (0); |
|
} |
} |
|
|
/* |
/* |
|
|
return (edit_ifile(h)); |
return (edit_ifile(h)); |
} |
} |
|
|
|
public IFILE |
|
save_curr_ifile() |
|
{ |
|
if (curr_ifile != NULL_IFILE) |
|
hold_ifile(curr_ifile, 1); |
|
return (curr_ifile); |
|
} |
|
|
|
public void |
|
unsave_ifile(save_ifile) |
|
IFILE save_ifile; |
|
{ |
|
if (save_ifile != NULL_IFILE) |
|
hold_ifile(save_ifile, -1); |
|
} |
|
|
/* |
/* |
|
* Reedit the ifile which was previously open. |
|
*/ |
|
public void |
|
reedit_ifile(save_ifile) |
|
IFILE save_ifile; |
|
{ |
|
IFILE next; |
|
IFILE prev; |
|
|
|
/* |
|
* Try to reopen the ifile. |
|
* Note that opening it may fail (maybe the file was removed), |
|
* in which case the ifile will be deleted from the list. |
|
* So save the next and prev ifiles first. |
|
*/ |
|
unsave_ifile(save_ifile); |
|
next = next_ifile(save_ifile); |
|
prev = prev_ifile(save_ifile); |
|
if (edit_ifile(save_ifile) == 0) |
|
return; |
|
/* |
|
* If can't reopen it, open the next input file in the list. |
|
*/ |
|
if (next != NULL_IFILE && edit_inext(next, 0) == 0) |
|
return; |
|
/* |
|
* If can't open THAT one, open the previous input file in the list. |
|
*/ |
|
if (prev != NULL_IFILE && edit_iprev(prev, 0) == 0) |
|
return; |
|
/* |
|
* If can't even open that, we're stuck. Just quit. |
|
*/ |
|
quit(QUIT_ERROR); |
|
} |
|
|
|
/* |
* Edit standard input. |
* Edit standard input. |
*/ |
*/ |
public int |
public int |
|
|
{ |
{ |
if (isatty(fd0)) |
if (isatty(fd0)) |
{ |
{ |
#if MSOFTC || OS2 |
error("Missing filename (\"less --help\" for help)", NULL_PARG); |
error("Missing filename (\"less -?\" for help)", NULL_PARG); |
|
#else |
|
error("Missing filename (\"less -\\?\" for help)", NULL_PARG); |
|
#endif |
|
quit(QUIT_OK); |
quit(QUIT_OK); |
} |
} |
return (edit("-")); |
return (edit("-")); |
|
|
/* |
/* |
* {{ We could use access() here. }} |
* {{ We could use access() here. }} |
*/ |
*/ |
|
filename = shell_unquote(filename); |
exists = open(filename, OPEN_READ); |
exists = open(filename, OPEN_READ); |
close(exists); |
close(exists); |
exists = (exists >= 0); |
exists = (exists >= 0); |
|
|
/* |
/* |
* Don't do anything. |
* Don't do anything. |
*/ |
*/ |
|
free(filename); |
return; |
return; |
case 'q': |
case 'q': |
quit(QUIT_OK); |
quit(QUIT_OK); |
|
|
*/ |
*/ |
parg.p_string = filename; |
parg.p_string = filename; |
error("Cannot write to \"%s\"", &parg); |
error("Cannot write to \"%s\"", &parg); |
|
free(filename); |
|
return; |
} |
} |
|
free(filename); |
|
SET_BINARY(logfile); |
} |
} |
|
|
#endif |
#endif |