ftp.nice.ch/pub/next/unix/editor/ne-1.0.NI.s.tar.gz#/ne-1.0.NI.s/src/ne.c

This is ne.c in view mode; [Download] [Up]

/* main(), global initialization and global buffer functions.

   Copyright (C) 1993 Sebastiano Vigna

    This file is part of ne, the nice editor.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2, or (at your option)
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

In other words, you are welcome to use, share and improve this program.
You are forbidden to forbid anyone else to use, share and improve
what you give them.   Help stamp out software-hoarding!  */


#include "ne.h"
#include "version.h"
#include "regex.h"
#include <signal.h>
#include <limits.h>


/* This is the array containing the "NO WARRANTY" message, which is displayed
when ne is called without any specific file name or macro to execute. The
message disappears as soon as any key is typed. */

char *NO_WARRANTY_msg[] = {	PROGRAM_NAME " " VERSION ".",
										COPYRIGHT ".",
										"",
										"This program is free software; you can redistribute it and/or modify",
										"it under the terms of the GNU General Public License as published by",
										"the Free Software Foundation; either version 2, or (at your option)",
										"any later version.",
										"",
										"This program is distributed in the hope that it will be useful,",
										"but WITHOUT ANY WARRANTY; without even the implied warranty of",
										"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the",
										"GNU General Public License for more details.",
										NULL
									};


/* These lists contains the existing buffers, clips and macros. cur_buffer
denotes the currently displayed buffer. */

list buffers = { (node *)&buffers.tail, NULL, (node *)&buffers.head };
list clips = { (node *)&clips.tail, NULL, (node *)&clips.head };
list macros = { (node *)&macros.tail, NULL, (node *)&macros.head };

buffer *cur_buffer;


/* These function live here because they access cur_buffer. new_buffer()
creates a new buffer, adds it to the buffer list, and assign it to
cur_buffer. delete_buffer() destroys cur_buffer, and makes the previous or
next buffer the current buffer, if any of the two exists. */

buffer *new_buffer(void) {
	buffer *b = alloc_buffer(cur_buffer);

	if (b) {
		clear_buffer(b);
		if (cur_buffer) add(&b->b_node, &cur_buffer->b_node);
		else add_head(&buffers, &b->b_node);
		cur_buffer = b;
	}

	return(b);
}

int delete_buffer(void) {

	buffer *nb = (buffer *)cur_buffer->b_node.next, *pb = (buffer *)cur_buffer->b_node.prev;

	rem(&cur_buffer->b_node);
	free_buffer(cur_buffer);

	if (pb->b_node.prev) {
		cur_buffer = pb;
      return(TRUE);
	}

	if (nb->b_node.next) {
		cur_buffer = nb;
		return(TRUE);
	}

	return(FALSE);
}



/* The main() function. It is responsible for argument parsing, calling
some terminal and signal initialization functions, and entering the
event loop. */

int main(int argc, char **argv) {

	input_class ic;
	int i, c, no_config = FALSE, displaying_info = FALSE;
	char *macro_name = NULL;
	clip_desc *cd;

	for(i=1; i<argc; i++) {

		/* Special arguments start with two dashes. If we find one, we
		cancel its entry in argv[], so that it will be skipped when opening
		the specified files. */

		if (argv[i][0] == '-' && argv[i][1] == '-') {
			if (!strcmp(&argv[i][2], "noconfig" "\0" VERSION_STRING)) {
				no_config = TRUE;
				argv[i] = NULL;
			}
			else if (!strcmp(&argv[i][2], "macro")) {
				if (i<argc-1) {
					macro_name = argv[i+1];
					argv[i] = argv[i+1] = NULL;
				}
			}
		}
	}

	/* Unless --noconfig was specified, we try to configure the
	menus and the keyboard. Note that these functions can exit() on error. */

	if (!no_config) {
		get_menu_configuration();
		get_key_bindings();
	}

	/* If we cannot even create a buffer, better go... */

	if (!new_buffer()) exit(1);

	clear_buffer(cur_buffer);

	/* The INT_MAX clip always exists, and it is used by the Through command. */

	if (!(cd = alloc_clip_desc(INT_MAX, 0))) exit(1);

	add_head(&clips, &cd->cd_node);

	/* General terminfo and cursor motion initalization. From here onwards,
	we cannot exit() lightly. */

	term_init();

	/* This is necessary so that buffer.c can ignore terminfo. */

	cur_buffer->turbo = lines*2;

	/* We will be always using the last line for the status bar. */

	set_terminal_window(lines-1);

	/* We read in all the key capabilities. */

	read_key_capabilities();

	/* Some initializations of other modules... */

	re_set_syntax(
		/* RE_CHAR_CLASSES		|  I would *love* character classes, but they do not seem to work... 8^( */
		RE_CONTEXT_INDEP_ANCHORS |
		RE_CONTEXT_INDEP_OPS	| RE_HAT_LISTS_NOT_NEWLINE |
		RE_NEWLINE_ALT			| RE_NO_BK_PARENS				|
		RE_NO_BK_VBAR			| RE_NO_EMPTY_RANGES
	);

#ifndef _AMIGA

	/* This function sets fatal_code() as signal interrupt handler
	for all the dangerous signals (SIGILL, SIGSEGV etc.). */

	set_fatal_code();

	/* Both SIGINT and SIGQUIT are used for the interrupt character---we
	get whatever arrives. */

	signal(SIGINT, set_stop);
	signal(SIGQUIT, set_stop);

	/* We do not want to be stopped. */

	signal(SIGTSTP, SIG_IGN);

#endif

	/* The terminal is prepared for interactive I/O. */

	set_interactive_mode();

	clear_entire_screen();

	load_auto_prefs(cur_buffer, DEF_PREFS_NAME);

	if (argc > 1) {

		/* The first file opened does not need a NEW_BUFFER call. Note that
		file loading can be interrupted (wildcarding can sometimes produce
		unwanted results). */

		int first_file = TRUE;

		stop = FALSE;

		for(i=1; i<argc && !stop; i++) {
			if (argv[i]) {
				if (!first_file) do_action(cur_buffer, NEW_BUFFER, -1, NULL);
				else first_file = FALSE;

				do_action(cur_buffer, OPEN, -1, str_dup(argv[i]));
			}
		}

		/* This call makes current the first specified file. It is called
		only if more than one buffer exist. */

		if (get_nth_buffer(1)) do_action(cur_buffer, NEXT_BUFFER, -1, NULL);
	}

	/* Note that we do not need to update the display. clear_entire_screen() is
	ok if no file was loaded; otherwise, OPEN will call update_window(). */

	refresh_window(cur_buffer);

	if (macro_name) do_action(cur_buffer, MACRO, -1, str_dup(macro_name));
	else if (argc == 1) {

		/* If there is no file to load, and no macro to execute, we display
		the "NO WARRANTY" message. */

		displaying_info = TRUE;

		for(i=0; NO_WARRANTY_msg[i]; i++) {
			move_cursor(i, 0);
			output_string(NO_WARRANTY_msg[i]);
		}
	}

	while(TRUE) {

		/* If we are displaying the "NO WARRANTY" info, we should not refresh the
		window now */

		if (!displaying_info) refresh_window(cur_buffer);
	
		draw_status_bar();

		move_cursor(cur_buffer->cur_y, cur_buffer->cur_x);

		while( (ic = char_class[c = get_key_code()]) == IGNORE);

		if (displaying_info) {

			displaying_info = FALSE;

			for(i=0; NO_WARRANTY_msg[i]; i++) {
				move_cursor(i, 0);
				clear_to_eol();
			}

			fflush(stdout);
		}

		switch(ic) {
			case ALPHA:
				print_error(do_action(cur_buffer, INSERT_CHAR, c, NULL));
				break;

			case RETURN:
				print_error(do_action(cur_buffer, INSERT_LINE, -1, NULL));
				break;

			case COMMAND:
				print_error(execute_command_line(cur_buffer, key_binding[c]));
				break;

			default:
				break;
		}
	}
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.