gno/bin/less/edit.c
gdr-ftp 784e3de7cd Initial checkin of aroff, binprint, center, less, ls, make, makemake,
passwd, ps, purge, shutdown, stty, upper, and vi.  These sources are
for the versions of the utils shipped with GNO v2.0.4.
1998-03-09 08:30:21 +00:00

462 lines
8.1 KiB
C

#pragma noroot
#include "less.h"
#if __MSDOS__
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
#endif
#ifdef _ORCAC_
#include <unistd.h>
#include <fcntl.h>
segment "LoadSegONE";
#endif
#define ISPIPE(fd) ((fd)==STDIN_FILENO)
extern int ispipe;
extern int new_file;
extern int errmsgs;
extern int quit_at_eof;
extern int file;
extern int cbufs;
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;
#if LOGFILE
extern int logfile;
extern int force_logfile;
extern char *namelogfile;
#endif
/*
* Edit a new file.
* Filename == "-" means standard input.
* Filename == NULL means just close the current file.
*/
public int
edit(filename, just_looking)
register char *filename;
int just_looking;
{
register int f;
char *s;
int answer;
int no_display;
struct scrpos scrpos;
PARG parg;
if (filename == NULL)
{
/*
* Close the current file, but don't open a new one.
*/
f = -1;
} else if (strcmp(filename, "-") == 0)
{
/*
* Use standard input.
*/
f = STDIN_FILENO;
} else if ((parg.p_string = bad_file(filename)) != NULL)
{
error("\r%s\r", &parg);
free(parg.p_string);
return (1);
#if __MSDOS__
} else if ((f = open(filename, O_RDONLY|O_BINARY)) < 0)
#else
/* } else if ((f = open(filename, 0)) < 0)*/
} else if ((f = open(filename, O_RDONLY|O_BINARY)) < 0)
#endif
{
parg.p_string = errno_message(filename);
error("%s", &parg);
free(parg.p_string);
return (1);
} else if (!force_open && !just_looking && bin_file(f))
{
parg.p_string = filename;
answer = query("\"%s\" may be a binary file. Continue? ",
&parg);
if (answer != 'y' && answer != 'Y')
{
close(f);
return (1);
}
}
if (f >= 0 && isatty(f))
{
/*
* Not really necessary to call this an error,
* but if the control terminal (for commands)
* and the input file (for data) are the same,
* we get weird results at best.
*/
#if __MSDOS__
parg.p_string = "less -?";
#else
parg.p_string = "less -\\?";
#endif
error("Cannot take input from a terminal (\"%s\" for help)",
&parg);
if (!ISPIPE(f))
close(f);
return (1);
}
#if LOGFILE
s = namelogfile;
end_logfile();
if (f >= 0 && ISPIPE(f) && s != NULL && is_tty)
use_logfile(s);
#endif
/*
* We are now committed to using the new file.
* Close the current input file and set up to use the new one.
*/
if (curr_ifile != NULL_IFILE)
{
/*
* Save the current position so that we can return to
* the same position if we edit this file again.
*/
get_scrpos(&scrpos);
if (scrpos.pos != NULL_POSITION)
{
store_pos(curr_ifile, &scrpos);
lastmark();
}
}
/*
* Close the current file, unless it is a pipe.
*/
if (!ISPIPE(file))
close(file);
file = f;
if (f < 0)
return (1);
/*
* Get the new ifile.
* Get the saved position for that file.
*/
old_ifile = curr_ifile;
curr_ifile = get_ifile(filename, curr_ifile);
get_pos(curr_ifile, &initial_scrpos);
ispipe = ISPIPE(f);
if (ispipe)
ch_pipe();
else
ch_nonpipe();
(void) ch_nbuf(cbufs);
ch_flush();
new_file = 1;
#if __MSDOS__
top_filename();
#endif
if (every_first_cmd != NULL)
ungetsc(every_first_cmd);
no_display = !any_display;
flush();
any_display = 1;
if (is_tty)
{
/*
* Output is to a real tty.
*/
/*
* Indicate there is nothing displayed yet.
*/
pos_clear();
clr_linenum();
if (no_display && errmsgs > 0)
{
/*
* We displayed some messages on error output
* (file descriptor 2; see error() function).
* Before erasing the screen contents,
* display the file name and wait for a keystroke.
*/
parg.p_string = filename;
error("%s", &parg);
}
}
return (0);
}
/*
* Edit a space-separated list of files.
* For each filename in the list, enter it into the ifile list.
* Then edit the first one.
*/
public void
edit_list(list)
char *list;
{
register char *s;
register char *es;
register char *filename;
char *good_filename;
IFILE save_curr_ifile;
/*
* good_filename keeps track of the first valid filename.
*/
good_filename = NULL;
s = list;
es = s + strlen(s);
save_curr_ifile = curr_ifile;
while ((s = skipsp(s)) < es)
{
/*
* Get the next filename and null terminate it.
*/
filename = s;
while (*s != ' ' && *s != '\0')
s++;
if (*s != '\0')
*s++ = '\0';
/*
* Try to edit the file.
* This enters it into the command line list (if it is good).
* If it is the first good file we've seen, remember it.
* {{ A little weirdness here: if any of the filenames
* are already in the list, subsequent ones get
* entered after the position where that one already
* was, instead of at the end. }}
*/
if (edit(filename, 1) == 0 && good_filename == NULL)
good_filename = filename;
}
/*
* Edit the first valid filename in the list.
*/
if (good_filename != NULL)
{
curr_ifile = save_curr_ifile;
(void) edit(good_filename, 0);
}
}
/*
* Edit the first file in the command line (ifile) list.
*/
public int
edit_first(void)
{
curr_ifile = NULL_IFILE;
return (edit_next(1));
}
/*
* Edit the last file in the command line (ifile) list.
*/
public int
edit_last(void)
{
curr_ifile = NULL_IFILE;
return (edit_prev(1));
}
/*
* Edit the next file in the command line (ifile) list.
*/
public int
edit_next(n)
int n;
{
IFILE h;
h = curr_ifile;
while (--n >= 0 || edit(get_filename(h), 0))
{
if ((h = next_ifile(h)) == NULL_IFILE)
/*
* Reached end of the ifile list.
*/
return (1);
}
/*
* Found a file that we can edit.
*/
return (0);
}
/*
* Edit the previous file in the command line list.
*/
public int
edit_prev(n)
int n;
{
IFILE h;
h = curr_ifile;
while (--n >= 0 || edit(get_filename(h), 0))
{
if ((h = prev_ifile(h)) == NULL_IFILE)
/*
* Reached beginning of the ifile list.
*/
return (1);
}
/*
* Found a file that we can edit.
*/
return (0);
}
/*
* Edit a specific file in the command line (ifile) list.
*/
public int
edit_index(n)
int n;
{
IFILE h;
h = NULL_IFILE;
do
{
if ((h = next_ifile(h)) == NULL_IFILE)
{
/*
* Reached end of the list without finding it.
*/
return (1);
}
} while (get_index(h) != n);
return (edit(get_filename(h), 0));
}
/*
* Copy a file directly to standard output.
* Used if standard output is not a tty.
*/
public void
cat_file(void)
{
register int c;
while ((c = ch_forw_get()) != EOI)
putchr(c);
flush();
}
#if LOGFILE
/*
* If the user asked for a log file and our input file
* is standard input, create the log file.
* We take care not to blindly overwrite an existing file.
*/
public void
use_logfile(filename)
char *filename;
{
register int exists;
register int answer;
PARG parg;
/*
* {{ We could use access() here. }}
*/
/* exists = open(filename, 0);*/
exists = open(filename, O_RDWR);
close(exists);
exists = (exists >= 0);
/*
* Decide whether to overwrite the log file or append to it.
* (If it doesn't exist we "overwrite" it.
*/
if (!exists || force_logfile)
{
/*
* Overwrite (or create) the log file.
*/
answer = 'O';
} else
{
/*
* Ask user what to do.
*/
parg.p_string = filename;
answer = query("Warning: \"%s\" exists; Overwrite, Append or Don't log? ", &parg);
}
loop:
switch (answer)
{
case 'O': case 'o':
/*
* Overwrite: create the file.
*/
logfile = creat(filename, 0644);
break;
case 'A': case 'a':
/*
* Append: open the file and seek to the end.
*/
#if __MSDOS__
logfile = open(filename, O_APPEND|O_WRONLY);
#else
/* logfile = open(filename, 1);*/
logfile = open(filename, O_APPEND|O_WRONLY);
#endif
if (lseek(logfile, (offset_t)0, 2) == BAD_LSEEK)
{
close(logfile);
logfile = -1;
}
break;
case 'D': case 'd':
/*
* Don't do anything.
*/
return;
case 'q':
quit(0);
/*NOTREACHED*/
default:
/*
* Eh?
*/
answer = query("Overwrite, Append, or Don't log? ", NULL_PARG);
goto loop;
}
if (logfile < 0)
{
/*
* Error in opening logfile.
*/
parg.p_string = filename;
error("Cannot write to \"%s\"", &parg);
}
}
#endif