Scandum 6 سال پیش
والد
کامیت
17978b07ab
47فایلهای تغییر یافته به همراه2910 افزوده شده و 1818 حذف شده
  1. 3 2
      CREDITS
  2. 26 13
      TODO
  3. 52 7
      mods/igr.mods
  4. 8 9
      src/Makefile.in
  5. 0 89
      src/action.c
  6. 0 151
      src/alias.c
  7. 12 15
      src/buffer.c
  8. 3 1
      src/chat.c
  9. 8 1
      src/class.c
  10. 54 12
      src/config.c
  11. 10 3
      src/cursor.c
  12. 39 14
      src/data.c
  13. 10 0
      src/debug.c
  14. 10 0
      src/event.c
  15. 21 5
      src/files.c
  16. 0 72
      src/gag.c
  17. 109 20
      src/help.c
  18. 0 211
      src/highlight.c
  19. 1 1
      src/history.c
  20. 30 92
      src/input.c
  21. 142 69
      src/line.c
  22. 40 14
      src/log.c
  23. 0 66
      src/macro.c
  24. 13 13
      src/main.c
  25. 292 183
      src/mapper.c
  26. 3 1
      src/math.c
  27. 1 1
      src/misc.c
  28. 14 5
      src/net.c
  29. 3 3
      src/parse.c
  30. 5 2
      src/port.c
  31. 0 197
      src/prompt.c
  32. 121 26
      src/screen.c
  33. 23 8
      src/session.c
  34. 75 42
      src/show.c
  35. 100 2
      src/split.c
  36. 2 2
      src/ssl.c
  37. 1040 56
      src/substitute.c
  38. 0 56
      src/tab.c
  39. 135 12
      src/tables.c
  40. 18 15
      src/telopt_client.c
  41. 1 1
      src/telopt_server.c
  42. 19 26
      src/text.c
  43. 361 282
      src/tintin.h
  44. 1 1
      src/tokenize.c
  45. 2 2
      src/utils.c
  46. 69 7
      src/variable.c
  47. 34 8
      src/vt102.c

+ 3 - 2
CREDITS

@@ -23,9 +23,10 @@ Special thanks to the following
 
 Beta Testers
 -----------------------------------------------------------------------------
-There are too many to list, but your help has been greatly appreciated. You
-are important to TinTin++'s continued success.
+Unfortunately (or fortunately) there are too many to list, but your help has
+been greatly appreciated. You are invaluable to TinTin++'s continued success.
 
+Thanks!
 
 
 Modification History

+ 26 - 13
TODO

@@ -1,21 +1,36 @@
 * STUFF THAT IS PROBABLY GONNA GET DONE
 
-  - add #line background option that prevents automatic session
-    activation.
+  - #loop {1} {1000} {cnt} {#var test[$cnt] 123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-}
 
-  - add syntax highlighting to map data.
+  - add #map destroy area <area>
 
-  - add maze flag for maze handling.
+  - make format %X take unicode
+
+  - more potent long-click handling including held down ticks.
+
+  - look into discord api / arachnos
+
+  - finish mth true color conversion code
+
+  - #bell off option.
+
+  - draw example in #help
+
+  - make *draw_room more comprehensible
 
-  - asciivnum void room display.
+  - give SUB_FIX its own flag to avoid confusion.
 
-  - look into empty symbol setting.
+  - #detach command.
 
-  - easier bit checks for map data
+  - Improve #draw including 0000 mode.
+
+  - Add gtd->cursor_level to avoid saving an already saved cursor position
+
+  - add maze flag for maze handling.
+
+  - #buffer copy {lines} with strip option. #line strip?
 
-  - #buffer copy {lines} with strip option.
 
-  - add #line logmode {raw|html|plain} option
 
   - add class specific debug
 
@@ -23,8 +38,6 @@
 
   - Work on VT2020
 
-  - massive map / html map drawing.
-
   - add tunnel void utility to #map interface. (covered by #map move tho)
 
   - make #split static and fix wrapping of split line on horizontal shrink.
@@ -51,8 +64,6 @@
 
   - set packet patch on EOR and GA detection. #config packet patch auto ?
 
-  - See if cpu usage of time events can be lowered.
-
   - Add debugger to syntax highlighter, substitution highlighing, 256 color support, and variable expansion.
 
   - allow #class save/load to memory.
@@ -170,6 +181,8 @@
 
   - http://tintin.sourceforge.net/board/viewtopic.php?p=9934 Strange #map pathdir bug
 
+  - Add seconds till execution message to delays and tickers.
+
 --------------------------------------------------------------------------------
 
 * ROADMAP

+ 52 - 7
mods/igr.mods

@@ -1,4 +1,55 @@
-Jul 2019        2.02.0
+Sep 2019        2.01.92
+------------------------------------------------------------------------------
+
+Aug 2019        2.01.91
+------------------------------------------------------------------------------
+vt100.c         Added %2 rows %3 cols arguments to the VT100 SCROLL REGION
+                event to increase ease of use.
+
+mapper.c        Changed #map at to also take an exit for the location.
+
+data.c          No longer saving or displaying the priority of triggers which
+                are set to the default priority.
+
+mapper.c        Added #map map <rows> <cols> draw <square> to draw the map at
+                the given location. This is no real alternative for using #map
+                offset as #map offset allows mouse map events.
+
+draw.c          Added unicode drawing options.
+
+line.c          Added #line logmode {html|plain|raw} {argument} Allows you
+                to execute a command with a temporary logging mode.
+
+mapper.c        Now drawing + and - for muds using nu dn eu ed exits.
+
+macro.c         Added ^ support to macros to make a macro only trigger at the
+                start of input. If you want to macro a literal ^ use \^ at
+                the start of the line. It behaves very similar to the ~ for
+                color triggers.
+
+mapper.c        Improved exit drawing in unicode mode.
+
+draw.c          Added #draw command and #help file.
+
+mapper.c        Added #map update option to force an update of the vtmap. Keep
+                in mind the vtmap will only update once every 0.1 seconds.
+
+screen.c        Added #screen clear {split|top|bottom} to clear split lines.
+
+config.c        Added #config {wordwrap {on|off|number} when a number is given
+                tintin will wrap at the given width, and will also report the
+                given width to MUDs over TELNET.
+
+config.c        Added #config {telnet} {on|off|debug} which allows enabling or
+                disabling telnet support. The debug option is the same as
+                #config {debug telnet} on and will eventually replace it. To
+                disable debug mode use #config telnet on.
+
+help.c          Added #help button
+
+button.c        Added #button.
+
+Jul 2019        2.01.90
 ------------------------------------------------------------------------------
 mapper.c        Added MAP FOLLOWED MAP event which triggers on map movement.
                 %0 = new vnum %1 = old vnum %2 = exit name. Keep in mind
@@ -118,8 +169,6 @@ mapper.c        Further improved unicodegraphics mode.
 
 mapper.c        Further improved blockgraphics mode.
 
-mapper.c        Hidden rooms are now shown to avoid confusion.
-
 mapper.c        Added #map color avoid
 
 mapper.c        Added #map color hide
@@ -176,10 +225,6 @@ event.c         Changed all MOUSE events to %0=row %1=col %2=-row %3=-row
                 and because I've repeatedly swapped row and col in VT100 which
                 can be a tricky bug to track down.
 
-Jul 2019        2.01.9 (beta)
-------------------------------------------------------------------------------
-
-
 session.c       Added the 'ats' keyword to the session find routine to return
                 the active tintin session.
 

+ 8 - 9
src/Makefile.in

@@ -57,15 +57,14 @@ DEFAULT_FILE_DIR = $(HOME)
 FFLAGS= $(F1) $(F6)
 
 
-OFILES = action.o alias.o files.o help.o highlight.o strhash.o input.o log.o \
-         main.o misc.o net.o parse.o path.o update.o history.o tab.o vt102.o \
-         terminal.o session.o function.o text.o substitute.o tick.o memory.o \
-         math.o split.o debug.o tinexp.o mapper.o tables.o buffer.o prompt.o \
-         class.o event.o tokenize.o chat.o utf8.o config.o gag.o advertise.o \
-         list.o forkpty.o cursor.o system.o line.o data.o variable.o macro.o \
-         msdp.o ssl.o port.o scan.o telopt_client.o screen.o telopt_server.o \
-         utils.o nest.o show.o mccp.o
-
+OFILES = \
+files.o help.o strhash.o input.o main.o misc.o net.o parse.o debug.o \
+update.o history.o vt102.o terminal.o text.o memory.o math.o split.o \
+system.o mapper.o tables.o buffer.o event.o tokenize.o chat.o utf8.o \
+advertise.o list.o forkpty.o utils.o line.o data.o variable.o msdp.o \
+port.o scan.o telopt_client.o screen.o cursor.o nest.o show.o mccp.o \
+telopt_server.o draw.o log.o path.o session.o class.o config.o ssl.o \
+regex.o trigger.o substitute.o
 
 default: all
 

+ 0 - 89
src/action.c

@@ -1,89 +0,0 @@
-/******************************************************************************
-*   This file is part of TinTin++                                             *
-*                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
-*                                                                             *
-*   TinTin++ 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 3 of the License, 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 TinTin++.  If not, see https://www.gnu.org/licenses.           *
-******************************************************************************/
-
-/******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
-*                                                                             *
-*                         coded by Peter Unold 1992                           *
-******************************************************************************/
-
-#include "tintin.h"
-
-DO_COMMAND(do_action)
-{
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE];
-
-	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
-	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
-	arg = get_arg_in_braces(ses, arg, arg3, GET_ALL);
-
-	if (*arg3 == 0)
-	{
-		strcpy(arg3, "5");
-	}
-
-	if (*arg1 == 0)
-	{
-		show_list(ses->list[LIST_ACTION], 0);
-	}
-	else if (*arg1 && *arg2 == 0)
-	{
-		if (show_node_with_wild(ses, arg1, ses->list[LIST_ACTION]) == FALSE)
-		{
-			show_message(ses, LIST_ACTION, "#ACTION: NO MATCH(ES) FOUND FOR {%s}.", arg1);
-		}
-	}
-	else
-	{
-		update_node_list(ses->list[LIST_ACTION], arg1, arg2, arg3, "");
-
-		show_message(ses, LIST_ACTION, "#OK. #ACTION {%s} NOW TRIGGERS {%s} @ {%s}.", arg1, arg2, arg3);
-	}
-	return ses;
-}
-
-
-DO_COMMAND(do_unaction)
-{
-	delete_node_with_wild(ses, LIST_ACTION, arg);
-
-	return ses;
-}
-
-
-void check_all_actions(struct session *ses, char *original, char *line)
-{
-	struct listroot *root = ses->list[LIST_ACTION];
-	char buf[BUFFER_SIZE];
-
-	for (root->update = 0 ; root->update < root->used ; root->update++)
-	{
-		if (check_one_regexp(ses, root->list[root->update], line, original, 0))
-		{
-			show_debug(ses, LIST_ACTION, "#DEBUG ACTION {%s}", root->list[root->update]->arg1);
-
-			substitute(ses, root->list[root->update]->arg2, buf, SUB_ARG|SUB_SEC);
-
-			script_driver(ses, LIST_ACTION, buf);
-
-			return;
-		}
-	}
-}

+ 0 - 151
src/alias.c

@@ -1,151 +0,0 @@
-/******************************************************************************
-*   This file is part of TinTin++                                             *
-*                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
-*                                                                             *
-*   TinTin++ 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 3 of the License, 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 TinTin++.  If not, see https://www.gnu.org/licenses.           *
-******************************************************************************/
-
-/******************************************************************************
-*               (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                  *
-*                                                                             *
-*                        coded by Peter Unold 1992                            *
-*                   recoded by Igor van den Hoven 2009                        *
-******************************************************************************/
-
-#include "tintin.h"
-
-
-DO_COMMAND(do_alias)
-{
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE];
-
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
-	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
-	arg = get_arg_in_braces(ses, arg, arg3, GET_ALL);
-
-	if (*arg3 == 0)
-	{
-		strcpy(arg3, "5");
-	}
-
-	if (*arg1 == 0)
-	{
-		show_list(ses->list[LIST_ALIAS], 0);
-	}
-	else if (*arg2 == 0)
-	{
-		if (show_node_with_wild(ses, arg1, ses->list[LIST_ALIAS]) == FALSE)
-		{
-			show_message(ses, LIST_ALIAS, "#ALIAS: NO MATCH(ES) FOUND FOR {%s}.", arg1);
-		}
-	}
-	else
-	{
-		update_node_list(ses->list[LIST_ALIAS], arg1, arg2, arg3, "");
-
-		show_message(ses, LIST_ALIAS, "#ALIAS {%s} NOW TRIGGERS {%s} @ {%s}.", arg1, arg2, arg3);
-	}
-	return ses;
-}
-
-
-DO_COMMAND(do_unalias)
-{
-	delete_node_with_wild(ses, LIST_ALIAS, arg);
-
-	return ses;
-}
-
-int check_all_aliases(struct session *ses, char *input)
-{
-	struct listnode *node;
-	struct listroot *root;
-	char tmp[BUFFER_SIZE], line[BUFFER_SIZE], *arg;
-	int i;
-
-	root = ses->list[LIST_ALIAS];
-
-	if (HAS_BIT(root->flags, LIST_FLAG_IGNORE))
-	{
-		return FALSE;
-	}
-
-	substitute(ses, input, line, SUB_VAR|SUB_FUN);
-
-	for (root->update = 0 ; root->update < root->used ; root->update++)
-	{
-		if (check_one_regexp(ses, root->list[root->update], line, line, PCRE_ANCHORED))
-		{
-			node = root->list[root->update];
-
-			i = strlen(node->arg1);
-
-			if (!strncmp(node->arg1, line, i))
-			{
-				if (line[i])
-				{
-					if (line[i] != ' ')
-					{
-						continue;
-					}
-					arg = &line[i + 1];
-				}
-				else
-				{
-					arg = &line[i];
-				}
-
-				RESTRING(gtd->vars[0], arg)
-
-				for (i = 1 ; i < 100 ; i++)
-				{
-					arg = get_arg_in_braces(ses, arg, tmp, GET_ONE);
-
-					RESTRING(gtd->vars[i], tmp);
-
-					if (*arg == 0)
-					{
-						while (++i < 100)
-						{
-							if (*gtd->vars[i])
-							{
-								RESTRING(gtd->vars[i], "");
-							}
-						}
-						break;
-					}
-
-				}
-			}
-
-			substitute(ses, node->arg2, tmp, SUB_ARG);
-
-			if (!strncmp(node->arg1, line, strlen(node->arg1)) && !strcmp(node->arg2, tmp) && *gtd->vars[0])
-			{
-				sprintf(input, "%s %s", tmp, gtd->vars[0]);
-			}
-			else
-			{
-				sprintf(input, "%s", tmp);
-			}
-
-			show_debug(ses, LIST_ALIAS, "#DEBUG ALIAS {%s} {%s}", node->arg1, gtd->vars[0]);
-
-			return TRUE;
-		}
-	}
-	return FALSE;
-}

+ 12 - 15
src/buffer.c

@@ -200,11 +200,11 @@ void add_line_buffer(struct session *ses, char *line, int prompt)
 		str_hash_grep(ses->scroll->buffer[ses->scroll->row], TRUE);
 	}
 
-	if (!HAS_BIT(ses->flags, SES_FLAG_LOGLEVEL)) // flag name could be clearer
+	if (!HAS_BIT(ses->logmode, LOG_FLAG_LOW))
 	{
 		if (ses->logfile)
 		{
-			logit(ses, linebuf, ses->logfile, TRUE);
+			logit(ses, linebuf, ses->logfile, LOG_FLAG_LINEFEED);
 		}
 	}
 
@@ -321,7 +321,7 @@ DO_COMMAND(do_grep)
 				continue;
 			}
 
-			if (find(ses, ses->scroll->buffer[scroll_cnt], arg2, SUB_NONE))
+			if (find(ses, ses->scroll->buffer[scroll_cnt], arg2, SUB_NONE, SUB_NONE))
 			{
 				grep_add = str_hash_lines(ses->scroll->buffer[scroll_cnt]);
 
@@ -363,7 +363,7 @@ DO_COMMAND(do_grep)
 				continue;
 			}
 
-			if (find(ses, ses->scroll->buffer[scroll_cnt], arg2, SUB_NONE))
+			if (find(ses, ses->scroll->buffer[scroll_cnt], arg2, SUB_NONE, SUB_NONE))
 			{
 				grep_add = str_hash_lines(ses->scroll->buffer[scroll_cnt]);
 
@@ -404,7 +404,7 @@ DO_COMMAND(do_grep)
 				continue;
 			}
 
-			if (find(ses, ses->scroll->buffer[scroll_cnt], arg2, SUB_NONE))
+			if (find(ses, ses->scroll->buffer[scroll_cnt], arg2, SUB_NONE, SUB_NONE))
 			{
 				grep_add = str_hash_lines(ses->scroll->buffer[scroll_cnt]);
 
@@ -507,7 +507,7 @@ int show_buffer(struct session *ses)
 
 	if (ses->scroll->buffer[scroll_cnt] && scroll_cut)
 	{
-		word_wrap_split(ses, ses->scroll->buffer[scroll_cnt], temp, TRUE, scroll_cut, scroll_tmp - ses->scroll->base);
+		word_wrap_split(ses, ses->scroll->buffer[scroll_cnt], temp, ses->wrap, scroll_cut, scroll_tmp - ses->scroll->base);
 
 		printf("%s\n", temp);
 
@@ -550,7 +550,7 @@ int show_buffer(struct session *ses)
 
 	if (ses->scroll->buffer[scroll_cnt] && scroll_cut)
 	{
-		word_wrap_split(ses, ses->scroll->buffer[scroll_cnt], temp, TRUE, 0, scroll_cut);
+		word_wrap_split(ses, ses->scroll->buffer[scroll_cnt], temp, ses->wrap, 0, scroll_cut);
 
 		printf("%s\n", temp);
 
@@ -925,7 +925,7 @@ DO_BUFFER(buffer_find)
 				continue;
 			}
 
-			if (find(ses, ses->scroll->buffer[scroll_cnt], arg2, SUB_NONE))
+			if (find(ses, ses->scroll->buffer[scroll_cnt], arg2, SUB_NONE, SUB_NONE))
 			{
 				grep_cnt++;
 
@@ -962,7 +962,7 @@ DO_BUFFER(buffer_find)
 				continue;
 			}
 
-			if (find(ses, ses->scroll->buffer[scroll_cnt], arg2, SUB_NONE))
+			if (find(ses, ses->scroll->buffer[scroll_cnt], arg2, SUB_NONE, SUB_NONE))
 			{
 				grep_cnt--;
 
@@ -1067,10 +1067,7 @@ DO_BUFFER(buffer_write)
 		{
 			show_message(ses, LIST_COMMAND, "#OK: WRITING BUFFER TO '%s'.", arg1);
 
-			if (HAS_BIT(ses->flags, SES_FLAG_LOGHTML))
-			{
-				write_html_header(ses, fp);
-			}
+			loginit(ses, fp, LOG_FLAG_OVERWRITE | HAS_BIT(ses->logmode, LOG_FLAG_HTML));
 
 			cnt = ses->scroll->row;
 
@@ -1090,11 +1087,11 @@ DO_BUFFER(buffer_write)
 					continue;
 				}
 
-				if (HAS_BIT(ses->flags, SES_FLAG_LOGPLAIN))
+				if (HAS_BIT(ses->logmode, LOG_FLAG_PLAIN))
 				{
 					strip_vt102_codes(ses->scroll->buffer[cnt], out);
 				}
-				else if (HAS_BIT(ses->flags, SES_FLAG_LOGHTML))
+				else if (HAS_BIT(ses->logmode, LOG_FLAG_HTML))
 				{
 					vt102_to_html(ses, ses->scroll->buffer[cnt], out);
 				}

+ 3 - 1
src/chat.c

@@ -81,6 +81,8 @@ DO_COMMAND(do_chat)
 		arg = sub_arg_in_braces(ses, arg, arg1,  chat_table[cnt].lval, SUB_VAR|SUB_FUN);
 		arg = sub_arg_in_braces(ses, arg, arg2, chat_table[cnt].rval, SUB_VAR|SUB_FUN);
 
+		chat_table[cnt].fun(arg1, arg2);
+
 		return ses;
 	}
 
@@ -2197,7 +2199,7 @@ DO_CHAT(chat_cancelfile)
 
 DO_CHAT(chat_color)
 {
-	if (*arg1 == 0 || get_highlight_codes(gtd->ses, arg1, arg2) == FALSE)
+	if (*arg1 == 0 || get_color_names(gtd->ses, arg1, arg2) == FALSE)
 	{
 		chat_printf("Valid colors are:\n\nreset, bold, dim, light, dark, underscore, blink, reverse, black, red, green, yellow, blue, magenta, cyan, white, b black, b red, b green, b yellow, b blue, b magenta, b cyan, b white");
 

+ 8 - 1
src/class.c

@@ -75,6 +75,8 @@ DO_COMMAND(do_class)
 		{
 			if (!search_node_list(ses->list[LIST_CLASS], arg1))
 			{
+				check_all_events(ses, SUB_ARG, 0, 1, "CLASS CREATED", arg1);
+
 				update_node_list(ses->list[LIST_CLASS], arg1, arg2, arg3, "");
 			}
 			class_table[i].group(ses, arg1, arg3);
@@ -285,8 +287,11 @@ DO_CLASS(class_kill)
 
 	if (!search_node_list(ses->list[LIST_CLASS], arg1))
 	{
-		update_node_list(ses->list[LIST_CLASS], arg1, "", "0", "");
+		show_error(ses, LIST_CLASS, "#CLASS {%s} DOES NOT EXIST.", arg1);
+
+		return ses;
 	}
+
 	group = search_index_list(ses->list[LIST_CLASS], arg1, NULL);
 
 	for (type = 0 ; type < LIST_MAX ; type++)
@@ -305,6 +310,8 @@ DO_CLASS(class_kill)
 		}
 	}
 
+	check_all_events(ses, SUB_ARG, 0, 1, "CLASS DESTROYED", arg1);
+
 	delete_index_list(ses->list[LIST_CLASS], group);
 
 	show_message(ses, LIST_CLASS, "#CLASS {%s} HAS BEEN KILLED.", arg1);

+ 54 - 12
src/config.c

@@ -203,18 +203,29 @@ DO_CONFIG(config_wordwrap)
 {
 	if (!strcasecmp(arg, "ON"))
 	{
-		SET_BIT(ses->flags, SES_FLAG_WORDWRAP);
+		ses->wrap = -1;
 	}
 	else if (!strcasecmp(arg, "OFF"))
 	{
-		DEL_BIT(ses->flags, SES_FLAG_WORDWRAP);
+		ses->wrap = 0;
+	}
+	else if (is_number(arg))
+	{
+		if (atoi(arg) < 1 || atoi(arg) > 10000)
+		{
+			show_error(ses, LIST_CONFIG, "#ERROR: #CONFIG BUFFER: PROVIDE A NUMBER BETWEEN 1 and 10000");
+
+			return NULL;
+		}
+		ses->wrap = atoi(arg);
 	}
 	else
 	{
-		show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF>", config_table[index].name);
+		show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF|NUMBER>", config_table[index].name);
 
 		return NULL;
 	}
+
 	update_node_list(ses->list[LIST_CONFIG], config_table[index].name, capitalize(arg), "", "");
 
 	SET_BIT(gtd->flags, TINTIN_FLAG_RESETBUFFER);
@@ -222,22 +233,25 @@ DO_CONFIG(config_wordwrap)
 	return ses;
 }
 
-DO_CONFIG(config_log)
+DO_CONFIG(config_logmode)
 {
 	if (!strcasecmp(arg, "HTML"))
 	{
-		DEL_BIT(ses->flags, SES_FLAG_LOGPLAIN);
-		SET_BIT(ses->flags, SES_FLAG_LOGHTML);
+		SET_BIT(ses->logmode, LOG_FLAG_HTML);
+		DEL_BIT(ses->logmode, LOG_FLAG_PLAIN);
+		DEL_BIT(ses->logmode, LOG_FLAG_RAW);
 	}
 	else if (!strcasecmp(arg, "PLAIN"))
 	{
-		SET_BIT(ses->flags, SES_FLAG_LOGPLAIN);
-		DEL_BIT(ses->flags, SES_FLAG_LOGHTML);
+		DEL_BIT(ses->logmode, LOG_FLAG_HTML);
+		SET_BIT(ses->logmode, LOG_FLAG_PLAIN);
+		DEL_BIT(ses->logmode, LOG_FLAG_RAW);
 	}
 	else if (!strcasecmp(arg, "RAW"))
 	{
-		DEL_BIT(ses->flags, SES_FLAG_LOGPLAIN);
-		DEL_BIT(ses->flags, SES_FLAG_LOGHTML);
+		DEL_BIT(ses->logmode, LOG_FLAG_HTML);
+		DEL_BIT(ses->logmode, LOG_FLAG_PLAIN);
+		SET_BIT(ses->logmode, LOG_FLAG_RAW);
 	}
 	else
 	{
@@ -416,6 +430,34 @@ DO_CONFIG(config_debugtelnet)
 	return ses;
 }
 
+DO_CONFIG(config_telnet)
+{
+	if (!strcasecmp(arg, "ON"))
+	{
+		DEL_BIT(ses->telopts, TELOPT_FLAG_DEBUG);
+		SET_BIT(ses->flags, SES_FLAG_TELNET);
+	}
+	else if (!strcasecmp(arg, "OFF"))
+	{
+		DEL_BIT(ses->telopts, TELOPT_FLAG_DEBUG);
+		DEL_BIT(ses->flags, SES_FLAG_TELNET);
+	}
+	else if (!strcasecmp(arg, "DEBUG"))
+	{
+		SET_BIT(ses->telopts, TELOPT_FLAG_DEBUG);
+		SET_BIT(ses->flags, SES_FLAG_TELNET);
+	}
+	else
+	{
+		show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF|DEBUG>", config_table[index].name);
+
+		return NULL;
+	}
+	update_node_list(ses->list[LIST_CONFIG], config_table[index].name, capitalize(arg), "", "");
+
+	return ses;
+}
+
 DO_CONFIG(config_convertmeta)
 {
 	if (!strcasecmp(arg, "ON"))
@@ -441,11 +483,11 @@ DO_CONFIG(config_loglevel)
 {
 	if (!strcasecmp(arg, "LOW"))
 	{
-		SET_BIT(ses->flags, SES_FLAG_LOGLEVEL);
+		SET_BIT(ses->logmode, LOG_FLAG_LOW);
 	}
 	else if (!strcasecmp(arg, "HIGH"))
 	{
-		DEL_BIT(ses->flags, SES_FLAG_LOGLEVEL);
+		DEL_BIT(ses->logmode, LOG_FLAG_LOW);
 	}
 	else
 	{

+ 10 - 3
src/cursor.c

@@ -694,7 +694,7 @@ DO_CURSOR(cursor_history_next)
 
 		for (root->update++ ; root->update < root->used ; root->update++)
 		{
-			if (*gtd->input_buf && find(ses, root->list[root->update]->arg1, gtd->input_buf, SUB_NONE))
+			if (*gtd->input_buf && find(ses, root->list[root->update]->arg1, gtd->input_buf, SUB_NONE, SUB_NONE))
 			{
 				break;
 			}
@@ -758,7 +758,7 @@ DO_CURSOR(cursor_history_prev)
 
 		for (root->update-- ; root->update >= 0 ; root->update--)
 		{
-			if (*gtd->input_buf && find(ses, root->list[root->update]->arg1, gtd->input_buf, SUB_NONE))
+			if (*gtd->input_buf && find(ses, root->list[root->update]->arg1, gtd->input_buf, SUB_NONE, SUB_NONE))
 			{
 				break;
 			}
@@ -877,14 +877,18 @@ DO_CURSOR(cursor_history_find)
 		}
 	}
 
+	gtd->quiet_level++;
+
 	for (root->update = root->used - 1 ; root->update >= 0 ; root->update--)
 	{
-		if (*gtd->input_buf && find(ses, root->list[root->update]->arg1, gtd->input_buf, SUB_NONE))
+		if (*gtd->input_buf && find(ses, root->list[root->update]->arg1, gtd->input_buf, SUB_NONE, SUB_NONE))
 		{
 			break;
 		}
 	}
 
+	gtd->quiet_level--;
+
 	if (root->update >= 0)
 	{
 		input_printf("\e[%dG ]  %.*s\e[%dG", gtd->input_off + inputline_cur_str_len(), gtd->input_off + inputline_max_str_len() - inputline_cur_str_len() - 4, root->list[root->update]->arg1, gtd->input_off + gtd->input_pos - gtd->input_hid);
@@ -1066,11 +1070,14 @@ DO_CURSOR(cursor_redraw_input)
 	}
 	else
 	{
+//		cursor_redraw_line(ses, "");
+
 		input_printf("\e[1G\e[0K%s%s\e[0K", ses->more_output, gtd->input_buf);
 
 		gtd->input_cur = gtd->input_len;
 
 		gtd->input_pos = gtd->input_len % gtd->screen->cols;
+
 	}
 }
 

+ 39 - 14
src/data.c

@@ -121,6 +121,11 @@ struct listnode *insert_node_list(struct listroot *root, char *arg1, char *arg2,
 
 	node = (struct listnode *) calloc(1, sizeof(struct listnode));
 
+	if (HAS_BIT(root->flags, LIST_FLAG_PRIORITY) && *arg3 == 0)
+	{
+		strcpy(arg3, "5");
+	}
+
 	node->arg1 = strdup(arg1);
 	node->arg2 = strdup(arg2);
 	node->arg3 = strdup(arg3);
@@ -179,6 +184,11 @@ struct listnode *update_node_list(struct listroot *root, char *arg1, char *arg2,
 				break;
 		}
 
+		if (HAS_BIT(root->flags, LIST_FLAG_PRIORITY) && *arg3 == 0)
+		{
+			strcpy(arg3, "5");
+		}
+
 		switch (list_table[root->type].mode)
 		{
 			case SORT_PRIORITY:
@@ -495,26 +505,33 @@ int nsearch_list(struct listroot *root, char *text)
 
 void show_node(struct listroot *root, struct listnode *node, int level)
 {
-	char *str = str_dup("");
+	char *str_arg2 = str_dup("");
 
-	show_nest_node(node, &str, TRUE);
+	show_nest_node(node, &str_arg2, TRUE);
 
 	switch (list_table[root->type].args)
 	{
 		case 4:
-			tintin_printf2(root->ses, "%s" COLOR_TINTIN "#" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}", indent(level), list_table[root->type].name, node->arg1, str, node->arg3, node->arg4);
+			tintin_printf2(root->ses, "%s" COLOR_TINTIN "#" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}", indent(level), list_table[root->type].name, node->arg1, str_arg2, node->arg3, node->arg4);
 			break;
 		case 3:
-			tintin_printf2(root->ses, "%s" COLOR_TINTIN "#" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}", indent(level), list_table[root->type].name, node->arg1, str, node->arg3);
+			if (HAS_BIT(list_table[root->type].flags, LIST_FLAG_PRIORITY) && !strcmp(node->arg3, "5"))
+			{
+				tintin_printf2(root->ses, "%s" COLOR_TINTIN "#" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}", indent(level), list_table[root->type].name, node->arg1, str_arg2);
+			}
+			else
+			{
+				tintin_printf2(root->ses, "%s" COLOR_TINTIN "#" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}", indent(level), list_table[root->type].name, node->arg1, str_arg2, node->arg3);
+			}
 			break;
 		case 2:
-			tintin_printf2(root->ses, "%s" COLOR_TINTIN "#" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}", indent(level), list_table[root->type].name, node->arg1, str);
+			tintin_printf2(root->ses, "%s" COLOR_TINTIN "#" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}", indent(level), list_table[root->type].name, node->arg1, str_arg2);
 			break;
 		case 1:
 			tintin_printf2(root->ses, "%s" COLOR_TINTIN "#" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", indent(level), list_table[root->type].name, node->arg1);
 			break;
 	}
-	str_free(str);
+	str_free(str_arg2);
 }
 
 /*
@@ -554,16 +571,24 @@ int show_node_with_wild(struct session *ses, char *text, struct listroot *root)
 			case LIST_FUNCTION:
 			case LIST_MACRO:
 				tintin_printf2(ses, COLOR_TINTIN "%c" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\n{\n" COLOR_STRING "%s\n" COLOR_BRACE "}\n\n", gtd->tintin_char, list_table[root->type].name, node->arg1, script_viewer(ses, node->arg2));
-//				show_lines(ses, SUB_COL, "<138>%c<168>%s <258>{<278>%s<258>}\n<158>{\n<278>%s\n<258>}<088>\n\n", gtd->tintin_char, list_table[root->type].name, node->arg1, script_viewer(ses, node->arg2));
 				break;
 
 			case LIST_ACTION:
 			case LIST_ALIAS:
+			case LIST_BUTTON:
+				if (!strcmp(node->arg3, "5"))
+				{
+					tintin_printf2(ses, COLOR_TINTIN "%c" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\n{\n" COLOR_STRING "%s\n" COLOR_BRACE "}\n", gtd->tintin_char, list_table[root->type].name, node->arg1, script_viewer(ses, node->arg2));
+				}
+				else
+				{
+					tintin_printf2(ses, COLOR_TINTIN "%c" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\n{\n" COLOR_STRING "%s\n" COLOR_BRACE "}\n{" COLOR_STRING "%s" COLOR_BRACE "}\n", gtd->tintin_char, list_table[root->type].name, node->arg1, script_viewer(ses, node->arg2), node->arg3);
+				}
+				break;
+
 			case LIST_DELAY:
 			case LIST_TICKER:
-			case LIST_SUBSTITUTE:
 				tintin_printf2(ses, COLOR_TINTIN "%c" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\n{\n" COLOR_STRING "%s\n" COLOR_BRACE "}\n{" COLOR_STRING "%s" COLOR_BRACE "}\n\n", gtd->tintin_char, list_table[root->type].name, node->arg1, script_viewer(ses, node->arg2), node->arg3);
-//				show_lines(ses, SUB_COL, "<138>%c<168>%s <258>{<278>%s<258>}\n<258>{\n<278>%s\n<258>}\n<258>{<278>%s<258>}<088>\n\n", gtd->tintin_char, list_table[root->type].name, node->arg1, script_viewer(ses, node->arg2), node->arg3);
 				break;
 
 			default:
@@ -998,7 +1023,7 @@ DO_COMMAND(do_info)
 
 					add_nest_node(ses->list[LIST_VARIABLE], name, "{CLIENT}{{NAME}{%s}{VERSION}{%-3s}}", CLIENT_NAME, CLIENT_VERSION);
 
-					add_nest_node(ses->list[LIST_VARIABLE], name, "{SCROLL}{{BASE}{%d}{LINE}{%d}{MAX}{%d}{ROW}{%d}}", ses->scroll->base, ses->scroll->line, ses->scroll->max, ses->scroll->row);
+					add_nest_node(ses->list[LIST_VARIABLE], name, "{HOME}{%s}{LANG}{%s}{OS}{%s}{TERM}{%s}", gtd->home, gtd->lang, gtd->os, gtd->term);
 
 					show_message(ses, LIST_COMMAND, "#INFO: DATA WRITTEN TO {info[SYSTEM]}");
 				}
@@ -1006,10 +1031,10 @@ DO_COMMAND(do_info)
 				{
 					tintin_printf2(ses, "#INFO SYSTEM: CLIENT_NAME = %s", CLIENT_NAME);
 					tintin_printf2(ses, "#INFO SYSTEM: CLIENT_VERSION = %s", CLIENT_VERSION);
-					tintin_printf2(ses, "#INFO SYSTEM: SCROLL_BASE = %d", ses->scroll->base);
-					tintin_printf2(ses, "#INFO SYSTEM: SCROLL_LINE = %d", ses->scroll->line);
-					tintin_printf2(ses, "#INFO SYSTEM: SCROLL_MAX = %d", ses->scroll->max);
-					tintin_printf2(ses, "#INFO SYSTEM: SCROLL_ROW = %d", ses->scroll->row);
+					tintin_printf2(ses, "#INFO SYSTEM: HOME = %s", gtd->home);
+					tintin_printf2(ses, "#INFO SYSTEM: LANG = %s", gtd->lang);
+					tintin_printf2(ses, "#INFO SYSTEM: OS = %s", gtd->os);
+					tintin_printf2(ses, "#INFO SYSTEM: TERM = %s", gtd->term);
 				}
 			}
 			else

+ 10 - 0
src/debug.c

@@ -90,6 +90,16 @@ void dump_stack(void)
 	}
 }
 
+void dump_stack_fatal(void)
+{
+	unsigned char i;
+
+	for (i = 0 ; i < debug_index && i < MAX_STACK_SIZE ; i++)
+	{
+		printf("\e[1;32mDEBUG_STACK[\e[1;31m%03d\e[1;32m] = \e[1;31m%s\e[0m\n", i, debug_stack[i]);
+	}
+}
+
 void dump_full_stack(void)
 {
 	unsigned char i;

+ 10 - 0
src/event.c

@@ -282,6 +282,8 @@ void mouse_handler(struct session *ses, int flags, int row, int col, char type)
 		}
 	}
 
+	check_all_buttons(ses, row, col, arg1, arg2, word, line);
+
 	check_all_events(ses, SUB_ARG, 2, 6, "%s %s", arg1, arg2, ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);
 
 	check_all_events(ses, SUB_ARG, 3, 6, "%s %s %d", arg1, arg2, row, ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);
@@ -304,6 +306,8 @@ void mouse_handler(struct session *ses, int flags, int row, int col, char type)
 			{
 				if (click[0] - click[2] < 500000)
 				{
+					check_all_buttons(ses, row, col, "TRIPLE-CLICKED", arg2, word, line);
+
 					check_all_events(ses, SUB_ARG, 1, 6, "TRIPLE-CLICKED %s", arg2, ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);
 
 					check_all_events(ses, SUB_ARG, 2, 6, "TRIPLE-CLICKED %s %d", arg2, row, ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);
@@ -316,6 +320,8 @@ void mouse_handler(struct session *ses, int flags, int row, int col, char type)
 				}
 				else
 				{
+					check_all_buttons(ses, row, col, "DOUBLE-CLICKED", arg2, word, line);
+
 					check_all_events(ses, SUB_ARG, 1, 6, "DOUBLE-CLICKED %s", arg2, ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);
 
 					check_all_events(ses, SUB_ARG, 2, 6, "DOUBLE-CLICKED %s %d", arg2, row, ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);
@@ -339,6 +345,8 @@ void mouse_handler(struct session *ses, int flags, int row, int col, char type)
 	{
 		if (utime() - click[0] >= 500000)
 		{
+			check_all_buttons(ses, row, col, "LONG-CLICKED", arg2, word, line);
+
 			check_all_events(ses, SUB_ARG, 1, 6, "LONG-CLICKED %s", arg2, ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);
 
 			check_all_events(ses, SUB_ARG, 2, 6, "LONG-CLICKED %s %d", arg2, row, ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);
@@ -349,6 +357,8 @@ void mouse_handler(struct session *ses, int flags, int row, int col, char type)
 		}
 		else if (click[0] - click[1] >= 500000)
 		{
+			check_all_buttons(ses, row, col, "SHORT-CLICKED", arg2, word, line);
+
 			check_all_events(ses, SUB_ARG, 1, 6, "SHORT-CLICKED %s", arg2, ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);
 
 			check_all_events(ses, SUB_ARG, 2, 6, "SHORT-CLICKED %s %d", arg2, row, ntos(row), ntos(col), ntos(-1 - (gtd->screen->rows - row)), ntos(-1 - (gtd->screen->cols - col)), word, line);

+ 21 - 5
src/files.c

@@ -287,7 +287,7 @@ DO_COMMAND(do_read)
 
 	sprintf(temp, "{TINTIN CHAR} {%c}", bufo[0]);
 
-	gtd->quiet++;
+	gtd->quiet_level++;
 
 	do_configure(ses, temp);
 
@@ -306,7 +306,7 @@ DO_COMMAND(do_read)
 
 		if (strlen(bufi) >= BUFFER_SIZE)
 		{
-/*			gtd->quiet--;
+/*			gtd->quiet_level--;
 
 			bufi[20] = 0;
 */
@@ -329,7 +329,7 @@ DO_COMMAND(do_read)
 		pti++;
 	}
 
-	gtd->quiet--;
+	gtd->quiet_level--;
 
 	if (!HAS_BIT(ses->flags, SES_FLAG_VERBOSE))
 	{
@@ -367,7 +367,7 @@ DO_COMMAND(do_write)
 	FILE *file;
 	char filename[BUFFER_SIZE], forceful[BUFFER_SIZE];
 	struct listroot *root;
-	int i, j, cnt = 0;
+	int i, j, fix, cnt = 0;
 
 	arg = get_arg_in_braces(ses, arg, filename, GET_ONE);
 	arg = get_arg_in_braces(ses, arg, forceful, GET_ONE);
@@ -402,6 +402,8 @@ DO_COMMAND(do_write)
 			continue;
 		}
 
+		fix = 0;
+
 		for (j = 0 ; j < root->used ; j++)
 		{
 			if (*root->list[j]->group == 0)
@@ -409,8 +411,14 @@ DO_COMMAND(do_write)
 				write_node(ses, i, root->list[j], file);
 
 				cnt++;
+				fix++;
 			}
 		}
+
+		if (fix)
+		{
+			fputs("\n", file);
+		}
 	}
 
 	fclose(file);
@@ -440,7 +448,15 @@ void write_node(struct session *ses, int list, struct listnode *node, FILE *file
 
 		case LIST_ACTION:
 		case LIST_ALIAS:
-			asprintf(&result, "%c%s {%s}\n{\n%s\n}\n{%s}\n\n", gtd->tintin_char, list_table[list].name, node->arg1, script_writer(ses, node->arg2), node->arg3);
+		case LIST_BUTTON:
+			if (!strcmp(node->arg3, "5"))
+			{
+				asprintf(&result, "%c%s {%s}\n{\n%s\n}\n\n", gtd->tintin_char, list_table[list].name, node->arg1, script_writer(ses, node->arg2));
+			}
+			else
+			{
+				asprintf(&result, "%c%s {%s}\n{\n%s\n}\n{%s}\n\n", gtd->tintin_char, list_table[list].name, node->arg1, script_writer(ses, node->arg2), node->arg3);
+			}
 			break;
 
 		case LIST_VARIABLE:

+ 0 - 72
src/gag.c

@@ -1,72 +0,0 @@
-/******************************************************************************
-*   This file is part of TinTin++                                             *
-*                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
-*                                                                             *
-*   TinTin++ 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 3 of the License, 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 TinTin++.  If not, see https://www.gnu.org/licenses.           *
-******************************************************************************/
-
-/******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
-*                                                                             *
-*                       coded by Igor van den Hoven 2007                      *
-******************************************************************************/
-
-
-#include "tintin.h"
-
-DO_COMMAND(do_gag)
-{
-	char arg1[BUFFER_SIZE];
-
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
-
-	if (*arg1 == 0)
-	{
-		show_list(ses->list[LIST_GAG], 0);
-	}
-	else
-	{
-		update_node_list(ses->list[LIST_GAG], arg1, "", "", "");
-
-		show_message(ses, LIST_GAG, "#OK. {%s} IS NOW GAGGED.", arg1);
-	}
-	return ses;
-}
-
-
-DO_COMMAND(do_ungag)
-{
-	delete_node_with_wild(ses, LIST_GAG, arg);
-
-	return ses;
-}
-
-void check_all_gags(struct session *ses, char *original, char *line)
-{
-	struct listroot *root = ses->list[LIST_GAG];
-
-	for (root->update = 0 ; root->update < root->used ; root->update++)
-	{
-		if (check_one_regexp(ses, root->list[root->update], line, original, 0))
-		{
-			show_debug(ses, LIST_GAG, "#DEBUG GAG {%s}", root->list[root->update]->arg1);
-
-			SET_BIT(ses->flags, SES_FLAG_GAG);
-
-			return;
-		}
-	}
-}

+ 109 - 20
src/help.c

@@ -41,6 +41,8 @@ char *help_related(struct session *ses, int index, int html)
 	char tmp[BUFFER_SIZE], link[BUFFER_SIZE];
 	static char buf[BUFFER_SIZE];
 
+	push_call("help_related(%p,%d,%d)",ses,index,html);
+
 	arg = help_table[index].also;
 
 	buf[0] = 0;
@@ -67,10 +69,11 @@ char *help_related(struct session *ses, int index, int html)
 			}
 			else
 			{
-				cat_sprintf(buf, " and %s.");
+				cat_sprintf(buf, " and %s.", tmp);
 			}
 		}
 	}
+	pop_call();
 	return buf;
 }
 
@@ -89,7 +92,7 @@ DO_COMMAND(do_help)
 		{
 			if (strlen(buf) + 19 > gtd->screen->cols)
 			{
-				show_lines(ses, SUB_COL, "<088>%s<088>\n", buf);
+				print_lines(ses, SUB_COL, "<088>%s<088>\n", buf);
 
 				*buf = 0;
 			}
@@ -98,7 +101,7 @@ DO_COMMAND(do_help)
 
 		if (*buf)
 		{
-			show_lines(ses, SUB_COL, "<088>%s<088>\n", buf);
+			print_lines(ses, SUB_COL, "<088>%s<088>\n", buf);
 		}
 	}
 	else if (!strcasecmp(arg1, "dump"))
@@ -107,7 +110,7 @@ DO_COMMAND(do_help)
 
 		do_configure(ses, "{log} {html}");
 
-		if (HAS_BIT(ses->flags, SES_FLAG_LOGHTML))
+		if (HAS_BIT(ses->logmode, LOG_FLAG_HTML))
 		{
 			write_html_header(ses, logfile);
 		}
@@ -213,11 +216,11 @@ DO_COMMAND(do_help)
 		{
 			if (is_abbrev(arg1, help_table[cnt].name))
 			{
-				show_lines(ses, SUB_COL, "%s<088>\n", help_table[cnt].text);
+				print_lines(ses, SUB_COL, "%s<088>\n", help_table[cnt].text);
 				
 				if (*help_table[cnt].also)
 				{
-					show_lines(ses, SUB_COL, "%s<088>\n\n", help_related(ses, cnt, 0));
+					print_lines(ses, SUB_COL, "%s<088>\n\n", help_related(ses, cnt, 0));
 				}
 				return ses;
 			}
@@ -228,11 +231,11 @@ DO_COMMAND(do_help)
 		{
 			if (match(ses, help_table[cnt].name, arg1, SUB_VAR|SUB_FUN))
 			{
-				show_lines(ses, SUB_COL, "%s<088>\n", help_table[cnt].text);
+				print_lines(ses, SUB_COL, "%s<088>\n", help_table[cnt].text);
 
 				if (*help_table[cnt].also)
 				{
-					show_lines(ses, SUB_COL, "%s<088>\n\n", help_related(ses, cnt, 0));
+					print_lines(ses, SUB_COL, "%s<088>\n\n", help_related(ses, cnt, 0));
 				}
 				found = TRUE;
 			}
@@ -455,6 +458,47 @@ struct help_type help_table[] =
 
 		"echo grep macro showme screen"
 	},
+	{
+		"BUTTON",
+
+		"<178>Command<278>: #button <178>{<278>square<178>} {<278>commands<178>} {<278>priority<178>}<278>\n"
+		"\n"
+		"         The #button command can be used to respond with one or several\n"
+		"         commands to a mouse click received within the specified square.\n"
+		"         The click coordinates are stored in %0-%3 and can be used in the\n"
+		"         command part of the button.\n"
+		"\n"
+		"         The square part should exists of two coordinates defining the\n"
+		"         upper left and bottom right corner using row, col, row, col syntax.\n"
+		"         The square arguments should be separated by spaces, semi-colons or\n"
+		"         braces.\n"
+		"\n"
+		"         By default the button is set to respond to a mouse button press, to\n"
+		"         respond to other button presses you must add a 5th argument to the\n"
+		"         square that defines the button press type. You can enable #info\n"
+		"         button on to see button events and their type as they happen.\n"
+		"\n"
+		"         The priority part is optional and determines the priority of the\n"
+		"         button, it defaults to 5.\n"
+		"\n"
+		"         You must enable #config {mouse tracking} on for buttons to work.\n"
+		"\n"
+		"         This command draws no visible button, you'll have to do so separately\n"
+		"         if needed.\n"
+		"\n"
+		"<178>Example<278>: #button {1;1;2;2} {#showme You clicked the upper left corner.}\n"
+		"\n"
+		"         Buttons are ordered alphabetically and only one button can trigger at\n"
+		"         a time. To change the order you can assign a priority, which defaults\n"
+		"         to 5, with a lower number indicating a higher priority. The priority\n"
+		"         can be a floating point number.\n"
+		"\n"
+		"<178>Comment<278>: To see button clicks trigger use #info button on.\n"
+		"\n"
+		"<178>Comment<278>: You can remove a button with the #unbutton command.\n",
+
+		"delay event ticker"
+	},
 	{
 		"CASE",
 
@@ -764,6 +808,33 @@ struct help_type help_table[] =
 		
 		"event ticker"
 	},
+	{
+		"DRAW",
+		
+		"<178>Command<278>: #draw <178>{<278>option<178>} {<278>square<178>} {<278>argument<178>}\n"
+		"<278>\n"
+		"         The draw commands allows you to draw various lines and shapes on the\n"
+		"         screen. Available options and a brief description are provided when\n"
+		"         you type #draw without an argument.\n"
+		"\n"
+		"         The square argument should exists of two coordinates defining the\n"
+		"         upper left and bottom right corner using row, col, row, col syntax.\n"
+		"\n"
+		"         You can prefix the option as following:\n"
+		"\n"
+		"         PRUNED  will prune the corners of any drawn shape.\n"
+		"         ROUNDED will round the corners.\n"
+		"         CROSSED will cross the corners.\n"
+		"\n"
+		"         Some draw options take an additional argument, most notably the\n"
+		"         BOX TEXT option which allows you to place the given text inside\n"
+		"         the drawn box.\n"
+		"\n"
+		"<178>Example<278>: #draw {box text} 1 1 3 20 {Hello world!}\n",
+
+		"buffer echo grep showme"
+	},
+
 	{
 		"ECHO",
 
@@ -904,7 +975,7 @@ struct help_type help_table[] =
 		"         SCAN CSV LINE         %0 all args %1 arg1 %2 arg3 .. %99 arg99\n"
 		"         SCAN TSV HEADER       %0 all args %1 arg1 %2 arg3 .. %99 arg99\n"
 		"         SCAN TSV LINE         %0 all args %1 arg1 %2 arg3 .. %99 arg99\n"
-		"         SCREEN RESIZE         %0 rows %1 cols\n"
+		"         SCREEN RESIZE         %0 rows %1 cols %1 height %2 width\n"
 		"         SCROLLED <VAR>        %0 row %1 col %2 -row %3 -col %4 word %5 line\n"
 		"         SECOND                %6 second\n"
 		"         SEND OUTPUT           %0 raw text %1 size\n"
@@ -921,17 +992,20 @@ struct help_type help_table[] =
 		"         TRIPLE-CLICKED <VAR>  %0 row %1 col %2 -row %3 -col %4 word %5 line\n"
 		"         UNKNOWN COMMAND       %0 raw text\n"
 		"         VARIABLE UPDATE <VAR> %0 name %1 value\n"
-		"         VT100 SCROLL REGION   %0 top row %1 bot row\n"
+		"         VT100 SCROLL REGION   %0 top row %1 bot row %2 rows %3 cols %4 wrap\n"
 		"         WEEK <DAY>            %2 day of the week\n"
 		"         WINDOW FOCUS IN       %0 name\n"
 		"         WINDOW FOCUS OUT      %0 name\n"
 		"         YEAR                  %0 year\n"
 		"\n"
+		"         To see all events trigger use #event info on. Since this can quite\n"
+		"         spammy it's possible to gag event info messages.\n"
+		"\n"
 		"<178>Example<278>: #event {SESSION CONNECTED} {#read mychar.tin}\n"
 		"\n"
 		"<178>Comment<278>: You can remove an event with the #unevent command.\n",
 		
-		"delay ticker"
+		"button delay ticker"
 	},
 	{
 		"FORALL",
@@ -1556,16 +1630,19 @@ struct help_type help_table[] =
 
 		"<178>Command<278>: #line <178>{<278>option<178>} {<278>argument<178>}<278>\n"
 		"\n"
-		"         #line log {filename} {[text]}          Log the current or given line to\n"
-		"                                                file.\n"
-		"\n"
-		"         #line logverbatim {filename} {[text]}  Log text without variable\n"
-		"                                                substitution.\n"
+		"         #line background                       Prevent new session activation.\n"
 		"\n"
 		"         #line gag                              Gag the next line.\n"
 		"\n"
 		"         #line ignore {argument}                Argument is executed without\n"
 		"                                                any triggers being checked.\n"
+		"\n"
+		"         #line log {filename} {[text]}          Log the current or given line to\n"
+		"                                                file.\n"
+		"\n"
+		"         #line logverbatim {filename} {[text]}  Log text without variable\n"
+		"                                                substitution.\n"
+
 		"\n"
 		"         #line quiet {argument}                 Argument is executed with\n"
 		"                                                suppression of system messages.\n"
@@ -1690,6 +1767,9 @@ struct help_type help_table[] =
 		"         Another option is pressing ctrl-v, which will enable CONVERT META for\n"
 		"         the next key pressed.\n"
 		"\n"
+		"         If you only want a key sequence to trigger at the start of an input\n"
+		"         line prefix the key sequence with ^.\n"
+		"\n"
 		"<178>Example<278>: #macro {(press ctrl-v)(press F1)} {#showme \\e[2J;#buffer lock}\n"
 		"         Clear the screen and lock the window when you press F1, useful when the\n"
 		"         boss is near.\n"
@@ -1697,6 +1777,9 @@ struct help_type help_table[] =
 		"<178>Example<278>: #macro {\\eOM} {#cursor enter}\n"
 		"         Makes the keypad's enter key work as an enter in keypad mode.\n"
 		"\n"
+		"<178>Example<278>: #macro {^nn} {n}\n"
+		"         Makes pressing n twice on an empty line execute north.\n"
+		"\n"
 		"<178>Comment<278>: Not all terminals properly initialize the keypad key sequences.\n"
 		"         If this is the case you can still use the keypad, but instead of the\n"
 		"         arrow keys use ctrl b, f, p, and n.\n"
@@ -1712,8 +1795,8 @@ struct help_type help_table[] =
 		"\n"
 		"         The map command is the backbone of the auto mapping feature.\n"
 		"\n"
-		"         <178>#map at <location> <command>\n"
-		"         <278>  Execute the command at the location.\n"
+		"         <178>#map at <exit|vnum> <command>\n"
+		"         <278>  Execute the command at the given exit or vnum.\n"
 		"\n"
 		"         <178>#map color <field> [value]\n"
 		"         <278>  Sets the map color for the given color field.\n"
@@ -1851,6 +1934,11 @@ struct help_type help_table[] =
 		"         <278>  If {rows} or {cols} are a negative number this number is\n"
 		"         <278>  subtracted from the scrolling window size.\n"
 		"\n"
+		"         <178>#map map <rows> <cols> draw <square>\n"
+		"         <278>  Display a drawing of the map of the given height and width.\n"
+		"         <278>  The square argument exists of 4 numbers formulating the top\n"
+		"         <278>  left corner and bottom right corner of a square.\n"
+		"\n"
 		"         <278>  If you use {append|overwrite} the map is written to the specified\n"
 		"         <278>  file name which must be given as the 4th argument.\n"
 		"         <278>  If you use {list|variable} the map is saved to the specified\n"
@@ -1877,6 +1965,8 @@ struct help_type help_table[] =
 		"         <278>  Returns you to your last known room after leaving the map\n"
 		"         <278>  or loading a map.\n"
 		"\n"
+		"         <178>#map roomflag <flags> <get|on|off>\n"
+		"         <278>\n"
 		"         <178>#map roomflag avoid\n"
 		"         <278>  When set, '#map find' will avoid a route leading\n"
 		"         <278>  through that room. Useful when you want to avoid death traps.\n"
@@ -2759,8 +2849,7 @@ struct help_type help_table[] =
 		"<178>Comment<278>: The #prompt helpfile contains more information on using the\n"
 		"         option {row} and {col} arguments.\n",
 
-		"buffer echo grep"
-		
+		"buffer draw echo grep"
 	},
 	{
 		"SNOOP",

+ 0 - 211
src/highlight.c

@@ -1,211 +0,0 @@
-/******************************************************************************
-*   This file is part of TinTin++                                             *
-*                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
-*                                                                             *
-*   TinTin++ 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 3 of the License, 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 TinTin++.  If not, see https://www.gnu.org/licenses.           *
-******************************************************************************/
-
-/******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
-*                                                                             *
-*                          coded by Bill Reiss 1993                           *
-*                     recoded by Igor van den Hoven 2004                      *
-******************************************************************************/
-
-
-#include "tintin.h"
-
-
-DO_COMMAND(do_highlight)
-{
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE], temp[BUFFER_SIZE];
-
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
-	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
-	arg = get_arg_in_braces(ses, arg, arg3, GET_ALL);
-
-	if (*arg3 == 0)
-	{
-		strcpy(arg3, "5");
-	}
-
-	if (*arg1 == 0)
-	{
-		show_list(ses->list[LIST_HIGHLIGHT], 0);
-	}
-	else if (*arg1 && *arg2 == 0)
-	{
-		if (show_node_with_wild(ses, arg1, ses->list[LIST_HIGHLIGHT]) == FALSE)
-		{
-			show_message(ses, LIST_HIGHLIGHT, "#HIGHLIGHT: NO MATCH(ES) FOUND FOR {%s}.", arg1);
-		}
-	}
-	else
-	{
-		if (get_highlight_codes(ses, arg2, temp) == FALSE)
-		{
-			tintin_printf2(ses, "#HIGHLIGHT: VALID COLORS ARE:\n");
-			tintin_printf2(ses, "reset, bold, light, faint, dim, dark, underscore, blink, reverse, black, red, green, yellow, blue, magenta, cyan, white, b black, b red, b green, b yellow, b blue, b magenta, b cyan, b white, azure, ebony, jade, lime, orange, pink, silver, tan, violet.");
-		}
-		else
-		{
-			update_node_list(ses->list[LIST_HIGHLIGHT], arg1, arg2, arg3, "");
-
-			show_message(ses, LIST_HIGHLIGHT, "#OK. {%s} NOW HIGHLIGHTS {%s} @ {%s}.", arg1, arg2, arg3);
-		}
-	}
-	return ses;
-}
-
-
-DO_COMMAND(do_unhighlight)
-{
-	delete_node_with_wild(ses, LIST_HIGHLIGHT, arg);
-
-	return ses;
-}
-
-void check_all_highlights(struct session *ses, char *original, char *line)
-{
-	struct listroot *root = ses->list[LIST_HIGHLIGHT];
-	struct listnode *node;
-	char *pto, *ptl, *ptm;
-	char match[BUFFER_SIZE], color[BUFFER_SIZE], reset[BUFFER_SIZE], output[BUFFER_SIZE], plain[BUFFER_SIZE];
-	int len;
-
-	push_call("check_all_highlights(%p,%p,%p)",ses,original,line);
-
-	for (root->update = 0 ; root->update < root->used ; root->update++)
-	{
-		if (check_one_regexp(ses, root->list[root->update], line, original, 0))
-		{
-			node = root->list[root->update];
-
-			get_highlight_codes(ses, node->arg2, color);
-
-			*output = *reset = 0;
-
-			pto = original;
-			ptl = line;
-
-			do
-			{
-				if (*gtd->vars[0] == 0)
-				{
-					break;
-				}
-
-				strcpy(match, gtd->vars[0]);
-
-				strip_vt102_codes(match, plain);
-
-				if (*node->arg1 == '~')
-				{
-					ptm = strstr(pto, match);
-
-					len = strlen(match);
-				}
-				else
-				{
-					ptm = strip_vt102_strstr(pto, match, &len);
-
-					ptl = strstr(ptl, match) + strlen(match);
-				}
-
-				*ptm = 0;
-
-				get_color_codes(reset, pto, reset);
-
-				cat_sprintf(output, "%s%s%s\e[0m%s", pto, color, plain, reset);
-
-				pto = ptm + len;
-
-				show_debug(ses, LIST_HIGHLIGHT, "#DEBUG HIGHLIGHT {%s}", node->arg1);
-			}
-			while (check_one_regexp(ses, node, ptl, pto, 0));
-
-			strcat(output, pto);
-
-			strcpy(original, output);
-		}
-	}
-	pop_call();
-	return;
-}
-
-int get_highlight_codes(struct session *ses, char *string, char *result)
-{
-	int cnt;
-
-	*result = 0;
-
-	if (*string == '<')
-	{
-		substitute(ses, string, result, SUB_COL);
-
-		return TRUE;
-	}
-
-	if (*string == '\\')
-	{
-		substitute(ses, string, result, SUB_ESC);
-
-		return TRUE;
-	}
-
-	while (*string)
-	{
-		if (isalpha((int) *string))
-		{
-			for (cnt = 0 ; *color_table[cnt].name ; cnt++)
-			{
-				if (is_abbrev(color_table[cnt].name, string))
-				{
-					substitute(ses, color_table[cnt].code, result, SUB_COL);
-
-					result += strlen(result);
-
-					break;
-				}
-			}
-
-			if (*color_table[cnt].name == 0)
-			{
-				return FALSE;
-			}
-
-			string += strlen(color_table[cnt].name);
-		}
-
-		switch (*string)
-		{
-			case ' ':
-			case ';':
-			case ',':
-			case '{':
-			case '}':
-				string++;
-				break;
-
-			case 0:
-				return TRUE;
-
-			default:
-				return FALSE;
-		}
-	}
-	return TRUE;
-}

+ 1 - 1
src/history.c

@@ -71,7 +71,7 @@ void add_line_history(struct session *ses, char *line)
 
 	root = ses->list[LIST_HISTORY];
 
-	if (HAS_BIT(root->flags, LIST_FLAG_IGNORE))
+	if (HAS_BIT(root->flags, LIST_FLAG_IGNORE) || gtd->ignore_level)
 	{
 		return;
 	}

+ 30 - 92
src/input.c

@@ -107,10 +107,14 @@ void read_line()
 
 	buffer[len] = 0;
 
-	if (HAS_BIT(gtd->ses->flags, SES_FLAG_CONVERTMETA) || HAS_BIT(gtd->flags, TINTIN_FLAG_CONVERTMETACHAR))
+	if (HAS_BIT(gtd->ses->flags, SES_FLAG_CONVERTMETA))
 	{
 		convert_meta(buffer, &gtd->macro_buf[strlen(gtd->macro_buf)], FALSE);
 	}
+	else if (HAS_BIT(gtd->flags, TINTIN_FLAG_CONVERTMETACHAR))
+	{
+		convert_meta(buffer, &gtd->macro_buf[strlen(gtd->macro_buf)], TRUE);
+	}
 	else
 	{
 		strcat(gtd->macro_buf, buffer);
@@ -127,7 +131,11 @@ void read_line()
 			{
 				node = root->list[root->update];
 
-				if (!strcmp(gtd->macro_buf, node->arg3))
+				if (*node->arg1 == '^' && gtd->input_len)
+				{
+					continue;
+				}
+				else if (!strcmp(gtd->macro_buf, node->arg3))
 				{
 					script_driver(gtd->ses, LIST_MACRO, node->arg2);
 
@@ -165,7 +173,7 @@ void read_line()
 			return;
 		}
 
-		if (gtd->macro_buf[0] == ESCAPE)
+		if (gtd->macro_buf[0] == ASCII_ESC)
 		{
 			if (gtd->macro_buf[1] == '[')
 			{
@@ -291,7 +299,7 @@ void read_line()
 		}
 	}
 
-	if (gtd->macro_buf[0] == ESCAPE)
+	if (gtd->macro_buf[0] == ASCII_ESC)
 	{
 		strcpy(buffer, gtd->macro_buf);
 
@@ -312,8 +320,8 @@ void read_line()
 	{
 		switch (gtd->macro_buf[0])
 		{
-			case '\r':
-			case '\n':
+			case ASCII_CR:
+			case ASCII_LF:
 				cursor_enter(gtd->ses, "");
 
 				memmove(gtd->macro_buf, &gtd->macro_buf[1], 1 + strlen(&gtd->macro_buf[1]));
@@ -430,7 +438,11 @@ void read_key(void)
 			{
 				node = root->list[root->update];
 
-				if (!strcmp(gtd->macro_buf, node->arg3))
+				if (*node->arg1 == '^' && gtd->input_buf[0])
+				{
+					continue;
+				}
+				else if (!strcmp(gtd->macro_buf, node->arg3))
 				{
 					script_driver(gtd->ses, LIST_MACRO, node->arg2);
 
@@ -454,7 +466,8 @@ void read_key(void)
 	{
 		switch (gtd->macro_buf[cnt])
 		{
-			case '\n':
+			case ASCII_CR:
+			case ASCII_LF:
 				gtd->input_buf[0] = 0;
 				gtd->macro_buf[0] = 0;
 				gtd->input_len = 0;
@@ -514,13 +527,13 @@ void convert_meta(char *input, char *output, int eol)
 	{
 		switch (*pti)
 		{
-			case ESCAPE:
+			case ASCII_ESC:
 				*pto++ = '\\';
 				*pto++ = 'e';
 				pti++;
 				break;
 
-			case 127:
+			case ASCII_DEL:
 				*pto++ = '\\';
 				*pto++ = 'x';
 				*pto++ = '7';
@@ -528,31 +541,31 @@ void convert_meta(char *input, char *output, int eol)
 				pti++;
 				break;
 
-			case '\a':
+			case ASCII_BEL:
 				*pto++ = '\\';
 				*pto++ = 'a';
 				pti++;
 				break;
 
-			case '\b':
+			case ASCII_BS:
 				*pto++ = '\\';
 				*pto++ = 'b';
 				pti++;
 				break;
 
-			case '\f':
+			case ASCII_FF:
 				*pto++ = '\\';
 				*pto++ = 'f';
 				pti++;
 				break;
 
-			case '\t':
+			case ASCII_HTAB:
 				*pto++ = '\\';
 				*pto++ = 't';
 				pti++;
 				break;
 
-			case '\r':
+			case ASCII_CR:
 				if (eol)
 				{
 					*pto++ = '\\';
@@ -561,13 +574,13 @@ void convert_meta(char *input, char *output, int eol)
 				*pto++ = *pti++;
 				break;
 
-			case '\v':
+			case ASCII_VTAB:
 				*pto++ = '\\';
 				*pto++ = 'v';
 				pti++;
 				break;
 
-			case '\n':
+			case ASCII_LF:
 				if (eol)
 				{
 					*pto++ = '\\';
@@ -614,81 +627,6 @@ char *str_convert_meta(char *input, int eol)
 	return buf;
 }
 
-void unconvert_meta(char *input, char *output)
-{
-	char *pti, *pto;
-
-	pti = input;
-	pto = output;
-
-	while (*pti)
-	{
-		switch (pti[0])
-		{
-			case '\\':
-				switch (pti[1])
-				{
-					case 'C':
-						if (pti[2] == '-' && pti[3])
-						{
-							*pto++  = pti[3] - 'a' + 1;
-							pti    += 4;
-						}
-						else
-						{
-							*pto++ = *pti++;
-						}
-						break;
-
-					case 'c':
-						*pto++ = pti[2] % 32;
-						pti += 3;
-						break;
-
-					case 'a':
-						*pto++  = '\a';
-						pti += 2;
-						break;
-
-					case 'b':
-						*pto++  = 127;
-						pti    += 2;
-						break;
-
-					case 'e':
-						*pto++  = ESCAPE;
-						pti    += 2;
-						break;
-
-					case 't':
-						*pto++  = '\t';
-						pti    += 2;
-						break;
-
-					case 'x':
-						if (pti[2] && pti[3])
-						{
-							*pto++ = hex_number_8bit(&pti[2]);
-							pti += 4;
-						}
-						else
-						{
-							*pto++ = *pti++;
-						}
-						break;
-					default:
-						*pto++ = *pti++;
-						break;
-				}
-				break;
-
-			default:
-				*pto++ = *pti++;
-				break;
-		}
-	}
-	*pto = 0;
-}
 
 /*
 	Currenly only used in split mode.

+ 142 - 69
src/line.c

@@ -59,6 +59,27 @@ DO_COMMAND(do_line)
 	return ses;
 }
 
+DO_LINE(line_background)
+{
+	char arg1[BUFFER_SIZE];
+
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
+
+	if (*arg1 == 0)
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {BACKGROUND} {command}.");
+
+		return ses;
+	}
+
+	gtd->background_level++;
+
+	ses = script_driver(ses, LIST_COMMAND, arg1);
+
+	gtd->background_level--;
+
+	return ses;
+}
 
 DO_LINE(line_gag)
 {
@@ -73,6 +94,28 @@ DO_LINE(line_gag)
 	return ses;
 }
 
+DO_LINE(line_ignore)
+{
+	char arg1[BUFFER_SIZE];
+
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
+
+	if (*arg1 == 0)
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {IGNORE} {command}.");
+		
+		return ses;
+	}
+
+	gtd->ignore_level++;
+
+	ses = script_driver(ses, LIST_COMMAND, arg1);
+
+	gtd->ignore_level--;
+
+	return ses;
+}
+
 // Without an argument mark next line to be logged, otherwise log the given line to file.
 
 DO_LINE(line_log)
@@ -89,7 +132,7 @@ DO_LINE(line_log)
 
 		if (ses->logline_time == gtd->time && !strcmp(ses->logline_name, arg1))
 		{
-			logit(ses, arg2, ses->logline_file, FALSE);
+			logit(ses, arg2, ses->logline_file, LOG_FLAG_NONE);
 		}
 		else
 		{
@@ -105,17 +148,9 @@ DO_LINE(line_log)
 				ses->logline_file = logfile;
 				ses->logline_time = gtd->time;
 
-				if (HAS_BIT(ses->flags, SES_FLAG_LOGHTML))
-				{
-					fseek(logfile, 0, SEEK_END);
+				loginit(ses, ses->logline_file, LOG_FLAG_APPEND | HAS_BIT(ses->logmode, LOG_FLAG_HTML));
 
-					if (ftell(logfile) == 0)
-					{
-						write_html_header(ses, logfile);
-					}
-				}
-
-				logit(ses, arg2, ses->logline_file, FALSE);
+				logit(ses, arg2, ses->logline_file, LOG_FLAG_NONE);
 			}
 			else
 			{
@@ -127,7 +162,7 @@ DO_LINE(line_log)
 	{
 		if (ses->lognext_time == gtd->time && !strcmp(ses->lognext_name, arg1))
 		{
-			SET_BIT(ses->flags, SES_FLAG_LOGNEXT);
+			SET_BIT(ses->logmode, LOG_FLAG_NEXT);
 		}
 		else if ((logfile = fopen(arg1, "a")))
 		{
@@ -141,7 +176,7 @@ DO_LINE(line_log)
 			ses->lognext_file = logfile;
 			ses->lognext_time = gtd->time;
 
-			SET_BIT(ses->flags, SES_FLAG_LOGNEXT);
+			SET_BIT(ses->logmode, LOG_FLAG_NEXT);
 		}
 		else
 		{
@@ -151,6 +186,72 @@ DO_LINE(line_log)
 	return ses;
 }
 
+DO_LINE(line_logmode)
+{
+	struct session *active_ses;
+
+	char arg1[BUFFER_SIZE];
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+
+	DEL_BIT(ses->logmode, LOG_FLAG_OLD_HTML|LOG_FLAG_OLD_PLAIN|LOG_FLAG_OLD_RAW);
+
+	switch (HAS_BIT(ses->logmode, LOG_FLAG_HTML|LOG_FLAG_PLAIN|LOG_FLAG_RAW))
+	{
+		case LOG_FLAG_HTML:
+			SET_BIT(ses->logmode, LOG_FLAG_OLD_HTML);
+			break;
+		case LOG_FLAG_PLAIN:
+			SET_BIT(ses->logmode, LOG_FLAG_OLD_PLAIN);
+			break;
+		case LOG_FLAG_RAW:
+			SET_BIT(ses->logmode, LOG_FLAG_OLD_RAW);
+			break;
+	}
+
+	DEL_BIT(ses->logmode, LOG_FLAG_HTML|LOG_FLAG_PLAIN|LOG_FLAG_RAW);
+
+	if (is_abbrev(arg1, "HTML"))
+	{
+		SET_BIT(ses->logmode, LOG_FLAG_HTML);
+	}
+	else if (is_abbrev(arg1, "PLAIN"))
+	{
+		SET_BIT(ses->logmode, LOG_FLAG_PLAIN);
+	}
+	else if (is_abbrev(arg1, "RAW"))
+	{
+		SET_BIT(ses->logmode, LOG_FLAG_RAW);
+	}
+	else
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {LOGMODE} {HTML|PLAIN|RAW} {command}.");
+
+		return ses;
+	}
+
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
+
+	active_ses = script_driver(ses, LIST_COMMAND, arg1);
+
+	DEL_BIT(ses->logmode, LOG_FLAG_HTML|LOG_FLAG_PLAIN|LOG_FLAG_RAW);
+
+	switch (HAS_BIT(ses->logmode, LOG_FLAG_OLD_HTML|LOG_FLAG_OLD_PLAIN|LOG_FLAG_OLD_RAW))
+	{
+		case LOG_FLAG_OLD_HTML:
+			SET_BIT(ses->logmode, LOG_FLAG_HTML);
+			break;
+		case LOG_FLAG_OLD_PLAIN:
+			SET_BIT(ses->logmode, LOG_FLAG_PLAIN);
+			break;
+		case LOG_FLAG_OLD_RAW:
+			SET_BIT(ses->logmode, LOG_FLAG_RAW);
+			break;
+	}
+
+	return ses = active_ses;
+}
+
 DO_LINE(line_logverbatim)
 {
 	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
@@ -163,7 +264,7 @@ DO_LINE(line_logverbatim)
 	{
 		if (!strcmp(ses->logline_name, arg1))
 		{
-			logit(ses, arg2, ses->logline_file, TRUE);
+			logit(ses, arg2, ses->logline_file, LOG_FLAG_LINEFEED);
 		}
 		else
 		{
@@ -177,17 +278,9 @@ DO_LINE(line_logverbatim)
 				ses->logline_name = strdup(arg1);
 				ses->logline_file = logfile;
 
-				if (HAS_BIT(ses->flags, SES_FLAG_LOGHTML))
-				{
-					fseek(logfile, 0, SEEK_END);
+				loginit(ses, ses->logline_file, LOG_FLAG_APPEND | HAS_BIT(ses->logmode, LOG_FLAG_HTML));
 
-					if (ftell(logfile) == 0)
-					{
-						write_html_header(ses, logfile);
-					}
-				}
-
-				logit(ses, arg2, ses->logline_file, TRUE);
+				logit(ses, arg2, ses->logline_file, LOG_FLAG_LINEFEED);
 			}
 			else
 			{
@@ -199,7 +292,7 @@ DO_LINE(line_logverbatim)
 	{
 		if (!strcmp(ses->lognext_name, arg1))
 		{
-			SET_BIT(ses->flags, SES_FLAG_LOGNEXT);
+			SET_BIT(ses->logmode, LOG_FLAG_NEXT);
 		}
 		else if ((logfile = fopen(arg1, "a")))
 		{
@@ -211,7 +304,7 @@ DO_LINE(line_logverbatim)
 			ses->lognext_name = strdup(arg1);
 			ses->lognext_file = logfile;
 
-			SET_BIT(ses->flags, SES_FLAG_LOGNEXT);
+			SET_BIT(ses->logmode, LOG_FLAG_NEXT);
 		}
 		else
 		{
@@ -221,6 +314,29 @@ DO_LINE(line_logverbatim)
 	return ses;
 }
 
+
+DO_LINE(line_quiet)
+{
+	char arg1[BUFFER_SIZE];
+
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
+
+	if (*arg1 == 0)
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {QUIET} {command}.");
+		
+		return ses;
+	}
+
+	gtd->quiet_level++;
+
+	ses = script_driver(ses, LIST_COMMAND, arg1);
+
+	gtd->quiet_level--;
+
+	return ses;
+}
+
 DO_LINE(line_strip)
 {
 	char arg1[BUFFER_SIZE], strip[BUFFER_SIZE];
@@ -327,47 +443,4 @@ DO_LINE(line_verbose)
 	return ses;
 }
 
-DO_LINE(line_ignore)
-{
-	char arg1[BUFFER_SIZE];
-
-	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
-
-	if (*arg1 == 0)
-	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {IGNORE} {command}.");
-		
-		return ses;
-	}
-
-	gtd->ignore_level++;
-
-	ses = script_driver(ses, LIST_COMMAND, arg1);
-
-	gtd->ignore_level--;
-
-	return ses;
-}
-
-DO_LINE(line_quiet)
-{
-	char arg1[BUFFER_SIZE];
-
-	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
-
-	if (*arg1 == 0)
-	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {QUIET} {command}.");
-		
-		return ses;
-	}
-
-	gtd->quiet++;
-
-	ses = script_driver(ses, LIST_COMMAND, arg1);
-
-	gtd->quiet--;
-
-	return ses;
-}
 	

+ 40 - 14
src/log.c

@@ -27,17 +27,17 @@
 #include "tintin.h"
 
 
-void logit(struct session *ses, char *txt, FILE *file, int newline)
+void logit(struct session *ses, char *txt, FILE *file, int flags)
 {
 	char out[BUFFER_SIZE];
 
-	push_call("logit(%p,%p,%p,%d)",ses,txt,file,newline);
+	push_call("logit(%p,%p,%p,%d)",ses,txt,file,flags);
 
-	if (HAS_BIT(ses->flags, SES_FLAG_LOGPLAIN))
+	if (HAS_BIT(ses->logmode, LOG_FLAG_PLAIN))
 	{
 		strip_vt102_codes(txt, out);
 	}
-	else if (HAS_BIT(ses->flags, SES_FLAG_LOGHTML))
+	else if (HAS_BIT(ses->logmode, LOG_FLAG_HTML))
 	{
 		vt102_to_html(ses, txt, out);
 	}
@@ -46,7 +46,7 @@ void logit(struct session *ses, char *txt, FILE *file, int newline)
 		strcpy(out, txt);
 	}
 
-	if (newline)
+	if (HAS_BIT(flags, LOG_FLAG_LINEFEED))
 	{
 		strcat(out, "\n");
 	}
@@ -58,6 +58,32 @@ void logit(struct session *ses, char *txt, FILE *file, int newline)
 	return;
 }
 
+void loginit(struct session *ses, FILE *file, int flags)
+{
+	push_call("loginit(%p,%p,%d)",ses,file,flags);
+
+	if (HAS_BIT(flags, LOG_FLAG_APPEND))
+	{
+		if (HAS_BIT(flags, LOG_FLAG_HTML))
+		{
+			fseek(file, 0, SEEK_END);
+
+			if (ftell(file) == 0)
+			{
+				write_html_header(ses, file);
+			}
+		}
+	}
+	else if (HAS_BIT(flags, LOG_FLAG_OVERWRITE) && HAS_BIT(flags, LOG_FLAG_HTML))
+	{
+		if (HAS_BIT(ses->logmode, LOG_FLAG_HTML))
+		{
+			write_html_header(ses, ses->logfile);
+		}
+	}
+	pop_call();
+	return;
+}
 
 DO_COMMAND(do_log)
 {
@@ -80,12 +106,10 @@ DO_COMMAND(do_log)
 
 		if ((ses->logfile = fopen(arg2, "a")))
 		{
-			fseek(ses->logfile, 0, SEEK_END);
+			SET_BIT(ses->logmode, LOG_FLAG_APPEND);
+
+			loginit(ses, ses->logfile, ses->logmode);
 
-			if (ftell(ses->logfile) == 0 && HAS_BIT(ses->flags, SES_FLAG_LOGHTML))
-			{
-				write_html_header(ses, ses->logfile);
-			}
 			show_message(ses, LIST_COMMAND, "#LOG: LOGGING OUTPUT TO '%s' FILESIZE: %ld", arg2, ftell(ses->logfile));
 		}
 		else
@@ -102,10 +126,10 @@ DO_COMMAND(do_log)
 
 		if ((ses->logfile = fopen(arg2, "w")))
 		{
-			if (HAS_BIT(ses->flags, SES_FLAG_LOGHTML))
-			{
-				write_html_header(ses, ses->logfile);
-			}
+			SET_BIT(ses->logmode, LOG_FLAG_OVERWRITE);
+
+			loginit(ses, ses->logfile, ses->logmode);
+
 			show_message(ses, LIST_COMMAND, "#LOG: LOGGING OUTPUT TO '%s'", arg2);
 		}
 		else
@@ -117,6 +141,8 @@ DO_COMMAND(do_log)
 	{
 		if (ses->logfile)
 		{
+			DEL_BIT(ses->logmode, LOG_FLAG_APPEND|LOG_FLAG_OVERWRITE);
+
 			fclose(ses->logfile);
 			ses->logfile = NULL;
 			show_message(ses, LIST_COMMAND, "#LOG: LOGGING TURNED OFF.");

+ 0 - 66
src/macro.c

@@ -1,66 +0,0 @@
-/******************************************************************************
-*   This file is part of TinTin++                                             *
-*                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
-*                                                                             *
-*   TinTin++ 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 3 of the License, 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 TinTin++.  If not, see https://www.gnu.org/licenses.           *
-******************************************************************************/
-
-/******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
-*                                                                             *
-*                      coded by Igor van den Hoven 2006                       *
-******************************************************************************/
-
-
-#include "tintin.h"
-
-DO_COMMAND(do_macro)
-{
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE];
-
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
-	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
-
-	if (*arg1 == 0)
-	{
-		show_list(ses->list[LIST_MACRO], 0);
-	}
-	else if (*arg1 && *arg2 == 0)
-	{
-		if (show_node_with_wild(ses, arg1, ses->list[LIST_MACRO]) == FALSE)
-		{
-			show_message(ses, LIST_MACRO, "#MACRO: NO MATCH(ES) FOUND FOR {%s}.", arg1);
-		}
-	}
-	else
-	{
-		unconvert_meta(arg1, arg3);
-
-		update_node_list(ses->list[LIST_MACRO], arg1, arg2, arg3, "");
-
-		show_message(ses, LIST_MACRO, "#OK. MACRO {%s} HAS BEEN SET TO {%s}.", arg1, arg2);
-	}
-	return ses;
-}
-
-
-DO_COMMAND(do_unmacro)
-{
-	delete_node_with_wild(ses, LIST_MACRO, arg);
-
-	return ses;
-}
-

+ 13 - 13
src/main.c

@@ -239,9 +239,9 @@ int main(int argc, char **argv)
 					break;
 
 				case 'e':
-					gtd->quiet++;
+					gtd->quiet_level++;
 					gtd->ses = script_driver(gtd->ses, LIST_COMMAND, optarg);
-					gtd->quiet--;
+					gtd->quiet_level--;
 					break;
 
 				case 'G':
@@ -351,7 +351,8 @@ void init_tintin(int greeting)
 
 	gtd->input_off      = 1;
 
-	gtd->home           = strdup(getenv("HOME") ? getenv("HOME") : ".");
+	gtd->os             = strdup(getenv("OS") ? getenv("OS") : "UNKNOWN");
+	gtd->home           = strdup(getenv("HOME") ? getenv("HOME") : "~/");
 	gtd->lang           = strdup(getenv("LANG") ? getenv("LANG") : "UNKNOWN");
 	gtd->term           = strdup(getenv("TERM") ? getenv("TERM") : "UNKNOWN");
 
@@ -414,7 +415,7 @@ void init_tintin(int greeting)
 	do_configure(gts, "{CONNECT RETRY}       {0}");
 	do_configure(gts, "{CHARSET}          {AUTO}");
 	do_configure(gts, "{HISTORY SIZE}     {1000}");
-	do_configure(gts, "{LOG}               {RAW}");
+	do_configure(gts, "{LOG MODE}          {RAW}");
 	do_configure(gts, "{MOUSE TRACKING}    {OFF}");
 	do_configure(gts, "{PACKET PATCH}     {AUTO}");
 	do_configure(gts, "{RANDOM SEED}      {AUTO}");
@@ -431,6 +432,7 @@ void init_tintin(int greeting)
 	}
 	do_configure(gts, "{SCROLL LOCK}        {ON}");
 	do_configure(gts, "{SPEEDWALK}         {OFF}");
+	do_configure(gts, "{TELNET}             {ON}");
 	do_configure(gts, "{TINTIN CHAR}         {#}");
 	do_configure(gts, "{VERBATIM}          {OFF}");
 	do_configure(gts, "{VERBATIM CHAR}      {\\}");
@@ -601,12 +603,12 @@ void syserr_signal(int signal, char *msg)
 		exit(-1);
 	}
 
-	dump_stack();
-
 	reset_terminal(gts);
 
 	reset_screen(gts);
 
+	dump_stack_fatal();
+
 	sprintf(buf, "\e[1;31mFATAL SIGNAL FROM (%s): %s\e[0m\n", msg, strsignal(signal));
 
 	printf("%s", buf);
@@ -639,18 +641,16 @@ void syserr_fatal(int signal, char *msg)
 		sprintf(errstr, "(signal %d: %s)", signal, strsignal(signal));
 	}
 
-	if (gtd->quiet)
+	if (gtd->quiet_level)
 	{
-		gtd->quiet = 0;
+		gtd->quiet_level = 0;
 	}
 
-	reset_terminal(gtd->ses);
-
-	reset_screen(gtd->ses);
+	reset_terminal(gts);
 
-	DEL_BIT(gtd->ses->flags, SES_FLAG_SPLIT);
+	reset_screen(gts);
 
-	dump_stack();
+	dump_stack_fatal();
 
 	sprintf(buf, "\n\e[1;31mFATAL ERROR \e[1;32m%s %s\e[0m\n", msg, errstr);
 

+ 292 - 183
src/mapper.c

@@ -72,6 +72,7 @@ DO_COMMAND(do_map)
 		tintin_printf2(ses, "#map list     <location>               (shows list of matching rooms)");
 		tintin_printf2(ses, "#map map      <radius> <filename>      (shows an ascii map)");
 		tintin_printf2(ses, "#map move     <direction>              (move to given direction)");
+		tintin_printf2(ses, "#map offset   <square>                 (place vtmap in given square)");
 		tintin_printf2(ses, "#map read     <filename>               (load a map from file)");
 		tintin_printf2(ses, "#map resize   <size>                   (resize the maximum size)");
 		tintin_printf2(ses, "#map roomflag <room flag>              (set room based flags)");
@@ -131,6 +132,7 @@ DO_COMMAND(do_map)
 
 DO_MAP(map_at)
 {
+	struct exit_data *exit;
 	int new_room;
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
@@ -140,9 +142,15 @@ DO_MAP(map_at)
 
 	if (new_room == 0)
 	{
-		show_message(ses, LIST_COMMAND, "#MAP AT: Couldn't find room {%s}.", arg1);
+		exit = find_exit(ses, ses->map->in_room, arg1);
 
-		return;
+		if (exit == NULL)
+		{
+			show_error(ses, LIST_COMMAND, "#MAP AT: Couldn't find room or exit {%s}.", arg1);
+
+			return;
+		}
+		new_room = exit->vnum;
 	}
 
 	ses->map->at_room = ses->map->in_room;
@@ -188,7 +196,7 @@ DO_MAP(map_color)
 				{
 					strncpy(ses->map->color[index], arg2, COLOR_SIZE - 1);
 				}
-				get_highlight_codes(ses, ses->map->color[index], buf);
+				get_color_names(ses, ses->map->color[index], buf);
 
 				show_message(ses, LIST_COMMAND, "#MAP COLOR %s%10s\e[0m SET TO {%s}", buf, map_color_table[index].name, ses->map->color[index]);
 
@@ -208,7 +216,7 @@ DO_MAP(map_color)
 	{
 		for (index = 0 ; map_color_table[index].name ; index++)
 		{
-			get_highlight_codes(ses, ses->map->color[index], buf);
+			get_color_names(ses, ses->map->color[index], buf);
 
 			show_message(ses, LIST_COMMAND, "#MAP COLOR %s%10s\e[0m SET TO {%s}", buf, map_color_table[index].name, ses->map->color[index]);
 		}
@@ -265,7 +273,7 @@ DO_MAP(map_delete)
 
 		if (room == 0)
 		{
-			show_error(ses, LIST_COMMAND, "#MAP DELETE {%d} - No room with that vnum found", arg1);
+			show_error(ses, LIST_COMMAND, "#MAP DELETE {%s} - No room with that vnum found", arg1);
 
 			return;
 		}
@@ -1447,7 +1455,7 @@ DO_MAP(map_map)
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = sub_arg_in_braces(ses, arg, arg3, GET_ONE, SUB_VAR|SUB_FUN);
-	arg = sub_arg_in_braces(ses, arg, arg4, GET_ONE, SUB_VAR|SUB_FUN);
+	arg = sub_arg_in_braces(ses, arg, arg4, GET_ALL, SUB_VAR|SUB_FUN);
 
 	push_call("map_map(%p,%p)",ses,arg);
 
@@ -1485,18 +1493,24 @@ DO_MAP(map_map)
 		{
 			case 'a':
 			case 'A':
+
 				strcpy(arg3, "APPEND");
 
 				logfile = fopen(arg4, "a");
 
-				if (HAS_BIT(ses->flags, SES_FLAG_LOGHTML))
-				{
-					fseek(logfile, 0, SEEK_END);
+				loginit(ses, logfile, LOG_FLAG_APPEND | HAS_BIT(ses->logmode, LOG_FLAG_HTML));
 
-					if (ftell(logfile) == 0)
-					{
-						write_html_header(ses, logfile);
-					}
+				break;
+
+			case 'd':
+			case 'D':
+				strcpy(arg3, "DRAW");
+
+				if (*arg4 == 0)
+				{
+					show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP MAP {%s} {%s} {%s} {square}", arg1, arg2, arg3);
+					pop_call();
+					return;
 				}
 				break;
 
@@ -1506,10 +1520,8 @@ DO_MAP(map_map)
 
 				logfile = fopen(arg4, "w");
 
-				if (HAS_BIT(ses->flags, SES_FLAG_LOGHTML))
-				{
-					write_html_header(ses, logfile);
-				}
+				loginit(ses, logfile, LOG_FLAG_OVERWRITE | HAS_BIT(ses->logmode, LOG_FLAG_HTML));
+
 				break;
 
 			case 'l':
@@ -1523,10 +1535,11 @@ DO_MAP(map_map)
 				break;
 
 			default:
-				show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP MAP {rows} {cols} {append|write|list|variable} {name}");
+				show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP MAP {rows} {cols} {append|overwrite|list|variable} {name}");
 				pop_call();
 				return;
 		}
+
 		if (*arg4 == 0)
 		{
 			show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP MAP {%s} {%s} {%s} {name}", arg1, arg2, arg3);
@@ -1593,32 +1606,19 @@ DO_MAP(map_map)
 					str_cat(&gtd->buf, draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], line, x, y));
 				}
 
-/*				if (*ses->map->color[MAP_COLOR_BACK] == 0)
-				{
-					for (x = strlen(buf) - 1 ; x > 0 ; x--)
-					{
-						if (buf[x] != ' ')
-						{
-							break;
-						}
-					}
-					buf[x+1] = 0;
-					strcat(buf, "<088>");
-				}
-*/
 				str_clone(&gtd->out, gtd->buf);
 
 				substitute(ses, gtd->buf, gtd->out, SUB_COL|SUB_CMP|SUB_LIT);
 
 				if (logfile)
 				{
-					logit(ses, gtd->out, logfile, TRUE);
+					logit(ses, gtd->out, logfile, LOG_FLAG_LINEFEED);
 				}
 				else if (*arg3 == 'L')
 				{
 					cat_sprintf(arg1, "{%02d}{%s}", ++row, gtd->out);
 				}
-				else if (*arg3 == 'V')
+				else if (*arg3 == 'V' || *arg3 == 'D')
 				{
 					cat_sprintf(arg1, "%s\n", gtd->out);
 				}
@@ -1642,19 +1642,6 @@ DO_MAP(map_map)
 					str_cat(&gtd->buf, draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], line, x, y));
 				}
 
-/*				if (*ses->map->color[MAP_COLOR_BACK] == 0)
-				{
-					for (x = strlen(buf) - 1 ; x > 0 ; x--)
-					{
-						if (buf[x] != ' ')
-						{
-							break;
-						}
-					}
-					buf[x+1] = 0;
-					str_cat(&buf, "<088>");
-				}
-*/
 				str_clone(&gtd->out, gtd->buf);
 
 				substitute(ses, gtd->buf, gtd->out, SUB_COL|SUB_CMP|SUB_LIT);
@@ -1667,7 +1654,7 @@ DO_MAP(map_map)
 				{
 					cat_sprintf(arg1, "{%02d}{%s\e[0m}", ++row, gtd->out);
 				}
-				else if (*arg3 == 'V')
+				else if (*arg3 == 'V' || *arg3 == 'D')
 				{
 					cat_sprintf(arg1, "%s\e[0m\n", gtd->out);
 				}
@@ -1688,22 +1675,6 @@ DO_MAP(map_map)
 			{
 				str_cat(&gtd->buf, draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], 0, x, y));
 			}
-/*
-			if (*ses->map->color[MAP_COLOR_BACK] == 0)
-			{
-				for (x = strlen(buf) - 1 ; x > 0 ; x--)
-				{
-					if (buf[x] != ' ')
-					{
-						break;
-					}
-				}
-				buf[x+1] = 0;
-
-				strcat(buf, "<088>");
-			}
-*/
-			str_clone(&gtd->out, gtd->buf);
 
 			substitute(ses, gtd->buf, gtd->out, SUB_COL|SUB_CMP|SUB_LIT);
 
@@ -1715,7 +1686,7 @@ DO_MAP(map_map)
 			{
 				cat_sprintf(arg1, "{%02d}{%s}", ++row, gtd->out);
 			}
-			else if (*arg3 == 'V')
+			else if (*arg3 == 'V' || *arg3 == 'D')
 			{
 				cat_sprintf(arg1, "%s\n", gtd->out);
 			}
@@ -1730,6 +1701,10 @@ DO_MAP(map_map)
 	{
 		fclose(logfile);
 	}
+	else if (*arg3 == 'D')
+	{
+		draw_map(ses, 1, 2, 3, 4, 5, 6, 7, arg4, arg2, arg1);
+	}
 	else if (*arg3 == 'L')
 	{
 		set_nest_node(ses->list[LIST_VARIABLE], arg4, "%s", arg1);
@@ -1795,7 +1770,7 @@ DO_MAP(map_offset)
 
 	if (ses->map->bot_row == 0)
 	{
-		ses->map->bot_row = ses->top_row;
+		ses->map->bot_row = ses->top_row - 1;
 	}
 	else if (ses->map->bot_row < 0)
 	{
@@ -1833,7 +1808,7 @@ DO_MAP(map_read)
 		return;
 	}
 
-	gtd->quiet++;
+	gtd->quiet_level++;
 
 	if (fgets(buffer, BUFFER_SIZE - 1, myfile))
 	{
@@ -1857,7 +1832,7 @@ DO_MAP(map_read)
 		}
 		else
 		{
-			gtd->quiet--;
+			gtd->quiet_level--;
 
 			show_error(ses, LIST_COMMAND, "#MAP READ {%s}: INVALID START OF FILE. ABORTING READ..", file);
 
@@ -1868,7 +1843,7 @@ DO_MAP(map_read)
 	}
 	else
 	{
-		gtd->quiet--;
+		gtd->quiet_level--;
 
 		show_error(ses, LIST_COMMAND, "#MAP: INVALID READ ON LINE %d. ABORTING READ..", line);
 
@@ -1901,7 +1876,7 @@ DO_MAP(map_read)
 				switch (buffer[1])
 				{
 					case ' ':
-						gtd->quiet--;
+						gtd->quiet_level--;
 
 						show_error(ses, LIST_COMMAND, "#MAP: INVALID COMMAND {%d} {%s} ON LINE %d. ABORTING READ..", buffer[0], buffer, line);
 
@@ -1967,7 +1942,7 @@ DO_MAP(map_read)
 				break;
 
 			default:
-				gtd->quiet--;
+				gtd->quiet_level--;
 
 				show_error(ses, LIST_COMMAND, "#MAP: INVALID COMMAND {%d} {%s} ON LINE %d. ABORTING READ..", buffer[0], buffer, line);
 
@@ -1979,7 +1954,7 @@ DO_MAP(map_read)
 		}
 	}
 
-	gtd->quiet--;
+	gtd->quiet_level--;
 
 	fclose(myfile);
 
@@ -2080,11 +2055,12 @@ DO_MAP(map_return)
 
 DO_MAP(map_roomflag)
 {
-	char buf[BUFFER_SIZE];
+	char buf[BUFFER_SIZE], *str, arg3[BUFFER_SIZE];
 	int flag = 0;
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
-	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
+	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
+	arg = sub_arg_in_braces(ses, arg, arg3, GET_ALL, SUB_VAR|SUB_FUN);
 
 	if (*arg1 == 0)
 	{
@@ -2099,9 +2075,11 @@ DO_MAP(map_roomflag)
 		return;
 	}
 
-	while (*arg1)
+	str = arg1;
+
+	while (*str)
 	{
-		arg1 = get_arg_in_braces(ses, arg1, buf, GET_ONE);
+		str = get_arg_in_braces(ses, str, buf, GET_ONE);
 
 		if (is_abbrev(buf, "avoid"))
 		{
@@ -2141,8 +2119,11 @@ DO_MAP(map_roomflag)
 
 			return;
 		}
-		
-		if (*arg1 == COMMAND_SEPARATOR) arg1++;
+
+		if (*str == COMMAND_SEPARATOR)
+		{
+			str++;
+		}
 	}
 
 	if (*arg2 == 0)
@@ -2157,9 +2138,21 @@ DO_MAP(map_roomflag)
 	{
 		DEL_BIT(ses->map->room_list[ses->map->in_room]->flags, flag);
 	}
+	else if (is_abbrev(arg2, "GET"))
+	{
+		if (*arg3 == 0)
+		{
+			show_error(ses, LIST_COMMAND, "#SYNTAX #MAP ROOMFLAG {%s} {GET} {<VARIABLE>}.", buf);
+		}
+		else
+		{
+			set_nest_node(ses->list[LIST_VARIABLE], arg3, "%d", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, flag));
+		}
+		return;
+	}
 	else
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX #MAP ROOMFLAG {%s} {[ON|OFF]}.", buf);
+		show_error(ses, LIST_COMMAND, "#SYNTAX #MAP ROOMFLAG {%s} {[GET|ON|OFF]}.", buf);
 	}
 
 
@@ -2513,7 +2506,28 @@ DO_MAP(map_unlink)
 
 DO_MAP(map_update)
 {
-	show_message(ses, LIST_COMMAND, "#MAP UPDATE: OK.");
+	if (ses->map == NULL)
+	{
+		show_message(ses, LIST_COMMAND, "#MAP UPDATE: NO MAP DATA.");
+	}
+	else if (ses->map->room_list[ses->map->in_room] == NULL)
+	{
+		show_message(ses, LIST_COMMAND, "#MAP UPDATE: NOT INSIDE MAP.");
+	}
+	else if (!HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP))
+	{
+		show_message(ses, LIST_COMMAND, "#MAP UPDATE: VTMAP FLAG NOT SET.");
+	}
+	else if (ses != gtd->ses)
+	{
+		show_message(ses, LIST_COMMAND, "#MAP UPDATE: NOT THE ACTIVE SESSION.");
+	}
+	else
+	{
+		show_message(ses, LIST_COMMAND, "#MAP UPDATE: OK.");
+		
+		SET_BIT(ses->flags, SES_FLAG_UPDATEVTMAP);
+	}
 }
 
 DO_MAP(map_run)
@@ -2756,9 +2770,9 @@ void create_map(struct session *ses, char *arg)
 		map_group_table[group].end = legend;
 	}
 				
-	gtd->quiet++;
+	gtd->quiet_level++;
 	do_map(ses, "LEGEND RESET");
-	gtd->quiet--;
+	gtd->quiet_level--;
 
 	pop_call();
 	return;
@@ -2874,13 +2888,14 @@ void delete_room(struct session *ses, int room, int exits)
 	}
 }
 
-struct exit_data *create_exit(struct session *ses, int room, char *format, ...)
+struct exit_data *create_exit(struct session *ses, int vnum, char *format, ...)
 {
 	struct exit_data *newexit;
+	struct room_data *room;
 	va_list args;
 	char *arg, buf[BUFFER_SIZE];
 
-	push_call("create_exit(%p,%d,%p)",ses,room,format);
+	push_call("create_exit(%p,%d,%p)",ses,vnum,format);
 
 	va_start(args, format);
 	vsprintf(buf, format, args);
@@ -2888,6 +2903,8 @@ struct exit_data *create_exit(struct session *ses, int room, char *format, ...)
 
 	newexit = (struct exit_data *) calloc(1, sizeof(struct exit_data));
 
+	room = ses->map->room_list[vnum];
+
 	arg = buf;
 
 	arg = get_arg_in_braces(ses, arg, buf, GET_ONE);	newexit->vnum   = atoi(buf);
@@ -2903,17 +2920,25 @@ struct exit_data *create_exit(struct session *ses, int room, char *format, ...)
 		newexit->dir = get_exit_dir(ses, newexit->name);
 	}
 
+	newexit->grid = get_exit_grid(ses, newexit->dir);
+
+	if (room->exit_grid[newexit->grid] == NULL)
+	{
+		room->exit_grid[newexit->grid] = newexit;
+	}
+
 	if (newexit->weight <= 0)
 	{
 		newexit->weight = 1;
 	}
 
-	LINK(newexit, ses->map->room_list[room]->f_exit, ses->map->room_list[room]->l_exit);
+	LINK(newexit, room->f_exit, room->l_exit);
+
+	room->exit_size++;
 
-	ses->map->room_list[room]->exit_size++;
-	SET_BIT(ses->map->room_list[room]->exit_dirs, (1LL << newexit->dir));
+	SET_BIT(room->exit_dirs, (1LL << newexit->dir));
 
-	show_message(ses, LIST_COMMAND, "#MAP CREATE EXIT %5d {%s} {%s}.", newexit->vnum, newexit->name, newexit->cmd);
+	show_message(ses, LIST_COMMAND, "#MAP CREATE EXIT {%s} {%s} TO ROOM %d.", newexit->name, newexit->cmd, newexit->vnum);
 
 	pop_call();
 	return newexit;
@@ -2948,23 +2973,69 @@ int get_exit_dir(struct session *ses, char *arg)
 	}
 }
 
+int get_exit_grid(struct session *ses, int dir)
+{
+	switch (dir)
+	{
+		case 0:
+			return EXIT_GRID_0;
+		case MAP_EXIT_N:
+			return EXIT_GRID_N;
+		case MAP_EXIT_E:
+			return EXIT_GRID_E;
+		case MAP_EXIT_S:
+			return EXIT_GRID_S;
+		case MAP_EXIT_W:
+			return EXIT_GRID_W;
+		case MAP_EXIT_N|MAP_EXIT_E:
+			return EXIT_GRID_NE;
+		case MAP_EXIT_N|MAP_EXIT_W:
+			return EXIT_GRID_NW;
+		case MAP_EXIT_S|MAP_EXIT_E:
+			return EXIT_GRID_SE;
+		case MAP_EXIT_S|MAP_EXIT_W:
+			return EXIT_GRID_SW;
+	}
+
+	if (HAS_BIT(dir, MAP_EXIT_D))
+	{
+		return EXIT_GRID_D;
+	}
+
+	if (HAS_BIT(dir, MAP_EXIT_U))
+	{
+		return EXIT_GRID_U;
+	}
+
+	return EXIT_GRID_0;
+}
+
 int get_room_exits(struct session *ses, int room)
 {
 	return ses->map->room_list[room]->exit_size;
 }
 
-void set_room_exits(struct session *ses, int room)
+void set_room_exits(struct session *ses, int vnum)
 {
 	struct exit_data *exit;
+	struct room_data *room;
 
-	ses->map->room_list[room]->exit_dirs = 0;
-	ses->map->room_list[room]->exit_size = 0;
+	room = ses->map->room_list[vnum];
 
-	for (exit = ses->map->room_list[room]->f_exit ; exit ; exit = exit->next)
+	room->exit_dirs = 0;
+	room->exit_size = 0;
+
+	memset(room->exit_grid, 0, sizeof(struct exit_data *) * 11);
+
+	for (exit = room->f_exit ; exit ; exit = exit->next)
 	{
-		SET_BIT(ses->map->room_list[room]->exit_dirs, 1LL << exit->dir);
+		SET_BIT(room->exit_dirs, 1LL << exit->dir);
 
-		ses->map->room_list[room]->exit_size++;
+		if (room->exit_grid[exit->grid] == NULL)
+		{
+			room->exit_grid[exit->grid] = exit;
+		}
+		room->exit_size++;
 	}
 }
 
@@ -3356,7 +3427,9 @@ void show_vtmap(struct session *ses)
 		cols    = gtd->screen->cols;
 	}
 
-	printf("\e[%d;%d;%d;%d${", top_row, top_col, bot_row, bot_col);
+	erase_square(ses, top_row, top_col, bot_row, bot_col);
+
+//	printf("\e[%d;%d;%d;%d${", top_row, top_col, bot_row, bot_col);
 
 	if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
 	{
@@ -3489,13 +3562,19 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 	static char buf[201], *room_color, room_left[101], room_right[101];
 	int index, flags, exits, exit1, exit2, room1, room2, offset;
 
-	push_call("draw_room(%p,%p,%p,%d,%d)",ses,room,line,x,y);
+	push_call("draw_room(%p,%p,%d,%d,%d)",ses,room,line,x,y);
 
 	offset = HAS_BIT(ses->flags, SES_FLAG_UTF8) ? LEGEND_UNICODE : LEGEND_ASCII;
 
+	room_color = ses->map->color[MAP_COLOR_ROOM];
+
 	if (room)
 	{
-		if (*room->color)
+		if (HAS_BIT(room->flags, ROOM_FLAG_PATH) && room->search_stamp == ses->map->search->stamp)
+		{
+			room_color = ses->map->color[MAP_COLOR_PATH];
+		}
+		else if (*room->color)
 		{
 			room_color = room->color;
 		}
@@ -3521,18 +3600,10 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 			{
 				room_color = ses->map->color[MAP_COLOR_AVOID];
 			}
-			else if (HAS_BIT(room->flags, ROOM_FLAG_PATH) && room->search_stamp == ses->map->search->stamp)
-			{
-				room_color = ses->map->color[MAP_COLOR_PATH];
-			}
 			else if (HAS_BIT(ses->map->flags, MAP_FLAG_SYMBOLGRAPHICS))
 			{
 				room_color = ses->map->color[MAP_COLOR_SYMBOL];
 			}
-			else
-			{
-				room_color = ses->map->color[MAP_COLOR_ROOM];
-			}
 		}
 
 		if (HAS_BIT(room->flags, ROOM_FLAG_CURVED))
@@ -3554,36 +3625,36 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 
 				DEL_BIT(exits, MAP_EXIT_U|MAP_EXIT_D);
 
-					switch (exits)
-					{
-						case MAP_EXIT_N:
-							index = 24;
-							break;
-						case MAP_EXIT_N+MAP_EXIT_E:
-							index = 25;
-							break;
-						case MAP_EXIT_E:
-							index = 26;
-							break;
-						case MAP_EXIT_S+MAP_EXIT_E:
-							index = 27;
-							break;
-						case MAP_EXIT_S:
-							index = 28;
-							break;
-						case MAP_EXIT_W+MAP_EXIT_S:
-							index = 29;
-							break;
-						case MAP_EXIT_W:
-							index = 30;
-							break;
-						case MAP_EXIT_W+MAP_EXIT_N:
-							index = 31;
-							break;
-						default:
-							index = 17;
-							break;
-					}
+				switch (exits)
+				{
+					case MAP_EXIT_N:
+						index = 24;
+						break;
+					case MAP_EXIT_N+MAP_EXIT_E:
+						index = 25;
+						break;
+					case MAP_EXIT_E:
+						index = 26;
+						break;
+					case MAP_EXIT_S+MAP_EXIT_E:
+						index = 27;
+						break;
+					case MAP_EXIT_S:
+						index = 28;
+						break;
+					case MAP_EXIT_W+MAP_EXIT_S:
+						index = 29;
+						break;
+					case MAP_EXIT_W:
+						index = 30;
+						break;
+					case MAP_EXIT_W+MAP_EXIT_N:
+						index = 31;
+						break;
+					default:
+						index = 17;
+						break;
+				}
 			}
 			else
 			{
@@ -3603,14 +3674,16 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 
 		exit_n = exit_nw = exit_w = 0;
 
-		if (room && HAS_BIT(room->exit_dirs, MAP_DIR_N))
+		if (room && room->exit_grid[EXIT_GRID_N])
 		{
 			SET_BIT(exit_n, MAP_DIR_N);
 		}
+
 		if (room_n && HAS_BIT(room_n->exit_dirs, MAP_DIR_S))
 		{
 			SET_BIT(exit_n, MAP_DIR_S);
 		}
+
 		if (room_n && HAS_BIT(room_n->exit_dirs, MAP_DIR_D))
 		{
 			SET_BIT(exit_n, MAP_DIR_D);
@@ -3620,6 +3693,7 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 		{
 			SET_BIT(exit_nw, MAP_DIR_SE);
 		}
+
 		if (room_n && HAS_BIT(room_n->exit_dirs, MAP_DIR_SW))
 		{
 			SET_BIT(exit_nw, MAP_DIR_NE);
@@ -3628,18 +3702,20 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 		{
 			SET_BIT(exit_nw, MAP_DIR_NW);
 		}
+
 		if (room_w && HAS_BIT(room_w->exit_dirs, MAP_DIR_NE))
 		{
 			SET_BIT(exit_nw, MAP_DIR_SW);
 		}
 
-		if (room && HAS_BIT(room->exit_dirs, MAP_DIR_W))
+		if (room && room->exit_grid[EXIT_GRID_W])
 		{
-			SET_BIT(exit_w, MAP_DIR_W);
+			SET_BIT(exit_w, MAP_DIR_E);
 		}
-		if (room_w && HAS_BIT(room_w->exit_dirs, MAP_DIR_E))
+
+		if (room_w && room_w->exit_grid[EXIT_GRID_E])
 		{
-			SET_BIT(exit_w, MAP_DIR_E);
+			SET_BIT(exit_w, MAP_DIR_W);
 		}
 
 		sprintf(buf, "%s", ses->map->color[MAP_COLOR_EXIT]);
@@ -3746,9 +3822,9 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 						break;
 				}
 
-				if (room && HAS_BIT(room->exit_dirs, MAP_DIR_U))
+				if (room && room->exit_grid[EXIT_GRID_U])
 				{
-					flags = dir_flags(ses, room->vnum, MAP_EXIT_U);
+					flags = room->exit_grid[EXIT_GRID_U]->flags;
 
 					if (HAS_BIT(flags, EXIT_FLAG_AVOID))
 					{
@@ -3777,7 +3853,14 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 			case 2:
 				if (room == NULL)
 				{
-					strcpy(buf, "     ");
+					if (HAS_BIT(exit_w, MAP_DIR_W))
+					{
+						sprintf(buf, "%s→    ", ses->map->color[MAP_COLOR_EXIT]);
+					}
+					else
+					{
+						strcpy(buf, "     ");
+					}
 					pop_call();
 					return buf;
 				}
@@ -3788,13 +3871,20 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 						strcpy(buf, "  ");
 						break;
 					case MAP_DIR_W:
-						sprintf(buf, "%s ", ses->map->color[MAP_COLOR_EXIT]);
+						sprintf(buf, "%s ", ses->map->color[MAP_COLOR_EXIT]);
 						break;
 					case MAP_DIR_E:
-						sprintf(buf, "%s ", ses->map->color[MAP_COLOR_EXIT]);
+						sprintf(buf, "%s ", ses->map->color[MAP_COLOR_EXIT]);
 						break;
 					case MAP_DIR_W|MAP_DIR_E:
-						sprintf(buf, "%s‒‒", ses->map->color[MAP_COLOR_EXIT]);
+						if (room->exit_grid[EXIT_GRID_W]->vnum == room_w->vnum && room_w->exit_grid[EXIT_GRID_E]->vnum == room->vnum)
+						{
+							sprintf(buf, "%s‒‒", ses->map->color[MAP_COLOR_EXIT]);
+						}
+						else
+						{
+							sprintf(buf, "%s→←", ses->map->color[MAP_COLOR_EXIT]);
+						}
 						break;
 					default:
 						strcat(buf, "??");
@@ -4101,7 +4191,7 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 				break;
 
 			case 2:
-				if (!HAS_BIT(room->flags, ROOM_FLAG_VOID) && !HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS))
+				if (!HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS))
 				{
 					strcat(buf, HAS_BIT(room->exit_dirs, MAP_DIR_W) ? "-" : " ");
 				}
@@ -4157,7 +4247,7 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 					}
 				}
 
-				if (HAS_BIT(room->flags, ROOM_FLAG_VOID) || !HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS))
+				if (!HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS))
 				{
 					strcat(buf, HAS_BIT(room->exit_dirs, MAP_DIR_E) ? "--" : "  ");
 				}
@@ -4271,22 +4361,18 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 		if (HAS_BIT(room->exit_dirs, MAP_DIR_NW))
 		{
 			SET_BIT(exit1, 1 << 1);
-			SET_BIT(exits, MAP_EXIT_NW);
 		}
 		if (HAS_BIT(room->exit_dirs, MAP_DIR_NE))
 		{
 			SET_BIT(exit2, 1 << 1);
-			SET_BIT(exits, MAP_EXIT_NE);
 		}
 		if (HAS_BIT(room->exit_dirs, MAP_DIR_SW))
 		{
 			SET_BIT(exit1, 1 << 3);
-			SET_BIT(exits, MAP_EXIT_SW);
 		}
 		if (HAS_BIT(room->exit_dirs, MAP_DIR_SE))
 		{
 			SET_BIT(exit2, 1 << 3);
-			SET_BIT(exits, MAP_EXIT_SE);
 		}
 
 		room1 = exit1 + LEGEND_MUDFONT_NWS;
@@ -4300,22 +4386,22 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 
 		if (HAS_BIT(room->flags, ROOM_FLAG_CURVED))
 		{
-			switch (exits)
+			switch (room->exit_dirs)
 			{
-				case MAP_EXIT_N|MAP_EXIT_E:
-				case MAP_EXIT_N|MAP_EXIT_SE:
+				case MAP_DIR_N|MAP_DIR_E:
+				case MAP_DIR_N|MAP_DIR_SE:
 					room1 = LEGEND_MUDFONT_CURVED + 0;
 					break;
-				case MAP_EXIT_S|MAP_EXIT_E:
-				case MAP_EXIT_S|MAP_EXIT_NE:
+				case MAP_DIR_S|MAP_DIR_E:
+				case MAP_DIR_S|MAP_DIR_NE:
 					room1 = LEGEND_MUDFONT_CURVED + 1;
 					break;
-				case MAP_EXIT_S|MAP_EXIT_W:
-				case MAP_EXIT_S|MAP_EXIT_NW:
+				case MAP_DIR_S|MAP_DIR_W:
+				case MAP_DIR_S|MAP_DIR_NW:
 					room2 = LEGEND_MUDFONT_CURVED + 2;
 					break;
-				case MAP_EXIT_N|MAP_EXIT_W:
-				case MAP_EXIT_N|MAP_EXIT_SW:
+				case MAP_DIR_N|MAP_DIR_W:
+				case MAP_DIR_N|MAP_DIR_SW:
 					room2 = LEGEND_MUDFONT_CURVED + 3;
 					break;
 			}
@@ -4339,18 +4425,18 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 			{
 				if (HAS_BIT(room->flags, ROOM_FLAG_CURVED))
 				{
-					switch (exits)
+					switch (room->exit_dirs)
 					{
-						case MAP_EXIT_N|MAP_EXIT_E:
+						case MAP_DIR_N|MAP_DIR_E:
 							exits = 16 + 4;
 							break;
-						case MAP_EXIT_S|MAP_EXIT_E:
+						case MAP_DIR_S|MAP_DIR_E:
 							exits = 16 + 5;
 							break;
-						case MAP_EXIT_S|MAP_EXIT_W:
+						case MAP_DIR_S|MAP_DIR_W:
 							exits = 16 + 6;
 							break;
-						case MAP_EXIT_N|MAP_EXIT_W:
+						case MAP_DIR_N|MAP_DIR_W:
 							exits = 16 + 7;
 							break;
 					}
@@ -4449,7 +4535,14 @@ void map_search_compile(struct session *ses, char *arg, char *var)
 
 	arg = sub_arg_in_braces(ses, tmp, buf, GET_ALL, SUB_VAR|SUB_FUN); // name
 
-	ses->map->search->vnum = (int) get_number(ses, buf);
+	if (is_math(ses, buf))
+	{
+		ses->map->search->vnum = (int) get_number(ses, buf);
+	}
+	else
+	{
+		ses->map->search->vnum = 0;
+	}
 
 	if (ses->map->search->vnum)
 	{
@@ -4491,30 +4584,46 @@ void map_search_compile(struct session *ses, char *arg, char *var)
 
 		tmp[0] = 0;
 
-		ses->map->search->exit_dirs = get_number(ses, buf);
+		if (is_math(ses, buf))
+		{
+			ses->map->search->exit_dirs = get_number(ses, buf);
 
-		while (*ptb)
+			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_N))  ses->map->search->exit_size++;
+			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_E))  ses->map->search->exit_size++;
+			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_S))  ses->map->search->exit_size++;
+			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_W))  ses->map->search->exit_size++;
+			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_U))  ses->map->search->exit_size++;
+			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_D))  ses->map->search->exit_size++;
+			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_NE)) ses->map->search->exit_size++;
+			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_NW)) ses->map->search->exit_size++;
+			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_SE)) ses->map->search->exit_size++;
+			if (HAS_BIT(ses->map->search->exit_dirs, MAP_DIR_SW)) ses->map->search->exit_size++;
+		}
+		else
 		{
-			ptb = get_arg_in_braces(ses, ptb, exit, GET_ONE);
+			while (*ptb)
+			{
+				ptb = get_arg_in_braces(ses, ptb, exit, GET_ONE);
 
-			node = search_node_list(ses->list[LIST_PATHDIR], exit);
+				node = search_node_list(ses->list[LIST_PATHDIR], exit);
 
-			ses->map->search->exit_size++;
+				ses->map->search->exit_size++;
 
-			if (node)
-			{
-				SET_BIT(ses->map->search->exit_dirs, 1LL << atoi(node->arg3));
-			}
-			else
-			{
-				SET_BIT(ses->map->search->exit_dirs, 1); // flag indicates no exits
+				if (node)
+				{
+					SET_BIT(ses->map->search->exit_dirs, 1LL << atoi(node->arg3));
+				}
+				else
+				{
+					SET_BIT(ses->map->search->exit_dirs, 1); // flag indicates no exits
 
-				cat_sprintf(tmp, "{%s}", exit);
-			}
+					cat_sprintf(tmp, "{%s}", exit);
+				}
 
-			if (*ptb == COMMAND_SEPARATOR)
-			{
-				ptb++;
+				if (*ptb == COMMAND_SEPARATOR)
+				{
+					ptb++;
+				}
 			}
 		}
 		ses->map->search->exit_list = strdup(tmp);

+ 3 - 1
src/math.c

@@ -109,7 +109,9 @@ long double get_double(struct session *ses, char *str)
 	
 void get_number_string(struct session *ses, char *str, char *result)
 {
-	sprintf(result, "%.*Lf", precision, get_number(ses, str));
+	long double val = get_number(ses, str);
+
+	sprintf(result, "%.*Lf", precision, val);
 }
 
 long double mathswitch(struct session *ses, char *left, char *right)

+ 1 - 1
src/misc.c

@@ -96,7 +96,7 @@ DO_COMMAND(do_echo)
 
 			substitute(ses, left, temp, SUB_COL|SUB_ESC);
 
-			do_one_prompt(ses, temp, row, 0);
+			split_show(ses, temp, row, 0);
 
 			return ses;
 		}

+ 14 - 5
src/net.c

@@ -69,7 +69,7 @@ int connect_mud(struct session *ses, char *host, char *port)
 
 		if (error)
 		{
-			tintin_printf(ses, "#SESSION '%s' COULD NOT CONNECT - UNKNOWN HOST.", ses->name);
+			tintin_printf2(ses, "#SESSION '%s' COULD NOT CONNECT - UNKNOWN HOST.", ses->name);
 
 			return -1;
 		}
@@ -96,7 +96,7 @@ int connect_mud(struct session *ses, char *host, char *port)
 
 		freeaddrinfo(address);
 
-		return 0;
+		return -1;
 	}
 
 	if (fcntl(sock, F_SETFL, O_NDELAY|O_NONBLOCK) == -1)
@@ -107,12 +107,19 @@ int connect_mud(struct session *ses, char *host, char *port)
 
 		freeaddrinfo(address);
 
-		return 0;
+		return -1;
 	}
 
-	getnameinfo(address->ai_addr, address->ai_addrlen, ip, 100, NULL, 0, NI_NUMERICHOST);
+	error = getnameinfo(address->ai_addr, address->ai_addrlen, ip, 100, NULL, 0, NI_NUMERICHOST);
 
-	RESTRING(ses->session_ip, ip);
+	if (error)
+	{
+		syserr_printf(ses, "connect_mud: getnameinfo:");
+	}
+	else
+	{
+		RESTRING(ses->session_ip, ip);
+	}
 
 	freeaddrinfo(address);
 
@@ -126,6 +133,8 @@ int connect_mud(struct session *ses, char *host, char *port)
 	int sock, d;
 	struct sockaddr_in sockaddr;
 
+	printf("debug: NO ADDRESS INFO?\n");
+
 	if (sscanf(host, "%d.%d.%d.%d", &d, &d, &d, &d) == 4)
 	{
 		sockaddr.sin_addr.s_addr = inet_addr(host);

+ 3 - 3
src/parse.c

@@ -849,11 +849,11 @@ void do_one_line(char *line, struct session *ses)
 		check_all_highlights(ses, line, strip);
 	}
 
-	if (HAS_BIT(ses->flags, SES_FLAG_LOGNEXT))
+	if (HAS_BIT(ses->logmode, LOG_FLAG_NEXT))
 	{
-		logit(ses, line, ses->lognext_file, TRUE);
+		logit(ses, line, ses->lognext_file, LOG_FLAG_LINEFEED);
 
-		DEL_BIT(ses->flags, SES_FLAG_LOGNEXT);
+		DEL_BIT(ses->logmode, LOG_FLAG_NEXT);
 	}
 	pop_call();
 	return;

+ 5 - 2
src/port.c

@@ -277,7 +277,10 @@ int port_new(struct session *ses, int sock)
 
 	port_printf(ses, "New connection: %s D%d.", new_buddy->ip, new_buddy->fd);
 
-	announce_support(ses, new_buddy);
+	if (HAS_BIT(ses->flags, SES_FLAG_TELNET))
+	{
+		announce_support(ses, new_buddy);
+	}
 
 	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 3, "PORT CONNECTION", new_buddy->name, new_buddy->ip, ntos(new_buddy->port));
 
@@ -916,7 +919,7 @@ DO_PORT(port_zap)
 
 DO_PORT(port_color)
 {
-	if (*arg1 == 0 || get_highlight_codes(gtd->ses, arg1, arg2) == FALSE)
+	if (*arg1 == 0 || get_color_names(gtd->ses, arg1, arg2) == FALSE)
 	{
 		port_printf(ses, "Valid colors are:\n\nreset, bold, dim, light, dark, underscore, blink, reverse, black, red, green, yellow, blue, magenta, cyan, white, b black, b red, b green, b yellow, b blue, b magenta, b cyan, b white");
 

+ 0 - 197
src/prompt.c

@@ -1,197 +0,0 @@
-/******************************************************************************
-*   This file is part of TinTin++                                             *
-*                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
-*                                                                             *
-*   TinTin++ 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 3 of the License, 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 TinTin++.  If not, see https://www.gnu.org/licenses.           *
-******************************************************************************/
-
-/******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
-*                                                                             *
-*                      coded by Igor van den Hoven 2004                       *
-******************************************************************************/
-
-#include "tintin.h"
-
-
-DO_COMMAND(do_prompt)
-{
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE], arg4[BUFFER_SIZE];
-
-	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
-	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
-
-
-	if (*arg1 == 0)
-	{
-		show_list(ses->list[LIST_PROMPT], 0);
-	}
-	else if (*arg1 && *arg2 == 0)
-	{
-		if (show_node_with_wild(ses, arg1, ses->list[LIST_PROMPT]) == FALSE)
-		{
-			show_message(ses, LIST_PROMPT, "#PROMPT: NO MATCH(ES) FOUND FOR {%s}.", arg1);
-		}
-	}
-	else
-	{
-		arg = sub_arg_in_braces(ses, arg, arg3, GET_ONE, SUB_VAR|SUB_FUN);
-		arg = sub_arg_in_braces(ses, arg, arg4, GET_ONE, SUB_VAR|SUB_FUN);
-
-		update_node_list(ses->list[LIST_PROMPT], arg1, arg2, arg3, arg4);
-
-		show_message(ses, LIST_PROMPT, "#OK. {%s} NOW PROMPTS {%s} @ {%s} {%s}.", arg1, arg2, arg3, arg4);
-	}
-	return ses;
-}
-
-
-DO_COMMAND(do_unprompt)
-{
-	delete_node_with_wild(ses, LIST_PROMPT, arg);
-
-	return ses;
-}
-
-
-void check_all_prompts(struct session *ses, char *original, char *line)
-{
-	struct listroot *root = ses->list[LIST_PROMPT];
-	struct listnode *node;
-
-	if (!HAS_BIT(ses->flags, SES_FLAG_SPLIT))
-	{
-		return;
-	}
-
-	for (root->update = 0 ; root->update < root->used ; root->update++)
-	{
-		if (check_one_regexp(ses, root->list[root->update], line, original, 0))
-		{
-			node = root->list[root->update];
-
-			if (*node->arg2)
-			{
-				substitute(ses, node->arg2, original, SUB_ARG);
-				substitute(ses, original, original, SUB_VAR|SUB_FUN|SUB_COL|SUB_ESC);
-			}
-
-			show_debug(ses, LIST_PROMPT, "#DEBUG PROMPT {%s}", node->arg1);
-			show_debug(ses, LIST_GAG, "#DEBUG GAG {%s}", node->arg1);
-
-			do_one_prompt(ses, original, atoi(node->arg3), atoi(node->arg4));
-
-			SET_BIT(ses->flags, SES_FLAG_GAG);
-		}
-	}
-}
-
-void do_one_prompt(struct session *ses, char *prompt, int row, int col)
-{
-	char temp[BUFFER_SIZE];
-	int original_row, original_col, len, clear;
-
-	original_row = row;
-	original_col = col;
-
-	if (row < 0)
-	{
-		row = 1 + gtd->screen->rows + row;
-	}
-	else if (row == 0)
-	{
-		row = gtd->screen->rows - 2;
-	}
-
-	clear = 0;
-
-	if (col < 0)
-	{
-		col = 1 + gtd->screen->cols + col;
-	}
-	else if (col == 0)
-	{
-		col = 1;
-		clear = 1;
-	}
-
-	if (row < 1 || row > gtd->screen->rows)
-	{
-		show_error(ses, LIST_PROMPT, "#ERROR: PROMPT ROW IS OUTSIDE THE SCREEN: {%s} {%d} {%d}.", prompt, original_row, original_col);
-
-		return;
-	}
-
-	if (col < 0 || col > gtd->screen->cols)
-	{
-		show_error(ses, LIST_PROMPT, "#ERROR: PROMPT COLUMN IS OUTSIDE THE SCREEN: {%s} {%d} {%d}.", prompt, original_row, original_col);
-
-		return;
-	}
-
-	if (row > ses->top_row && row < ses->bot_row)
-	{
-		show_error(ses, LIST_PROMPT, "#ERROR: PROMPT ROW IS INSIDE THE SCROLLING REGION: {%s} {%d}.", prompt, original_row);
-
-		return;
-	}
-
-	if (ses != gtd->ses)
-	{
-		return;
-	}
-
-	len = strip_vt102_strlen(ses, prompt);
-
-	if (len == 0)
-	{
-		sprintf(temp, "%.*s", gtd->screen->cols + 4, "\e[0m--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
-	}
-	else if (col - 1 + len <= gtd->screen->cols)
-	{
-		sprintf(temp, "%s", prompt);
-	}
-	else
-	{
-		show_debug(ses, LIST_PROMPT, "#DEBUG PROMPT {%s}", prompt);
-
-		sprintf(temp, "#PROMPT SIZE (%d) LONGER THAN ROW SIZE (%d)", len, gtd->screen->cols);
-	}
-
-	if (!HAS_BIT(ses->flags, SES_FLAG_READMUD) && IS_SPLIT(ses))
-	{
-		save_pos(ses);
-	}
-
-	if (row == gtd->screen->rows)
-	{
-		gtd->input_off = len + 1;
-
-		printf("\e[%d;1H\e[%d;1H\e[K%s%s\e[%d;%dH\e7\e[%d;1H", row, row, temp, gtd->input_buf, row, gtd->input_off + gtd->input_cur, ses->bot_row);
-	}
-	else
-	{
-		printf("\e[%d;%dH\e[%d;%dH%s%s\e[%d;1H", row, col, row, col, clear ? "\e[2K" : "", temp, ses->bot_row);
-	}
-
-	set_line_screen(temp, row - 1, col - 1);
-
-	if (!HAS_BIT(ses->flags, SES_FLAG_READMUD) && IS_SPLIT(ses))
-	{
-		restore_pos(ses);
-	}
-
-}

+ 121 - 26
src/screen.c

@@ -56,23 +56,29 @@ DO_COMMAND(do_screen)
 		{
 			if (is_abbrev(arg1, screen_table[cnt].name))
 			{
-				if (HAS_BIT(screen_table[cnt].get1, SCREEN_FLAG_GET_ONE))
+				if (!HAS_BIT(screen_table[cnt].get1, SCREEN_FLAG_GET_NONE))
 				{
-					arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+					if (HAS_BIT(screen_table[cnt].get1, SCREEN_FLAG_GET_ONE))
+					{
+						arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+					}
+					else
+					{
+						arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
+					}
 				}
-				else
-				{
-					arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
-				}
-				if (HAS_BIT(screen_table[cnt].get2, SCREEN_FLAG_GET_ONE))
-				{
-					arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
-				}
-				else
+
+				if (!HAS_BIT(screen_table[cnt].get2, SCREEN_FLAG_GET_NONE))
 				{
-					arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
+					if (HAS_BIT(screen_table[cnt].get2, SCREEN_FLAG_GET_ONE))
+					{
+						arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
+					}
+					else
+					{
+						arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
+					}
 				}
-
 				screen_table[cnt].fun(ses, cnt, arg, arg1, arg2);
 
 				return ses;
@@ -135,21 +141,31 @@ DO_SCREEN(screen_clear)
 	{
 		printf("\e[2J");
 	}
+	else if (is_abbrev(arg1, "BOTTOM SPLIT"))
+	{
+		erase_bot_region(ses);
+	}
+	else if (is_abbrev(arg1, "TOP SPLIT"))
+	{
+		erase_top_region(ses);
+	}
 	else if (is_abbrev(arg1, "SCROLL REGION"))
 	{
-//		erase_scroll_region(ses);
-
-		printf("\e[%d;%d;%d;%d${", ses->top_row, 1, ses->bot_row, gtd->screen->cols);
+		erase_scroll_region(ses);
+	}
+	else if (is_abbrev(arg1, "SPLIT REGION"))
+	{
+		erase_split_region(ses);
 	}
 	else if (is_abbrev(arg1, "SQUARE"))
 	{
-		strcpy(arg1, arg2);
+		arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 		arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
 
 		top_row = get_row_index(ses, arg1);
 		top_col = get_col_index(ses, arg2);
 
-		tintin_printf2(ses, "debug: (%s) (%s) %d %d", arg1, arg2, top_row, top_col);
+//		tintin_printf2(ses, "debug: (%s) (%s) %d %d", arg1, arg2, top_row, top_col);
 
 		arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 		arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
@@ -157,7 +173,7 @@ DO_SCREEN(screen_clear)
 		bot_row = get_row_index(ses, arg1);
 		bot_col = get_col_index(ses, arg2);
 
-		tintin_printf2(ses, "debug: (%s) (%s) %d %d", arg1, arg2, bot_row, bot_col);
+//		tintin_printf2(ses, "debug: (%s) (%s) %d %d", arg1, arg2, bot_row, bot_col);
 
 		if (bot_col == 0)
 		{
@@ -165,12 +181,14 @@ DO_SCREEN(screen_clear)
 		}
 		else
 		{
-			printf("\e[%d;%d;%d;%d${", top_row, top_col, bot_row, bot_col);
+			erase_square(ses, top_row, top_col, bot_row, bot_col);
+
+//			printf("\e[%d;%d;%d;%d${", top_row, top_col, bot_row, bot_col); VT400 not widely supported
 		}
 	}
 	else
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN CLEAR {ALL|SCROLL REGION|SQUARE}");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN CLEAR {ALL|SCROLL|SPLIT|SQUARE}");
 	}
 }
 
@@ -927,19 +945,96 @@ void set_line_screen(char *str, int row, int col)
 
 void erase_scroll_region(struct session *ses)
 {
-	push_call("erase_scroll_region(%p) (%d,%d)",ses,ses->top_row,ses->bot_row);
+	int row;
 
-//	printf("\e[%d;%d;%d;%d${", ses->top_row, 1, ses->bot_row, gtd->screen->cols); VT400
+	push_call("erase_scroll_region(%p) [%d,%d]",ses,ses->top_row,ses->bot_row);
 
-	printf("\e7\e[%d;1H\e[%dM\e8", ses->top_row, ses->bot_row - ses->top_row);
+	if (ses->wrap <= 0)
+	{
+		save_pos(ses);
+		goto_pos(ses, ses->top_row, 1);
+		erase_lines(ses, ses->bot_row - ses->top_row);
+		load_pos(ses);
+	}
+	else
+	{
+		save_pos(ses);
+		goto_pos(ses, ses->top_row, 1);
+
+		for (row = ses->top_row ; row < ses->bot_row ; row++)
+		{
+			printf("\e[%dX\n", ses->wrap);
+		}
+		load_pos(ses);
+	}
 
-	ses->sav_row = ses->cur_row;
-	ses->sav_col = ses->cur_col;
+//	printf("\e[%d;%d;%d;%d${", ses->top_row, 1, ses->bot_row, gtd->screen->cols); VT400 not widely supported
 
 	pop_call();
 	return;
 }
 
+void erase_split_region(struct session *ses)
+{
+	erase_top_region(ses);
+
+	erase_bot_region(ses);
+}
+
+void erase_top_region(struct session *ses)
+{
+	int row;
+
+	if (ses->top_row > 1)
+	{
+		save_pos(ses);
+		goto_pos(ses, 1, 1);
+
+		for (row = 1 ; row < ses->top_row ; row++)
+		{
+			printf("\e[K\n");
+		}
+		load_pos(ses);
+	}
+}
+
+void erase_bot_region(struct session *ses)
+{
+	int row;
+
+	if (ses->bot_row < gtd->screen->rows)
+	{
+		save_pos(ses);
+		goto_pos(ses, ses->bot_row + 1, 1);
+
+		for (row = ses->bot_row + 1 ; row < gtd->screen->rows ; row++)
+		{
+			printf("\e[K\n");
+		}
+		load_pos(ses);
+	}
+}
+
+void erase_square(struct session *ses, int top_row, int top_col, int bot_row, int bot_col)
+{
+	int row;
+
+	push_call("erase_square(%p,%d,%d,%d,%d)",ses,top_row,top_col,bot_row,bot_col);
+
+	save_pos(ses);
+
+	for (row = top_row ; row <= bot_row ; row++)
+	{
+		goto_pos(ses, row, top_col);
+		printf("\e[%dX", bot_col - top_col + 1);
+	}
+	load_pos(ses);
+
+	pop_call();
+	return;
+}
+
+
 void get_line_screen(char *result, int row)
 {
 	strcpy(result, gtd->screen->lines[row]->str);

+ 23 - 8
src/session.c

@@ -380,9 +380,14 @@ struct session *new_session(struct session *ses, char *name, char *arg, int desc
 		}
 	}
 
+	newses->top_split = gts->top_split;
+	newses->bot_split = gts->bot_split;
+
 	newses->top_row = gts->top_row;
 	newses->bot_row = gts->bot_row;
 
+	newses->wrap    = gts->wrap;
+
 	init_buffer(newses, -1);
 
 	memcpy(&newses->cur_terminal, &gts->cur_terminal, sizeof(gts->cur_terminal));
@@ -400,10 +405,13 @@ struct session *new_session(struct session *ses, char *name, char *arg, int desc
 		tintin_printf(ses, "#TRYING TO LAUNCH '%s' RUNNING '%s'.", newses->name, newses->session_host);
 	}
 
-	gtd->ses = newses;
-
 	dirty_screen(newses);
 
+	if (gtd->background_level == 0)
+	{
+		gtd->ses = newses;
+	}
+
 	if (desc == 0)
 	{
 		newses = connect_session(newses);
@@ -425,7 +433,7 @@ struct session *new_session(struct session *ses, char *name, char *arg, int desc
 	if (newses == NULL)
 	{
 		pop_call();
-		return gtd->ses;
+		return ses;
 	}
 
 #ifdef HAVE_GNUTLS_H
@@ -443,16 +451,23 @@ struct session *new_session(struct session *ses, char *name, char *arg, int desc
 	}
 #endif
 
-	gtd->ses = newses;
 
 	if (*file)
 	{
-		gtd->ses = do_read(newses, file);
+		newses = do_read(newses, file);
 	}
 	check_all_events(newses, SUB_ARG, 0, 4, "SESSION CREATED", newses->name, newses->session_host, newses->session_ip, newses->session_port);
 
-	pop_call();
-	return gtd->ses;
+	if (gtd->background_level == 0)
+	{
+		pop_call();
+		return newses;
+	}
+	else
+	{
+		pop_call();
+		return ses;
+	}
 }
 
 struct session *connect_session(struct session *ses)
@@ -470,7 +485,7 @@ struct session *connect_session(struct session *ses)
 
 	if (sock == -1)
 	{
-		syserr_printf(ses, "connect_session: connect");
+//		syserr_printf(ses, "connect_session: connect");
 
 		cleanup_session(ses);
 

+ 75 - 42
src/show.c

@@ -60,7 +60,7 @@ DO_COMMAND(do_showme)
 
 	if (*arg2)
 	{
-		do_one_prompt(ses, arg1, (int) get_number(ses, arg2), (int) get_number(ses, arg3));
+		split_show(ses, arg1, (int) get_number(ses, arg2), (int) get_number(ses, arg3));
 
 		return ses;
 	}
@@ -117,14 +117,14 @@ void show_message(struct session *ses, int index, char *format, ...)
 		goto display;
 	}
 
-	if (HAS_BIT(root->flags, LIST_FLAG_MESSAGE))
+	if (!HAS_BIT(root->flags, LIST_FLAG_MESSAGE))
 	{
-		if (gtd->input_level == 0)
-		{
-			goto display;
-		}
-		pop_call();
-		return;
+		goto end;
+	}
+
+	if (gtd->input_level)
+	{
+		goto end;
 	}
 
 	display:
@@ -135,16 +135,28 @@ void show_message(struct session *ses, int index, char *format, ...)
 
 	tintin_puts2(ses, buffer);
 
+	free(buffer);
+
+	pop_call();
+	return;
+
+	end:
+
+
 	if (HAS_BIT(root->flags, LIST_FLAG_LOG))
 	{
 		if (ses->logfile)
 		{
-			logit(ses, buffer, ses->logfile, TRUE);
+			va_start(args, format);
+			vasprintf(&buffer, format, args);
+			va_end(args);
+
+			logit(ses, buffer, ses->logfile, LOG_FLAG_LINEFEED);
+
+			free(buffer);
 		}
 	}
 
-	free(buffer);
-
 	pop_call();
 	return;
 }
@@ -170,14 +182,6 @@ void show_error(struct session *ses, int index, char *format, ...)
 
 	root = ses->list[index];
 
-	if (HAS_BIT(root->flags, LIST_FLAG_LOG))
-	{
-		if (ses->logfile)
-		{
-			logit(ses, buffer, ses->logfile, TRUE);
-		}
-	}
-
 	if (HAS_BIT(root->flags, LIST_FLAG_DEBUG))
 	{
 		tintin_puts2(ses, buffer);
@@ -188,6 +192,16 @@ void show_error(struct session *ses, int index, char *format, ...)
 	if (HAS_BIT(root->flags, LIST_FLAG_MESSAGE))
 	{
 		tintin_puts2(ses, buffer);
+
+		goto end;
+	}
+
+	if (HAS_BIT(root->flags, LIST_FLAG_LOG))
+	{
+		if (ses->logfile)
+		{
+			logit(ses, buffer, ses->logfile, LOG_FLAG_LINEFEED);
+		}
 	}
 
 	end:
@@ -236,7 +250,7 @@ void show_debug(struct session *ses, int index, char *format, ...)
 	{
 		if (ses->logfile)
 		{
-			logit(ses, buf, ses->logfile, TRUE);
+			logit(ses, buf, ses->logfile, LOG_FLAG_LINEFEED);
 		}
 	}
 	pop_call();
@@ -275,27 +289,47 @@ void show_info(struct session *ses, int index, char *format, ...)
 	return;
 }
 
-void show_lines(struct session *ses, int flags, char *format, ...)
+void print_lines(struct session *ses, int flags, char *format, ...)
 {
-	char *buffer, *str_buf, *pto, *ptf;
+	char *buffer, *str_buf;
 	va_list args;
 
-	push_call("show_lines(%p,%d,%p,...)",ses,flags,format);
+	push_call("print_lines(%p,%d,%p,...)",ses,flags,format);
 
 	va_start(args, format);
 	vasprintf(&buffer, format, args);
 	va_end(args);
 
-	str_buf = str_alloc(BUFFER_SIZE + strlen(buffer) * 2);
+	if (flags)
+	{
+		str_buf = str_alloc(BUFFER_SIZE + strlen(buffer) * 2);
+
+		substitute(ses, buffer, str_buf, flags);
+
+		show_lines(ses, str_buf);
+
+		str_free(str_buf);
+	}
+	else
+	{
+		show_lines(ses, buffer);
+	}
 
-	substitute(ses, buffer, str_buf, flags);
+	free(buffer);
+
+	pop_call();
+	return;
+}
 
+void show_lines(struct session *ses, char *str)
+{
+	char *ptf;
 
-	pto = str_buf;
+	push_call("show_lines(%p,%p,...)",ses,str);
 
-	while (*pto)
+	while (*str)
 	{
-		ptf = strchr(pto, '\n');
+		ptf = strchr(str, '\n');
 
 		if (ptf == NULL)
 		{
@@ -303,14 +337,10 @@ void show_lines(struct session *ses, int flags, char *format, ...)
 		}
 		*ptf++ = 0;
 
-		tintin_puts3(ses, pto);
+		tintin_puts3(ses, str);
 
-		pto = ptf;
+		str = ptf;
 	}
-
-	free(buffer);
-	str_free(str_buf);
-
 	pop_call();
 	return;
 }
@@ -320,28 +350,31 @@ void tintin_header(struct session *ses, char *format, ...)
 {
 	char arg[BUFFER_SIZE], buf[BUFFER_SIZE];
 	va_list args;
+	int cols;
 
 	va_start(args, format);
 	vsprintf(arg, format, args);
 	va_end(args);
 
-	if ((int) strlen(arg) > gtd->screen->cols - 2)
+	cols = ses->wrap > 0 ? ses->wrap : gtd->screen->cols;
+
+	if ((int) strlen(arg) > cols - 2)
 	{
-		arg[gtd->screen->cols - 2] = 0;
+		arg[cols - 2] = 0;
 	}
 
 	if (HAS_BIT(ses->flags, SES_FLAG_SCREENREADER))
 	{
-		memset(buf, ' ', gtd->screen->cols);
+		memset(buf, ' ', cols);
 	}
 	else
 	{
-		memset(buf, '#', gtd->screen->cols);
+		memset(buf, '#', cols);
 	}
 
-	memcpy(&buf[(gtd->screen->cols - strlen(arg)) / 2], arg, strlen(arg));
+	memcpy(&buf[(cols - strlen(arg)) / 2], arg, strlen(arg));
 
-	buf[gtd->screen->cols] = 0;
+	buf[cols] = 0;
 
 	tintin_puts2(ses, buf);
 }
@@ -427,7 +460,7 @@ void tintin_puts2(struct session *ses, char *string)
 		ses = gtd->ses;
 	}
 
-	if (!HAS_BIT(gtd->ses->flags, SES_FLAG_VERBOSE) && gtd->quiet && gtd->verbose_level == 0)
+	if (!HAS_BIT(gtd->ses->flags, SES_FLAG_VERBOSE) && gtd->quiet_level && gtd->verbose_level == 0)
 	{
 		pop_call();
 		return;
@@ -483,7 +516,7 @@ void tintin_puts3(struct session *ses, char *string)
 		ses = gtd->ses;
 	}
 
-	if (!HAS_BIT(gtd->ses->flags, SES_FLAG_VERBOSE) && gtd->quiet && gtd->verbose_level == 0)
+	if (!HAS_BIT(gtd->ses->flags, SES_FLAG_VERBOSE) && gtd->quiet_level && gtd->verbose_level == 0)
 	{
 		pop_call();
 		return;

+ 100 - 2
src/split.c

@@ -143,14 +143,14 @@ void init_split(struct session *ses, int top, int bot)
 
 	for (bot = 1 ; gtd->screen->rows - bot > ses->bot_row ; bot++)
 	{
-		do_one_prompt(ses, "", gtd->screen->rows - bot, 0);
+		split_show(ses, "", gtd->screen->rows - bot, 0);
 	}
 
 	set_line_screen("", ses->bot_row - 1, 0);
 
 	for (top = 1 ; top < ses->top_row ; top++)
 	{
-		do_one_prompt(ses, "", top, 0);
+		split_show(ses, "", top, 0);
 	}
 
 	goto_rowcol(ses, gtd->screen->rows, 1);
@@ -222,3 +222,101 @@ void dirty_screen(struct session *ses)
 	pop_call();
 	return;
 }
+
+
+void split_show(struct session *ses, char *prompt, int row, int col)
+{
+	char temp[BUFFER_SIZE];
+	int original_row, original_col, len, clear;
+
+	original_row = row;
+	original_col = col;
+
+	if (row < 0)
+	{
+		row = 1 + gtd->screen->rows + row;
+	}
+	else if (row == 0)
+	{
+		row = gtd->screen->rows - 2;
+	}
+
+	clear = 0;
+
+	if (col < 0)
+	{
+		col = 1 + gtd->screen->cols + col;
+	}
+	else if (col == 0)
+	{
+		col = 1;
+		clear = 1;
+	}
+
+	if (row < 1 || row > gtd->screen->rows)
+	{
+		show_error(ses, LIST_PROMPT, "#ERROR: PROMPT ROW IS OUTSIDE THE SCREEN: {%s} {%d} {%d}.", prompt, original_row, original_col);
+
+		return;
+	}
+
+	if (col < 0 || col > gtd->screen->cols)
+	{
+		show_error(ses, LIST_PROMPT, "#ERROR: PROMPT COLUMN IS OUTSIDE THE SCREEN: {%s} {%d} {%d}.", prompt, original_row, original_col);
+
+		return;
+	}
+
+	if (row > ses->top_row && row < ses->bot_row)
+	{
+		show_error(ses, LIST_PROMPT, "#ERROR: PROMPT ROW IS INSIDE THE SCROLLING REGION: {%s} {%d}.", prompt, original_row);
+
+		return;
+	}
+
+	if (ses != gtd->ses)
+	{
+		return;
+	}
+
+	len = strip_vt102_strlen(ses, prompt);
+
+	if (len == 0)
+	{
+		sprintf(temp, "%.*s", gtd->screen->cols + 4, "\e[0m--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
+	}
+	else if (col - 1 + len <= gtd->screen->cols)
+	{
+		sprintf(temp, "%s", prompt);
+	}
+	else
+	{
+		show_debug(ses, LIST_PROMPT, "#DEBUG PROMPT {%s}", prompt);
+
+		sprintf(temp, "#PROMPT SIZE (%d) LONGER THAN ROW SIZE (%d)", len, gtd->screen->cols);
+	}
+
+	if (!HAS_BIT(ses->flags, SES_FLAG_READMUD) && IS_SPLIT(ses))
+	{
+		save_pos(ses);
+	}
+
+	if (row == gtd->screen->rows)
+	{
+		gtd->input_off = len + 1;
+
+		printf("\e[%d;1H\e[%d;1H\e[K%s%s\e[%d;%dH\e7\e[%d;1H", row, row, temp, gtd->input_buf, row, gtd->input_off + gtd->input_cur, ses->bot_row);
+	}
+	else
+	{
+		printf("\e[%d;%dH\e[%d;%dH%s%s\e[%d;1H", row, col, row, col, clear ? "\e[2K" : "", temp, ses->bot_row);
+	}
+
+	set_line_screen(temp, row - 1, col - 1);
+
+	if (!HAS_BIT(ses->flags, SES_FLAG_READMUD) && IS_SPLIT(ses))
+	{
+		restore_pos(ses);
+	}
+
+}

+ 2 - 2
src/ssl.c

@@ -51,7 +51,7 @@ DO_COMMAND(do_ssl)
 	{
 		ses = new_session(ses, arg1, arg, 0, 1);
 	}
-	return gtd->ses;
+	return ses;
 }
 
 gnutls_session_t ssl_negotiate(struct session *ses)
@@ -69,7 +69,7 @@ gnutls_session_t ssl_negotiate(struct session *ses)
 	gnutls_init(&ssl_ses, GNUTLS_CLIENT);
 	gnutls_set_default_priority(ssl_ses);
 	gnutls_credentials_set(ssl_ses, GNUTLS_CRD_CERTIFICATE, ssl_cred);
-	gnutls_transport_set_ptr(ssl_ses, (gnutls_transport_ptr_t) ses->socket);
+	gnutls_transport_set_ptr(ssl_ses, (gnutls_transport_ptr_t) (long int) ses->socket);
 
 	do 
 	{

+ 1040 - 56
src/substitute.c

@@ -21,114 +21,1098 @@
 /******************************************************************************
 *                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
 *                                                                             *
-*                         coded by Peter Unold 1992                           *
+*                      coded by Igor van den Hoven 2004                       *
 ******************************************************************************/
 
-
 #include "tintin.h"
 
-DO_COMMAND(do_substitute)
+int is_variable(struct session *ses, char *str)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE], *str;
+	struct listroot *root;
+	char temp[BUFFER_SIZE], *ptt;
+	int i = 1;
+
+	while (str[i] == str[0])
+	{
+		i++;
+	}
 
-	str = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
-	arg = get_arg_in_braces(ses, str, arg2, GET_ALL);
-	arg = get_arg_in_braces(ses, arg, arg3, GET_ALL);
+	if (str[i] == DEFAULT_OPEN)
+	{
+		return TRUE;
+	}
 
-	if (*arg3 == 0)
+	if (str[i] != '_' && isalpha((int) str[i]) == 0)
 	{
-		strcpy(arg3, "5");
+		return FALSE;
 	}
 
-	if (*arg1 == 0)
+	ptt = temp;
+
+	while (isalnum((int) str[i]) || str[i] == '_')
 	{
-		show_list(ses->list[LIST_SUBSTITUTE], 0);
+		*ptt++ = str[i];
+
+		i++;
 	}
-	else if (*str == 0)
+	*ptt = 0;
+
+	root = local_list(ses);
+
+	if (search_node_list(root, temp) == NULL)
 	{
-		if (show_node_with_wild(ses, arg1, ses->list[LIST_SUBSTITUTE]) == FALSE)
+		root = ses->list[LIST_VARIABLE];
+
+		if (search_node_list(root, temp) == NULL)
 		{
-			show_message(ses, LIST_SUBSTITUTE, "#SUBSTITUTE: NO MATCH(ES) FOUND FOR {%s}.", arg1);
+			return FALSE;
 		}
 	}
-	else
+
+	return TRUE;
+}
+
+int is_function(struct session *ses, char *str)
+{
+	char temp[BUFFER_SIZE], *ptt;
+	int i = 1;
+
+	while (str[i] == str[0])
 	{
-		update_node_list(ses->list[LIST_SUBSTITUTE], arg1, arg2, arg3, "");
+		i++;
+	}
 
-		show_message(ses, LIST_SUBSTITUTE, "#OK. {%s} IS NOW SUBSTITUTED AS {%s} @ {%s}.", arg1, arg2, arg3);
+	if (str[i] != '_' && isalpha((int) str[i]) == 0)
+	{
+		return FALSE;
 	}
-	return ses;
-}
 
+	ptt = temp;
 
-DO_COMMAND(do_unsubstitute)
-{
-	delete_node_with_wild(ses, LIST_SUBSTITUTE, arg);
+	while (isalnum((int) str[i]) || str[i] == '_')
+	{
+		*ptt++ = str[i];
+
+		i++;
+	}
+	*ptt = 0;
+
+	if (str[i] != DEFAULT_OPEN)
+	{
+		return FALSE;
+	}
+
+	if (search_node_list(ses->list[LIST_FUNCTION], temp) == NULL)
+	{
+		if (find_session(temp) == NULL)
+		{
+			return FALSE;
+		}
+	}
 
-	return ses;
+	return TRUE;
 }
 
-void check_all_substitutions(struct session *ses, char *original, char *line)
+int substitute(struct session *ses, char *string, char *result, int flags)
 {
-	char match[BUFFER_SIZE], subst[BUFFER_SIZE], output[BUFFER_SIZE], temp[BUFFER_SIZE], *ptl, *ptm, *pto;
-	struct listroot *root = ses->list[LIST_SUBSTITUTE];
 	struct listnode *node;
-	int len;
+	struct listroot *root;
+	struct session *sesptr;
+	char temp[BUFFER_SIZE], buf[BUFFER_SIZE], buffer[BUFFER_SIZE], *pti, *pto, *ptt, *str;
+	char *pte, old[10] = { 0 };
+	int i, cnt, escape = FALSE, flags_neol = flags;
+
+	push_call("substitute(%p,%p,%p,%d)",ses,string,result,flags);
+
+	pti = string;
+	pto = (string == result) ? buffer : result;
 
-	for (root->update = 0 ; root->update < root->used ; root->update++)
+	DEL_BIT(flags_neol, SUB_EOL|SUB_LNF);
+
+	while (TRUE)
 	{
-		if (check_one_regexp(ses, root->list[root->update], line, original, 0))
+		if (HAS_BIT(ses->flags, SES_FLAG_BIG5) && *pti & 128 && pti[1] != 0)
+		{
+			*pto++ = *pti++;
+			*pto++ = *pti++;
+			continue;
+		}
+
+		switch (*pti)
 		{
-			node = root->list[root->update];
+			case '\0':
+				if (HAS_BIT(flags, SUB_EOL))
+				{
+					if (HAS_BIT(ses->flags, SES_FLAG_RUN))
+					{
+						*pto++ = '\r';
+					}
+					else
+					{
+						*pto++ = '\r';
+						*pto++ = '\n';
+					}
+				}
+
+				if (HAS_BIT(flags, SUB_LNF))
+				{
+					*pto++ = '\n';
+				}
 
-			pto = original;
-			ptl = line;
+				*pto = 0;
 
-			*output = 0;
+				if (string == result)
+				{
+					strcpy(result, buffer);
 
-			do
-			{
-				if (*gtd->vars[0] == 0)
+					pop_call();
+					return pto - buffer;
+				}
+				else
 				{
-					break;
+					pop_call();
+					return pto - result;
 				}
+				break;
+
+			case '@':
+				if (HAS_BIT(flags, SUB_FUN) && !HAS_BIT(ses->list[LIST_FUNCTION]->flags, LIST_FLAG_IGNORE))
+				{
+					i = 1;
+					escape = FALSE;
+					sesptr = NULL;
+
+					while (pti[i] == '@')
+					{
+						escape = TRUE;
 
-				strcpy(match, gtd->vars[0]);
+						i++;
+					}
 
-				substitute(ses, node->arg2, temp, SUB_ARG);
-				substitute(ses, temp, subst, SUB_VAR|SUB_FUN|SUB_COL|SUB_ESC);
+					for (ptt = temp ; isalnum((int) pti[i]) || pti[i] == '_' ; i++)
+					{
+						*ptt++ = pti[i];
+					}
+					*ptt = 0;
 
-				if (*node->arg1 == '~')
+					if (pti[i] != DEFAULT_OPEN)
+					{
+						while (*pti == '@')
+						{
+							*pto++ = *pti++;
+						}
+						continue;
+					}
+
+					node = search_node_list(ses->list[LIST_FUNCTION], temp);
+
+					if (node == NULL)
+					{
+						sesptr = find_session(temp);
+					}
+
+					if (sesptr == NULL && node == NULL)
+					{
+						while (*pti == '@')
+						{
+							*pto++ = *pti++;
+						}
+						continue;
+					}
+
+					if (escape)
+					{
+						pti++;
+
+						while (*pti == '@')
+						{
+							*pto++ = *pti++;
+						}
+						continue;
+					}
+
+					pti = get_arg_in_braces(ses, &pti[i], temp, GET_ONE);
+
+					if (sesptr)
+					{
+						substitute(sesptr, temp, pto, flags_neol);
+
+						pto += strlen(pto);
+						
+						continue;
+					}
+					else
+					{
+						substitute(ses, temp, buf, flags_neol);
+					}
+
+					show_debug(ses, LIST_FUNCTION, "#DEBUG FUNCTION {%s}", node->arg1);
+
+					RESTRING(gtd->vars[0], buf);
+
+					pte = buf;
+
+					for (i = 1 ; i < 100 ; i++)
+					{
+						pte = get_arg_in_braces(ses, pte, temp, GET_ALL);
+
+						RESTRING(gtd->vars[i], temp);
+
+						if (*pte == 0)
+						{
+							while (++i < 100)
+							{
+								if (*gtd->vars[i])
+								{
+									RESTRING(gtd->vars[i], "");
+								}
+							}
+							break;
+						}
+
+						if (*pte == COMMAND_SEPARATOR)
+						{
+							pte++;
+						}
+
+					}
+
+					substitute(ses, node->arg2, buf, SUB_ARG);
+
+					script_driver(ses, LIST_FUNCTION, buf);
+
+					substitute(ses, "$result", pto, flags_neol|SUB_VAR);
+
+					pto += strlen(pto);
+				}
+				else
 				{
-					ptm = strstr(pto, match);
+					if (HAS_BIT(flags, SUB_SEC) && !HAS_BIT(flags, SUB_ARG) && is_function(ses, pti))
+					{
+						*pto++ = '\\';
+					}
+					*pto++ = *pti++;
+				}
+				break;
 
-					len = strlen(match);
+			case '*':
+				if (HAS_BIT(flags, SUB_VAR) && !HAS_BIT(ses->list[LIST_VARIABLE]->flags, LIST_FLAG_IGNORE) && pti[1])
+				{
+					int brace = FALSE;
+					i = 1;
+					escape = FALSE;
+
+					while (pti[i] == '*')
+					{
+						escape = TRUE;
+
+						i++;
+					}
+
+					if (pti[i] == DEFAULT_OPEN)
+					{
+						brace = TRUE;
+
+						ptt = get_arg_in_braces(ses, &pti[i], buf, GET_ALL);
+
+						i += strlen(buf) + 2;
+
+						substitute(ses, buf, temp, flags_neol);
+					}
+					else
+					{
+						ptt = temp;
+
+						while (isalnum((int) pti[i]) || pti[i] == '_')
+						{
+							*ptt++ = pti[i];
+
+							i++;
+						}
+						*ptt = 0;
+					}
+
+					if (*temp)
+					{
+						root = local_list(ses);
+
+						if ((node = search_node_list(root, temp)) == NULL)
+						{
+							root = ses->list[LIST_VARIABLE];
+
+							node = search_node_list(root, temp);
+						}
+					}
+					else
+					{
+						root = ses->list[LIST_VARIABLE];
+						node = NULL;
+					}
+
+					if (brace == FALSE && node == NULL)
+					{
+						while (*pti == '*')
+						{
+							*pto++ = *pti++;
+						}
+						continue;
+					}
+
+					if (escape)
+					{
+						pti++;
+
+						while (*pti == '*')
+						{
+							*pto++ = *pti++;
+						}
+						continue;
+					}
+
+					pti = get_arg_at_brackets(ses, &pti[i], temp + strlen(temp));
+
+					substitute(ses, temp, buf, flags_neol);
+
+					str = str_dup("");
+
+					get_nest_node_key(root, buf, &str, brace);
+
+					substitute(ses, str, pto, flags_neol - SUB_VAR);
+
+					pto += strlen(pto);
+
+					str_free(str);
 				}
 				else
 				{
-					ptm = strip_vt102_strstr(pto, match, &len);
+					if (HAS_BIT(flags, SUB_SEC) && !HAS_BIT(flags, SUB_ARG) && is_variable(ses, pti))
+					{
+						*pto++ = '\\';
+					}
+					*pto++ = *pti++;
+				}
+				break;
 
-					ptl = strstr(ptl, match) + strlen(match);
+			case '$':
+				if (HAS_BIT(flags, SUB_VAR) && !HAS_BIT(ses->list[LIST_VARIABLE]->flags, LIST_FLAG_IGNORE) && pti[1])
+				{
+					int brace = FALSE;
+					i = 1;
+					escape = FALSE;
+
+					while (pti[i] == '$')
+					{
+						escape = TRUE;
+
+						i++;
+					}
+
+					if (pti[i] == DEFAULT_OPEN)
+					{
+						brace = TRUE;
+
+						ptt = get_arg_in_braces(ses, &pti[i], buf, GET_ALL);
+
+						i += strlen(buf) + 2;
+
+						substitute(ses, buf, temp, flags_neol);
+					}
+					else
+					{
+						ptt = temp;
+
+						while (isalnum((int) pti[i]) || pti[i] == '_')
+						{
+							*ptt++ = pti[i];
+
+							i++;
+						}
+						*ptt = 0;
+					}
+
+					if (*temp)
+					{
+						root = local_list(ses);
+
+						if ((node = search_node_list(root, temp)) == NULL)
+						{
+							root = ses->list[LIST_VARIABLE];
+
+							node = search_node_list(root, temp);
+						}
+					}
+					else
+					{
+						root = ses->list[LIST_VARIABLE];
+						node = NULL;
+					}
+
+					if (brace == FALSE && node == NULL)
+					{
+						while (*pti == '$')
+						{
+							*pto++ = *pti++;
+						}
+						continue;
+					}
+
+					if (escape)
+					{
+						pti++;
+
+						while (*pti == '$')
+						{
+							*pto++ = *pti++;
+						}
+						continue;
+					}
+
+					pti = get_arg_at_brackets(ses, &pti[i], temp + strlen(temp));
+
+					substitute(ses, temp, buf, flags_neol);
+
+					str = str_dup("");
+
+					get_nest_node_val(root, buf, &str, brace);
+
+					substitute(ses, str, pto, flags_neol - SUB_VAR);
+
+					pto += strlen(pto);
+
+					str_free(str);
+				}
+				else
+				{
+					if (HAS_BIT(flags, SUB_SEC) && !HAS_BIT(flags, SUB_ARG) && is_variable(ses, pti))
+					{
+						*pto++ = '\\';
+					}
+					*pto++ = *pti++;
+				}
+				break;
+
+			case '&':
+				if (HAS_BIT(flags, SUB_CMD) && (isdigit((int) pti[1]) || pti[1] == '&'))
+				{
+					if (pti[1] == '&')
+					{
+						while (pti[1] == '&')
+						{
+							*pto++ = *pti++;
+						}
+						if (isdigit((int) pti[1]))
+						{
+							pti++;
+						}
+						else
+						{
+							*pto++ = *pti++;
+						}
+					}
+					else
+					{
+						i = isdigit((int) pti[2]) ? (pti[1] - '0') * 10 + pti[2] - '0' : pti[1] - '0';
+
+						for (cnt = 0 ; gtd->cmds[i][cnt] ; cnt++)
+						{
+							*pto++ = gtd->cmds[i][cnt];
+						}
+						pti += isdigit((int) pti[2]) ? 3 : 2;
+					}
+				}
+				else if (HAS_BIT(flags, SUB_VAR) && !HAS_BIT(ses->list[LIST_VARIABLE]->flags, LIST_FLAG_IGNORE))
+				{
+					int brace = FALSE;
+					i = 1;
+					escape = FALSE;
+
+					while (pti[i] == '&')
+					{
+						escape = TRUE;
+
+						i++;
+					}
+
+					if (pti[i] == DEFAULT_OPEN)
+					{
+						brace = TRUE;
+
+						ptt = get_arg_in_braces(ses, &pti[i], buf, GET_ALL);
+
+						i += strlen(buf) + 2;
+
+						substitute(ses, buf, temp, flags_neol);
+					}
+					else
+					{
+						ptt = temp;
+
+						while (isalnum((int) pti[i]) || pti[i] == '_')
+						{
+							*ptt++ = pti[i];
+
+							i++;
+						}
+						*ptt = 0;
+					}
+
+					if (*temp)
+					{
+						root = local_list(ses);
+
+						if ((node = search_node_list(root, temp)) == NULL)
+						{
+							root = ses->list[LIST_VARIABLE];
+							node = search_node_list(root, temp);
+						}
+					}
+					else
+					{
+						root = ses->list[LIST_VARIABLE];
+						node = NULL;
+					}
+
+					if (brace == FALSE && node == NULL)
+					{
+						while (*pti == '&')
+						{
+							*pto++ = *pti++;
+						}
+						continue;
+					}
+
+					if (escape)
+					{
+						pti++;
+
+						while (*pti == '&')
+						{
+							*pto++ = *pti++;
+						}
+						continue;
+					}
+
+					pti = get_arg_at_brackets(ses, &pti[i], temp + strlen(temp));
+
+					substitute(ses, temp, buf, flags_neol);
+
+					str = str_dup("");
+
+					get_nest_index(root, buf, &str, brace);
+
+					substitute(ses, str, pto, flags_neol - SUB_VAR);
+
+					pto += strlen(pto);
+
+					str_free(str);
+				}
+				else
+				{
+					if (HAS_BIT(flags, SUB_SEC) && !HAS_BIT(flags, SUB_ARG) && is_variable(ses, pti))
+					{
+						*pto++ = '\\';
+					}
+					*pto++ = *pti++;
 				}
+				break;
+
+			case '%':
+				if (HAS_BIT(flags, SUB_ARG) && (isdigit((int) pti[1]) || pti[1] == '%'))
+				{
+					if (pti[1] == '%')
+					{
+						while (pti[1] == '%')
+						{
+							*pto++ = *pti++;
+						}
+						pti++;
+					}
+					else
+					{
+						i = isdigit((int) pti[2]) ? (pti[1] - '0') * 10 + pti[2] - '0' : pti[1] - '0';
+
+						ptt = gtd->vars[i];
+
+						while (*ptt)
+						{
+							if (HAS_BIT(ses->flags, SES_FLAG_BIG5) && *ptt & 128 && ptt[1] != 0)
+							{
+								*pto++ = *ptt++;
+								*pto++ = *ptt++;
+								continue;
+							}
+
+							if (HAS_BIT(flags, SUB_SEC))
+							{
+								switch (*ptt)
+								{
+									case '\\':
+										*pto++ = '\\';
+										*pto++ = '\\';
+										break;
+
+									case '{':
+										*pto++ = '\\';
+										*pto++ = 'x';
+										*pto++ = '7';
+										*pto++ = 'B';
+										break;
 
-				*ptm = 0;
+									case '}':
+										*pto++ = '\\';
+										*pto++ = 'x';
+										*pto++ = '7';
+										*pto++ = 'D';
+										break;
 
-				cat_sprintf(output, "%s%s", pto, subst);
+									case '$':
+									case '&':
+									case '*':
+										if (is_variable(ses, ptt))
+										{
+											*pto++ = '\\';
+											*pto++ = *ptt;
+										}
+										else
+										{
+											*pto++ = *ptt;
+										}
+										break;
 
-				pto = ptm + len;
+									case '@':
+										if (is_function(ses, ptt))
+										{
+											*pto++ = '\\';
+											*pto++ = *ptt;
+										}
+										else
+										{
+											*pto++ = *ptt;
+										}
+										break;
 
-				show_debug(ses, LIST_SUBSTITUTE, "#DEBUG SUBSTITUTE {%s} {%s}", node->arg1, match);
-			}
-			while (check_one_regexp(ses, node, ptl, pto, 0));
+									case COMMAND_SEPARATOR:
+										*pto++ = '\\';
+										*pto++ = COMMAND_SEPARATOR;
+										break;
 
-			strcat(output, pto);
+									default:
+										*pto++ = *ptt;
+										break;
+								}
+								ptt++;
+							}
+							else
+							{
+								*pto++ = *ptt++;
+							}
+						}
+						pti += isdigit((int) pti[2]) ? 3 : 2;
+					}
+				}
+				else
+				{
+					*pto++ = *pti++;
+				}
+				break;
+
+			case '<':
+				if (HAS_BIT(flags, SUB_COL) && isalnum((int) pti[1]))
+				{
+					if (HAS_BIT(flags, SUB_CMP) && old[0] && !strncmp(old, pti, strlen(old)))
+					{
+						pti += strlen(old);
+					}
+					else if (isdigit((int) pti[1]) && isdigit((int) pti[2]) && isdigit((int) pti[3]) && pti[4] == '>')
+					{
+						if (pti[1] != '8' || pti[2] != '8' || pti[3] != '8')
+						{
+							*pto++ = ASCII_ESC;
+							*pto++ = '[';
+
+							switch (pti[1])
+							{
+								case '2':
+									*pto++ = '2';
+									*pto++ = '2';
+									*pto++ = ';';
+									break;
+								case '8':
+									break;
+								default:
+									*pto++ = pti[1];
+									*pto++ = ';';
+							}
+							switch (pti[2])
+							{
+								case '8':
+									break;
+								default:
+									*pto++ = '3';
+									*pto++ = pti[2];
+									*pto++ = ';';
+									break;
+							}
+							switch (pti[3])
+							{
+								case '8':
+									break;
+								default:
+									*pto++ = '4';
+									*pto++ = pti[3];
+									*pto++ = ';';
+									break;
+							}
+							pto--;
+							*pto++ = 'm';
+						}
+						pti += sprintf(old, "<%c%c%c>", pti[1], pti[2], pti[3]);
+					}
+					else if (pti[1] >= 'a' && pti[1] <= 'f' && pti[2] >= 'a' && pti[2] <= 'f' && pti[3] >= 'a' && pti[3] <= 'f' && pti[4] == '>')
+					{
+						*pto++ = ASCII_ESC;
+						*pto++ = '[';
+						*pto++ = '3';
+						*pto++ = '8';
+						*pto++ = ';';
+						*pto++ = '5';
+						*pto++ = ';';
+						cnt = 16 + (pti[1] - 'a') * 36 + (pti[2] - 'a') * 6 + (pti[3] - 'a');
+						*pto++ = '0' + cnt / 100;
+						*pto++ = '0' + cnt % 100 / 10;
+						*pto++ = '0' + cnt % 10;
+						*pto++ = 'm';
+						pti += sprintf(old, "<%c%c%c>", pti[1], pti[2], pti[3]);
+					}
+					else if (pti[1] >= 'A' && pti[1] <= 'F' && pti[2] >= 'A' && pti[2] <= 'F' && pti[3] >= 'A' && pti[3] <= 'F' && pti[4] == '>')
+					{
+						*pto++ = ASCII_ESC;
+						*pto++ = '[';
+						*pto++ = '4';
+						*pto++ = '8';
+						*pto++ = ';';
+						*pto++ = '5';
+						*pto++ = ';';
+						cnt = 16 + (pti[1] - 'A') * 36 + (pti[2] - 'A') * 6 + (pti[3] - 'A');
+						*pto++ = '0' + cnt / 100;
+						*pto++ = '0' + cnt % 100 / 10;
+						*pto++ = '0' + cnt % 10;
+						*pto++ = 'm';
+						pti += sprintf(old, "<%c%c%c>", pti[1], pti[2], pti[3]);
+					}
+					else if (pti[1] == 'g' && isdigit((int) pti[2]) && isdigit((int) pti[3]) && pti[4] == '>')
+					{
+						*pto++ = ASCII_ESC;
+						*pto++ = '[';
+						*pto++ = '3';
+						*pto++ = '8';
+						*pto++ = ';';
+						*pto++ = '5';
+						*pto++ = ';';
+						cnt = 232 + (pti[2] - '0') * 10 + (pti[3] - '0');
+						*pto++ = '0' + cnt / 100;
+						*pto++ = '0' + cnt % 100 / 10;
+						*pto++ = '0' + cnt % 10;
+						*pto++ = 'm';
+						pti += sprintf(old, "<g%c%c>", pti[2], pti[3]);
+					}
+					else if (pti[1] == 'G' && isdigit((int) pti[2]) && isdigit((int) pti[3]) && pti[4] == '>')
+					{
+						*pto++ = ASCII_ESC;
+						*pto++ = '[';
+						*pto++ = '4';
+						*pto++ = '8';
+						*pto++ = ';';
+						*pto++ = '5';
+						*pto++ = ';';
+						cnt = 232 + (pti[2] - '0') * 10 + (pti[3] - '0');
+						*pto++ = '0' + cnt / 100;
+						*pto++ = '0' + cnt % 100 / 10;
+						*pto++ = '0' + cnt % 10;
+						*pto++ = 'm';
+						pti += sprintf(old, "<G%c%c>", pti[2], pti[3]);
+					}
+					else if (toupper((int) pti[1]) == 'F' && isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && pti[5] == '>')
+					{
+						*pto++ = ASCII_ESC;
+						*pto++ = '[';
+						*pto++ = '3';
+						*pto++ = '8';
+						*pto++ = ';';
+						*pto++ = '2';
+						*pto++ = ';';
+						cnt  = isdigit(pti[2]) ? (pti[2] - '0') : (pti[2] - 'A' + 10);
+						cnt += cnt * 16;
+						*pto++ = '0' + cnt / 100;
+						*pto++ = '0' + cnt % 100 / 10;
+						*pto++ = '0' + cnt % 10;
+						*pto++ = ';';
+						cnt  = isdigit(pti[3]) ? (pti[3] - '0') : (pti[3] - 'A' + 10);
+						cnt += cnt * 16;
+						*pto++ = '0' + cnt / 100;
+						*pto++ = '0' + cnt % 100 / 10;
+						*pto++ = '0' + cnt % 10;
+						*pto++ = ';';
+						cnt  = isdigit(pti[4]) ? (pti[4] - '0') : (pti[4] - 'A' + 10);
+						cnt += cnt * 16;
+						*pto++ = '0' + cnt / 100;
+						*pto++ = '0' + cnt % 100 / 10;
+						*pto++ = '0' + cnt % 10;
+						*pto++ = 'm';
+						pti += sprintf(old, "<F%c%c%c>", pti[2], pti[3], pti[4]);
+					}
+					else if (toupper((int) pti[1]) == 'F' && isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && isxdigit((int) pti[5]) && isxdigit((int) pti[6]) && isxdigit((int) pti[7]) && pti[8] == '>')
+					{
+						*pto++ = ASCII_ESC;
+						*pto++ = '[';
+						*pto++ = '3';
+						*pto++ = '8';
+						*pto++ = ';';
+						*pto++ = '2';
+						*pto++ = ';';
+						cnt  = isdigit(pti[2]) ? 16 * (pti[2] - '0') : 16 * (pti[2] - 'A' + 10);
+						cnt += isdigit(pti[3]) ?  1 * (pti[3] - '0') :  1 * (pti[3] - 'A' + 10);
+						*pto++ = '0' + cnt / 100;
+						*pto++ = '0' + cnt % 100 / 10;
+						*pto++ = '0' + cnt % 10;
+						*pto++ = ';';
+						cnt  = isdigit(pti[4]) ? 16 * (pti[4] - '0') : 16 * (pti[4] - 'A' + 10);
+						cnt += isdigit(pti[5]) ?  1 * (pti[5] - '0') :  1 * (pti[5] - 'A' + 10);
+						*pto++ = '0' + cnt / 100;
+						*pto++ = '0' + cnt % 100 / 10;
+						*pto++ = '0' + cnt % 10;
+						*pto++ = ';';
+						cnt  = isdigit(pti[6]) ? 16 * (pti[6] - '0') : 16 * (pti[6] - 'A' + 10);
+						cnt += isdigit(pti[7]) ?  1 * (pti[7] - '0') :  1 * (pti[7] - 'A' + 10);
+						*pto++ = '0' + cnt / 100;
+						*pto++ = '0' + cnt % 100 / 10;
+						*pto++ = '0' + cnt % 10;
+						*pto++ = 'm';
+						pti += sprintf(old, "<F%c%c%c%c%c%c>", pti[2], pti[3], pti[4], pti[5], pti[6], pti[7]);
+					}
+					else if (toupper((int) pti[1]) == 'B' && isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && pti[5] == '>')
+					{
+						*pto++ = ASCII_ESC;
+						*pto++ = '[';
+						*pto++ = '4';
+						*pto++ = '8';
+						*pto++ = ';';
+						*pto++ = '2';
+						*pto++ = ';';
+						cnt  = isdigit(pti[2]) ? (pti[2] - '0') : (pti[2] - 'A' + 10);
+						cnt += cnt * 16;
+						*pto++ = '0' + cnt / 100;
+						*pto++ = '0' + cnt % 100 / 10;
+						*pto++ = '0' + cnt % 10;
+						*pto++ = ';';
+						cnt  = isdigit(pti[3]) ? (pti[3] - '0') : (pti[3] - 'A' + 10);
+						cnt += cnt * 16;
+						*pto++ = '0' + cnt / 100;
+						*pto++ = '0' + cnt % 100 / 10;
+						*pto++ = '0' + cnt % 10;
+						*pto++ = ';';
+						cnt  = isdigit(pti[4]) ? (pti[4] - '0') : (pti[4] - 'A' + 10);
+						cnt += cnt * 16;
+						*pto++ = '0' + cnt / 100;
+						*pto++ = '0' + cnt % 100 / 10;
+						*pto++ = '0' + cnt % 10;
+						*pto++ = 'm';
+						pti += sprintf(old, "<B%c%c%c>", pti[2], pti[3], pti[4]);
+					}
+					else if (toupper((int) pti[1]) == 'B' && isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && isxdigit((int) pti[5]) && isxdigit((int) pti[6]) && isxdigit((int) pti[7]) && pti[8] == '>')
+					{
+						*pto++ = ASCII_ESC;
+						*pto++ = '[';
+						*pto++ = '4';
+						*pto++ = '8';
+						*pto++ = ';';
+						*pto++ = '2';
+						*pto++ = ';';
+						cnt  = isdigit(pti[2]) ? 16 * (pti[2] - '0') : 16 * (pti[2] - 'A' + 10);
+						cnt += isdigit(pti[3]) ?  1 * (pti[3] - '0') :  1 * (pti[3] - 'A' + 10);
+						*pto++ = '0' + cnt / 100;
+						*pto++ = '0' + cnt % 100 / 10;
+						*pto++ = '0' + cnt % 10;
+						*pto++ = ';';
+						cnt  = isdigit(pti[4]) ? 16 * (pti[4] - '0') : 16 * (pti[4] - 'A' + 10);
+						cnt += isdigit(pti[5]) ?  1 * (pti[5] - '0') :  1 * (pti[5] - 'A' + 10);
+						*pto++ = '0' + cnt / 100;
+						*pto++ = '0' + cnt % 100 / 10;
+						*pto++ = '0' + cnt % 10;
+						*pto++ = ';';
+						cnt  = isdigit(pti[6]) ? 16 * (pti[6] - '0') : 16 * (pti[6] - 'A' + 10);
+						cnt += isdigit(pti[7]) ?  1 * (pti[7] - '0') :  1 * (pti[7] - 'A' + 10);
+						*pto++ = '0' + cnt / 100;
+						*pto++ = '0' + cnt % 100 / 10;
+						*pto++ = '0' + cnt % 10;
+						*pto++ = 'm';
+						pti += sprintf(old, "<B%c%c%c%c%c%c>", pti[2], pti[3], pti[4], pti[5], pti[6], pti[7]);
+					}
+					else
+					{
+						*pto++ = *pti++;
+					}
+				}
+				else
+				{
+					*pto++ = *pti++;
+				}
+				break;
 
-//			substitute(ses, output, original, SUB_VAR|SUB_FUN|SUB_COL|SUB_ESC);
 
-			strcpy(original, output);
+			case '\\':
+				if (HAS_BIT(flags, SUB_ESC))
+				{
+					pti++;
 
-			strip_vt102_codes(original, line);
+					switch (*pti)
+					{
+						case 'a':
+							*pto++ = '\a';
+							break;
+						case 'b':
+							*pto++ = '\b';
+							break;
+						case 'c':
+							if (pti[1])
+							{
+								pti++;
+								*pto++ = *pti % 32;
+							}
+							break;
+						case 'e':
+							*pto++ = '\e';
+							break;
+						case 'f':
+							*pto++ = '\f';
+							break;
+						case 'n':
+							*pto++ = '\n';
+							break;
+						case 'r':
+							*pto++ = '\r';
+							break;
+						case 't':
+							*pto++ = '\t';
+							break;
+						case 'x':
+							if (pti[1] && pti[2])
+							{
+								if (pti[1] == '0' && pti[2] == '0' && pti[3] == 0)
+								{
+									pti += 2;
+									DEL_BIT(flags, SUB_EOL);
+									DEL_BIT(flags, SUB_LNF);
+								}
+								else
+								{
+									pti++;
+									*pto++ = hex_number_8bit(pti);
+									pti++;
+								}
+							}
+							break;
+
+						case 'u':
+							if (pti[1] && pti[2] && pti[3] && pti[4])
+							{
+								pto += unicode_16_bit(&pti[1], pto);
+								pti += 4;
+							}
+							break;
+						case 'U':
+							if (pti[1] && pti[2] && pti[3] && pti[4] && pti[5] && pti[6])
+							{
+								pto += unicode_21_bit(&pti[1], pto);
+								pti += 6;
+							}
+							break;
+
+						case 'v':
+							*pto++ = '\v';
+							break;
+						case '0':
+							if (pti[1] == 0)
+							{
+								DEL_BIT(flags, SUB_EOL);
+								DEL_BIT(flags, SUB_LNF);
+							}
+							else if (pti[1] && pti[2])
+							{
+								pti++;
+								*pto++ = oct_number(pti);
+								pti++;
+							}
+							break;
+
+						case '\0':
+							DEL_BIT(flags, SUB_EOL);
+							DEL_BIT(flags, SUB_LNF);
+							continue;
+
+						default:
+							*pto++ = *pti;
+							break;
+					}
+					pti++;
+				}
+				else if (HAS_BIT(flags, SUB_SEC) && !HAS_BIT(flags, SUB_ARG))
+				{
+					*pto++ = '\\';
+					*pto++ = *pti++;
+				}
+				else if (HAS_BIT(flags, SUB_LIT))
+				{
+					*pto++ = *pti++;
+				}
+				else
+				{
+					*pto++ = *pti++;
+
+					if (*pti)
+					{
+						*pto++ = *pti++;
+					}
+				}
+				break;
+
+			default:
+				if (HAS_BIT(flags, SUB_SEC) && !HAS_BIT(flags, SUB_ARG))
+				{
+					switch (*pti)
+					{
+						case '{':
+							*pto++ = '\\';
+							*pto++ = 'x';
+							*pto++ = '7';
+							*pto++ = 'B';
+							break;
+
+						case '}':
+							*pto++ = '\\';
+							*pto++ = 'x';
+							*pto++ = '7';
+							*pto++ = 'D';
+							break;
+
+						case COMMAND_SEPARATOR:
+							*pto++ = '\\';
+							*pto++ = COMMAND_SEPARATOR;
+							break;
+
+						default:
+							*pto++ = *pti;
+							break;
+					}
+					pti++;
+				}
+				else
+				{
+					*pto++ = *pti++;
+				}
+				break;
 		}
 	}
+	pop_call();
+	return 0;
 }
-

+ 0 - 56
src/tab.c

@@ -1,56 +0,0 @@
-/******************************************************************************
-*   This file is part of TinTin++                                             *
-*                                                                             *
-*   Copyright 2004-2019 Igor van den Hoven                                    *
-*                                                                             *
-*   TinTin++ 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 3 of the License, 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 TinTin++.  If not, see https://www.gnu.org/licenses.           *
-******************************************************************************/
-
-/******************************************************************************
-*                (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                 *
-*                                                                             *
-*                      coded by Igor van den Hoven 2006                       *
-******************************************************************************/
-
-
-#include "tintin.h"
-
-
-DO_COMMAND(do_tab)
-{
-	char arg1[BUFFER_SIZE];
-
-	sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
-
-	if (*arg1 == 0)
-	{
-		show_list(ses->list[LIST_TAB], 0);
-	}
-	else
-	{
-		update_node_list(ses->list[LIST_TAB], arg1, "", "0", "");
-
-		show_message(ses, LIST_TAB, "#OK. {%s} IS NOW A TAB.", arg1);
-	}
-	return ses;
-}
-
-
-DO_COMMAND(do_untab)
-{
-	delete_node_with_wild(ses, LIST_TAB, arg);
-
-	return ses;
-}

+ 135 - 12
src/tables.c

@@ -37,6 +37,7 @@ struct command_type command_table[] =
 	{    "bell",              do_bell,              TOKEN_TYPE_COMMAND },
 	{    "break",             do_nop,               TOKEN_TYPE_BREAK   },
 	{    "buffer",            do_buffer,            TOKEN_TYPE_COMMAND },
+	{    "button",            do_button,            TOKEN_TYPE_COMMAND },
 	{    "case",              do_nop,               TOKEN_TYPE_CASE    },
 	{    "chat",              do_chat,              TOKEN_TYPE_COMMAND },
 	{    "class",             do_class,             TOKEN_TYPE_COMMAND },
@@ -48,6 +49,7 @@ struct command_type command_table[] =
 	{    "debug",             do_debug,             TOKEN_TYPE_COMMAND },
 	{    "default",           do_nop,               TOKEN_TYPE_DEFAULT },
 	{    "delay",             do_delay,             TOKEN_TYPE_COMMAND },
+	{    "draw",              do_draw,              TOKEN_TYPE_COMMAND },
 	{    "echo",              do_echo,              TOKEN_TYPE_COMMAND },
 	{    "else",              do_nop,               TOKEN_TYPE_ELSE    },
 	{    "elseif",            do_nop,               TOKEN_TYPE_ELSEIF  },
@@ -104,6 +106,7 @@ struct command_type command_table[] =
 	{    "ticker",            do_tick,              TOKEN_TYPE_COMMAND },
 	{    "unaction",          do_unaction,          TOKEN_TYPE_COMMAND },
 	{    "unalias",           do_unalias,           TOKEN_TYPE_COMMAND },
+	{    "unbutton",          do_unbutton,          TOKEN_TYPE_COMMAND },
 	{    "undelay",           do_undelay,           TOKEN_TYPE_COMMAND },
 	{    "unevent",           do_unevent,           TOKEN_TYPE_COMMAND },
 	{    "unfunction",        do_unfunction,        TOKEN_TYPE_COMMAND },
@@ -127,8 +130,9 @@ struct command_type command_table[] =
 
 struct list_type list_table[LIST_MAX] =
 {
-	{    "ACTION",            "ACTIONS",            SORT_PRIORITY,    3,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_REGEX },
-	{    "ALIAS",             "ALIASES",            SORT_PRIORITY,    3,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_REGEX },
+	{    "ACTION",            "ACTIONS",            SORT_PRIORITY,    3,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_REGEX|LIST_FLAG_PRIORITY },
+	{    "ALIAS",             "ALIASES",            SORT_PRIORITY,    3,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_REGEX|LIST_FLAG_PRIORITY },
+	{    "BUTTON",            "BUTTONS",            SORT_PRIORITY,    3,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_PRIORITY },
 	{    "CLASS",             "CLASSES",            SORT_PRIORITY,    2,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_INHERIT                                 },
 	{    "COMMAND",           "COMMANDS",           SORT_APPEND,      1,  LIST_FLAG_MESSAGE                                                                  },
 	{    "CONFIG",            "CONFIGURATIONS",     SORT_ALPHA,       2,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_INHERIT                 },
@@ -136,13 +140,13 @@ struct list_type list_table[LIST_MAX] =
 	{    "EVENT",             "EVENTS",             SORT_ALPHA,       2,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
 	{    "FUNCTION",          "FUNCTIONS",          SORT_ALPHA,       2,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
 	{    "GAG",               "GAGS",               SORT_ALPHA,       1,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
-	{    "HIGHLIGHT",         "HIGHLIGHTS",         SORT_PRIORITY,    3,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_REGEX },
+	{    "HIGHLIGHT",         "HIGHLIGHTS",         SORT_PRIORITY,    3,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_REGEX|LIST_FLAG_PRIORITY },
 	{    "HISTORY",           "HISTORIES",          SORT_APPEND,      1,  LIST_FLAG_MESSAGE                                                                  },
 	{    "MACRO",             "MACROS",             SORT_ALPHA,       2,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
 	{    "PATH",              "PATHS",              SORT_APPEND,      2,  LIST_FLAG_MESSAGE                                                                  },
 	{    "PATHDIR",           "PATHDIRS",           SORT_ALPHA,       3,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
-	{    "PROMPT",            "PROMPTS",            SORT_PRIORITY,    4,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_REGEX },
-	{    "SUBSTITUTE",        "SUBSTITUTES",        SORT_PRIORITY,    3,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_REGEX },
+	{    "PROMPT",            "PROMPTS",            SORT_PRIORITY,    4,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_REGEX|LIST_FLAG_PRIORITY },
+	{    "SUBSTITUTE",        "SUBSTITUTES",        SORT_PRIORITY,    3,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_REGEX|LIST_FLAG_PRIORITY },
 	{    "TAB",               "TABS",               SORT_ALPHA,       1,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
 	{    "TICKER",            "TICKERS",            SORT_ALPHA,       3,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT },
 	{    "VARIABLE",          "VARIABLES",          SORT_ALPHA,       2,  LIST_FLAG_MESSAGE|LIST_FLAG_READ|LIST_FLAG_WRITE|LIST_FLAG_CLASS|LIST_FLAG_INHERIT|LIST_FLAG_NEST }
@@ -258,10 +262,10 @@ struct config_type config_table[] =
 	},
 
 	{
-		"LOG",
+		"LOG MODE",
 		"",
-		"The data format of the log files",
-		config_log
+		"The data type mode of log files",
+		config_logmode
 	},
 
 	{
@@ -334,6 +338,13 @@ struct config_type config_table[] =
 		config_speedwalk
 	},
 
+	{
+		"TELNET",
+		"TELNET support is enabled.",
+		"TELNET support is disabled.",
+		config_telnet
+	},
+
 	{
 		"TINTIN CHAR",
 		"",
@@ -558,7 +569,7 @@ struct array_type array_table[] =
 
 struct map_type map_table[] =
 {
-	{     "AT",               map_at,              0,              1    },
+	{     "AT",               map_at,              0,              2    },
 	{     "COLOR",            map_color,           MAP_FLAG_VTMAP, 1    },
 	{     "CREATE",           map_create,          MAP_FLAG_VTMAP, 0    },
 	{     "DEBUG",            map_debug,           0,              2    },
@@ -594,7 +605,7 @@ struct map_type map_table[] =
 	{     "UNDO",             map_undo,            MAP_FLAG_VTMAP, 2    },
 	{     "UNINSERT",         map_uninsert,        MAP_FLAG_VTMAP, 2    },
 	{     "UNLINK",           map_unlink,          MAP_FLAG_VTMAP, 2    },
-	{     "UPDATE",           map_update,          MAP_FLAG_VTMAP, 2    },
+	{     "UPDATE",           map_update,          0,              0    },
 	{     "VNUM",             map_vnum,            MAP_FLAG_VTMAP, 2    },
 	{     "WRITE",            map_write,           0,              1    },
 	{     "",                 NULL,                0    }
@@ -954,6 +965,113 @@ struct cursor_type cursor_table[] =
 	}
 };
 
+struct draw_type draw_table[] =
+{
+	{
+		"BLANK SQUARE",
+		"Draw a blank square.",
+		draw_blank
+	},
+
+	{
+		"BOTTOM SIDE",
+		"Draw the bottom side of a box.",
+		draw_bot_line
+	},
+
+	{
+		"BOX",
+		"Draw a box.",
+		draw_box
+	},
+
+	{
+		"BOX TEXT",
+		"Draw a box with given text.",
+		draw_box_text
+	},
+
+	{
+		"CENTER LEFT LINE",
+		"Draw the center left line of two boxes.",
+		draw_center_left_line
+	},
+
+	{
+		"CENTER RIGHT LINE",
+		"Draw the center right line of two boxes.",
+		draw_center_right_line
+	},
+
+	{
+		"HORIZONTAL LINE",
+		"Draw a horizontal line.",
+		draw_horizontal_line
+	},
+
+	{
+		"LEFT SIDE",
+		"Draw the left side of a box.",
+		draw_left_line
+	},
+
+
+	{
+		"MIDDLE TOP LINE",
+		"Draw the middle top line of two boxes.",
+		draw_middle_top_line
+	},
+
+	{
+		"MIDDLE BOTTOM LINE",
+		"Draw the middle bottom line of two boxes.",
+		draw_middle_bot_line
+	},
+
+	{
+		"RIGHT SIDE",
+		"Draw the right side of a box.",
+		draw_right_line
+	},
+	
+	{
+		"SIDE LINES",
+		"Draw the left and right sides of a box.",
+		draw_side_lines
+	},
+
+	{
+		"SIDE LINES TEXT",
+		"Draw the side lines of a box with given text.",
+		draw_side_lines_text
+	},
+
+
+	{
+		"TOP LINE",
+		"Draw the bottom lines of a box.",
+		draw_top_line
+	},
+
+	{
+		"TEXT",
+		"Draw given text without a frame.",
+		draw_text
+	},
+
+	{
+		"VERTICAL LINE",
+		"Draw a vertical line.",
+		draw_vertical_line
+	},
+
+	{
+		"",
+		"",
+		NULL
+	}
+};
+
 struct screen_type screen_table[] =
 {
 	{
@@ -968,7 +1086,7 @@ struct screen_type screen_table[] =
 		"CLEAR",
 		"Clear the screen.",
 		SCREEN_FLAG_GET_ONE,
-		SCREEN_FLAG_GET_ONE,
+		SCREEN_FLAG_GET_NONE,
 		SCREEN_FLAG_CSIP,
 		screen_clear
 	},
@@ -1086,7 +1204,7 @@ struct screen_type screen_table[] =
 		screen_save
 	},
 	{
-		"Scrollbar",
+		"SCROLLBAR",
 		"Scrollbar settings.",
 		SCREEN_FLAG_GET_ONE,
 		SCREEN_FLAG_GET_ONE,
@@ -1128,7 +1246,9 @@ struct event_type event_table[] =
 	{    "CATCH ",                                 "Triggers on catch events."               },
 	{    "CHAT MESSAGE",                           "Triggers on any chat related message."   },
 	{    "CLASS ACTIVATED",                        "Triggers on class activations."          },
+	{    "CLASS CREATED",                          "Triggers on class creation."             },
 	{    "CLASS DEACTIVATED",                      "Triggers on class deactivations."        },
+	{    "CLASS DESTROYED",                        "Triggers on class destruction."          },
 	{    "DATE",                                   "Triggers on the given date."             },
 	{    "DAY",                                    "Triggers each day or given day."         },
 	{    "DOUBLE-CLICKED ",                        "Triggers when mouse is double-clicked"   },
@@ -1232,9 +1352,11 @@ struct path_type path_table[] =
 
 struct line_type line_table[] =
 {
+	{    "BACKGROUND",        line_background        },
 	{    "GAG",               line_gag               },
 	{    "IGNORE",            line_ignore            },
 	{    "LOG",               line_log               },
+	{    "LOGMODE",           line_logmode           },
 	{    "LOGVERBATIM",       line_logverbatim       },
 	{    "QUIET",             line_quiet             },
 	{    "STRIP",             line_strip             },
@@ -1770,6 +1892,7 @@ struct map_group_type map_group_table[] =
 	{ "NESW MISC",			"NESW MISC",		1, 1,	1, 1,	0, 0,	"{\\u2B51} {\\u2012} {\\u2507} {\\u254D}" },
 	{ "NESW CURVED",		"NESW CURVED",		1, 1,	1, 1,	0, 0,	"{\\u2570} {\\u256D} {\\u256E} {\\u256F}" },
 	{ "NESW DIRS",			"NESW DIRS",		1, 1,	1, 1,	0, 0,	"{\\u2191} {\\u2B08} {\\u2B95} {\\u2b0A} {\\u2193} {\\u2B0B} {\\u2B05} {\\u2B09}" },
+//	{ "NESW DIRS",			"NESW DIRS",		1, 1,	1, 1,	0, 0,	"{\\U01F805}{\\u2B08}{\\U01F806}{\\u2b0A}{\\U01F807}{\\u2B0B}{\\U01F804}{\\u2B09}" }, poor cross-platform support.
 
 	{ "MUDFONT",			"MUDFONT",		1, 2,	1, 2,	0, 0,	"" },
 	{ "MUDFONT PRIVATE",		"MUDFONT",		1, 2,	1, 2,	0, 0,	"{\\uE000} {\\uE001} {\\uE002} {\\uE003} {\\uE004} {\\uE005} {\\uE006} {\\uE007} {\\uE008} {\\uE009} {\\uE00A} {\\uE00B} {\\uE00C} {\\uE00D} {\\uE00E} {\\uE00F} {\\uE010} {\\uE011} {\\uE012} {\\uE013} {\\uE014} {\\uE015} {\\uE016} {\\uE017} {\\uE018} {\\uE019} {\\uE01A} {\\uE01B} {\\uE01C} {\\uE01D} {\\uE01E} {\\uE01F} {\\uE020} {\\uE021} {\\uE022} {\\uE023} {\\uE024} {\\uE025} {\\uE026} {\\uE027} {\\uE028} {\\uE029} {\\uE02A} {\\uE02B} {\\uE02C} {\\uE02D} {\\uE02E} {\\uE02F} {\\uE030} {\\uE031} {\\uE032} {\\uE033} {\\uE034} {\\uE035} {\\uE036} {\\uE037} {\\uE038} {\\uE039} {\\uE03A} {\\uE03B} {\\uE03C} {\\uE03D} {\\uE03E} {\\uE03F} {\\uE040} {\\uE041} {\\uE042} {\\uE043} {\\uE044} {\\uE045} {\\uE046} {\\uE047} {\\uE048} {\\uE049} {\\uE04A} {\\uE04B} {\\uE04C} {\\uE04D} {\\uE04E} {\\uE04F} {\\uE050} {\\uE051} {\\uE052} {\\uE053} {\\uE054} {\\uE055} {\\uE056} {\\uE057} {\\uE058} {\\uE059} {\\uE05A} {\\uE05B} {\\uE05C} {\\uE05D} {\\uE05E} {\\uE05F} {\\uE060} {\\uE061} {\\uE062} {\\uE063} {\\uE064} {\\uE065} {\\uE066} {\\uE067} {\\uE068} {\\uE069} {\\uE06A} {\\uE06B} {\\uE06C} {\\uE06D} {\\uE06E} {\\uE06F} {\\uE070} {\\uE071} {\\uE072} {\\uE073} {\\uE074} {\\uE075} {\\uE076} {\\uE077} {\\uE078} {\\uE079} {\\uE07A} {\\uE07B} {\\uE07C} {\\uE07D} {\\uE07E} {\\uE07F} {\\uE080} {\\uE081} {\\uE082} {\\uE083} {\\uE084} {\\uE085} {\\uE086} {\\uE087}" },

+ 18 - 15
src/telopt_client.c

@@ -216,7 +216,7 @@ int client_translate_telopts(struct session *ses, unsigned char *src, int cplen)
 		cpsrc = src;
 	}
 
-	if (HAS_BIT(ses->flags, SES_FLAG_LOGLEVEL) && ses->logfile)
+	if (HAS_BIT(ses->logmode, LOG_FLAG_LOW) && ses->logfile)
 	{
 		fwrite(cpsrc, 1, cplen, ses->logfile);
 
@@ -244,7 +244,7 @@ int client_translate_telopts(struct session *ses, unsigned char *src, int cplen)
 
 	while (cplen > 0)
 	{
-		if (!HAS_BIT(ses->flags, SES_FLAG_RUN) && *cpsrc == IAC)
+		if (*cpsrc == IAC && HAS_BIT(ses->flags, SES_FLAG_TELNET) && !HAS_BIT(ses->flags, SES_FLAG_RUN))
 		{
 			skip = 2;
 
@@ -435,7 +435,7 @@ int client_translate_telopts(struct session *ses, unsigned char *src, int cplen)
 
 			switch (*cpsrc)
 			{
-				case '\0':
+				case ASCII_NUL:
 					cpsrc++;
 					cplen--;
 					continue;
@@ -446,8 +446,8 @@ int client_translate_telopts(struct session *ses, unsigned char *src, int cplen)
 					cplen--;
 					continue;
 
-				case '\r':
-					if (cplen > 1 && cpsrc[1] == '\n')
+				case ASCII_CR:
+					if (cplen > 1 && cpsrc[1] == ASCII_LF)
 					{
 						cpsrc++;
 						cplen--;
@@ -455,7 +455,7 @@ int client_translate_telopts(struct session *ses, unsigned char *src, int cplen)
 					}
 					break;
 
-				case '\n':
+				case ASCII_LF:
 					if (HAS_BIT(ses->telopts, TELOPT_FLAG_PROMPT))
 					{
 						DEL_BIT(ses->telopts, TELOPT_FLAG_PROMPT);
@@ -465,7 +465,7 @@ int client_translate_telopts(struct session *ses, unsigned char *src, int cplen)
 					gtd->mud_output_len++;
 					cplen--;
 
-					while (*cpsrc == '\r')
+					while (*cpsrc == ASCII_CR)
 					{
 						cpsrc++;
 						cplen--;
@@ -474,7 +474,7 @@ int client_translate_telopts(struct session *ses, unsigned char *src, int cplen)
 					continue;
 
 				default:
-					if (cpsrc[0] == ESCAPE)
+					if (cpsrc[0] == ASCII_ESC)
 					{
 						if (cplen >= 2 && cpsrc[1] == 'Z')
 						{
@@ -753,29 +753,32 @@ int client_recv_do_naws(struct session *ses, int cplen, unsigned char *cpsrc)
 int client_send_sb_naws(struct session *ses, int cplen, unsigned char *cpsrc)
 {
 	int rows;
+	int cols;
 
 	rows = HAS_BIT(ses->flags, SES_FLAG_SPLIT) ? ses->bot_row - ses->top_row + 1 : gtd->screen->rows;
 
+	cols = ses->wrap > 0 ? ses->wrap : gtd->screen->cols;
+
 	// Properly handle row and colum size of 255
 
-	if (gtd->screen->cols % 256 == IAC && gtd->screen->rows % 256 == IAC)
+	if (cols % 256 == IAC && gtd->screen->rows % 256 == IAC)
 	{
-		telnet_printf(ses, 11, "%c%c%c%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_NAWS, gtd->screen->cols / 256, IAC, gtd->screen->cols % 256, rows / 256, IAC, rows % 256, IAC, SE);
+		telnet_printf(ses, 11, "%c%c%c%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_NAWS, cols / 256, IAC, cols % 256, rows / 256, IAC, rows % 256, IAC, SE);
 	}
-	else if (gtd->screen->cols % 256 == IAC)
+	else if (cols % 256 == IAC)
 	{
-		telnet_printf(ses, 10, "%c%c%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_NAWS, gtd->screen->cols / 256, IAC, gtd->screen->cols % 256, rows / 256, rows % 256, IAC, SE);
+		telnet_printf(ses, 10, "%c%c%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_NAWS, cols / 256, IAC, cols % 256, rows / 256, rows % 256, IAC, SE);
 	}
 	else if (gtd->screen->rows % 256 == IAC)
 	{
-		telnet_printf(ses, 10, "%c%c%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_NAWS, gtd->screen->cols / 256, gtd->screen->cols % 256, rows / 256, IAC, rows % 256, IAC, SE);
+		telnet_printf(ses, 10, "%c%c%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_NAWS, cols / 256, cols % 256, rows / 256, IAC, rows % 256, IAC, SE);
 	}
 	else
 	{
-		telnet_printf(ses, 9, "%c%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_NAWS, gtd->screen->cols / 256, gtd->screen->cols % 256, rows / 256, rows % 256, IAC, SE);
+		telnet_printf(ses, 9, "%c%c%c%c%c%c%c%c%c", IAC, SB, TELOPT_NAWS, cols / 256, cols % 256, rows / 256, rows % 256, IAC, SE);
 	}
 
-	client_telopt_debug(ses, "SENT IAC SB NAWS %d %d %d %d", gtd->screen->cols / 256, gtd->screen->cols % 256, gtd->screen->rows / 256, gtd->screen->rows % 256);
+	client_telopt_debug(ses, "SENT IAC SB NAWS %d %d %d %d", cols / 256, cols % 256, gtd->screen->rows / 256, gtd->screen->rows % 256);
 
 	return 3;
 }

+ 1 - 1
src/telopt_server.c

@@ -792,7 +792,7 @@ int process_do_msdp(struct session *ses, struct port_data *buddy, unsigned char
 
 	for (index = 0 ; index < gtd->msdp_table_size ; index++)
 	{
-		buddy->msdp_data[index] = (struct msdp_data *) calloc(1, sizeof(struct msdp_data *));
+		buddy->msdp_data[index] = (struct msdp_data *) calloc(1, sizeof(struct msdp_data));
 
 		buddy->msdp_data[index]->flags = msdp_table[index].flags;
 		buddy->msdp_data[index]->value = strdup("");

+ 19 - 26
src/text.c

@@ -54,7 +54,7 @@ void print_line(struct session *ses, char **str, int prompt)
 		str_cpy(str, out);
 	}
 
-	if (HAS_BIT(ses->flags, SES_FLAG_WORDWRAP))
+	if (ses->wrap)
 	{
 		word_wrap(ses, *str, out, TRUE);
 	}
@@ -129,12 +129,12 @@ int word_wrap(struct session *ses, char *textin, char *textout, int display)
 			lis = pti;
 		}
 
-		if (ses->cur_col > gtd->screen->cols)
+		if (ses->cur_col > gtd->screen->cols || (ses->wrap > 0 && ses->cur_col > ses->wrap))
 		{
 			cnt++;
 			ses->cur_col = 1;
 
-			if (HAS_BIT(ses->flags, SES_FLAG_WORDWRAP))
+			if (ses->wrap)
 			{
 				if (pto - los > 15 || !SCROLL(ses))
 				{
@@ -190,14 +190,14 @@ int word_wrap(struct session *ses, char *textin, char *textout, int display)
 	return (cnt + 1);
 }
 
-// store whatever falls inbetween skip and keep. Used by #buffer
+// store whatever falls inbetween skip and keep. Used by #buffer not checking SCROLL().
 
-int word_wrap_split(struct session *ses, char *textin, char *textout, int display, int start, int end)
+int word_wrap_split(struct session *ses, char *textin, char *textout, int wrap, int start, int end)
 {
 	char *pti, *pto, *lis, *los, *chi, *cho, *ptb;
-	int width, size, i = 0, cnt = 0;
+	int width, size, i = 0, lines = 0;
 
-	push_call("word_wrap_split(%s,%p,%p,%d,%d)",ses->name, textin,textout, start, end);
+	push_call("word_wrap_split(%s,%p,%p,%d,%d,%d)",ses->name,textin,textout,wrap,start,end);
 
 	pti = chi = lis = textin;
 	pto = cho = los = textout;
@@ -208,23 +208,16 @@ int word_wrap_split(struct session *ses, char *textin, char *textout, int displa
 	{
 		if (skip_vt102_codes(pti))
 		{
-//			if (cnt >= start && cnt < end)
+			for (i = skip_vt102_codes(pti) ; i > 0 ; i--)
 			{
-				for (i = skip_vt102_codes(pti) ; i > 0 ; i--)
-				{
-					*pto++ = *pti++;
-				}
+				*pto++ = *pti++;
 			}
-/*			else
-			{
-				pti += skip_vt102_codes(pti);
-			}*/
 			continue;
 		}
 
 		if (*pti == '\n')
 		{
-			if (cnt++ >= start && cnt < end)
+			if (lines++ >= start && lines < end)
 			{
 				*pto++ = *pti++;
 			}
@@ -246,16 +239,16 @@ int word_wrap_split(struct session *ses, char *textin, char *textout, int displa
 			lis = pti;
 		}
 
-		if (ses->cur_col > gtd->screen->cols)
+		if (ses->cur_col > gtd->screen->cols || (wrap > 0 && ses->cur_col > wrap))
 		{
-			cnt++;
+			lines++;
 			ses->cur_col = 1;
 
-			if (HAS_BIT(ses->flags, SES_FLAG_WORDWRAP))
+			if (wrap)
 			{
-				if (pto - los > 15 || !SCROLL(ses))
+				if (pto - los > 15 || ses->cur_col < 15)
 				{
-					if (cnt >= start && cnt < end)
+					if (lines >= start && lines < end)
 					{
 						*pto++ = '\n';
 					}
@@ -264,7 +257,7 @@ int word_wrap_split(struct session *ses, char *textin, char *textout, int displa
 				}
 				else if (lis != chi) // infinite VT loop detection
 				{
-					if (cnt >= start && cnt < end)
+					if (lines >= start && lines < end)
 					{
 						pto = los;
 						*pto++ = '\n';
@@ -274,7 +267,7 @@ int word_wrap_split(struct session *ses, char *textin, char *textout, int displa
 				}
 				else if (los != cho)
 				{
-					if (cnt >= start && cnt < end)
+					if (lines >= start && lines < end)
 					{
 						pto = cho = los;
 						pto++;
@@ -314,7 +307,7 @@ int word_wrap_split(struct session *ses, char *textin, char *textout, int displa
 				ses->cur_col++;
 			}
 
-			if (cnt < start || cnt >= end)
+			if (lines < start || lines >= end)
 			{
 				pto = ptb;
 			}
@@ -323,6 +316,6 @@ int word_wrap_split(struct session *ses, char *textin, char *textout, int displa
 	*pto = 0;
 
 	pop_call();
-	return (cnt + 1);
+	return (lines + 1);
 }
 

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 361 - 282
src/tintin.h


+ 1 - 1
src/tokenize.c

@@ -924,7 +924,7 @@ struct scriptnode *parse_script(struct scriptroot *root, int lvl, struct scriptn
 			case TOKEN_TYPE_REGEX:
 				split = NULL;
 
-				token->regex->val = find(root->ses, token->str, token->regex->str, SUB_CMD);
+				token->regex->val = find(root->ses, token->str, token->regex->str, SUB_VAR|SUB_FUN, SUB_CMD);
 
 				if (token->regex->val)
 				{

+ 2 - 2
src/utils.c

@@ -400,9 +400,9 @@ char *indent(int len)
 
 	cnt = (cnt + 1) % 10;
 
-	memset(outbuf[cnt], '\t', len);
+	memset(outbuf[cnt], ' ', len * 5);
 
-	outbuf[cnt][len] = 0;
+	outbuf[cnt][len * 5] = 0;
 
 	return outbuf[cnt];
 }

+ 69 - 7
src/variable.c

@@ -39,7 +39,7 @@ DO_COMMAND(do_variable)
 	{
 		show_list(root, 0);
 	}
-	else if (*arg1 && *arg == 0)
+	else if (*arg == 0)
 	{
 		node = search_nest_node(root, arg1);
 
@@ -53,7 +53,7 @@ DO_COMMAND(do_variable)
 
 				view_nest_node(node, &str_result, 0, 1);
 
-				tintin_printf2(ses, COLOR_TINTIN "%c" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\n{\n" COLOR_STRING "%s" COLOR_BRACE "}" COLOR_RESET "\n", gtd->tintin_char, list_table[LIST_VARIABLE].name, node->arg1, str_result);
+				print_lines(ses, SUB_NONE, COLOR_TINTIN "%c" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\n{\n" COLOR_STRING "%s" COLOR_BRACE "}" COLOR_RESET "\n", gtd->tintin_char, list_table[LIST_VARIABLE].name, node->arg1, str_result);
 
 				str_free(str_result);
 			}
@@ -288,13 +288,75 @@ void charactertonumber(struct session *ses, char *str)
 
 void colorstring(struct session *ses, char *str)
 {
-	char result[BUFFER_SIZE] = { 0 };
+	char result[BUFFER_SIZE];
 
-	get_highlight_codes(ses, str, result);
+	get_color_names(ses, str, result);
 
 	strcpy(str, result);
+}
 
-	strcpy(str, result);
+int get_color_names(struct session *ses, char *string, char *result)
+{
+	int cnt;
+
+	*result = 0;
+
+	if (*string == '<')
+	{
+		substitute(ses, string, result, SUB_COL);
+
+		return TRUE;
+	}
+
+	if (*string == '\\')
+	{
+		substitute(ses, string, result, SUB_ESC);
+
+		return TRUE;
+	}
+
+	while (*string)
+	{
+		if (isalpha(*string))
+		{
+			for (cnt = 0 ; *color_table[cnt].name ; cnt++)
+			{
+				if (is_abbrev(color_table[cnt].name, string))
+				{
+					substitute(ses, color_table[cnt].code, result, SUB_COL);
+
+					result += strlen(result);
+
+					break;
+				}
+			}
+
+			if (*color_table[cnt].name == 0)
+			{
+				return FALSE;
+			}
+
+			string += strlen(color_table[cnt].name);
+		}
+
+		switch (*string)
+		{
+			case ' ':
+			case ';':
+			case ',':
+			case '{':
+			case '}':
+				string++;
+				break;
+
+			case 0:
+				return TRUE;
+
+			default:
+				return FALSE;
+		}
+	}
+	return TRUE;
 }
 
 void headerstring(char *str)
@@ -490,7 +552,7 @@ void wrapstring(struct session *ses, char *str)
 
 				get_color_codes(color, tmp, color);
 
-				sprintf(tmp, "%.*s", pti - sos, sos);
+				sprintf(tmp, "%.*s", (int) (pti - sos), sos);
 
 				substitute(ses, tmp, sec, SUB_SEC);
 
@@ -505,7 +567,7 @@ void wrapstring(struct session *ses, char *str)
 
 				get_color_codes(color, tmp, color);
 
-				sprintf(tmp, "%.*s", lis - sos, sos);
+				sprintf(tmp, "%.*s", (int) (lis - sos), sos);
 
 				substitute(ses, tmp, sec, SUB_SEC);
 

+ 34 - 8
src/vt102.c

@@ -28,12 +28,22 @@
 
 void save_pos(struct session *ses)
 {
-	printf("\e7"); 
+	if (ses->cur_row == gtd->screen->rows)
+	{
+		printf("\e7"); 
 
-	ses->sav_row = ses->cur_row;
-	ses->sav_col = ses->cur_col;
+		ses->sav_row = ses->cur_row;
+		ses->sav_col = ses->cur_col;
+	}
 }
 
+void load_pos(struct session *ses)
+{
+	printf("\e8\e8"); 
+
+	ses->cur_row = ses->sav_row;
+	ses->cur_col = ses->sav_col;
+}
 
 void restore_pos(struct session *ses)
 {
@@ -43,13 +53,26 @@ void restore_pos(struct session *ses)
 	ses->cur_col = ses->sav_col;
 }
 
+void goto_pos(struct session *ses, int row, int col)
+{
+	printf("\e[%d;%dH", row, col);
+
+	ses->cur_row = row;
+	ses->cur_col = col;
+}
+
 void goto_rowcol(struct session *ses, int row, int col)
 {
 	printf("\e[%d;%dH", row, col);
 
 	ses->cur_row = row;
+	ses->cur_col = col;
 }
 
+void erase_lines(struct session *ses, int rows)
+{
+	printf("\e[%dM", rows);
+}
 
 void erase_toeol(void)
 {
@@ -60,9 +83,12 @@ void erase_toeol(void)
 	doesn't do much
 */
 
-void reset(void)
+void reset(struct session *ses)
 {
-	printf("%cc", ESCAPE);
+	ses->cur_row = 1;
+	ses->cur_col = 1;
+
+	printf("\ec");
 }
 
 
@@ -70,12 +96,12 @@ void scroll_region(struct session *ses, int top, int bot)
 {
 	push_call("scroll_region(%p,%d,%d)",ses,top,bot);
 
-	printf("%c[%d;%dr", ESCAPE, top, bot);
+	printf("\e[%d;%dr", top, bot);
 
 	ses->top_row = top;
 	ses->bot_row = bot;
 
-	check_all_events(ses, SUB_ARG, 0, 2, "VT100 SCROLL REGION", ntos(top), ntos(bot));
+	check_all_events(ses, SUB_ARG, 0, 4, "VT100 SCROLL REGION", ntos(top), ntos(bot), ntos(gtd->screen->rows), ntos(gtd->screen->cols), ntos(ses->wrap > 0 ? ses->wrap : gtd->screen->cols));
 
 	pop_call();
 	return;
@@ -86,7 +112,7 @@ void reset_scroll_region(struct session *ses)
 {
 	if (ses == gtd->ses)
 	{
-		printf("%c[r", ESCAPE);
+		printf("\e[r");
 	}
 	ses->top_row = 1;
 	ses->bot_row = gtd->screen->rows;

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است