diff miscellany/less-177/edit.c @ 0:bce86c4163a3

Initial revision
author kono
date Mon, 18 Apr 2005 23:46:02 +0900
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/miscellany/less-177/edit.c	Mon Apr 18 23:46:02 2005 +0900
@@ -0,0 +1,451 @@
+#include "less.h"
+
+#if __MSDOS__
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <io.h>
+#endif
+
+#define	ISPIPE(fd)	((fd)==0)
+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 = 0;
+	} else if ((parg.p_string = bad_file(filename)) != NULL)
+	{
+		error("%s", &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)
+#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()
+{
+	curr_ifile = NULL_IFILE;
+	return (edit_next(1));
+}
+
+/*
+ * Edit the last file in the command line (ifile) list.
+ */
+	public int
+edit_last()
+{
+	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()
+{
+	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);
+	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);
+#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