/* Main typedefs and defines.

   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 1, 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!  */


#ifndef _AMIGA
#define _INCLUDE_POSIX_SOURCE
#include <termios.h>
#endif
#include <curses.h>
#include <term.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/types.h>
#include <math.h>
#include <sys/stat.h>

#ifdef _AMIGA
#define CURDIR ""
#define _S_IFDIR S_IFDIR
#else
#include <unistd.h>
#define CURDIR "."
#endif


/* This is the list of all possible actions that do_action() can execute.
Note that also menu handling is governed by such a command (ESCAPE). */

typedef enum {
		NOP,

		OPEN, SAVE, SAVEAS, CLEAR, QUIT, EXIT, ABOUT,

		NEW_BUFFER, CLOSE_BUFFER, NEXT_BUFFER, PREV_BUFFER, SELECT_BUFFER,

		MARK_BLOCK, CUT, COPY, PASTE, ERASE, MARK_VERT, PASTE_VERT, OPEN_CLIP, SAVE_CLIP,

		FIND, FIND_REGEXP, REPLACE, REPLACE_ONCE, REPLACE_ALL, REPEAT_LAST, GOTO_LINE, GOTO_COLUMN, GOTO_MARK, MATCH_BRACKET,

		RECORD, PLAY, OPEN_MACRO, SAVE_MACRO, MACRO, UNLOAD_MACROS,

		REFRESH, UNDEL_LINE, CENTER, PARAGRAPH, TO_UPPER, TO_LOWER, CAPITALIZE,

		MOVE_LEFT, MOVE_RIGHT, LINE_UP, LINE_DOWN, PREV_PAGE, NEXT_PAGE,
		MOVE_TO_EOL, MOVE_TO_SOL, MOVE_TO_EOF, MOVE_TO_SOF, TOGGLE_SOF_EOF, TOGGLE_SOL_EOL,
		NEXT_WORD, PREV_WORD, MOVE_TO_EOW, SET_BOOKMARK, GOTO_BOOKMARK,

		TAB_SIZE, INSERT, FREE_FORM, STATUS_BAR, CASE_SEARCH, SEARCH_BACK,
		FAST_GUI, WORD_WRAP, RIGHT_MARGIN, AUTO_INDENT, AUTO_PREFS, BINARY, TURBO, NO_FILE_REQ,
		VERBOSE_MACROS, DO_UNDO, READ_ONLY, CLIP_NUMBER,
		LOAD_PREFS, SAVE_PREFS, LOAD_AUTO_PREFS, SAVE_AUTO_PREFS, SAVE_DEF_PREFS,

		INSERT_CHAR, DELETE_CHAR, BACKSPACE,
		INSERT_LINE, DELETE_LINE, DELETE_TO_EOL,

		UNDO, REDO,

		HELP, BEEP, FLASH, EXEC, SYSTEM, ESCAPE,

		ACTION_COUNT
} action;


/* The input_class of a character is a first differentiation between
alphabetic, command-activating, and ignorable character. The class[] vector
(indexed by the extended character code) gives back the input class. */

typedef enum {
	ALPHA, COMMAND, RETURN, IGNORE, INPUT_CLASS_COUNT
} input_class;


/* The number of bookmarks per buffer. */

#define NUM_BOOKMARKS 10

/* The name of the default preferences file name. */

#define DEF_PREFS_NAME			".default"

/* The number of extended key codes. */

#define NUM_KEYS					(256+128)

/* This number is used throughout ne when an integer has to be expanded in
characters. It is expected that sprintf("%d")ing an integer will produce a
string shorter than the following number. PORTABILITY PROBLEM: improbable,
but possible. */

#define MAX_INT_LEN				32



/* These are the list and node structures used throughout ne. See the exec.c
source for some elaborations on the subject. Note the cumbersome way we are
forced to use in order to define recursive typedefs. */

struct struct_node {
    struct struct_node *next;
    struct struct_node *prev;
};

typedef struct struct_node node;

typedef struct {
   node *head;
   node *tail;
   node *tail_pred;
} list;



/* All the structures that follow have an assertion macro which checks for
partial internal consistency of the structure. These macros are extensively
used in the code. */


/* This structure represent a sequence, or stream, of NULL-terminated
strings. It is used for many purposes, such as storage of macros, clips,
etc. General functions allow to allocate, free, load, save and append to
such streams. Size represent the size of the chunk of memory pointed to by
stream, while len gives you the number of bytes currently used. You can
append in the last size-len bytes, or realloc() stream, updating size
correspondingly. */

typedef struct {
	int size, len;
	unsigned char *stream;
} char_stream;


#define assert_char_stream(cs) {if ((cs)) {\
	assert((cs)->len<=(cs)->size);\
	assert((cs)->len>=0);\
	assert(((cs)->size == 0) == ((cs)->stream == NULL));\
}}



/* This structure defines a line descriptor; it is a node containing a pointer
to the line text, and an integer containing the line length in bytes. The
line pointer by ld_text is NOT NULL-terminated. line_len is zero iff line
is zero, in which case we are representing an empty line. ld_node->next
is NULL iff this node is free for use. */


typedef struct {
	node ld_node;
	unsigned char *line;
	short line_len;
} line_desc;

#define assert_line_desc(ld) {if ((ld)) {\
	assert((ld)->line_len >= 0);\
	assert(((ld)->line == NULL) == ((ld)->line_len == 0));\
	assert(((ld)->line_len == 0) || ((ld)->line[0] != 0 && (ld)->line[(ld)->line_len-1] != 0));\
}}



/* This structure defines a pool of line descriptors. pool points to an
array of size line descriptors. The first free descriptor is contained in
first_free. The last free descriptor is contained in last_free. The
allocated_items field keeps track of how many items are allocated. */

typedef struct {
	node ldp_node;
	list free_list;
	int size;
	int allocated_items;
	line_desc *pool;
} line_desc_pool;

#define assert_line_desc_pool(ldp) {if ((ldp)) {\
	assert((ldp)->allocated_items <= (ldp)->size);\
	assert((ldp)->allocated_items == (ldp)->size || (ldp)->free_list.head->next);\
	assert((ldp)->pool != NULL);\
	assert((ldp)->size != 0);\
}}




/* This structure defines a pool of characters. size represents the size of
the pool pointed by pool, while first_used and last_used represent
the min and max characters which are used. A character is not used if it
is zero. It is perfectly possible (and likely) that between first_used
and last_used there are many free chars, which are named "lost" chars. See
the source buffer.c for some elaborations on the subject. */

typedef struct {
	node cp_node;
	int  size, first_used, last_used;
	unsigned char *pool;
} char_pool;

#define assert_char_pool(cp) {if ((cp)) {\
	assert((cp)->first_used<=(cp)->first_used);\
	assert((cp)->pool[(cp)->first_used] != 0);\
	assert((cp)->first_used >= 0);\
	assert((cp)->first_used == 0 || (cp)->pool[(cp)->first_used-1] == 0);\
	assert((cp)->pool[(cp)->last_used] != 0);\
	assert((cp)->last_used >= 0);\
	assert((cp)->last_used == (cp)->size-1 || (cp)->pool[(cp)->last_used+1] == 0);\
	assert((cp)->pool != NULL);\
	assert((cp)->size != 0);\
}}



/* This structure defines a macro. A macro is just a stream plus a node, a
file name and a hash code relative to the filename (it is used to make the
search for a given macro quicker). */

struct struct_macro_desc {
	struct struct_macro_desc *next;
	unsigned char *name;
	char_stream *cs;
};

typedef struct struct_macro_desc macro_desc;

#define assert_macro_desc(md) if (md) assert_char_stream((md)->cs);



/* This structure defines a clip. Clip are numbered from 0 onwards, and
contain a stream of characters. */

typedef struct {
	node cd_node;
	int n;
	char_stream *cs;
} clip_desc;

#define assert_clip_desc(cd) {if ((cd)) {\
	assert((cd)->n>=0);\
	assert_char_stream((cd)->cs);\
}}


/* An undo step is given by a position, a transformation which can be
INSERT_CHAR or DELETE_CHAR and the length of the stream to which the
transformation applies. For compactness reasons, the transformation is
really stored in the sign of the length. Plus means insert, minus means
delete. Note also that pos can be negative, in which case the real position
is -(pos+1), and the undo step is linked to the following one (in the sense
that they should be performed indivisibly). */

typedef struct {
	int line;
	int pos;
	int len;
} undo_step;




/* This structure defines an undo buffer. steps points to an array of
steps_size undo_steps, used up to cur_step. last_step represent the undo
step which is the next to be redone in case some undo had place. Note that
the characters stored in streams, which are used when executing an insertion
undo step, are not directly pointed to by the undo step. The correct position
is calculated incrementally, and kept in cur_stream and last_stream.
Finally, redo contains the stream of characters necessary to perform the
redo steps. */

typedef struct {
	undo_step *steps;
	unsigned char *streams;
	char_stream redo;
	int steps_size;
	int streams_size;
	int cur_step;
	int cur_stream;
	int last_step;
	int last_stream;
} undo_buffer;

#define assert_undo_buffer(ub) {if ((ub)) {\
	assert((ub)->cur_step<=(ub)->last_step);\
	assert((ub)->cur_stream<=(ub)->last_stream);\
	assert((ub)->cur_step<=(ub)->steps_size);\
	assert((ub)->cur_stream<=(ub)->streams_size);\
	assert((ub)->last_step<=(ub)->steps_size);\
	assert((ub)->last_stream<=(ub)->streams_size);\
	assert_char_stream(&(ub)->redo);\
}}



/* This structure defines a buffer node; a buffer is composed by two lists,
the list of line descriptor pools and the list of character pools, plus some
data as the current window and cursor position. The line descriptors are
kept in a list, too. The other fields are more or less autoexplicative.
wanted_x represent the position the cursor would like to be on, but cannot
because a line is too short or because it falls inside a TAB expansion. When
a flag is declared as multilevel, this means that the flag is
incremented/decremented rather than set/unset, so that activations and
deactivations can be nested. */

typedef struct {
	node b_node;
	list line_desc_pool_list;
	list line_desc_list;
	list char_pool_list;
	line_desc *cur_line_desc;
	line_desc *top_line_desc;
	char_stream *cur_macro;
	char_stream *last_deleted;
	unsigned char *filename;
	unsigned char *find_string;
	unsigned char *replace_string;
	unsigned char *command_line;
	int win_x, win_y;
	int cur_x, cur_y;
	int wanted_x;
	int cur_line, cur_pos;
	int line_num;
	int block_start_line, block_start_pos, block_start_col;
	int tab_size;
	int right_margin;
	int turbo;
	int cur_clip;
	int allocated_chars;
	int free_chars;
	undo_buffer undo;
	struct {
		int pos;
		int line;
	} bookmark[NUM_BOOKMARKS];

	unsigned int

		link_undos,									/* Link the undo steps. Multilevel. */
		buffer_is_modified:1, 					/* Buffer has been modified since last save */
		recording:1,								/* We are recording a macro */
		marking:1,									/* We are marking a block */
		x_wanted:1,									/* We're not where we would like to be */
		exec_only_options:1,						/* Only option changes can be executed */
		find_string_changed:1,					/* The search string has to be recompiled before usage. */
		last_was_replace:1,						/* The last search operation was a replace */
		last_was_regexp:1,						/* The last search operation was done with regexps */
		undoing:1,									/* We are currently undoing an action */
		redoing:1,									/* We are currently redoing an action */
		mark_is_vertical:1,						/* The current marking is vertical */

		free_form:1,					/* Editing is free form (cursor can be anywhere) */
		status_bar:1,					/* The status bar is displayed */
		fast_gui:1,						/* GUI should be as fast as possible (phone lines, etc.) */
		word_wrap:1,					/* Word wrap is on */
		auto_indent:1,					/* Replicate indentation when creating a new line */
		insert:1,						/* Insert mode */
		verbose_macros:1,				/* Macro learned are verbose */
		do_undo:1,						/* Record each action and allow undoing it */
		auto_prefs:1,					/* Use autoprefs */
		no_file_req:1,					/* Do not display the file requester */
		read_only:1,					/* Read-only mode */
		search_back:1,					/* Last search was backwards */
		case_search:1,					/* Look at case matching in searches */
		binary:1;						/* Load and save in binary mode */
} buffer;


#define assert_buffer(b) {if ((b)) {\
	assert((b)->cur_line_desc != NULL);\
	assert((b)->top_line_desc != NULL);\
	assert_line_desc((b)->cur_line_desc);\
	assert_line_desc((b)->top_line_desc);\
	assert_char_stream((b)->last_deleted);\
	assert_char_stream((b)->cur_macro);\
	assert((b)->win_y+(b)->cur_y<(b)->line_num);\
	assert((b)->line_num>0);\
	assert((b)->tab_size>0);\
	assert((b)->free_chars <= (b)->allocated_chars);\
	assert((b)->cur_line == (b)->win_y+(b)->cur_y);\
	assert_undo_buffer(&(b)->undo);\
}}


extern const unsigned char *key_binding[NUM_KEYS];

extern buffer *cur_buffer;

/* These are the global lists. */

extern list buffers, clips, macros;

/* This flag can be set anywhere to FALSE, and will become TRUE if the user
hits the interrupt key (usually CTRL-'\'). It is handled through SIGQUIT and
SIGINT. */

extern unsigned int stop;

/* This vector associates to an extended key code (as returned by
get_key_code()) its input class. */

extern const input_class class[NUM_KEYS];

/* This vector is a translation table for the regex library which maps
lower case characters to upper case characters. It is also used elsewhere. */

extern const unsigned char up_case[256];

/* Please to not change this number lightly. It has to be prime, and enough big
to allow a different hash code for each command name (short and long names get
separate hash tables). See also command.c. */

#define HASH_TABLE_SIZE (2503)

/* This number defines the macro hash table size. This table can have
conflicts. */

#define MACRO_HASH_TABLE_SIZE (101)


#include "keycodes.h"
#include "names.h"
#include "errors.h"
#include "protos.h"
#include "debug.h"
