Scandum 2 年之前
父节点
当前提交
4a162139ee
共有 47 个文件被更改,包括 2534 次插入1921 次删除
  1. 39 3
      SCRIPTS
  2. 57 12
      TODO
  3. 311 305
      docs/help.html
  4. 257 257
      docs/tutorial.html
  5. 77 0
      mods/igr.mods
  6. 12 15
      src/banner.c
  7. 1 1
      src/buffer.c
  8. 2 0
      src/class.c
  9. 1 1
      src/command.c
  10. 337 1
      src/config.c
  11. 21 2
      src/cursor.c
  12. 115 52
      src/data.c
  13. 4 2
      src/draw.c
  14. 3 1
      src/event.c
  15. 16 23
      src/files.c
  16. 2 2
      src/gui.h
  17. 289 283
      src/help.c
  18. 2 0
      src/history.c
  19. 16 18
      src/input.c
  20. 71 80
      src/line.c
  21. 17 2
      src/list.c
  22. 5 5
      src/log.c
  23. 12 6
      src/main.c
  24. 126 114
      src/mapper.c
  25. 5 6
      src/memory.c
  26. 7 3
      src/nest.c
  27. 117 60
      src/net.c
  28. 23 1
      src/parse.c
  29. 2 2
      src/path.c
  30. 84 35
      src/regex.c
  31. 1 1
      src/scan.c
  32. 19 12
      src/screen.c
  33. 12 6
      src/session.c
  34. 71 35
      src/show.c
  35. 0 5
      src/sort.c
  36. 44 53
      src/substitute.c
  37. 1 1
      src/system.c
  38. 14 240
      src/tables.c
  39. 1 0
      src/telopt_client.c
  40. 2 0
      src/text.c
  41. 73 90
      src/tintin.h
  42. 51 6
      src/tokenize.c
  43. 73 11
      src/trigger.c
  44. 67 90
      src/update.c
  45. 1 1
      src/utils.c
  46. 52 64
      src/variable.c
  47. 21 14
      src/vt102.c

+ 39 - 3
SCRIPTS

@@ -927,17 +927,53 @@
 }
 
 #nop -------------------------------------------------------------------------
-#nop 
+#nop It can be annoying to have short commands clog up the command history.
+#nop This script will remove commands shorter than 3 letters.
 #nop -------------------------------------------------------------------------
 
+#event {HISTORY UPDATE}
+{
+	#if {{%0} != {%+3*%*}}
+	{
+		#history delete
+	}
+}
+
 #nop -------------------------------------------------------------------------
-#nop 
+#nop Run to a room when you click it on the vtmap.
 #nop -------------------------------------------------------------------------
 
+#config mouse on
+
+#event {MAP SHORT-CLICKED MOUSE BUTTON ONE}
+{
+	#map run {%0} 0.25
+}
+
 #nop -------------------------------------------------------------------------
-#nop 
+#nop zMUD has the feature where your last command is highlighted and any input
+#nop other than enter will clear it. This scripts reproduces this behavior.
 #nop -------------------------------------------------------------------------
 
+#CONFIG REPEAT_ENTER ON
+
+#event {HISTORY UPDATE}
+{
+	#delay 0 #line ignore #showme {<aaf><FFF><788>%0<088>} {-1};
+	#var last_input {%0}
+}
+
+#event {PROCESSED KEYPRESS}
+{
+	#if {{%1} != {10} && {$last_input} !== {}}
+	{
+		#var last_input {};
+		#line ignore #showme {} {-1};
+		#cursor end;
+		#history insert {}
+	}
+}
+
 #nop -------------------------------------------------------------------------
 #nop 
 #nop -------------------------------------------------------------------------

+ 57 - 12
TODO

@@ -1,28 +1,72 @@
-- Handle more_output more cleanly in net.c
+#info mem
+#INFO MEMORY: STACK SIZE: 1800045
+#INFO MEMORY: STACK  MAX: 64
+#INFO MEMORY: STACK  CAP: 45
+#INFO MEMORY: STACK  LEN: 3
 
-- return #regex #else to old format
+#ERROR: index 386297 len = 1/0 max = 5706 flags = 6 (e)
+#INFO MEMORY: ALLOC SIZE: 17963354
+#INFO MEMORY: ALLOC USED: 13862779
+#INFO MEMORY: ALLOC  MAX: 1048576
+#INFO MEMORY: ALLOC  LEN: 547640
 
-- Look into #split 1 1 1 1 on termux when hiding / showing keyboard.
+#INFO MEMORY: FREED SIZE: 1626853344
+#INFO MEMORY: FREED  MAX: 1048576
+#INFO MEMORY: FREED  LEN: 546481
+
+#INFO MEMORY: DEBUG SIZE: 1024
+#INFO MEMORY: DEBUG  MAX: 48
+#INFO MEMORY: DEBUG  LEN: 4
+
+- #var foo {x;{a;b;c};y;z}
+  #list foo create {$foo}
+  #list foo simplify
+
+  #list explode has an issue with ';'
+
+- finish ? : support in #math
+
+- multiline triggers
 
-- Make WinTin++ 64 bit and double check windows console link opens main.tin
+- finish create_node()
+
+- Look into #split 1 1 1 1 on termux when hiding / showing keyboard.
 
 - look into invalid { } in MSDP / GMCP handling
 
 - mapper.c FAST handling
 
-- grid tables don't handle color codes
-
 - sandbox mode to disable shell integration.
 
-- color patch issues in #help
-
 - update telopt_server with MSSP, MTTS and TTYPE changes
 
-- look into #draw Yellow scroll bot side 1 1 1 80 drawing weird
+- #format %.3s prints two double-width characters.
+
+- fix ctrl-r so it compiles the pcre once.
+
+- #sleep <time>, possibly allow names to cancel or force continuation
+
+- #line escape {variables;functions}
+
+- look into a #debug flag for #class
+
+- switch to pcre2
+
+- Another nice thing would be if there was some flag to make a trigger match newlines as space.
+
+- fix up named delays and undelay
+
+- add a #regex like command for #cursor to update the input line.
+
+- custom mapping for unicode table to set width
+
+- color code for dynamic color ranges
+
+- #MACRO {\cz} {#cursor get t;#var t} does not handle { } in input.
+
+- Look into delete_index_list leaving a table with ->used set to 0 causing #list crashes
 
-- check that vertical split screen update is fast using a trigger
-  with an instant screen update for reference. Some issues reported
-  related to packet patch.
+- #daemon attach fails under high cpu load
 
 ----------------
   - add shadow session support with access to all events.
@@ -87,6 +131,7 @@
 
   - tab completion on directory structure.
 
+  - #map area command to list room counts per area.
   - direction field for exits that allow longer than 1x1x1 x/y/z jumps.
   - global mapper flag that would imply "Hide" on all exits that change area.
   - multiple global exit rooms and noglobal flags.

文件差异内容过多而无法显示
+ 311 - 305
docs/help.html


文件差异内容过多而无法显示
+ 257 - 257
docs/tutorial.html


+ 77 - 0
mods/igr.mods

@@ -1,3 +1,80 @@
+Jan 2023        2.02.31
+------------------------------------------------------------------------------
+cursor.c        #cursor {get} will escape braces and other special characters.
+
+config.c        Added the CONFIG event which triggers when a config option is
+                set. %0 holds the option name, and %1 the value set.
+
+mapper.c        When saving #map list to a table the vnum is now automatically
+                included.
+
+data.c          Added #info output which can be used to access the most recent
+                data received from the mud.
+
+config.c        Hybernate is now hibernate. Let's pretend that never happened.
+
+config.c        Added #config hibernate on/off. When enabled it will reduce
+                the idle cpu overhead by 90%, though tintin will be more
+                sluggish and timers will fire with decreased accuracy.
+
+trigger.c       A multi-line action can now trigger multiple times per block
+                of text, skipping to the next unmatched line after each match.
+
+nest.c          Fixed a bug reported by dzp where $var[] didn't behave
+                identical to $var[%*].
+
+show.c          A #showme containing a \n sequence will exclusively trigger
+                multi-line triggers.
+
+history.c       Added the HISTORY UPDATE event, %0 contains the command being
+                added to the command history.
+
+help.c          Added #help triggers which explains multi-line triggers.
+
+regex.c         Added initial support for multi-line triggers.
+
+mapper.c        The roomdesc now requires %a instead of %* to match multiple
+                lines in searches.
+
+net.c           Added the %1 argument to the RECEIVED OUTPUT event, which
+                holds the plain text version of the data received.
+
+regex.c         Added a warning when matching escape codes in a trigger
+                without the trigger starting with a '~'.
+
+line.c          Added #line logmode stamp option to force the adding of a
+                timestamp when using #line log.
+
+config.c        Added #config compact which is disabled by default. When
+                enabled it can get rid of blank lines surrounding a gagged
+                prompt line.
+
+substitute.c    Fixed #alias and #function so #info arguments save works.
+
+line.c          #line log no longer prints a stamp if #log timestamp is set,
+                unless you're writing to the active log file.
+
+main.c          The terminal title set with tt++ -t will now reset on exit.
+
+variable.c      Added support for #format %.-3s which will print the last
+                3 characters of the string.
+
+regex.c         It should now be possible to use %+10* %+1..5* etc
+
+variable.c      Fixed a crash bug in #cat reported by dzp.
+
+tokenize.c      Colorized some of the #debug messages, and added a debug
+                message to mark the end of a trigger.
+
+tokenize.c      Added error message for #foreach, #loop, #parse, #switch,
+                #while, and #regex if invalid syntax is used.
+
+net.c           Fixed a display problem related to #config packet_patch in
+                vertical split mode.
+
+mapper.c        Changed the usage of float to double to fix rounding issues in
+                path calculations.
+
 Jul 2022        2.02.30
 ------------------------------------------------------------------------------
 help.c          #help and #command when used with no argument display the

+ 12 - 15
src/banner.c

@@ -464,45 +464,42 @@ void banner_test(struct session *ses, char *arg1)
 
 struct session *banner_gui(struct session *ses, char *arg1)
 {
-	char *data;
-	FILE *fp;
+	char data[BUFFER_SIZE];
+	FILE *file;
 	size_t len;
 
-	fp = open_memstream(&data, (size_t *) &len);
+	strcpy(data, tt_gui);
 
-	fputs(tt_gui, fp);
+	len = strlen(data);
 
-	fclose(fp);
-
-	fp = fmemopen(data, len, "r");
+	file = fmemopen(data, len, "r");
 
 	gtd->level->quiet++;
 
-	ses = read_file(ses, fp, "tt_gui.h");
+	ses = read_file(ses, file, "tt_gui.h");
 
 	gtd->level->quiet--;
 
-	fclose(fp);
-
-	free(data);
+	fclose(file);
 
 	return ses;
+
 /*
 	char filename[PATH_SIZE];
-	FILE *fp;
+	FILE *file;
 
 	sprintf(filename, "%s/gui.tin", gtd->system->tt_dir);
 
-	if ((fp = fopen(filename, "w")) == NULL)
+	if ((file = fopen(filename, "w")) == NULL)
 	{
 		tintin_printf2(ses, "#BANNER GUI: FAILED TO CREATE {%s}.", filename);
 
 		return ses;
 	}
 
-	fputs(tt_gui, fp);
+	fputs(tt_gui, file);
 
-	fclose(fp);
+	fclose(file);
 
 	return command(ses, do_line, "quiet #read %s", filename);
 */

+ 1 - 1
src/buffer.c

@@ -1088,7 +1088,7 @@ DO_BUFFER(buffer_refresh)
 {
 	check_buffer(ses);
 
-	if (HAS_BIT(ses->flags, SES_FLAG_PRINTLINE) && ses->check_output == 0)
+	if (HAS_BIT(ses->flags, SES_FLAG_PRINTLINE))
 	{
 		if (ses == gtd->ses)
 		{

+ 2 - 0
src/class.c

@@ -314,6 +314,8 @@ DO_CLASS(class_load)
 
 	read_file(ses, file, arg1);
 
+	fclose(file);
+
 	check_all_events(ses, EVENT_FLAG_CLASS, 0, 1, "CLASS LOAD", arg1);
 	check_all_events(ses, EVENT_FLAG_CLASS, 1, 1, "CLASS LOAD %s", arg1, arg1);
 

+ 1 - 1
src/command.c

@@ -303,7 +303,7 @@ struct command_type command_table[] =
 	{    "highlight",         do_highlight,         3, TOKEN_TYPE_COMMAND },
 	{    "history",           do_history,           3, TOKEN_TYPE_COMMAND },
 	{    "if",                do_nop,               0, TOKEN_TYPE_IF      },
-	{    "ignore",            do_ignore,            2, TOKEN_TYPE_COMMAND },
+	{    "ignore",            do_ignore,            3, TOKEN_TYPE_COMMAND },
 	{    "info",              do_info,              2, TOKEN_TYPE_COMMAND },
 	{    "kill",              do_kill,              2, TOKEN_TYPE_COMMAND },
 	{    "killall",           do_killall,           2, TOKEN_TYPE_COMMAND },

+ 337 - 1
src/config.c

@@ -23,9 +23,295 @@
 *                      coded by Igor van den Hoven 2004                       *
 ******************************************************************************/
 
-
 #include "tintin.h"
 
+#define DO_CONFIG(config)    struct session *config (struct session *ses, char *arg1, char *arg2, int index)
+
+DO_CONFIG(config_autotab);
+DO_CONFIG(config_buffersize);
+DO_CONFIG(config_charset);
+DO_CONFIG(config_colormode);
+DO_CONFIG(config_colorpatch);
+DO_CONFIG(config_commandcolor);
+DO_CONFIG(config_commandecho);
+DO_CONFIG(config_compact);
+DO_CONFIG(config_connectretry);
+DO_CONFIG(config_childlock);
+DO_CONFIG(config_convertmeta);
+DO_CONFIG(config_debugtelnet);
+DO_CONFIG(config_historysize);
+DO_CONFIG(config_hibernate);
+DO_CONFIG(config_inheritance);
+DO_CONFIG(config_loglevel);
+DO_CONFIG(config_logmode);
+DO_CONFIG(config_mccp);
+DO_CONFIG(config_mousetracking);
+DO_CONFIG(config_packetpatch);
+DO_CONFIG(config_randomseed);
+DO_CONFIG(config_repeatchar);
+DO_CONFIG(config_repeatenter);
+DO_CONFIG(config_screenreader);
+DO_CONFIG(config_scrolllock);
+DO_CONFIG(config_speedwalk);
+DO_CONFIG(config_tabwidth);
+DO_CONFIG(config_telnet);
+DO_CONFIG(config_tintinchar);
+DO_CONFIG(config_verbatim);
+DO_CONFIG(config_verbatimchar);
+DO_CONFIG(config_verbose);
+DO_CONFIG(config_wordwrap);
+
+typedef struct session *CONFIG  (struct session *ses, char *arg1, char *arg2, int index);
+
+struct config_type
+{
+	char                  * name;
+	char                  * msg_on;
+	char                  * msg_off;
+	CONFIG                * config;
+};
+
+struct config_type config_table[] =
+{
+	{
+		"AUTO TAB",
+		"Buffer lines used for tab completion",
+		"",
+		config_autotab
+	},
+
+	{
+		"BUFFER SIZE",
+		"The size of the scrollback buffer",
+		"",
+		config_buffersize
+	},
+
+	{
+		"CHARSET",
+		"The character set encoding used",
+		"",
+		config_charset
+	},
+
+	{
+		"CHILD LOCK",
+		"TinTin++ is child locked.",
+		"TinTin++ is not child locked.",
+		config_childlock
+	},
+
+	{
+		"COLOR MODE",
+		"The color code encoding used",
+		"",
+		config_colormode
+	},
+
+	{
+		"COLOR PATCH",
+		"Color the start of each line",
+		"Leave color handling up to the server",
+		config_colorpatch
+	},
+
+	{
+		"COMMAND COLOR",
+		"The color of echoed commands",
+		"",
+		config_commandcolor
+	},
+
+	{
+		"COMMAND ECHO",
+		"Commands are echoed in split mode",
+		"Commands are not echoed in split mode",
+		config_commandecho
+	},
+
+	{
+		"COMPACT",
+		"Remove blank prompt lines",
+		"Do not remove blank prompt lines",
+		config_compact
+	},
+
+	{
+		"CONNECT RETRY",
+		"Seconds sessions try to connect on failure",
+		"",
+		config_connectretry
+	},
+
+	{
+		"CONVERT META",
+		"TinTin++ converts meta characters",
+		"TinTin++ doesn't convert meta characters",
+		config_convertmeta
+	},
+
+	{
+		"DEBUG TELNET",
+		"You see telnet negotiations",
+		"You do not see telnet negotatiations",
+		config_debugtelnet
+	},
+
+	{
+		"HIBERNATE",
+		"Go into low CPU usage mode",
+		"",
+		config_hibernate
+	},
+
+	{
+		"HISTORY SIZE",
+		"The size of the command history",
+		"",
+		config_historysize
+	},
+
+	{
+		"INHERITANCE",
+		"The startup session is inherited",
+		"The startup session is not inherited",
+		config_inheritance
+	},
+
+	{
+		"LOG MODE",
+		"The data type mode of log files",
+		"",
+		config_logmode
+	},
+
+	{
+		"LOG LEVEL",
+		"TinTin++ only logs low level server data",
+		"TinTin++ only logs high level server data",
+		config_loglevel
+	},
+
+	{
+		"MCCP",
+		"MCCP is enabled.",
+		"MCCP is disabled.",
+		config_mccp
+	},
+
+	{
+		"MOUSE",
+		"Generate mouse tracking events.",
+		"Do not generate mouse events.",
+		config_mousetracking
+	},
+
+	{
+		"PACKET PATCH",
+		"Seconds to try to patch broken packets",
+		"",
+		config_packetpatch
+	},
+
+	{
+		"RANDOM SEED",
+		"Seed value used for random numbers",
+		"",
+		config_randomseed
+	},
+
+	{
+		"REPEAT CHAR",
+		"Character used for repeating commands",
+		"",
+		config_repeatchar
+	},
+
+	{
+		"REPEAT ENTER",
+		"You send the last command on an enter",
+		"You send a carriage return on an enter",
+		config_repeatenter
+	},
+
+	{
+		"SCREEN READER",
+		"You are using a screen reader",
+		"You are not using a screen reader",
+		config_screenreader
+	},
+
+	{
+		"SCROLL LOCK",
+		"You do not see server output while scrolling",
+		"You see server output while scrolling",
+		config_scrolllock
+	},
+
+	{
+		"SPEEDWALK",
+		"Your input is scanned for speedwalks",
+		"Your input is not scanned for speedwalks",
+		config_speedwalk
+	},
+
+	{
+		"TAB WIDTH",
+		"Number of spaces used for a tab",
+		"",
+		config_tabwidth
+	},
+
+	{
+		"TELNET",
+		"TELNET support is enabled.",
+		"TELNET support is disabled.",
+		config_telnet
+	},
+
+	{
+		"TINTIN CHAR",
+		"Character used for TinTin++ commands",
+		"",
+		config_tintinchar
+	},
+
+	{
+		"VERBATIM",
+		"Keyboard input is send as is",
+		"Keyboard input is parsed by TinTin++",
+		config_verbatim
+	},
+
+	{
+		"VERBATIM CHAR",
+		"Character used for verbatim lines",
+		"",
+		config_verbatimchar
+	},
+
+	{
+		"VERBOSE",
+		"Read script files verbosely",
+		"Read script files quietly",
+		config_verbose
+	},
+
+	{
+		"WORDWRAP",
+		"Server output is word wrapped",
+		"Server output is line wrapped",
+		config_wordwrap
+	},
+
+
+	{
+		"",
+		"",
+		0,
+		0
+	}
+};
 
 DO_COMMAND(do_configure)
 {
@@ -81,6 +367,8 @@ DO_COMMAND(do_configure)
 
 						if (node)
 						{
+							check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "CONFIG", config_table[index].name, node->arg2);
+
 							show_message(ses, LIST_CONFIG, "#CONFIG {%s} HAS BEEN SET TO {%s}.", config_table[index].name, node->arg2);
 						}
 					}
@@ -347,6 +635,30 @@ DO_CONFIG(config_commandecho)
 	return ses;
 }
 
+DO_CONFIG(config_compact)
+{
+	if (*arg2)
+	{
+		if (is_abbrev(arg2, "ON"))
+		{
+			SET_BIT(ses->config_flags, CONFIG_FLAG_COMPACT);
+		}
+		else if (is_abbrev(arg2, "OFF"))
+		{
+			DEL_BIT(ses->config_flags, CONFIG_FLAG_COMPACT);
+		}
+		else
+		{
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF>", config_table[index].name);
+
+			return NULL;
+		}
+	}
+	strcpy(arg2, HAS_BIT(ses->config_flags, CONFIG_FLAG_COMPACT) ? "ON" : "OFF");
+
+	return ses;
+}
+
 DO_CONFIG(config_connectretry)
 {
 	if (*arg2)
@@ -444,6 +756,30 @@ DO_CONFIG(config_historysize)
 	return ses;
 }
 
+DO_CONFIG(config_hibernate)
+{
+	if (*arg2)
+	{
+		if (is_abbrev(arg2, "ON"))
+		{
+			SET_BIT(gtd->flags, TINTIN_FLAG_HIBERNATE);
+		}
+		else if (is_abbrev(arg2, "OFF"))
+		{
+			DEL_BIT(gtd->flags, TINTIN_FLAG_HIBERNATE);
+		}
+		else
+		{
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF>", config_table[index].name);
+
+			return NULL;
+		}
+	}
+	strcpy(arg2, HAS_BIT(gtd->flags, TINTIN_FLAG_HIBERNATE) ? "ON" : "OFF");
+
+	return ses;
+}
+
 DO_CONFIG(config_inheritance)
 {
 	if (*arg2)

+ 21 - 2
src/cursor.c

@@ -1296,7 +1296,7 @@ DO_CURSOR(cursor_flag)
 
 DO_CURSOR(cursor_get)
 {
-	char arg1[BUFFER_SIZE];
+	char arg1[BUFFER_SIZE], buf[BUFFER_SIZE];
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
 
@@ -1306,7 +1306,9 @@ DO_CURSOR(cursor_get)
 	}
 	else
 	{
-		set_nest_node_ses(ses, arg1, "%s", gtd->ses->input->buf);
+		substitute(ses, gtd->ses->input->buf, buf, SUB_SEC);
+
+		set_nest_node_ses(ses, arg1, "%s", buf);
 	}
 }
 
@@ -2650,6 +2652,23 @@ DO_CURSOR(cursor_tab)
 	char arg1[BUFFER_SIZE];
 	int flag = 0;
 
+	if (*arg == 0)
+	{
+		tintin_header(ses, 80, " CURSOR TAB OPTIONS ");
+
+		tintin_printf2(ses, "  [%-18s] %s", "CASELESS", "Make the tab completion caseless");
+		tintin_printf2(ses, "  [%-18s] %s", "COMPLETE", "Make the tab completion work while editing");
+		tintin_printf2(ses, "  [%-18s] %s", "DICTIONARY", "Make the tab completion include the dictionary");
+		tintin_printf2(ses, "  [%-18s] %s", "LIST", "Make the tab completion include the tab completion list");
+		tintin_printf2(ses, "  [%-18s] %s", "SCROLLBACK", "Make the tab completion include the scrollback buffer");
+		tintin_printf2(ses, "  [%-18s] %s", "BACKWARD", "Make the tab completion go backward");
+		tintin_printf2(ses, "  [%-18s] %s", "FORWARD", "Make the tab completion go forward");
+
+		tintin_header(ses, 80, "");
+
+		return;
+	}
+
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 
 	while (*arg)

+ 115 - 52
src/data.c

@@ -55,7 +55,7 @@ void kill_list(struct listroot *root)
 	{
 		delete_index_list(root, root->used - 1);
 	}
-	root->update = 0;
+	root->update = 0; // should be unnecessary
 }
 
 void free_list(struct listroot *root)
@@ -140,12 +140,24 @@ struct listroot *copy_list(struct session *ses, struct listroot *sourcelist, int
 	return ses->list[type];
 }
 
-struct listnode *create_node_list(struct listroot *root, char *arg1, char *arg2, char *arg3, char *arg4)
+struct listnode *create_node(char *arg1, char *arg2, char *arg3, char *arg4)
 {
 	struct listnode *node;
 
 	node = (struct listnode *) calloc(1, sizeof(struct listnode));
 
+	node->arg1 = str_dup(arg1);
+	node->arg2 = str_dup(arg2);
+	node->arg3 = str_dup(arg3);
+	node->arg4 = str_dup(arg4);
+
+	return node;
+}
+
+struct listnode *create_node_list(struct listroot *root, char *arg1, char *arg2, char *arg3, char *arg4)
+{
+	struct listnode *node;
+
 	if (list_table[root->type].priority_arg == 3 && *arg3 == 0)
 	{
 		strcpy(arg3, "5");
@@ -153,15 +165,10 @@ struct listnode *create_node_list(struct listroot *root, char *arg1, char *arg2,
 
 	if (HAS_BIT(root->flags, LIST_FLAG_NEST) && *arg1 == '\\')
 	{
-		node->arg1 = str_dup(arg1+1);
-	}
-	else
-	{
-		node->arg1 = str_dup(arg1);
+		arg1++;
 	}
-	node->arg2 = str_dup(arg2);
-	node->arg3 = str_dup(arg3);
-	node->arg4 = str_dup(arg4);
+
+	node = create_node(arg1, arg2, arg3, arg4);
 
 //	printf("debug: %p [%p] (%d) (%s) (%s)\n", root, root->ses, root->type, node->arg1, node->arg3);
 
@@ -338,6 +345,10 @@ void remove_index_list(struct listroot *root, int index)
 	{
 		root->update--;
 	}
+	if (index <= root->multi_update)
+	{
+		root->multi_update--;
+	}
 
 	memmove(&root->list[index], &root->list[index + 1], (root->used - index) * sizeof(struct listnode *));
 
@@ -353,11 +364,9 @@ void delete_node_list(struct session *ses, int type, struct listnode *node)
 	delete_index_list(ses->list[type], index);
 }
 
-void delete_index_list(struct listroot *root, int index)
+void delete_node(int type, struct listnode *node)
 {
-	struct listnode *node = root->list[index];
-
-	if (HAS_BIT(list_table[root->type].flags, LIST_FLAG_REGEX))
+	if (HAS_BIT(list_table[type].flags, LIST_FLAG_REGEX))
 	{
 		if (node->regex)
 		{
@@ -365,13 +374,8 @@ void delete_index_list(struct listroot *root, int index)
 		}
 	}
 
-	switch (root->type)
+	switch (type)
 	{
-		case LIST_TERRAIN:
-			delete_room_data(node->room);
-			free(node->room);
-			break;
-
 		case LIST_CLASS:
 			if (node->data)
 			{
@@ -382,22 +386,42 @@ void delete_index_list(struct listroot *root, int index)
 		case LIST_EVENT:
 			event_table[node->val32[0]].level--;
 			break;
-	}
 
-	remove_index_list(root, index);
+		case LIST_TERRAIN:
+			delete_room_data(node->room);
+			free(node->room);
+			break;
 
+		case LIST_VARIABLE:
+			if (node->root)
+			{
+				free_list(node->root);
+
+				node->root = NULL;
+			}
+			break;
+	}
 	// dispose in memory update for one shot handling
 
 	insert_index_list(gtd->dispose_list, node, gtd->dispose_list->used);
 }
 
+void delete_index_list(struct listroot *root, int index)
+{
+	struct listnode *node = root->list[index];
+
+	remove_index_list(root, index);
+
+	delete_node(root->type, node);
+}
+
 void dispose_node(struct listnode *node)
 {
-	if (node->root)
+/*	if (node->root)
 	{
 		free_list(node->root);
 	}
-
+*/
 	str_free(node->arg1);
 	str_free(node->arg2);
 	str_free(node->arg3);
@@ -1121,8 +1145,8 @@ DO_COMMAND(do_ignore)
 {
 	int index, found = FALSE;
 
-	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
-	arg = get_arg_in_braces(ses, arg, arg2, GET_ONE);
+	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);
 
 	if (*arg1 == 0)
 	{
@@ -1140,40 +1164,52 @@ DO_COMMAND(do_ignore)
 	}
 	else
 	{
-		for (index = found = 0 ; index < LIST_MAX ; index++)
+		arg = arg1;
+
+		do
 		{
-			if (HAS_BIT(list_table[index].flags, LIST_FLAG_HIDE))
-			{
-				continue;
-			}
+			arg = get_arg_in_braces(ses, arg, arg3, GET_ONE);
 
-			if (!is_abbrev(arg1, list_table[index].name_multi) && strcasecmp(arg1, "ALL"))
+			for (index = found = 0 ; index < LIST_MAX ; index++)
 			{
-				continue;
-			}
+				if (HAS_BIT(list_table[index].flags, LIST_FLAG_HIDE))
+				{
+					continue;
+				}
 
-			if (*arg2 == 0)
-			{
-				TOG_BIT(ses->list[index]->flags, LIST_FLAG_IGNORE);
-			}
-			else if (is_abbrev(arg2, "ON"))
-			{
-				SET_BIT(ses->list[index]->flags, LIST_FLAG_IGNORE);
-			}
-			else if (is_abbrev(arg2, "OFF"))
-			{
-				DEL_BIT(ses->list[index]->flags, LIST_FLAG_IGNORE);
+				if (!is_abbrev(arg3, list_table[index].name_multi) && strcasecmp(arg3, "ALL"))
+				{
+					continue;
+				}
+
+				if (*arg3 == 0)
+				{
+					TOG_BIT(ses->list[index]->flags, LIST_FLAG_IGNORE);
+				}
+				else if (is_abbrev(arg2, "ON"))
+				{
+					SET_BIT(ses->list[index]->flags, LIST_FLAG_IGNORE);
+				}
+				else if (is_abbrev(arg2, "OFF"))
+				{
+					DEL_BIT(ses->list[index]->flags, LIST_FLAG_IGNORE);
+				}
+				else
+				{
+					show_error(ses, LIST_COMMAND, "#SYNTAX: #IGNORE {%s} [ON|OFF]", arg1);
+				
+					return ses;
+				}
+				show_message(ses, LIST_COMMAND, "#OK: #IGNORE STATUS FOR %s HAS BEEN SET TO: %s.", list_table[index].name_multi, HAS_BIT(ses->list[index]->flags, LIST_FLAG_IGNORE) ? "ON" : "OFF");
+
+				found = TRUE;
 			}
-			else
+			if (*arg == COMMAND_SEPARATOR)
 			{
-				show_error(ses, LIST_COMMAND, "#SYNTAX: #IGNORE {%s} [ON|OFF]", arg1);
-				
-				return ses;
+				arg++;
 			}
-			show_message(ses, LIST_COMMAND, "#OK: #IGNORE STATUS FOR %s HAS BEEN SET TO: %s.", list_table[index].name_multi, HAS_BIT(ses->list[index]->flags, LIST_FLAG_IGNORE) ? "ON" : "OFF");
-
-			found = TRUE;
 		}
+		while (*arg);
 
 		if (found == FALSE)
 		{
@@ -1605,6 +1641,29 @@ DO_COMMAND(do_info)
 				}
 				break;
 
+			case CTRL_O:
+				if (is_abbrev(arg1, "OUTPUT"))
+				{
+					if (is_abbrev(arg2, "SAVE"))
+					{
+						set_nest_node_ses(ses, "info[OUTPUT]", "{RAWBUF}{%s}", gtd->mud_output_buf);
+						add_nest_node_ses(ses, "info[OUTPUT]", "{RAWLEN}{%s}", gtd->mud_output_len);
+						add_nest_node_ses(ses, "info[OUTPUT]", "{STRBUF}{%s}", gtd->mud_output_strip_buf);
+						add_nest_node_ses(ses, "info[OUTPUT]", "{STRLEN}{%d}", gtd->mud_output_strip_len);
+						add_nest_node_ses(ses, "info[OUTPUT]", "{LINE}{%s}",   gtd->mud_output_line);
+					}
+					else
+					{
+						tintin_printf2(ses, "#INFO OUTPUT: RAWBUF: %s", gtd->mud_output_buf);
+						tintin_printf2(ses, "#INFO OUTPUT: RAWLEN: %d", gtd->mud_output_len);
+						tintin_printf2(ses, "#INFO OUTPUT: STRBUF: %s", gtd->mud_output_strip_buf);
+						tintin_printf2(ses, "#INFO OUTPUT: STRLEN: %d", gtd->mud_output_strip_len);
+						tintin_printf2(ses, "#INFO OUTPUT: LINE: %s", gtd->mud_output_line);
+
+					}
+				}
+				break;
+
 			case CTRL_S:
 				if (is_abbrev(arg1, "SESSION"))
 				{
@@ -1616,6 +1675,7 @@ DO_COMMAND(do_info)
 						add_nest_node_ses(ses, "info[SESSION]", "{CREATED}{%d}", ses->created);
 						add_nest_node_ses(ses, "info[SESSION]", "{HOST} {%s}", ses->session_host);
 						add_nest_node_ses(ses, "info[SESSION]", "{IP} {%s}", ses->session_ip);
+						add_nest_node_ses(ses, "info[SESSION]", "{MTTS} {%d}", get_mtts_val(ses));
 						add_nest_node_ses(ses, "info[SESSION]", "{PORT} {%s}", ses->session_port);
 
 						show_message(ses, LIST_COMMAND, "#INFO: DATA WRITTEN TO {info[SESSION]}");
@@ -1628,6 +1688,7 @@ DO_COMMAND(do_info)
 						tintin_printf2(ses, "{CREATED}{%d}", ses->created);
 						tintin_printf2(ses, "{HOST} {%s}", ses->session_host);
 						tintin_printf2(ses, "{IP} {%s}", ses->session_ip);
+						tintin_printf2(ses, "{MTTS} {%d}", get_mtts_val(ses));
 						tintin_printf2(ses, "{PORT} {%s}", ses->session_port);
 					}
 				}
@@ -1649,6 +1710,7 @@ DO_COMMAND(do_info)
 							add_nest_node_ses(ses, name, "{CREATED}{%d}", sesptr->created);
 							add_nest_node_ses(ses, name, "{HOST} {%s}", sesptr->session_host);
 							add_nest_node_ses(ses, name, "{IP} {%s}", sesptr->session_ip);
+							add_nest_node_ses(ses, name, "{MTTS} {%d}", get_mtts_val(ses));
 							add_nest_node_ses(ses, name, "{PORT} {%s}", sesptr->session_port);
 						}
 						show_message(ses, LIST_COMMAND, "#INFO: DATA WRITTEN TO {info[SESSIONS]}");
@@ -1663,6 +1725,7 @@ DO_COMMAND(do_info)
 							tintin_printf2(ses, "{%s}{CREATED}{%d}", sesptr->name, sesptr->created);
 							tintin_printf2(ses, "{%s}{HOST} {%s}", sesptr->name, sesptr->session_host);
 							tintin_printf2(ses, "{%s}{IP} {%s}", sesptr->name, sesptr->session_ip);
+							tintin_printf2(ses, "{%s}{MTTS} {%d}", sesptr->name, get_mtts_val(ses));
 							tintin_printf2(ses, "{%s}{PORT} {%s}", sesptr->name, sesptr->session_port);
 						}
 					}

+ 4 - 2
src/draw.c

@@ -1432,6 +1432,8 @@ DO_DRAW(draw_bot_side)
 
 		if (HAS_BIT(flags, DRAW_FLAG_RIGHT) || HAS_BIT(flags, DRAW_FLAG_BOT))
 		{
+			SET_BIT(corner, DRAW_FLAG_RIGHT|DRAW_FLAG_BOT);
+
 			arg1 += sprintf(arg1, "%s", get_draw_corner(corner, "┘"));
 		}
 	}
@@ -2343,7 +2345,7 @@ DO_DRAW(draw_table_grid)
 
 						str = sub_arg_in_braces(ses, str, buf2 + strlen(buf2), GET_ALL, SUB_VAR|SUB_FUN|SUB_LIT|SUB_ESC|SUB_COL);
 
-						get_color_codes(row_color, buf2, row_color, GET_ALL);
+//						get_color_codes(row_color, buf2, row_color, GET_ALL);
 
 						top_r = top_row + r - 1;
 						top_c = top_col + c;
@@ -2708,7 +2710,7 @@ DO_DRAW(draw_top_side)
 
 	if (HAS_BIT(flags, DRAW_FLAG_LEFT) || HAS_BIT(flags, DRAW_FLAG_TOP))
 	{
-		SET_BIT(corner, DRAW_FLAG_LEFT|DRAW_FLAG_RIGHT);
+		SET_BIT(corner, DRAW_FLAG_LEFT|DRAW_FLAG_TOP);
 
 		arg1 += sprintf(arg1, "%s%s", box_color, get_draw_corner(corner, "┌"));
 	}

+ 3 - 1
src/event.c

@@ -241,6 +241,8 @@ int check_all_events(struct session *ses, int flags, int args, int vars, char *f
 
 			if (node)
 			{
+				// GAG and CATCH events need to use EVENT_FLAG_GAG and EVENT_FLAG_CATCH
+
 				if (node->val32[1] != flags)
 				{
 					tintin_printf2(ses, "\e[1;31merror: check_all_events: %s: flags: %d != %d", name, flags, node->val32[1]);
@@ -268,7 +270,7 @@ int check_all_events(struct session *ses, int flags, int args, int vars, char *f
 
 				if (!HAS_BIT(flags, EVENT_FLAG_UPDATE) && HAS_BIT(ses_ptr->list[LIST_EVENT]->flags, LIST_FLAG_DEBUG))
 				{
-					show_debug(ses_ptr, LIST_EVENT, "#DEBUG EVENT {%s} {%s}", node->arg1, node->arg2);
+					show_debug(ses_ptr, LIST_EVENT, COLOR_DEBUG "#DEBUG EVENT " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
 				}
 
 				if (node->shots && --node->shots == 0)

+ 16 - 23
src/files.c

@@ -31,11 +31,11 @@
 
 DO_COMMAND(do_read)
 {
-	FILE *fp;
+	FILE *file;
 
 	sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 
-	if ((fp = fopen(arg1, "r")) == NULL)
+	if ((file = fopen(arg1, "r")) == NULL)
 	{
 		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "READ ERROR", arg1, "FILE NOT FOUND.");
 
@@ -44,16 +44,20 @@ DO_COMMAND(do_read)
 		return ses;
 	}
 
-	return read_file(ses, fp, arg1);
+	ses = read_file(ses, file, arg1);
+
+	fclose(file);
+
+	return ses;
 }
 
-struct session *read_file(struct session *ses, FILE *fp, char *filename)
+struct session *read_file(struct session *ses, FILE *file, char *filename)
 {
 	char *bufi, *bufo, temp[INPUT_SIZE], *pti, *pto, last = 0;
 	int lvl, cnt, com, lnc, fix, ok, verbose, size;
 	int counter[LIST_MAX];
 
-	temp[0] = getc(fp);
+	temp[0] = getc(file);
 
 	if (!ispunct((int) temp[0]))
 	{
@@ -61,12 +65,10 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 
 		tintin_printf(ses, "#ERROR: #READ {%s} - INVALID START OF FILE '%c'.", filename, temp[0]);
 
-		fclose(fp);
-
 		return ses;
 	}
 
-	ungetc(temp[0], fp);
+	ungetc(temp[0], file);
 
 	for (cnt = 0 ; cnt < LIST_MAX ; cnt++)
 	{
@@ -76,11 +78,11 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 		}
 	}
 
-	fseek(fp, 0, SEEK_END);
+	fseek(file, 0, SEEK_END);
 
-	size = ftell(fp);
+	size = ftell(file);
 
-	fseek(fp, 0, SEEK_SET);
+	fseek(file, 0, SEEK_SET);
 
 	if ((bufi = (char *) calloc(1, size + 2)) == NULL || (bufo = (char *) calloc(1, size + 2)) == NULL)
 	{
@@ -88,19 +90,16 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 
 		tintin_printf(ses, "#ERROR: #READ {%s} - FAILED TO ALLOCATE %d BYTES OF MEMORY.", filename, size + 2);
 
-		fclose(fp);
-
 		return ses;
 	}
 
 
-	if (fread(bufi, 1, size, fp) <= 0)
+	if (fread(bufi, 1, size, file) <= 0)
 	{
 		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "READ ERROR", filename, "FREAD FAILURE");
 		
 		tintin_printf(ses, "#ERROR: #READ {%s} - FREAD FAILURE.", filename);
 
-		fclose(fp);
 		return ses;
 	}
 
@@ -300,8 +299,6 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 
 		tintin_printf(ses, "#ERROR: #READ {%s} - MISSING %d '%c' BETWEEN LINE %d AND %d.", filename, abs(lvl), lvl < 0 ? DEFAULT_OPEN : DEFAULT_CLOSE, fix == 0 ? 1 : ok, fix == 0 ? lnc + 1 : fix);
 
-		fclose(fp);
-
 		free(bufi);
 		free(bufo);
 
@@ -314,8 +311,6 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 
 		tintin_printf(ses, "#ERROR: #READ {%s} - MISSING %d '%s'", filename, abs(com), com < 0 ? "/*" : "*/");
 
-		fclose(fp);
-
 		free(bufi);
 		free(bufo);
 
@@ -401,8 +396,6 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 			}
 		}
 	}
-	fclose(fp);
-
 	free(bufi);
 	free(bufo);
 
@@ -576,7 +569,7 @@ void write_node(struct session *ses, int list, struct listnode *node, FILE *file
 	return;
 }
 
-char *fread_one_line(char **str, FILE *fp)
+char *fread_one_line(char **str, FILE *file)
 {
 	int byte;
 
@@ -584,7 +577,7 @@ char *fread_one_line(char **str, FILE *fp)
 
 	while (TRUE)
 	{
-		byte = getc(fp);
+		byte = getc(file);
 
 		switch (byte)
 		{

+ 2 - 2
src/gui.h

@@ -578,8 +578,8 @@ char *tt_gui = "#line quiet #port init gui 0\n"
 "	{\n"
 "		#draw jade Green rounded calign box -3 -13 -1 -1  {@gui_link{COMMAND;gui_remove;remove}};\n"
 "	};\n"
-"	#macro {\t} {gui_tab_forward};\n"
-"	#macro {\e[Z} {gui_tab_backward};\n"
+"	#macro {\\t} {gui_tab_forward};\n"
+"	#macro {\\e[Z} {gui_tab_backward};\n"
 "}\n"
 
 "#event {SESSION ACTIVATED}\n"

文件差异内容过多而无法显示
+ 289 - 283
src/help.c


+ 2 - 0
src/history.c

@@ -97,6 +97,8 @@ void add_line_history(struct session *ses, char *line)
 		delete_index_list(ses->list[LIST_HISTORY], 0);
 	}
 
+	check_all_events(ses, SUB_BRA|EVENT_FLAG_INPUT, 0, 1, "HISTORY UPDATE", line);
+
 	return;
 }
 

+ 16 - 18
src/input.c

@@ -195,6 +195,11 @@ void read_line(char *input, int len)
 	char buf[BUFFER_SIZE];
 	int size, width, index;
 
+	if (HAS_BIT(gtd->ses->log->mode, LOG_FLAG_LOW) && gtd->ses->log->file)
+	{
+		fwrite(input, 1, len, gtd->ses->log->file);
+	}
+
 	if (HAS_BIT(gtd->ses->config_flags, CONFIG_FLAG_CONVERTMETA) || gtd->level->convert)
 	{
 		convert_meta(input, &gtd->macro_buf[strlen(gtd->macro_buf)], FALSE);
@@ -454,6 +459,8 @@ int check_key(char *input, int len)
 				{
 					strcpy(buf, node->arg2);
 
+					show_debug(gtd->ses, LIST_MACRO, COLOR_DEBUG "#DEBUG MACRO " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
+
 					if (node->shots && --node->shots == 0)
 					{
 						delete_node_list(gtd->ses, LIST_MACRO, node);
@@ -865,7 +872,6 @@ void convert_meta(char *input, char *output, int eol)
 				{
 					*pto++ = *pti++;
 				}
-
 				break;
 
 			default:
@@ -919,31 +925,26 @@ char *str_convert_meta(char *input, int eol)
 void echo_command(struct session *ses, char *line)
 {
 	char buffer[BUFFER_SIZE];
+	int split = HAS_BIT(ses->flags, SES_FLAG_SPLIT) == SES_FLAG_SPLIT;
 
 	DEL_BIT(ses->telopts, TELOPT_FLAG_PROMPT);
 
 	if (ses->check_output)
 	{
-		strcpy(buffer, ses->more_output);
-
-		process_mud_output(ses, buffer, FALSE);
-	}
-	else
-	{
-		buffer[0] = 0;
+		process_more_output(ses, "", split); // add newline if not in split mode
 	}
 
 	if (ses->scroll->line != -1)
 	{
 		buffer_end(gtd->ses, "", "", "");
 
-		if (!HAS_BIT(ses->flags, SES_FLAG_SPLIT))
+		if (!split)
 		{
 			printf("%s\n", line);
 		}
 	}
 
-	if (!HAS_BIT(ses->flags, SES_FLAG_SPLIT))
+	if (!split)
 	{
 		add_line_buffer(ses, line, -1);
 
@@ -956,22 +957,19 @@ void echo_command(struct session *ses, char *line)
 	}
 	else
 	{
-
-		if (strip_vt102_strlen(ses, buffer) == 0)
+		if (strip_vt102_strlen(ses, ses->scroll->input) == 0)
 		{
 			return;
 		}
 		sprintf(buffer, "\e[0m");
 	}
 
-//	if (ses->wrap == gtd->screen->cols)
-	{
-		gtd->level->scroll++;
+	gtd->level->scroll++;
 
-		tintin_printf2(ses, "%s%s", ses->scroll->input, buffer);
+	tintin_printf2(ses, "%s%s", ses->scroll->input, buffer);
+
+	gtd->level->scroll--;
 
-		gtd->level->scroll--;
-	}
 	add_line_buffer(ses, buffer, -1);
 }
 

+ 71 - 80
src/line.c

@@ -241,9 +241,7 @@ DO_LINE(line_gag)
 	{
 		ses->gagline = 0;
 	}
-	show_debug(ses, LIST_GAG, "#DEBUG LINE GAG {%s} [%d]", arg1, ses->gagline);
-
-//	SET_BIT(ses->flags, SES_FLAG_GAG);
+	show_debug(ses, LIST_GAG, COLOR_DEBUG "#DEBUG LINE GAG " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} " COLOR_COMMAND "[" COLOR_STRING "%d" COLOR_COMMAND "]", arg1, ses->gagline);
 
 	return ses;
 }
@@ -335,7 +333,7 @@ DO_LINE(line_log)
 			}
 		}
 	}
-	else
+	else if (*arg1)
 	{
 		if (ses->log->next_time == gtd->time && !strcmp(ses->log->next_name, arg1))
 		{
@@ -360,77 +358,14 @@ DO_LINE(line_log)
 			show_error(ses, LIST_COMMAND, "#ERROR: #LINE LOG {%s} - COULDN'T OPEN FILE.", arg1);
 		}
 	}
-	return ses;
-}
-
-DO_LINE(line_logmode)
-{
-	struct session *active_ses;
-
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
-
-	DEL_BIT(ses->log->mode, LOG_FLAG_OLD_HTML|LOG_FLAG_OLD_PLAIN|LOG_FLAG_OLD_RAW);
-
-	switch (HAS_BIT(ses->log->mode, LOG_FLAG_HTML|LOG_FLAG_PLAIN|LOG_FLAG_RAW))
-	{
-		case LOG_FLAG_HTML:
-			SET_BIT(ses->log->mode, LOG_FLAG_OLD_HTML);
-			break;
-		case LOG_FLAG_PLAIN:
-			SET_BIT(ses->log->mode, LOG_FLAG_OLD_PLAIN);
-			break;
-		case LOG_FLAG_RAW:
-			SET_BIT(ses->log->mode, LOG_FLAG_OLD_RAW);
-			break;
-	}
-
-	if (is_abbrev(arg1, "HTML"))
-	{
-		SET_BIT(ses->log->mode, LOG_FLAG_HTML);
-		DEL_BIT(ses->log->mode, LOG_FLAG_PLAIN);
-		DEL_BIT(ses->log->mode, LOG_FLAG_RAW);
-	}
-	else if (is_abbrev(arg1, "PLAIN"))
-	{
-		SET_BIT(ses->log->mode, LOG_FLAG_PLAIN);
-		DEL_BIT(ses->log->mode, LOG_FLAG_HTML);
-		DEL_BIT(ses->log->mode, LOG_FLAG_RAW);
-	}
-	else if (is_abbrev(arg1, "RAW"))
-	{
-		SET_BIT(ses->log->mode, LOG_FLAG_RAW);
-		DEL_BIT(ses->log->mode, LOG_FLAG_HTML);
-		DEL_BIT(ses->log->mode, LOG_FLAG_PLAIN);
-	}
 	else
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {LOGMODE} {HTML|PLAIN|RAW} {command}.");
-
-		return ses;
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {LOG} {filename} [string]");
 	}
-
-	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
-
-	active_ses = script_driver(ses, LIST_COMMAND, arg1);
-
-	DEL_BIT(ses->log->mode, LOG_FLAG_HTML|LOG_FLAG_PLAIN|LOG_FLAG_RAW);
-
-	switch (HAS_BIT(ses->log->mode, LOG_FLAG_OLD_HTML|LOG_FLAG_OLD_PLAIN|LOG_FLAG_OLD_RAW))
-	{
-		case LOG_FLAG_OLD_HTML:
-			SET_BIT(ses->log->mode, LOG_FLAG_HTML);
-			break;
-		case LOG_FLAG_OLD_PLAIN:
-			SET_BIT(ses->log->mode, LOG_FLAG_PLAIN);
-			break;
-		case LOG_FLAG_OLD_RAW:
-			SET_BIT(ses->log->mode, LOG_FLAG_RAW);
-			break;
-	}
-
-	return ses = active_ses;
+	return ses;
 }
 
+
 DO_LINE(line_logverbatim)
 {
 	FILE *logfile;
@@ -440,9 +375,13 @@ DO_LINE(line_logverbatim)
 
 	if (*arg1 && *arg2)
 	{
-		if (!strcmp(ses->log->line_name, arg1))
+		if (ses->log->file && !strcmp(ses->log->name, arg1))
 		{
-			logit(ses, arg2, ses->log->line_file, LOG_FLAG_LINEFEED);
+			logit(ses, arg2, ses->log->file, LOG_FLAG_LINEFEED);
+		}
+		else if (ses->log->line_time == gtd->time && !strcmp(ses->log->line_name, arg1))
+		{
+			logit(ses, arg2, ses->log->line_file, LOG_FLAG_LINEFEED|LOG_FLAG_PLAIN);
 		}
 		else
 		{
@@ -453,12 +392,12 @@ DO_LINE(line_logverbatim)
 					fclose(ses->log->line_file);
 				}
 				free(ses->log->line_name);
+
 				ses->log->line_name = strdup(arg1);
 				ses->log->line_file = logfile;
+				ses->log->line_time = gtd->time;
 
-				logheader(ses, ses->log->line_file, LOG_FLAG_APPEND | HAS_BIT(ses->log->mode, LOG_FLAG_HTML));
-
-				logit(ses, arg2, ses->log->line_file, LOG_FLAG_LINEFEED);
+				logit(ses, arg2, ses->log->line_file, LOG_FLAG_LINEFEED|LOG_FLAG_PLAIN);
 			}
 			else
 			{
@@ -466,9 +405,9 @@ DO_LINE(line_logverbatim)
 			}
 		}
 	}
-	else
+	else if (*arg1)
 	{
-		if (!strcmp(ses->log->next_name, arg1))
+		if (ses->log->next_time == gtd->time && !strcmp(ses->log->next_name, arg1))
 		{
 			SET_BIT(ses->log->mode, LOG_FLAG_NEXT);
 		}
@@ -479,8 +418,10 @@ DO_LINE(line_logverbatim)
 				fclose(ses->log->next_file);
 			}
 			free(ses->log->next_name);
+
 			ses->log->next_name = strdup(arg1);
 			ses->log->next_file = logfile;
+			ses->log->next_time = gtd->time;
 
 			SET_BIT(ses->log->mode, LOG_FLAG_NEXT);
 		}
@@ -489,9 +430,59 @@ DO_LINE(line_logverbatim)
 			show_error(ses, LIST_COMMAND, "#ERROR: #LINE LOGVERBATIM {%s} - COULDN'T OPEN FILE.", arg1);
 		}
 	}
+	else
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {LOGVERBATIM} {filename} {string}");
+	}
 	return ses;
 }
 
+DO_LINE(line_logmode)
+{
+	struct session *active_ses;
+
+	int old_mode = ses->log->mode;
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+
+	if (is_abbrev(arg1, "HTML"))
+	{
+		SET_BIT(ses->log->mode, LOG_FLAG_HTML);
+		DEL_BIT(ses->log->mode, LOG_FLAG_PLAIN);
+		DEL_BIT(ses->log->mode, LOG_FLAG_RAW);
+	}
+	else if (is_abbrev(arg1, "PLAIN"))
+	{
+		SET_BIT(ses->log->mode, LOG_FLAG_PLAIN);
+		DEL_BIT(ses->log->mode, LOG_FLAG_HTML);
+		DEL_BIT(ses->log->mode, LOG_FLAG_RAW);
+	}
+	else if (is_abbrev(arg1, "RAW"))
+	{
+		SET_BIT(ses->log->mode, LOG_FLAG_RAW);
+		DEL_BIT(ses->log->mode, LOG_FLAG_HTML);
+		DEL_BIT(ses->log->mode, LOG_FLAG_PLAIN);
+	}
+	else if (is_abbrev(arg1, "STAMP"))
+	{
+		SET_BIT(ses->log->mode, LOG_FLAG_STAMP);
+	}
+	else
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {LOGMODE} {HTML|PLAIN|RAW|STAMP} {command}.");
+
+		return ses;
+	}
+
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
+
+	active_ses = script_driver(ses, LIST_COMMAND, arg1);
+
+	ses->log->mode = old_mode;
+
+	return active_ses;
+}
+
 DO_LINE(line_msdp)
 {
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
@@ -524,8 +515,8 @@ DO_LINE(line_json)
 
 	char *str_sub = str_alloc_stack(0);
 
-	struct listroot *root = ses->list[LIST_VARIABLE];
-	struct listnode *node = search_nest_node(root, arg1);
+//	struct listroot *root = ses->list[LIST_VARIABLE];
+	struct listnode *node = search_nest_node_ses(ses, arg1);
 
 	if (node)
 	{
@@ -533,7 +524,7 @@ DO_LINE(line_json)
 		{
 			view_nest_node_json(node, &str_sub, 0, TRUE);
 
-//			print_lines(ses, SUB_NONE, "%s\n", str_sub);
+//			print_lines(ses, SUB_NONE, "", "%s\n", str_sub);
 		}
 		else
 		{

+ 17 - 2
src/list.c

@@ -343,6 +343,11 @@ DO_ARRAY(array_delete)
 		{
 			delete_index_list(list->root, index);
 		}
+
+		if (list->root->used == 0)
+		{
+			array_clear(ses, list, arg, var, arg1, arg2);
+		}
 	}
 	else
 	{
@@ -450,7 +455,12 @@ DO_ARRAY(array_filter)
 				}
 			}
 		}
-		if (found && numerate)
+
+		if (found && list->root->used == 0)
+		{
+			array_clear(ses, list, arg, var, arg1, arg2);
+		}
+		else if (found && numerate)
 		{
 			array_numerate(ses, list, arg, var, arg1, arg2);
 		}
@@ -759,10 +769,15 @@ DO_ARRAY(array_refine)
 			}
 		}
 
-		if (found && numerate)
+		if (found && list->root->used == 0)
+		{
+			array_clear(ses, list, arg, var, arg1, arg2);
+		}
+		else if (found && numerate)
 		{
 			array_numerate(ses, list, arg, var, arg1, arg2);
 		}
+
 	}
 
 	return ses;

+ 5 - 5
src/log.c

@@ -243,7 +243,7 @@ void logit(struct session *ses, char *txt, FILE *file, int flags)
 
 	push_call("logit(%p,%p,%p,%d)",ses,txt,file,flags);
 
-	if (*ses->log->stamp_strf)
+	if (*ses->log->stamp_strf && (HAS_BIT(ses->log->mode, LOG_FLAG_STAMP) || file == ses->log->file))
 	{
 		if (ses->log->stamp_time != gtd->time)
 		{
@@ -257,8 +257,8 @@ void logit(struct session *ses, char *txt, FILE *file, int flags)
 		}
 		fputs(ses->log->stamp_text, file);
 	}
-			
-	if (HAS_BIT(ses->log->mode, LOG_FLAG_PLAIN))
+
+	if (HAS_BIT(ses->log->mode, LOG_FLAG_PLAIN) || HAS_BIT(flags, LOG_FLAG_PLAIN))
 	{
 		strip_vt102_codes(txt, out);
 	}
@@ -327,7 +327,7 @@ char *get_charset_html(struct session *ses)
 void write_html_header(struct session *ses, FILE *fp)
 {
 	char header[BUFFER_SIZE];
-	
+
 		sprintf(header,
 		"<!DOCTYPE html>\n"
 		"<html>\n"
@@ -418,7 +418,7 @@ void vt102_to_html(struct session *ses, char *txt, char *out)
 								rgb[2] = URANGE(0, atoi(tmp), 255);
 
 								fgc = rgb[0] * 256 * 256 + rgb[1] * 256 + rgb[2];
-	
+
 								DEL_BIT(vtc, COL_TCF_R);
 								SET_BIT(vtc, COL_TCF);
 							}

+ 12 - 6
src/main.c

@@ -352,7 +352,10 @@ int main(int argc, char **argv)
 
 				case 't':
 					SET_BIT(greeting, STARTUP_FLAG_NOTITLE);
-					print_stdout(0, 0, "\e]0;%s\007", optarg);
+					command(gts, do_screen, "LOAD BOTH");
+					command(gts, do_screen, "SAVE BOTH");
+					command(gts, do_screen, "SET BOTH %s", optarg);
+//					print_stdout(0, 0, "\e]0;%s\007", optarg);
 					break;
 
 				case 'T':
@@ -458,6 +461,8 @@ void init_tintin(int greeting)
 
 	gtd->mud_output_max = 16384;
 	gtd->mud_output_buf = (char *) calloc(1, gtd->mud_output_max);
+	gtd->mud_output_strip_buf = (char *) calloc(1, gtd->mud_output_max);
+	gtd->mud_output_line = gtd->mud_output_buf;
 
 	// WSL: /proc/sys/kernel/osrelease
 
@@ -569,27 +574,28 @@ void init_tintin(int greeting)
 
 	gtd->level->input++;
 
-	command(gts, do_configure, "{AUTO TAB}         {5000}");
+/*	command(gts, do_configure, "{AUTO TAB}         {5000}"); */ gts->scrollback_tab = 5000;
 	command(gts, do_configure, "{BUFFER SIZE}     {10000}");
 	command(gts, do_configure, "{COLOR MODE}         {ON}");
 	command(gts, do_configure, "{COLOR PATCH}       {OFF}");
 	command(gts, do_configure, "{COMMAND COLOR}   {<078>}");
 	command(gts, do_configure, "{COMMAND ECHO}       {ON}");
-	command(gts, do_configure, "{CONNECT RETRY}       {0}");
+	command(gts, do_configure, "{COMPACT}           {OFF}");
+/*	command(gts, do_configure, "{CONNECT RETRY}       {0}"); */
 	command(gts, do_configure, "{CHARSET}          {AUTO}");
 	command(gts, do_configure, "{HISTORY SIZE}     {1000}");
 	command(gts, do_configure, "{LOG MODE}          {RAW}");
 	command(gts, do_configure, "{MOUSE}             {OFF}");
 	command(gts, do_configure, "{PACKET PATCH}     {AUTO}");
-	command(gts, do_configure, "{RANDOM SEED}      {AUTO}");
+/*	command(gts, do_configure, "{RANDOM SEED}      {AUTO}"); */ seed_rand(gts, ++gtd->utime);
 	command(gts, do_configure, "{REPEAT CHAR}         {!}");
 	command(gts, do_configure, "{REPEAT ENTER}      {OFF}");
 	command(gts, do_configure, "{SCREEN READER}      {%s}", HAS_BIT(greeting, STARTUP_FLAG_SCREENREADER) ? "ON" : "OFF");
 	command(gts, do_configure, "{SCROLL LOCK}        {ON}");
 	command(gts, do_configure, "{SPEEDWALK}         {OFF}");
-	command(gts, do_configure, "{TAB WIDTH}        {AUTO}");
+/*	command(gts, do_configure, "{TAB WIDTH}        {AUTO}"); */ gts->tab_width = 8;
 	command(gts, do_configure, "{TELNET}             {ON}");
-	command(gts, do_configure, "{TINTIN CHAR}         {#}");
+/*	command(gts, do_configure, "{TINTIN CHAR}         {#}"); */
 	command(gts, do_configure, "{VERBATIM}          {OFF}");
 	command(gts, do_configure, "{VERBATIM CHAR}      {\\}");
 	command(gts, do_configure, "{VERBOSE}            {%s}", HAS_BIT(greeting, STARTUP_FLAG_VERBOSE) ? "ON" : "OFF");

+ 126 - 114
src/mapper.c

@@ -51,7 +51,7 @@ extern  int find_new_room(struct session *ses);
 extern struct exit_data *find_exit(struct session *ses, int room, char *arg);
 extern struct exit_data *find_exit_vnum(struct session *ses, int room, int vnum);
 extern  int get_exit_dir(struct session *ses, char *arg);
-extern float get_exit_length(struct session *ses, struct exit_data *exit);
+extern double get_exit_length(struct session *ses, struct exit_data *exit);
 extern char *get_exit_color(struct session *ses, int room, struct exit_data *exit);
 extern  int dir_to_grid(int dir);
 extern  int revdir_to_grid(int dir);
@@ -171,6 +171,12 @@ void create_map(struct session *ses, char *arg, int flags)
 
 	ses->map->search = calloc(1, sizeof(struct search_data));
 
+	ses->map->search->name    = create_node("", "", "", "");
+	ses->map->search->desc    = create_node("", "", "", "");
+	ses->map->search->area    = create_node("", "", "", "");
+	ses->map->search->note    = create_node("", "", "", "");
+	ses->map->search->terrain = create_node("", "", "", "");
+
 	ses->map->flags = MAP_FLAG_ASCIIGRAPHICS|MAP_FLAG_DIRECTION|MAP_FLAG_TERRAIN | flags;
 
 	ses->map->global_exit         = (struct exit_data *) calloc(1, sizeof(struct exit_data));
@@ -277,6 +283,15 @@ int delete_map(struct session *ses)
 	free(ses->map->grid_rooms);
 	free(ses->map->grid_vnums);
 	free(ses->map->global_exit);
+
+	// probably need to use a dummy node
+
+	delete_node(LIST_ACTION, ses->map->search->area);
+	delete_node(LIST_ACTION, ses->map->search->desc);
+	delete_node(LIST_ACTION, ses->map->search->name);
+	delete_node(LIST_ACTION, ses->map->search->note);
+	delete_node(LIST_ACTION, ses->map->search->terrain);
+
 	free(ses->map->search);
 
 	free(ses->map);
@@ -323,7 +338,7 @@ struct room_data *create_room(struct session *ses, char *format, ...)
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE); newroom->note    = strdup(arg1);
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE); newroom->terrain = strdup(arg1);
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE); newroom->data    = strdup(arg1);
-	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE); newroom->weight  = (float) atof(arg1);
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE); newroom->weight  = (double) atof(arg1);
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE); newroom->id      = strdup(arg1);
 
 	if (HAS_BIT(newroom->flags, ROOM_FLAG_AVOID))
@@ -455,9 +470,9 @@ struct exit_data *create_exit(struct session *ses, int vnum, char *format, ...)
 	arg = get_arg_in_braces(ses, arg, buf, GET_ONE);	newexit->dir    = atoi(buf);
 	arg = get_arg_in_braces(ses, arg, buf, GET_ONE);	newexit->flags  = atoi(buf);
 	arg = get_arg_in_braces(ses, arg, buf, GET_ALL);	newexit->data   = strdup(buf);
-	arg = get_arg_in_braces(ses, arg, buf, GET_ONE);	newexit->weight = (float) atof(buf);
+	arg = get_arg_in_braces(ses, arg, buf, GET_ONE);	newexit->weight = (double) atof(buf);
 	arg = get_arg_in_braces(ses, arg, buf, GET_ONE);        newexit->color  = strdup(buf);
-	arg = get_arg_in_braces(ses, arg, buf, GET_ONE);        newexit->delay  = (float) atof(buf);
+	arg = get_arg_in_braces(ses, arg, buf, GET_ONE);        newexit->delay  = (double) atof(buf);
 
 	if (!HAS_BIT(ses->map->flags, MAP_FLAG_READ))
 	{
@@ -526,7 +541,7 @@ int get_exit_dir(struct session *ses, char *arg)
 	}
 }
 
-float get_room_weight(struct session *ses, int vnum)
+double get_room_weight(struct session *ses, int vnum)
 {
 	struct room_data *room = ses->map->room_list[vnum];
 
@@ -537,7 +552,7 @@ float get_room_weight(struct session *ses, int vnum)
 	return room->weight;
 }
 
-float get_exit_weight(struct session *ses, int vnum, struct exit_data *exit)
+double get_exit_weight(struct session *ses, int vnum, struct exit_data *exit)
 {
 	struct room_data *room = ses->map->room_list[vnum];
 
@@ -548,7 +563,7 @@ float get_exit_weight(struct session *ses, int vnum, struct exit_data *exit)
 	return exit->weight;
 }
 
-float get_exit_length(struct session *ses, struct exit_data *exit)
+double get_exit_length(struct session *ses, struct exit_data *exit)
 {
 	return exit->weight + ses->map->room_list[exit->vnum]->length;
 }
@@ -2018,14 +2033,14 @@ struct grid_node
 	int x;
 	int y;
 	int z;
-	float length;
+	double length;
 	struct exit_data *exit;
 };
 
 void displaygrid_build(struct session *ses, int vnum, int x, int y, int z)
 {
 	int head, tail, index, iprev, loop;
-	float length;
+	double length;
 	struct grid_node *node, *temp, list[MAP_BF_SIZE], *node_list[MAP_BF_SIZE];
 	struct exit_data *exit, *exit_next;
 	struct room_data *room, *toroom;
@@ -2239,7 +2254,7 @@ void displaygrid_build(struct session *ses, int vnum, int x, int y, int z)
 int spatialgrid_find(struct session *ses, int from, int x, int y, int z)
 {
 	int head, tail, index, iprev, loop;
-	float length;
+	double length;
 	struct grid_node *node, *temp, list[MAP_BF_SIZE], *node_list[MAP_BF_SIZE];
 	struct exit_data *exit, *exit_next;
 	struct room_data *room, *toroom;
@@ -3419,7 +3434,7 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 					{
 						if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIILENGTH))
 						{
-							cat_sprintf(buf, "%s%5.1f", ses->map->color[MAP_COLOR_USER], room->length, ses->map->color[MAP_COLOR_EXIT]);
+							cat_sprintf(buf, "%s%5.1f%s", ses->map->color[MAP_COLOR_USER], room->length, ses->map->color[MAP_COLOR_EXIT]);
 						}
 						else
 						{
@@ -3861,6 +3876,7 @@ void map_search_compile(struct session *ses, char *arg, char *var)
 {
 	char tmp[BUFFER_SIZE], buf[BUFFER_SIZE], *ptb;
 	struct listnode *node;
+	struct search_data *search;
 
 	push_call("map_search_compile(%p,%p,%p)",ses,arg,var);
 
@@ -3868,44 +3884,46 @@ 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->min = ses->map->search->max = ses->map->search->vnum = 0;
+	search = ses->map->search;
+
+	search->min = search->max = search->vnum = 0;
 
 	if (is_math(ses, buf))
 	{
 		if (strstr(buf, ".."))
 		{
-			get_ellipsis(ses, ses->map->size, buf, &ses->map->search->min, &ses->map->search->max);
-			ses->map->search->min++;
-			ses->map->search->max++;
+			get_ellipsis(ses, ses->map->size, buf, &search->min, &search->max);
+			search->min++;
+			search->max++;
 		}
 		else
 		{
-			ses->map->search->vnum = (int) get_number(ses, buf);
+			search->vnum = (int) get_number(ses, buf);
 		}
 	}
 
-	if (ses->map->search->vnum || ses->map->search->min || ses->map->search->max)
+	if (search->vnum || search->min || search->max)
 	{
 		pop_call();
 		return;
 	}
 
-	if (ses->map->search->arg)
+	if (search->arg)
 	{
-		free(ses->map->search->arg);
+		free(search->arg);
 	}
 
 	if (*buf)
 	{
-		ses->map->search->arg = strdup(buf);
+		search->arg = strdup(buf);
 
-		node = search_node_list(ses->list[LIST_LANDMARK], ses->map->search->arg);
+		node = search_node_list(ses->list[LIST_LANDMARK], search->arg);
 
 		if (node)
 		{
-			ses->map->search->vnum = node->val32[0];
+			search->vnum = node->val32[0];
 
-			if (ses->map->search->vnum)
+			if (search->vnum)
 			{
 				pop_call();
 				return;
@@ -3914,33 +3932,30 @@ void map_search_compile(struct session *ses, char *arg, char *var)
 	}
 	else
 	{
-		ses->map->search->arg = NULL;
+		search->arg = NULL;
 	}
 
-	if (ses->map->search->name)
+	if (search->name->regex)
 	{
-		free(ses->map->search->name);
+		free(search->name->regex);
+		search->name->regex = NULL;
 	}
 
 	if (*buf)
 	{
 		strcat(buf, "$");
 
-		ses->map->search->name = tintin_regexp_compile(ses, NULL, buf, PCRE_ANCHORED);
-	}
-	else
-	{
-		ses->map->search->name = NULL;
+		search->name->regex = tintin_regexp_compile(ses, search->name, buf, PCRE_ANCHORED);
 	}
 
 	arg = sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN); // exits
 
-	ses->map->search->exit_dirs = 0;
-	ses->map->search->exit_size = 0;
+	search->exit_dirs = 0;
+	search->exit_size = 0;
 
-	if (ses->map->search->exit_list)
+	if (search->exit_list)
 	{
-		free(ses->map->search->exit_list);
+		free(search->exit_list);
 	}
 
 	if (*buf)
@@ -3952,18 +3967,18 @@ void map_search_compile(struct session *ses, char *arg, char *var)
 
 		if (is_math(ses, buf))
 		{
-			ses->map->search->exit_dirs = get_number(ses, buf);
+			search->exit_dirs = get_number(ses, buf);
 
-			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++;
+			if (HAS_BIT(search->exit_dirs, MAP_DIR_N))  search->exit_size++;
+			if (HAS_BIT(search->exit_dirs, MAP_DIR_E))  search->exit_size++;
+			if (HAS_BIT(search->exit_dirs, MAP_DIR_S))  search->exit_size++;
+			if (HAS_BIT(search->exit_dirs, MAP_DIR_W))  search->exit_size++;
+			if (HAS_BIT(search->exit_dirs, MAP_DIR_U))  search->exit_size++;
+			if (HAS_BIT(search->exit_dirs, MAP_DIR_D))  search->exit_size++;
+			if (HAS_BIT(search->exit_dirs, MAP_DIR_NE)) search->exit_size++;
+			if (HAS_BIT(search->exit_dirs, MAP_DIR_NW)) search->exit_size++;
+			if (HAS_BIT(search->exit_dirs, MAP_DIR_SE)) search->exit_size++;
+			if (HAS_BIT(search->exit_dirs, MAP_DIR_SW)) search->exit_size++;
 		}
 		else
 		{
@@ -3971,17 +3986,17 @@ void map_search_compile(struct session *ses, char *arg, char *var)
 			{
 				ptb = get_arg_in_braces(ses, ptb, exit, GET_ONE);
 
-				ses->map->search->exit_size++;
+				search->exit_size++;
 
 				node = search_node_list(ses->list[LIST_PATHDIR], exit);
 
 				if (node)
 				{
-					SET_BIT(ses->map->search->exit_dirs, 1LL << pdir(node));
+					SET_BIT(search->exit_dirs, 1LL << pdir(node));
 				}
 				else
 				{
-					SET_BIT(ses->map->search->exit_dirs, 1); // flag indicates no exits
+					SET_BIT(search->exit_dirs, 1); // flag indicates no exits
 
 					cat_sprintf(tmp, "{%s}", exit);
 				}
@@ -3992,89 +4007,77 @@ void map_search_compile(struct session *ses, char *arg, char *var)
 				}
 			}
 		}
-		ses->map->search->exit_list = strdup(tmp);
+		search->exit_list = strdup(tmp);
 	}
 	else
 	{
-		ses->map->search->exit_list = strdup("");
+		search->exit_list = strdup("");
 	}
 
 	arg = sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN); // desc
 
-	if (ses->map->search->desc)
+	if (search->desc->regex)
 	{
-		free(ses->map->search->desc);
+		free(search->desc->regex);
+		search->desc->regex = NULL;
 	}
 
 	if (*buf)
 	{
 		strcat(buf, "$");
 
-		ses->map->search->desc = tintin_regexp_compile(ses, NULL, buf, PCRE_ANCHORED|PCRE_DOLLAR_ENDONLY|PCRE_DOTALL);
-	}
-	else
-	{
-		ses->map->search->desc = NULL;
+		search->desc->regex = tintin_regexp_compile(ses, search->desc, buf, PCRE_ANCHORED);
 	}
 
 	arg = sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN);
 
 	// area
 
-	if (ses->map->search->area)
+	if (search->area->regex)
 	{
-		free(ses->map->search->area);
+		free(search->area->regex);
+		search->area->regex = NULL;
 	}
 
 	if (*buf)
 	{
 		strcat(buf, "$");
 
-		ses->map->search->area = tintin_regexp_compile(ses, NULL, buf, PCRE_ANCHORED);
-	}
-	else
-	{
-		ses->map->search->area = NULL;
+		search->area->regex = tintin_regexp_compile(ses, search->area, buf, PCRE_ANCHORED);
 	}
 
 	// note
 
 	arg = sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN);
 
-	if (ses->map->search->note)
+	if (search->note->regex)
 	{
-		free(ses->map->search->note);
+		free(search->note->regex);
+		search->note->regex = NULL;
 	}
 
 	if (*buf)
 	{
 		strcat(buf, "$");
 
-		ses->map->search->note = tintin_regexp_compile(ses, NULL, buf, PCRE_ANCHORED);
-	}
-	else
-	{
-		ses->map->search->note = NULL;
+		search->note->regex = tintin_regexp_compile(ses, search->note, buf, PCRE_ANCHORED);
 	}
 
 	// terrain
 
 	arg = sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN);
 
-	if (ses->map->search->terrain)
+	if (search->terrain->regex)
 	{
-		free(ses->map->search->terrain);
+		free(search->terrain->regex);
+		search->terrain->regex = NULL;
 	}
 
 	if (*buf)
 	{
 		strcat(buf, "$");
 
-		ses->map->search->terrain = tintin_regexp_compile(ses, NULL, buf, PCRE_ANCHORED);
-	}
-	else
-	{
-		ses->map->search->terrain = NULL;
+		search->terrain->regex = tintin_regexp_compile(ses, search->terrain, buf, PCRE_ANCHORED);
 	}
 
 	// flag
@@ -4086,8 +4089,8 @@ void map_search_compile(struct session *ses, char *arg, char *var)
 		char flags[BUFFER_SIZE], *ptf;
 		long long *flag;
 
-		ses->map->search->flag = get_number(ses, buf);
-		ses->map->search->galf = 0;
+		search->flag = get_number(ses, buf);
+		search->galf = 0;
 
 		ptb = buf;
 
@@ -4098,12 +4101,12 @@ void map_search_compile(struct session *ses, char *arg, char *var)
 
 			if (ptf[0] == '!')
 			{
-				flag = &ses->map->search->galf;
+				flag = &search->galf;
 				ptf++;
 			}
 			else
 			{
-				flag = &ses->map->search->flag;
+				flag = &search->flag;
 			}
 
 			if (is_abbrev(ptf, "avoid"))
@@ -4143,35 +4146,35 @@ void map_search_compile(struct session *ses, char *arg, char *var)
 	}
 	else
 	{
-		ses->map->search->flag = 0;
-		ses->map->search->galf = 0;
+		search->flag = 0;
+		search->galf = 0;
 	}
 
 	arg = sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN); // id
 
-	if (ses->map->search->id)
+	if (search->id)
 	{
-		free(ses->map->search->id);
+		free(search->id);
 	}
 
 	if (*buf)
 	{
-		ses->map->search->id = strdup(buf);
+		search->id = strdup(buf);
 	}
 	else
 	{
-		ses->map->search->id = NULL;
+		search->id = NULL;
 	}
 
 	arg = sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN); // distance
 
 	if (*buf)
 	{
-		ses->map->search->distance = (float) get_number(ses, buf);
+		search->distance = (double) get_number(ses, buf);
 	}
 	else
 	{
-		ses->map->search->distance = 0;
+		search->distance = 0;
 	}
 
 	pop_call();
@@ -4203,9 +4206,9 @@ int match_room(struct session *ses, int vnum, struct search_data *search)
 		return !strcmp(room->id, search->id);
 	}
 
-	if (search->name)
+	if (search->name->regex)
 	{
-		if (!regexp_compare(ses, search->name, room->name, "", 0, 0))
+		if (!regexp_compare(ses, search->name->regex, room->name, room->name, 0, 0))
 		{
 			return 0;
 		}
@@ -4254,28 +4257,27 @@ int match_room(struct session *ses, int vnum, struct search_data *search)
 		match = 1;
 	}
 
-	if (search->desc)
+	if (search->desc->regex)
 	{
-
-		if (!regexp_compare(ses, search->desc, room->desc, "", 0, 0))
+		if (!regexp_compare(ses, search->desc->regex, room->desc, room->desc, 0, 0))
 		{
 			return 0;
 		}
 		match = 1;
 	}
 
-	if (search->area)
+	if (search->area->regex)
 	{
-		if (!regexp_compare(ses, search->area, room->area, "", 0, 0))
+		if (!regexp_compare(ses, search->area->regex, room->area, room->area, 0, 0))
 		{
 			return 0;
 		}
 		match = 1;
 	}
 
-	if (search->note)
+	if (search->note->regex)
 	{
-		if (!regexp_compare(ses, search->note, room->note, "", 0, 0))
+		if (!regexp_compare(ses, search->note->regex, room->note, room->note, 0, 0))
 		{
 			return 0;
 		}
@@ -4284,7 +4286,7 @@ int match_room(struct session *ses, int vnum, struct search_data *search)
 
 	if (search->terrain)
 	{
-		if (!regexp_compare(ses, search->terrain, room->terrain, "", 0, 0))
+		if (!regexp_compare(ses, search->terrain->regex, room->terrain, room->terrain, 0, 0))
 		{
 			return 0;
 		}
@@ -4653,7 +4655,7 @@ int tunnel_void(struct session *ses, int from, int room, int dir)
 int searchgrid_find(struct session *ses, int from, struct search_data *search)
 {
 	int vnum, head, tail, index, iprev, loop;
-	float length;
+	double length;
 	struct grid_node *node, *temp, list[MAP_BF_SIZE], *node_list[MAP_BF_SIZE];
 	struct exit_data *exit;
 	struct room_data *room, *toroom;
@@ -4822,7 +4824,7 @@ int searchgrid_find(struct session *ses, int from, struct search_data *search)
 struct exit_data *searchgrid_walk(struct session *ses, int from, int dest)
 {
 	int vnum, head, tail, index, iprev, loop, last;
-	float length;
+	double length;
 	struct grid_node *node, *temp, list[MAP_BF_SIZE], *node_list[MAP_BF_SIZE];
 	struct exit_data *exit;
 	struct room_data *room, *toroom;
@@ -5800,7 +5802,7 @@ void exit_edit(struct session *ses, struct exit_data *exit, char *opt, char *arg
 		}
 		else
 		{
-			exit->delay = (float) get_number(ses, arg3);
+			exit->delay = (double) get_number(ses, arg3);
 
 			if (rev_exit)
 			{
@@ -5905,7 +5907,7 @@ void exit_edit(struct session *ses, struct exit_data *exit, char *opt, char *arg
 		}
 		else
 		{
-			exit->weight = (float) get_number(ses, arg3);
+			exit->weight = (double) get_number(ses, arg3);
 
 			if (rev_exit)
 			{
@@ -6833,7 +6835,14 @@ void map_legend_index(struct session *ses, char *arg, int head, int tail)
 
 	for (cnt = head ; cnt < tail ; cnt++)
 	{
-		arg = sub_arg_in_braces(ses, arg, raw, GET_ONE, SUB_NONE);
+		if (head + 1 != tail)
+		{
+			arg = sub_arg_in_braces(ses, arg, raw, GET_ONE, SUB_NONE);
+		}
+		else
+		{
+			strcpy(raw, arg);
+		}
 
 		substitute(ses, raw, esc, SUB_ESC);
 
@@ -7123,7 +7132,7 @@ DO_MAP(map_list)
 
 			if (*var)
 			{
-				add_nest_node_ses(ses, var, "{%d} {{distance}{%.3f}{x}{%d}{y}{%d}{z}{%d}}", room->vnum, ses->map->search->stamp == room->search_stamp ? room->length  : -1, room->x, room->y, room->z);
+				add_nest_node_ses(ses, var, "{%d} {{distance}{%.3f}{vnum}{%d}{x}{%d}{y}{%d}{z}{%d}}", room->vnum, ses->map->search->stamp == room->search_stamp ? room->length  : -1, room->vnum, room->x, room->y, room->z);
 			}
 			else
 			{
@@ -7131,16 +7140,16 @@ DO_MAP(map_list)
 				{
 					if (room->w == 0)
 					{
-						tintin_printf2(ses, "vnum: %5d  dist: %8.3f  x: %4d  y: %4d  z: %4d  name: %s", room->vnum, room->length, room->x, room->y, room->z, room->name);
+						tintin_printf2(ses, "vnum: %5d  dist: %9.3f  x: %4d  y: %4d  z: %4d  name: %s", room->vnum, room->length, room->x, room->y, room->z, room->name);
 					}
 					else
 					{
-						tintin_printf2(ses, "vnum: %5d  dist: %8.3f  x: %4s  y: %4s  z: %4s  name: %s", room->vnum, room->length, "?", "?", "?", room->name);
+						tintin_printf2(ses, "vnum: %5d  dist: %9.3f  x: %4s  y: %4s  z: %4s  name: %s", room->vnum, room->length, "?", "?", "?", room->name);
 					}
 				}
 				else
 				{
-						tintin_printf2(ses, "vnum: %5d  dist: %8.3f  x: %4s  y: %4s  z: %4s  name: %s", room->vnum, -1, "?", "?", "?", room->name);
+						tintin_printf2(ses, "vnum: %5d  dist: %9s  x: %4s  y: %4s  z: %4s  name: %s", room->vnum, "-1", "?", "?", "?", room->name);
 				}
 			}
 		}
@@ -7393,7 +7402,8 @@ DO_MAP(map_map)
 				{
 					case 'A':
 					case 'O':
-						fprintf(logfile, "%s\n", gtd->out);
+						logit(ses, gtd->out, logfile, LOG_FLAG_LINEFEED);
+//						fprintf(logfile, "%s\n", gtd->out);
 						break;
 
 					case 'L':
@@ -7437,7 +7447,8 @@ DO_MAP(map_map)
 				{
 					case 'A':
 					case 'O':
-						fprintf(logfile, "%s\n", gtd->out);
+						logit(ses, gtd->out, logfile, LOG_FLAG_LINEFEED);
+//						fprintf(logfile, "%s\n", gtd->out);
 						break;
 
 					case 'L':
@@ -7479,7 +7490,8 @@ DO_MAP(map_map)
 			{
 				case 'A':
 				case 'O':
-					fprintf(logfile, "%s\n", gtd->out);
+					logit(ses, gtd->out, logfile, LOG_FLAG_LINEFEED);
+//					fprintf(logfile, "%s\n", gtd->out);
 					break;
 				
 				case 'L':
@@ -8168,7 +8180,7 @@ DO_MAP(map_set)
 			}
 			else
 			{
-				room->weight = (float) get_number(ses, arg2);
+				room->weight = (double) get_number(ses, arg2);
 
 				show_message(ses, LIST_COMMAND, "#MAP SET: roomweight set to: %.3f", room->weight);
 			}

+ 5 - 6
src/memory.c

@@ -100,7 +100,8 @@ char *get_str_str(struct str_data *str_ptr)
 
 struct str_data *str_ptr_realloc(struct str_data *str_ptr, int size)
 {
-	if (str_ptr->max <= size)
+//	if (str_ptr->max <= size)
+	if (size != str_ptr->max - 1)
 	{
 		str_ptr = (struct str_data *) realloc(str_ptr, sizeof(struct str_data) + size + 1);
 
@@ -568,7 +569,6 @@ char *str_mov(char **str, int dst, int src)
 	return *str;
 }
 
-
 void str_alloc_free(struct str_data *str_ptr)
 {
 	if (HAS_BIT(str_ptr->flags, STR_FLAG_STACK|STR_FLAG_FREE))
@@ -659,15 +659,14 @@ struct str_data *str_alloc_list(int size)
 
 	if (gtd->memory->free_len)
 	{
-		int index;
-
-		index = gtd->memory->free[--gtd->memory->free_len];
+		int index = gtd->memory->free[--gtd->memory->free_len];
 
 		str_ptr = gtd->memory->list[index];
 
 		DEL_BIT(str_ptr->flags, STR_FLAG_FREE);
 
-		if (size >= str_ptr->max)
+//		if (size >= str_ptr->max)
+		if (size != str_ptr->max - 1)
 		{
 			str_ptr = str_ptr_realloc(str_ptr, size);
 		}

+ 7 - 3
src/nest.c

@@ -678,7 +678,8 @@ int get_nest_size_val(struct listroot *root, char *variable, char **result)
 		{
 			for (index = 0 ; index < root->used ; index++)
 			{
-				str_cat_printf(result, "{%s}", root->list[index]->arg2);
+				show_nest_node(root->list[index], result, FALSE); // behaves like strcat
+//				str_cat_printf(result, "{%s}", root->list[index]->arg2);
 			}
 			return root->used + 1;
 		}
@@ -761,7 +762,8 @@ int get_nest_size_val(struct listroot *root, char *variable, char **result)
 			{
 				for (index = 0 ; index < root->used ; index++)
 				{
-					str_cat_printf(result, "{%s}", root->list[index]->arg2);
+					show_nest_node(root->list[index], result, FALSE); // behaves like strcat
+//					str_cat_printf(result, "{%s}", root->list[index]->arg2);
 				}
 				return root->used + 1;
 			}
@@ -1058,6 +1060,8 @@ void view_nest_node_json(struct listnode *node, char **str_result, int nest, int
 	}
 }
 
+// Adds gtd->level->local support
+
 struct listnode *set_nest_node_ses(struct session *ses, char *arg1, char *format, ...)
 {
 	struct listnode *node;
@@ -1216,7 +1220,7 @@ struct listnode *add_nest_node_ses(struct session *ses, char *arg1, char *format
 	}
 	else if (node)
 	{
-		str_cpy(&node->arg2, arg2);
+		str_cat(&node->arg2, arg2);
 	}
 	else
 	{

+ 117 - 60
src/net.c

@@ -46,6 +46,9 @@ int wait_on_connect(struct session *ses, int sock, int connect_error)
 	static fd_set wfd;
 	socklen_t len, val;
 
+	FD_ZERO(&rfd);
+	FD_ZERO(&wfd);
+
 	FD_SET(sock, &rfd);
 	FD_SET(sock, &wfd);
 
@@ -152,7 +155,10 @@ int connect_mud(struct session *ses, char *host, char *port)
 		syserr_printf(ses, "connect_mud: setsockopt:");
 	}
 
-	ses->connect_error = connect(sock, address->ai_addr, address->ai_addrlen);
+	if (gts->connect_retry == 0)
+	{
+		ses->connect_error = connect(sock, address->ai_addr, address->ai_addrlen);
+	}
 
 	if (fcntl(sock, F_SETFL, O_NDELAY|O_NONBLOCK) == -1)
 	{
@@ -165,22 +171,27 @@ int connect_mud(struct session *ses, char *host, char *port)
 		return -1;
 	}
 
-//	ses->connect_error = connect(sock, address->ai_addr, address->ai_addrlen);
-
-	if (ses->connect_error)
+	if (gts->connect_retry)
 	{
-//		ses->connect_error = wait_on_connect(ses, sock, ses->connect_error);
+		ses->connect_error = connect(sock, address->ai_addr, address->ai_addrlen);
 
 		if (ses->connect_error)
 		{
-			syserr_printf(ses, "connect_mud: connect");
+			ses->connect_error = wait_on_connect(ses, sock, ses->connect_error);
+		}
+	}
 
-			close(sock);
+	if (ses->connect_error)
+	{
+		if (gts->connect_retry == 0)
+		{
+			syserr_printf(ses, "connect_mud: connect");
+		}
+		close(sock);
 
-			freeaddrinfo(address);
+		freeaddrinfo(address);
 
-			return 0;
-		}
+		return 0;
 	}
 
 	error = getnameinfo(address->ai_addr, address->ai_addrlen, ip, 100, NULL, 0, NI_NUMERICHOST);
@@ -428,27 +439,47 @@ int detect_prompt(struct session *ses, char *original)
 
 void readmud(struct session *ses)
 {
-	char *line, *next_line;
+	char *line, *next_line/*, *strip*/;
 	char linebuf[BUFFER_SIZE];
 	int len;
 	struct session *cts;
 
 	push_call("readmud(%p)", ses);
 
-	gtd->mud_output_len = 0;
+	line = gtd->mud_output_buf;
 
-	if (gtd->mud_output_len < BUFFER_SIZE)
+	if (ses->check_output && *line == '\n')
 	{
-		check_all_events(ses, SUB_SEC|EVENT_FLAG_OUTPUT, 0, 1, "RECEIVED OUTPUT", gtd->mud_output_buf);
+		line++;
 
-		if (check_all_events(ses, SUB_SEC|EVENT_FLAG_CATCH, 0, 1, "CATCH RECEIVED OUTPUT", gtd->mud_output_buf))
+		process_more_output(ses, "", FALSE);
+	}
+	else if (HAS_BIT(ses->config_flags, CONFIG_FLAG_COMPACT))
+	{
+		if (*ses->scroll->input == 0 && *line == '\n')
 		{
-			pop_call();
-			return;
+			line++;
 		}
 	}
 
-	/* separate into lines and print away */
+//	strip = str_alloc(gtd->mud_output_len);
+
+	gtd->mud_output_strip_len = strip_vt102_codes(line, gtd->mud_output_strip_buf);
+
+	check_all_events(ses, SUB_SEC|EVENT_FLAG_OUTPUT, 0, 2, "RECEIVED OUTPUT", gtd->mud_output_buf, gtd->mud_output_strip_buf);
+
+	if (check_all_events(ses, SUB_SEC|EVENT_FLAG_CATCH, 0, 2, "CATCH RECEIVED OUTPUT", gtd->mud_output_buf, gtd->mud_output_strip_buf))
+	{
+		gtd->mud_output_len = 0;
+
+		// str_free(strip);
+		pop_call();
+		return;
+	}
+
+	check_one_line_multi(ses, line, gtd->mud_output_strip_buf);
+
+//	str_free(strip);
 
 	// cts = current tintin session, may have to make this global to avoid glitches
 
@@ -461,9 +492,12 @@ void readmud(struct session *ses)
 		goto_pos(gtd->ses, gtd->ses->split->bot_row, 1);
 	}
 
+
+	// separate into lines and print away
+
 	SET_BIT(cts->flags, SES_FLAG_READMUD);
 
-	for (line = gtd->mud_output_buf ; line && *line ; line = next_line)
+	for ( ; line && *line ; line = next_line)
 	{
 		next_line = strchr(line, '\n');
 
@@ -471,9 +505,7 @@ void readmud(struct session *ses)
 		{
 			if (next_line - line >= BUFFER_SIZE / 3)
 			{
-				// This is not ideal, but being a rare case it'll suffice for now
-
-				next_line = &line[BUFFER_SIZE / 3];
+				next_line = &line[BUFFER_SIZE / 3]; // Not ideal. Shorten too long lines.
 			}
 			*next_line++ = 0;
 		}
@@ -499,28 +531,22 @@ void readmud(struct session *ses)
 			{
 				if (!HAS_BIT(ses->telopts, TELOPT_FLAG_PROMPT))
 				{
-					if (ses->packet_patch)
-					{
-						str_cat(&ses->more_output, line);
-						ses->check_output = gtd->utime + ses->packet_patch;
-
-						break;
-					}
-					else if (HAS_BIT(ses->config_flags, CONFIG_FLAG_AUTOPATCH))
+					if (ses->packet_patch || HAS_BIT(ses->config_flags, CONFIG_FLAG_AUTOPATCH))
 					{
 						if (ses->list[LIST_PROMPT]->list[0])
 						{
 							if (!detect_prompt(ses, line))
 							{
 								str_cat(&ses->more_output, line);
-								ses->check_output = gtd->utime + 500000ULL;
+								ses->check_output = gtd->utime + (ses->packet_patch ? ses->packet_patch : 500000ULL);
+
 								break;
 							}
 						}
-						else if (HAS_BIT(ses->config_flags, CONFIG_FLAG_AUTOPROMPT))
+						else if (ses->packet_patch || HAS_BIT(ses->config_flags, CONFIG_FLAG_AUTOPROMPT))
 						{
 							str_cat(&ses->more_output, line);
-							ses->check_output = gtd->utime + 500000ULL;
+							ses->check_output = gtd->utime + (ses->packet_patch ? ses->packet_patch : 500000ULL);
 							break;
 						}
 					}
@@ -528,39 +554,26 @@ void readmud(struct session *ses)
 			}
 		}
 
-		if (ses->more_output[0])
+		if (ses->check_output)
 		{
-			if (ses->check_output)
-			{
-				str_cat(&ses->more_output, line);
-				strcpy(linebuf, ses->more_output);
+			process_more_output(ses, line, next_line == NULL);
 
-				str_cpy(&ses->more_output, "");
-			}
-			else
-			{
-				// clean this up some time.
-
-				strcpy(linebuf, line);
-			}
-		}
-		else
-		{
-			strcpy(linebuf, line);
+			continue;
 		}
 
 		if (HAS_BIT(ses->charset, CHARSET_FLAG_ALL_TOUTF8))
 		{
-			char tempbuf[BUFFER_SIZE];
-
-			all_to_utf8(ses, linebuf, tempbuf);
-
-			process_mud_output(ses, tempbuf, next_line == NULL);
+			all_to_utf8(ses, line, linebuf);
 		}
 		else
 		{
-			process_mud_output(ses, linebuf, next_line == NULL);
+			strcpy(linebuf, line);
 		}
+		gtd->mud_output_line = linebuf;
+
+		process_mud_output(ses, linebuf, next_line == NULL);
+
+		gtd->mud_output_line = gtd->mud_output_buf + gtd->mud_output_len;
 	}
 	DEL_BIT(cts->flags, SES_FLAG_READMUD);
 
@@ -568,11 +581,57 @@ void readmud(struct session *ses)
 	{
 		restore_pos(gtd->ses);
 	}
+	gtd->mud_output_len = 0;
 
 	pop_call();
 	return;
 }
 
+void process_more_output(struct session *ses, char *append, int prompt)
+{
+	char line[STRING_SIZE];
+
+	int readmud = HAS_BIT(ses->flags, SES_FLAG_READMUD);
+
+	if (readmud == 0)
+	{
+		if (HAS_BIT(ses->flags, SES_FLAG_SPLIT))
+		{
+			save_pos(ses);
+
+			goto_pos(ses, ses->split->bot_row, 1);
+		}
+		SET_BIT(ses->flags, SES_FLAG_READMUD);
+	}
+
+	if (*append)
+	{
+		str_cat(&ses->more_output, append);
+	}
+
+	if (HAS_BIT(ses->charset, CHARSET_FLAG_ALL_TOUTF8))
+	{
+		all_to_utf8(ses, ses->more_output, line);
+	}
+	else
+	{
+		strcpy(line, ses->more_output);
+	}
+	str_cpy(&ses->more_output, "");
+	ses->check_output = 0;
+
+	process_mud_output(ses, line, prompt);
+
+	if (readmud == 0)
+	{
+		DEL_BIT(ses->flags, SES_FLAG_READMUD);
+
+		if (HAS_BIT(ses->flags, SES_FLAG_SPLIT))
+		{
+			restore_pos(ses);
+		}
+	}
+}
 
 void process_mud_output(struct session *ses, char *linebuf, int prompt)
 {
@@ -581,8 +640,6 @@ void process_mud_output(struct session *ses, char *linebuf, int prompt)
 
 	push_call("process_mud_output(%p,%p,%d)",ses,linebuf,prompt);
 
-	ses->check_output = 0;
-
 	raw_len = strlen(linebuf);
 	str_len = strip_vt102_codes(linebuf, line);
 
@@ -614,7 +671,7 @@ void process_mud_output(struct session *ses, char *linebuf, int prompt)
 		linebuf = line;
 	}
 
-	do_one_line(linebuf, ses);   /* changes linebuf */
+	check_one_line(ses, linebuf);   /* changes linebuf */
 
 	/*
 		Take care of gags, vt102 support still goes
@@ -630,7 +687,7 @@ void process_mud_output(struct session *ses, char *linebuf, int prompt)
 
 		strip_vt102_codes(linebuf, line);
 
-		show_debug(ses, LIST_GAG, "#DEBUG GAG {%d} {%s}", ses->gagline + 1, line);
+		show_debug(ses, LIST_GAG, COLOR_DEBUG "#DEBUG GAG " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} " COLOR_COMMAND "[" COLOR_STRING "%d" COLOR_COMMAND "]", line, ses->gagline + 1);
 
 		pop_call();
 		return;

+ 23 - 1
src/parse.c

@@ -1166,7 +1166,24 @@ void write_mud(struct session *ses, char *command, int flags)
 	Check line for triggers
 */
 
-void do_one_line(char *line, struct session *ses)
+void check_one_line_multi(struct session *ses, char *original, char *stripped)
+{
+	char *buf;
+
+	if (gtd->level->ignore || HAS_BIT(ses->config_flags, CONFIG_FLAG_CONVERTMETA))
+	{
+		return;
+	}
+
+	buf = str_alloc_stack(0);
+
+	if (!HAS_BIT(ses->list[LIST_ACTION]->flags, LIST_FLAG_IGNORE))
+	{
+		check_all_actions_multi(ses, original, stripped, buf);
+	}
+}
+
+void check_one_line(struct session *ses, char *line)
 {
 	char *strip, *buf;
 
@@ -1175,6 +1192,11 @@ void do_one_line(char *line, struct session *ses)
 		return;
 	}
 
+	if (HAS_BIT(ses->config_flags, CONFIG_FLAG_CONVERTMETA))
+	{
+		return;
+	}
+
 	push_call("do_one_line(%s,%p)",ses->name,line);
 
 	push_script_stack(ses, LIST_VARIABLE);

+ 2 - 2
src/path.c

@@ -528,7 +528,7 @@ DO_PATH(path_insert)
 	{
 		show_message(ses, LIST_COMMAND, "#PATH INSERT: FORWARD {%s} BACKWARD {%s} DELAY {%s}.", arg1, arg2, arg3);
 
-		check_append_path(ses, arg1, arg2, (float) get_number(ses, arg3), 1, HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING));
+		check_append_path(ses, arg1, arg2, (double) get_number(ses, arg3), 1, HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING));
 	}
 }
 
@@ -954,7 +954,7 @@ DO_PATH(path_undo)
 	show_message(ses, LIST_COMMAND, "#PATH MOVE: POSITION SET TO %d.", root->update);
 }
 
-void check_append_path(struct session *ses, char *forward, char *backward, float delay, int force, int follow)
+void check_append_path(struct session *ses, char *forward, char *backward, double delay, int force, int follow)
 {
 	struct listroot *root = ses->list[LIST_PATH];
 	struct listnode *node;

+ 84 - 35
src/regex.c

@@ -128,7 +128,6 @@ int regexp_compare(struct session *ses, pcre *nodepcre, char *str, char *exp, in
 			for (i = matches ; i < gtd->cmdc ; i++)
 			{
 				*gtd->cmds[i] = 0;
-//				gtd->cmds[i] = restring(gtd->cmds[i], "");
 			}
 
 			for (i = 0 ; i < matches ; i++)
@@ -142,7 +141,6 @@ int regexp_compare(struct session *ses, pcre *nodepcre, char *str, char *exp, in
 			for (i = matches ; i < gtd->cmdc ; i++)
 			{
 				*gtd->cmds[i] = 0;
-//				gtd->cmds[i] = restring(gtd->cmds[i], "");
 			}
 
 			for (i = 0 ; i < matches ; i++)
@@ -158,7 +156,6 @@ int regexp_compare(struct session *ses, pcre *nodepcre, char *str, char *exp, in
 			for (i = matches ; i < gtd->varc ; i++)
 			{
 				*gtd->vars[i] = 0;
-//				gtd->vars[i] = restring(gtd->vars[i], "");
 			}
 
 			for (i = 0 ; i < matches ; i++)
@@ -172,7 +169,6 @@ int regexp_compare(struct session *ses, pcre *nodepcre, char *str, char *exp, in
 			for (i = matches ; i < gtd->varc ; i++)
 			{
 				*gtd->vars[i] = 0;
-//				gtd->vars[i] = restring(gtd->vars[i], "");
 			}
 
 			for (i = 0 ; i < matches ; i++)
@@ -231,7 +227,7 @@ int check_one_regexp(struct session *ses, struct listnode *node, char *line, cha
 		exp = node->arg1;
 	}
 
-	if (*node->arg1 == '~')
+	if (*exp == '~')
 	{
 		exp++;
 		str = original;
@@ -333,10 +329,10 @@ int get_regex_range(char *in, char *out, int *var, int *arg)
 				pto += sprintf(pto, "%s", "(\\S");
 				break;
 			case 'u':
-				pto += sprintf(pto, "%s", "((?:[\\x00-\\x7F]|[\\xC0-\\xFE][\\x80-\\xC0]{1,3})");
+				pto += sprintf(pto, "%s", "((?:[\\x00-\\x7F]|[\\xC0-\\xF4][\\x80-\\xC0]{1,3})");
 				break;
 			case 'U':
-				pto += sprintf(pto, "%s", "([\\x00-\\x7F\\xFF]");
+				pto += sprintf(pto, "%s", "([\\xF5-\\xFF]");
 				break;
 			case 'w':
 				pto += sprintf(pto, "%s", "(\\w");
@@ -344,6 +340,9 @@ int get_regex_range(char *in, char *out, int *var, int *arg)
 			case 'W':
 				pto += sprintf(pto, "%s", "(\\W");
 				break;
+			case '*':
+				pto += sprintf(pto, "%s", "(.");
+				break;
 
 			default:
 				goto end;
@@ -357,16 +356,18 @@ int get_regex_range(char *in, char *out, int *var, int *arg)
 	}
 	end:
 
-	if (var)
+/*	if (var)
 	{
 		gtd->args[next_arg(*var)] = next_arg(*arg);
-	}
+	}*/
 	strcpy(out, *pti ? "(.+?)" : "(.+)");
 
 	return 0;
 }
 
 
+// check if a table key is a regex
+
 int tintin_regexp_check(struct session *ses, char *exp)
 {
 	if (*exp == '^')
@@ -376,7 +377,6 @@ int tintin_regexp_check(struct session *ses, char *exp)
 
 	while (*exp)
 	{
-
 		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, exp))
 		{
 			exp += 2;
@@ -464,10 +464,19 @@ int tintin_regexp_check(struct session *ses, char *exp)
 	return FALSE;
 }
 
+// 1. convert tinexp to pcre
+// 2. store tintin %00-99 index in gtd->args that links to pcre index in gtd->vars or gtd->args
+// 3. call regexp_compare
+//    3.1 compile the pcre if not already compiled
+//    3.2 run the pcre and return FALSE if there's not a match
+//    3.3 set gtd->vars or gtd->args to the pcre index, unless %00-%99 was found and FIX flag is set
+//    3.4 If FIX is set the gtd->args index is used and valid tinexp is assumed
+//    3.4 return TRUE
+
 int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int option, int flag)
 {
 	char out[BUFFER_SIZE], *pti, *pto;
-	int arg = 1, var = 1, fix = 0;
+	int i, arg = 1, var = 1, fix = 0;
 
 	pti = exp;
 	pto = out;
@@ -507,6 +516,17 @@ int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int
 		switch (pti[0])
 		{
 			case '\\':
+				if (pti[1] == 'n')
+				{
+					SET_BIT(option, PCRE_MULTILINE);
+				}
+				else if (pti[1] == 0)
+				{
+					pti++;
+					*pto++ = '\\';
+					*pto++ = 'z';
+					break;
+				}
 				*pto++ = *pti++;
 				*pto++ = *pti++;
 				break;
@@ -533,20 +553,17 @@ int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int
 				*pto++ = *pti++;
 				break;
 
+			// variables should already have been substituted, check eol marker.
+
 			case '$':
-				if (pti[1] != DEFAULT_OPEN && !is_alnum(pti[1]))
+				for (i = 1 ; pti[i] == '$' ; i++)
 				{
-					int i = 0;
-
-					while (pti[++i] == '$')
-					{
-						continue;
-					}
+					continue;
+				}
 
-					if (pti[i])
-					{
-						*pto++ = '\\';
-					}
+				if (pti[i] != 0 && pti[i] != '\n')
+				{
+					*pto++ = '\\';
 				}
 				*pto++ = *pti++;
 				break;
@@ -638,7 +655,7 @@ int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int
 					case 'u':
 						gtd->args[next_arg(var)] = next_arg(arg);
 						pti += 2;
-						pto += sprintf(pto, "%s", *pti == 0 ? "((?:[\\x00-\\x7F|\\xC0-\\xFE][\\x80-\\xC0]{1,3})*)" : "((?:[\\xC0-\\xFE][\\x80-\\xC0]{1,3})*?)");
+						pto += sprintf(pto, "%s", *pti == 0 ? "((?:[\\x00-\\x7F|\\xC0-\\xF4][\\x80-\\xC0]{1,3})*)" : "((?:[\\xC0-\\xF4][\\x80-\\xC0]{1,3})*?)");
 						break;
 
 					case 'U':
@@ -667,6 +684,7 @@ int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int
 						break;
 
 					case '+':
+						gtd->args[next_arg(var)] = next_arg(arg);
 						pti += 2 + get_regex_range(&pti[2], pto, &var, &arg);
 						pto += strlen(pto);
 						break;
@@ -741,7 +759,7 @@ int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int
 							case 'u':
 								gtd->args[next_arg(var)] = next_arg(arg);
 								pti += 3;
-								pto += sprintf(pto, "%s", *pti == 0 ? "(?:[\\x00-\\x7F]|[\\xC0-\\xFE][\\x80-\\xC0]{1,3})*" : "(?:[\\x00-\\x7F]|[\\xC0-\\xFE][\\x80-\\xC0]{1,3})*?");
+								pto += sprintf(pto, "%s", *pti == 0 ? "(?:[\\x00-\\x7F]|[\\xC0-\\xF4][\\x80-\\xC0]{1,3})*" : "(?:[\\x00-\\x7F]|[\\xC0-\\xF4][\\x80-\\xC0]{1,3})*?");
 								break;
 
 							case 'U':
@@ -814,6 +832,8 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 	pti = exp;
 	pto = out;
 
+	node->flags = 0;
+
 	if (*pti == '~')
 	{
 		pti++;
@@ -854,6 +874,22 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 		switch (pti[0])
 		{
 			case '\\':
+				if (pti[1] == 'e')
+				{
+					SET_BIT(node->flags, NODE_FLAG_COLOR);
+				}
+				else if (pti[1] == 'n')
+				{
+					SET_BIT(option, PCRE_MULTILINE);
+					SET_BIT(node->flags, NODE_FLAG_MULTI);
+				}
+				else if (pti[1] == 0)
+				{
+					pti++;
+					*pto++ = '\\';
+					*pto++ = 'z';
+					break;
+				}
 				*pto++ = *pti++;
 				*pto++ = *pti++;
 				break;
@@ -865,7 +901,7 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 				{
 					if (pto[0] == '$' || pto[0] == '@')
 					{
-						if (pto[1])
+						if (pto[1] == DEFAULT_OPEN || is_alnum(pto[1]) || pto[0] == pto[1])
 						{
 							return NULL;
 						}
@@ -876,7 +912,7 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 				break;
 
 			case '&':
-				if (pti[1] == DEFAULT_OPEN || is_alnum(pti[1]) || pti[1] == '&')
+				if (pti[1] == DEFAULT_OPEN)
 				{
 					return NULL;
 				}
@@ -884,7 +920,7 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 				break;
 
 			case '@':
-				if (pti[1] == DEFAULT_OPEN || is_alnum(pti[1]) || pti[1] == '@')
+				if (pti[1] == DEFAULT_OPEN || is_alnum(pti[1]))
 				{
 					return NULL;
 				}
@@ -897,12 +933,9 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 					return NULL;
 				}
 				{
-					int i = 0;
-
-					while (pti[++i] == '$')
-					{
-						continue;
-					}
+					int i = 1;
+	
+					while (pti[i] == '$') i++;
 
 					if (pti[i])
 					{
@@ -943,7 +976,13 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 						pto += sprintf(pto, "%s", *pti == 0 ? "(.*)" : "(.*?)");
 						break;
 
+					case 'a':
+						pti += 2;
+						pto += sprintf(pto, "%s", *pti == 0 ? "([^\\0]*)" : "([^\\0]*?)");
+						break;
+
 					case 'c':
+						SET_BIT(node->flags, NODE_FLAG_COLOR);
 						pti += 2;
 						pto += sprintf(pto, "%s", *pti == 0 ? "((?:\\e\\[[0-9;]*m)*)" : "((?:\\e\\[[0-9;]*m)*?)");
 						break;
@@ -990,7 +1029,7 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 
 					case 'u':
 						pti += 2;
-						pto += sprintf(pto, "%s", *pti == 0 ? "((?:[\\x00-\\x7F]|[\\xC0-\\xFE][\\x80-\\xC0]{1,3})*)" : "((?:[\\x00-\\x7F]|[\\xC0-\\xFE][\\x80-\\xC0]{1,3})*?)");
+						pto += sprintf(pto, "%s", *pti == 0 ? "((?:[\\x00-\\x7F]|[\\xC0-\\xF4][\\x80-\\xC0]{1,3})*)" : "((?:[\\x00-\\x7F]|[\\xC0-\\xF4][\\x80-\\xC0]{1,3})*?)");
 						break;
 
 					case 'U':
@@ -1036,7 +1075,13 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 					case '!':
 						switch (pti[2])
 						{
+							case 'a':
+								pti += 3;
+								pto += sprintf(pto, "%s", *pti == 0 ? "[^\\0]*" : "[^\\0]*?");
+								break;
+
 							case 'c':
+								SET_BIT(node->flags, NODE_FLAG_COLOR);
 								pti += 3;
 								pto += sprintf(pto, "%s", *pti == 0 ? "(?:\\e\\[[0-9;]*m)*" : "(?:\\e\\[[0-9;]*m)*?");
 								break;
@@ -1107,7 +1152,7 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 								{
 									if (pto[0] == '$' || pto[0] == '@')
 									{
-										if (pto[1])
+										if (pto[1] == DEFAULT_OPEN || is_alnum(pto[1]) || pto[0] == pto[1])
 										{
 											return NULL;
 										}
@@ -1135,6 +1180,10 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 	}
 	*pto = 0;
 
+	if (HAS_BIT(node->flags, NODE_FLAG_COLOR) && *exp != '~')
+	{
+		show_error(ses, LIST_COMMAND, "\e[1;31mWARNING: REGEX MATCHES ESCAPE CODES BUT DOES NOT START WITH A '~' (%s)", exp);
+	}
 	return regexp_compile(ses, out, option);
 }
 

+ 1 - 1
src/scan.c

@@ -430,7 +430,7 @@ DO_SCAN(scan_file)
 DO_SCAN(scan_forward)
 {
 	char line[STRING_SIZE], *lnf;
-	float delay = 0;
+	double delay = 0;
 
 	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
 

+ 19 - 12
src/screen.c

@@ -581,6 +581,10 @@ DO_SCREEN(screen_fill)
 	{
 		fill_right_region(ses, arg2);
 	}
+	else if (is_abbrev(arg1, "SCROLL"))
+	{
+		fill_scroll_region(ses, arg2);
+	}
 	else
 	{
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN FILL {TOP|BOT|LEFT|RIGHT|SCROLL|SPLIT|DEFAULT} {arg}");
@@ -1458,14 +1462,15 @@ void erase_scroll_region(struct session *ses)
 
 	save_pos(ses);
 
+	goto_pos(ses, ses->split->top_row, ses->split->top_col);
+
 	for (row = ses->split->top_row ; row <= ses->split->bot_row ; row++)
 	{
-		if (row > 0 && row <= gtd->ses->split->bot_row)
+		if (ses == gtd->ses && row > 0 && row <= gtd->ses->split->bot_row)
 		{
 			str_cpy(&gtd->screen->line[row - 1]->str, "");
 		}
-
-		print_stdout(0, 0, "\e[%d;%dH\e[%dX", row, ses->split->top_col, ses->wrap);
+		print_stdout(0, 0, "\e[%dX\e[B", ses->wrap);
 	}
 	restore_pos(ses);
 
@@ -1508,7 +1513,7 @@ void erase_top_region(struct session *ses)
 
 		for (row = 1 ; row < ses->split->top_row ; row++)
 		{
-			print_stdout(0, 0, "\e[K\n");
+			print_stdout(0, 0, "\e[K\e[B");
 		}
 		restore_pos(ses);
 	}
@@ -1525,7 +1530,7 @@ void erase_bot_region(struct session *ses)
 
 		for (row = ses->split->bot_row + 1 ; row < gtd->screen->rows ; row++)
 		{
-			print_stdout(0, 0, "\e[K\n");
+			print_stdout(0, 0, "\e[K\e[B");
 		}
 		restore_pos(ses);
 	}
@@ -1538,10 +1543,11 @@ void erase_left_region(struct session *ses)
 	if (ses->split->top_col > 1)
 	{
 		save_pos(ses);
+		goto_pos(ses, ses->split->top_row, 1);
 
 		for (row = ses->split->top_row ; row <= ses->split->bot_row ; row++)
 		{
-			print_stdout(0, 0, "\e[%d;1H\e[%dX", row, ses->split->top_col - 1);
+			print_stdout(0, 0, "\e[%dX\e[B", ses->split->top_col - 1);
 		}
 		restore_pos(ses);
 	}
@@ -1554,10 +1560,11 @@ void erase_right_region(struct session *ses)
 	if (ses->split->bot_col < gtd->screen->cols)
 	{
 		save_pos(ses);
+		goto_pos(ses, ses->split->top_row, ses->split->bot_col + 1);
 
 		for (row = ses->split->top_row ; row <= ses->split->bot_row ; row++)
 		{
-			print_stdout(0, 0, "\e[%d;%dH\e[K", row, ses->split->bot_col + 1);
+			print_stdout(0, 0, "\e[K\e[B");
 		}
 		restore_pos(ses);
 	}
@@ -1572,10 +1579,11 @@ void erase_square(struct session *ses, int top_row, int top_col, int bot_row, in
 
 	save_pos(ses);
 
+	goto_pos(ses, top_row, top_col);
+
 	for (row = top_row ; row <= bot_row ; row++)
 	{
-		goto_pos(ses, row, top_col);
-		print_stdout(0, 0, "\e[%dX", bot_col - top_col + 1);
+		print_stdout(0, 0, "\e[%dX\e[B", bot_col - top_col + 1);
 	}
 	restore_pos(ses);
 
@@ -1589,15 +1597,14 @@ void fill_scroll_region(struct session *ses, char *arg)
 
 	save_pos(ses);
 
-	for (row = ses->split->top_row ; row < ses->split->bot_row ; row++)
+	for (row = ses->split->top_row ; row <= ses->split->bot_row ; row++)
 	{
 		goto_pos(ses, row, ses->split->top_col);
 
-		for (col = ses->split->top_col ; col < ses->split->bot_col ; col++)
+		for (col = ses->split->top_col ; col <= ses->split->bot_col ; col++)
 		{
 			print_stdout(0, 0, "%s", arg);
 		}
-		print_stdout(0, 0, "\n");
 	}
 	restore_pos(ses);
 }

+ 12 - 6
src/session.c

@@ -25,6 +25,7 @@
 ******************************************************************************/
 
 #include <sys/wait.h>
+#include <signal.h>
 
 #include "tintin.h"
 
@@ -32,10 +33,10 @@ DO_COMMAND(do_all)
 {
 	struct session *sesptr, *sesptr_next;
 
+	sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
+
 	if (gts->next)
 	{
-		sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
-
 		for (sesptr = gts->next ; sesptr ; sesptr = sesptr_next)
 		{
 			sesptr_next = sesptr->next;
@@ -48,7 +49,10 @@ DO_COMMAND(do_all)
 	}
 	else
 	{
-		show_error(ses, LIST_COMMAND, "#ALL: THERE AREN'T ANY SESSIONS.");
+		if (!check_all_events(ses, SUB_SEC|EVENT_FLAG_GAG, 0, 1, "GAG RECEIVED ERROR ALL", arg1))
+		{
+			show_error(ses, LIST_COMMAND, "#ALL: THERE AREN'T ANY SESSIONS.");
+		}
 	}
 	return ses;
 }
@@ -675,15 +679,17 @@ void cleanup_session(struct session *ses)
 		{
 			int status, pid;
 
-			pid = waitpid(atoi(ses->session_port), &status, WNOHANG);
+//			pid = waitpid(atoi(ses->session_port), &status, WNOHANG);
+
+			kill(atoi(ses->session_port), SIGTERM);
+
+			pid = waitpid(atoi(ses->session_port), &status, 0);
 
 			if (pid == -1)
 			{
 				syserr_printf(ses, "cleanup_session: waitpid");
 			}
-//			kill(atoi(ses->session_port), SIGTERM);
 		}
-
 	}
 
 	client_end_mccp2(ses);

+ 71 - 35
src/show.c

@@ -46,13 +46,22 @@ DO_COMMAND(do_showme)
 	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);
 
-	do_one_line(arg1, ses);
+	if (strchr(arg1, '\n'))
+	{
+		strip_vt102_codes(arg1, tmp);
+
+		check_one_line_multi(ses, arg1, tmp);
+	}
+	else
+	{
+		check_one_line(ses, arg1);
+	}
 
 	if (ses->gagline > 0)
 	{
 		ses->gagline--;
 
-		show_debug(ses, LIST_GAG, "#DEBUG GAG {%d} {%s}", ses->gagline + 1, arg1);
+		show_debug(ses, LIST_GAG, COLOR_DEBUG "#DEBUG GAG " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} " COLOR_COMMAND "[" COLOR_STRING "%d" COLOR_COMMAND "]", arg1, ses->gagline + 1);
 
 		return ses;
 	}
@@ -330,7 +339,7 @@ void show_info(struct session *ses, int index, char *format, ...)
 	return;
 }
 
-void print_lines(struct session *ses, int flags, char *format, ...)
+void print_lines(struct session *ses, int flags, char *color, char *format, ...)
 {
 	char *buffer, *str_buf;
 	va_list args;
@@ -355,11 +364,11 @@ void print_lines(struct session *ses, int flags, char *format, ...)
 
 		substitute(ses, buffer, str_buf, flags);
 
-		show_lines(ses, str_buf);
+		show_lines(ses, color, str_buf);
 	}
 	else
 	{
-		show_lines(ses, buffer);
+		show_lines(ses, color, buffer);
 	}
 
 	free(buffer);
@@ -368,7 +377,7 @@ void print_lines(struct session *ses, int flags, char *format, ...)
 	return;
 }
 
-void show_lines(struct session *ses, char *str)
+void show_lines(struct session *ses, char *color, char *str)
 {
 	char *ptf;
 
@@ -384,8 +393,14 @@ void show_lines(struct session *ses, char *str)
 		}
 		*ptf++ = 0;
 
-		tintin_puts3(ses, str, FALSE);
-
+		if (*color)
+		{
+			tintin_printf3(ses, "%s%s", color, str);
+		}
+		else
+		{
+			tintin_puts3(ses, str, FALSE);
+		}
 		str = ptf;
 	}
 	pop_call();
@@ -446,6 +461,26 @@ void tintin_header(struct session *ses, int width, char *format, ...)
 	return;
 }
 
+
+void tintin_printf(struct session *ses, char *format, ...)
+{
+	char *buffer;
+	va_list args;
+
+	push_call("tintin_printf(%p,%p,...)",ses,format);
+
+	buffer = str_alloc_stack(0);
+
+	va_start(args, format);
+	vsprintf(buffer, format, args);
+	va_end(args);
+
+	tintin_puts(ses, buffer);
+
+	pop_call();
+	return;
+}
+
 void tintin_printf2(struct session *ses, char *format, ...)
 {
 	char *buffer;
@@ -471,28 +506,32 @@ void tintin_printf2(struct session *ses, char *format, ...)
 	return;
 }
 
-void tintin_printf(struct session *ses, char *format, ...)
+void tintin_printf3(struct session *ses, char *format, ...)
 {
 	char *buffer;
 	va_list args;
 
-	push_call("tintin_printf(%p,%p,...)",ses,format);
-
-	buffer = str_alloc_stack(0);
+	push_call("tintin_printf2(%p,%p,...)",ses,format);
 
 	va_start(args, format);
-	vsprintf(buffer, format, args);
+	if (vasprintf(&buffer, format, args) == -1)
+	{
+		syserr_printf(ses, "tintin_printf2: vasprintf:");
+
+		pop_call();
+		return;
+	}
 	va_end(args);
 
-	tintin_puts(ses, buffer);
+	tintin_puts3(ses, buffer, FALSE);
+
+	free(buffer);
 
 	pop_call();
 	return;
 }
 
-/*
-	Show string and fire triggers
-*/
+// Show string and fire triggers
 
 void tintin_puts(struct session *ses, char *string)
 {
@@ -501,7 +540,7 @@ void tintin_puts(struct session *ses, char *string)
 		ses = gtd->ses;
 	}
 
-	do_one_line(string, ses);
+	check_one_line(ses, string);
 
 	if (ses->gagline > 0)
 	{
@@ -509,7 +548,7 @@ void tintin_puts(struct session *ses, char *string)
 
 		gtd->level->ignore++;
 
-		show_debug(ses, LIST_GAG, "#DEBUG GAG {%d} {%s}", ses->gagline + 1, string);
+		show_debug(ses, LIST_GAG, COLOR_DEBUG "#DEBUG GAG " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} " COLOR_COMMAND "[" COLOR_STRING "%d" COLOR_COMMAND "]", string, ses->gagline + 1);
 
 		gtd->level->ignore--;
 	}
@@ -519,9 +558,7 @@ void tintin_puts(struct session *ses, char *string)
 	}
 }
 
-/*
-	show string and don't fire triggers
-*/
+// show string and don't fire triggers
 
 void tintin_puts2(struct session *ses, char *string)
 {
@@ -539,11 +576,7 @@ void tintin_puts2(struct session *ses, char *string)
 	return;
 }
 
-
-
-/*
-	show string, no triggers, no color reset
-*/
+// show string, no triggers, no color reset
 
 void tintin_puts3(struct session *ses, char *string, int prompt)
 {
@@ -574,17 +607,22 @@ void tintin_puts3(struct session *ses, char *string, int prompt)
 		return;
 	}
 
-	output = str_alloc_stack(0);
-
-	if (strip_vt102_strlen(ses, ses->more_output) != 0)
+	if (ses->check_output)
 	{
-		str_cpy_printf(&output, "\n%s", string);
+		process_more_output(ses, "", FALSE);
 	}
-	else
+
+	output = str_alloc_stack(0);
+
+	// no new line when prompt is overwritten with input in split mode
+
+	if (gtd->level->scroll == 0 && *ses->scroll->input)
 	{
-		str_cpy(&output, string);
+		str_cpy(&output, "\n");
 	}
 
+	str_cat(&output, string);
+
 	add_line_buffer(ses, output, prompt);
 
 	if (ses == gtd->ses)
@@ -603,8 +641,6 @@ void tintin_puts3(struct session *ses, char *string, int prompt)
 			restore_pos(ses);
 		}
 	}
-
 	pop_call();
 	return;
 }
-

+ 0 - 5
src/sort.c

@@ -1446,11 +1446,6 @@ int cmp_str(const void * a, const void * b)
 	return strcmp(*(const char **) a, *(const char **) b);
 }
 
-int cmp_float(const void * a, const void * b)
-{
-	return *(float *) a - *(float *) b;
-}
-
 int cmp_num(const void * a, const void * b)
 {
 	unsigned char isnum_a, isnum_b;

+ 44 - 53
src/substitute.c

@@ -228,7 +228,15 @@ char int_to_256[6] =
 
 void c4096_rnd(struct session *ses, char *str)
 {
-	sprintf(str, "%c%c%c", int_to_hex[generate_rand(ses) % 16], int_to_hex[generate_rand(ses) % 16], int_to_hex[generate_rand(ses) % 16]);
+	int r, g, b;
+
+	r = str[0] == '?' ? 1 + generate_rand(ses) % 15 : str[0];
+	g = str[1] == '?' ? 1 + generate_rand(ses) % 15 : str[1];
+	b = str[2] == '?' ? 1 + generate_rand(ses) % 15 : str[2];
+
+//	printf("debug: %c%c%c\n", int_to_hex[r % 16], int_to_hex[g % 16], int_to_hex[b % 16]);
+	sprintf(str, "%c%c%c", int_to_hex[r % 16], int_to_hex[g % 16], int_to_hex[b % 16]);
+//	sprintf(str, "%c%c%c", int_to_hex[generate_rand(ses) % 16], int_to_hex[generate_rand(ses) % 16], int_to_hex[generate_rand(ses) % 16]);
 }
 
 int is_c32(char chr)
@@ -496,7 +504,7 @@ char *fuzzy_color_code(struct session *ses, char *in)
 
 					pti += 6;
 				}
-				else if (pti[2] == '?' && pti[3] == '?' && pti[4] == '?' && pti[5] == '>')
+				else if ((pti[2] == '?' || pti[3] == '?' || pti[4] == '?') && pti[5] == '>')
 				{
 					c4096_rnd(ses, &pti[2]);
 
@@ -523,7 +531,7 @@ char *fuzzy_color_code(struct session *ses, char *in)
 
 					pti += 6;
 				}
-				else if (pti[2] == '?' && pti[3] == '?' && pti[4] == '?' && pti[5] == '>')
+				else if ((pti[2] == '?' || pti[3] == '?' || pti[4] == '?') && pti[5] == '>')
 				{
 					c4096_rnd(ses, &pti[2]);
 
@@ -671,7 +679,7 @@ char *dim_color_code(struct session *ses, char *in, int mod)
 			}
 			else if (toupper((int) pti[1]) == 'F')
 			{
-				if (pti[2] == '?' && pti[3] == '?' && pti[4] == '?' && pti[5] == '>')
+				if ((pti[2] == '?' || pti[3] == '?' || pti[4] == '?') && pti[5] == '>')
 				{
 					c4096_rnd(ses, &pti[2]);
 				}
@@ -695,7 +703,7 @@ char *dim_color_code(struct session *ses, char *in, int mod)
 			}
 			else if (toupper((int) pti[1]) == 'B')
 			{
-				if (pti[2] == '?' && pti[3] == '?' && pti[4] == '?' && pti[5] == '>')
+				if ((pti[2] == '?' || pti[3] == '?' || pti[4] == '?') && pti[5] == '>')
 				{
 					c4096_rnd(ses, &pti[2]);
 				}
@@ -817,9 +825,9 @@ char *lit_color_code(struct session *ses, char *pti, int mod)
 
 				return fuzzy[cnt];
 			}
-			else if (pti[2] == '?' && pti[3] == '?' && pti[4] == '?' && pti[5] == '>')
+			else if ((pti[2] == '?' || pti[3] == '?' || pti[4] == '?') && pti[5] == '>')
 			{
-				sprintf(fuzzy[cnt], "<F??%c>%.9s", '?', &pti[6]);
+				sprintf(fuzzy[cnt], "<F%c%c%c>%.9s", pti[2], pti[3], pti[4], &pti[6]);
 
 				c4096_rnd(ses, &fuzzy[cnt][2]);
 
@@ -842,15 +850,15 @@ char *lit_color_code(struct session *ses, char *pti, int mod)
 
 				return fuzzy[cnt];
 			}
-			if (toupper((int) pti[1]) == 'B' && pti[2] == '?' && pti[3] == '?' && pti[4] == '?' && pti[5] == '>')
+			if ((pti[2] == '?' || pti[3] == '?' || pti[4] == '?') && pti[5] == '>')
 			{
-				sprintf(fuzzy[cnt], "<B??%c>%.9s", '?', &pti[6]);
+				sprintf(fuzzy[cnt], "<B%c%c%c>%.9s", pti[2], pti[3], pti[4], &pti[6]);
 
 				c4096_rnd(ses, &fuzzy[cnt][2]);
 
 				return dim_color_code(ses, fuzzy[cnt], mod);
 			}
-			if (toupper((int) pti[1]) == 'B' && is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && is_hex(pti[5]) && is_hex(pti[6]) && is_hex(pti[7]) && pti[8] == '>')
+			if (is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && is_hex(pti[5]) && is_hex(pti[6]) && is_hex(pti[7]) && pti[8] == '>')
 			{
 				sprintf(fuzzy[cnt], "<B%c%c%c>%.9s", lit_char(ses, 'F', pti[2], mod, 12), lit_char(ses, 'F', pti[4], mod, 12), lit_char(ses, mod, pti[6], 'F', 12), &pti[9]);
 
@@ -1185,8 +1193,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 					{
 						substitute(ses, temp, buf, flags_neol);
 					}
-
-					show_debug(ses, LIST_FUNCTION, "#DEBUG FUNCTION {%s}", node->arg1);
+					show_debug(ses, LIST_FUNCTION, COLOR_DEBUG "#DEBUG FUNCTION " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
 
 					RESTRING(gtd->vars[0], buf);
 
@@ -1198,15 +1205,15 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 
 						RESTRING(gtd->vars[i], temp);
 
+						gtd->varc = i + 1;
+
 						if (*pte == 0)
 						{
 							while (++i < 100)
 							{
-								if (*gtd->vars[i])
-								{
-									RESTRING(gtd->vars[i], "");
-								}
+								*gtd->vars[i] = 0;
 							}
+
 							break;
 						}
 
@@ -1214,9 +1221,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 						{
 							pte++;
 						}
-
 					}
-
 					substitute(ses, node->arg2, buf, SUB_ARG);
 
 					if (node->shots && --node->shots == 0)
@@ -1242,8 +1247,6 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 						}
 						else
 						{
-							show_debug(ses, LIST_FUNCTION, "#DEBUG FUNCTION: (%s) (%s) [%d]", node->arg1, node->arg2, flags_neol);
-
 							// sub color codes
 
 							pto += substitute(ses, node->arg2, pto, flags_neol);
@@ -1888,7 +1891,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 						}
 						pti += sprintf(old, "<F%c%c%c>", pti[2], pti[3], pti[4]);
 					}
-					else if (toupper((int) pti[1]) == 'F' && pti[2] == '?' && pti[3] == '?' && pti[4] == '?' && pti[5] == '>')
+					else if (toupper((int) pti[1]) == 'F' && (pti[2] == '?' || pti[3] == '?' || pti[4] == '?') && pti[5] == '>')
 					{
 						c4096_rnd(ses, &pti[2]);
 
@@ -1938,7 +1941,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 						}
 						pti += sprintf(old, "<B%c%c%c>", pti[2], pti[3], pti[4]);
 					}
-					else if (toupper((int) pti[1]) == 'B' && pti[2] == '?' && pti[3] == '?' && pti[4] == '?' && pti[5] == '>')
+					else if (toupper((int) pti[1]) == 'B' && (pti[2] == '?' || pti[3] == '?' || pti[4] == '?') && pti[5] == '>')
 					{
 						c4096_rnd(ses, &pti[2]);
 
@@ -2236,6 +2239,22 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 	return 0;
 }
 
+int is_tintin_code(char *pti)
+{
+	switch (*pti)
+	{
+		case '<':
+			return is_color_code(pti);
+
+		case '\\':
+			return find_escaped_color_code(pti);
+
+		case '\e':
+			return skip_vt102_codes(pti);
+	}
+	return 0;
+}
+
 int is_color_code(char *pti)
 {
 	if (pti[0] == '<')
@@ -2247,16 +2266,7 @@ int is_color_code(char *pti)
 
 		if (pti[4] == '>')
 		{
-
-			if (is_digit(pti[1]) && is_digit(pti[2]) && is_digit(pti[3]))
-			{
-				return 5;
-			}
-			if (pti[1] >= 'a' && pti[1] <= 'f' && pti[2] >= 'a' && pti[2] <= 'f' && pti[3] >= 'a' && pti[3] <= 'f')
-			{
-				return 5;
-			}
-			if (pti[1] >= 'A' && pti[1] <= 'F' && pti[2] >= 'A' && pti[2] <= 'F' && pti[3] >= 'A' && pti[3] <= 'F')
+			if (is_hex(pti[1]) && is_hex(pti[2]) && is_hex(pti[3]))
 			{
 				return 5;
 			}
@@ -2267,9 +2277,7 @@ int is_color_code(char *pti)
 				{
 					return 5;
 				}
-				return 0;
 			}
-
 			return 0;
 		}
 
@@ -2278,13 +2286,13 @@ int is_color_code(char *pti)
 			return 0;
 		}
 
-		if (toupper((int) pti[1]) == 'F')
+		if (toupper((int) pti[1]) == 'F' || toupper((int) pti[1]) == 'B')
 		{
 			if (is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && pti[5] == '>')
 			{
 				return 6;
 			}
-			else if (pti[2] == '?' && pti[3] == '?' && pti[4] == '?' && pti[5] == '>')
+			else if ((pti[2] == '?' || pti[3] == '?' || pti[4] == '?') && pti[5] == '>')
 			{
 				return 6;
 			}
@@ -2294,23 +2302,6 @@ int is_color_code(char *pti)
 			}
 			return 0;
 		}
-
-		if (toupper((int) pti[1]) == 'B')
-		{
-			if (is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && pti[5] == '>')
-			{
-				return 6;
-			}
-			if (toupper((int) pti[1]) == 'B' && pti[2] == '?' && pti[3] == '?' && pti[4] == '?' && pti[5] == '>')
-			{
-				return 6;
-			}
-			if (toupper((int) pti[1]) == 'B' && is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && is_hex(pti[5]) && is_hex(pti[6]) && is_hex(pti[7]) && pti[8] == '>')
-			{
-				return 9;
-			}
-			return 0;
-		}
 	}
 	return 0;
 }

+ 1 - 1
src/system.c

@@ -282,7 +282,7 @@ DO_COMMAND(do_system)
 
 	if (*arg1 == 0)
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #SYSTEM {COMMAND}.");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SYSTEM {COMMAND}");
 		
 		return ses;
 	}

+ 14 - 240
src/tables.c

@@ -76,16 +76,16 @@ struct charset_type charset_table[] =
 	{    "UTF-8",         "utf-8",       "UTF-8",      CHARSET_FLAG_UTF8  },
 	{    "BIG5",          "big5",        "BIG5",       CHARSET_FLAG_BIG5  },
 	{    "BIG-5",         "big5",        "BIG5",       CHARSET_FLAG_BIG5  },
-	{    "EUC-KR",        "euc-kr",      "EUC-KR",     CHARSET_FLAG_CP949 },
-	{    "CP949",         "euc-kr",      "EUC-KR",     CHARSET_FLAG_CP949 },
+	{    "CP949",         "cp949",       "CP949",      CHARSET_FLAG_CP949 },
+	{    "EUC-KR",        "cp949",       "CP949",      CHARSET_FLAG_CP949 },
 	{    "GBK-1",         "gb18030",     "GB18030",    CHARSET_FLAG_GBK1  },
 	{    "GB18030",       "gb18030",     "GB18030",    CHARSET_FLAG_GBK1  },
 	{    "BIG5TOUTF8",    "utf-8",       "BIG5",       CHARSET_FLAG_UTF8|CHARSET_FLAG_BIG5TOUTF8   },
 	{    "CP437TOUTF8",   "utf-8",       "CP437",      CHARSET_FLAG_UTF8|CHARSET_FLAG_FANSITOUTF8  },
 	{    "FANSITOUTF8",   "utf-8",       "CP437",      CHARSET_FLAG_UTF8|CHARSET_FLAG_FANSITOUTF8  },
 	{    "CP1251TOUTF8",  "utf-8",       "CP1251",     CHARSET_FLAG_UTF8|CHARSET_FLAG_CP1251TOUTF8 },
-	{    "EUCKRTOUTF8",   "utf-8",       "EUC-KR",     CHARSET_FLAG_UTF8|CHARSET_FLAG_CP949TOUTF8  },
-	{    "CP949TOUTF8",   "utf-8",       "EUC-KR",     CHARSET_FLAG_UTF8|CHARSET_FLAG_CP949TOUTF8  },
+	{    "CP949TOUTF8",   "utf-8",       "CP949",      CHARSET_FLAG_UTF8|CHARSET_FLAG_CP949TOUTF8  },
+	{    "EUCKRTOUTF8",   "utf-8",       "CP949",      CHARSET_FLAG_UTF8|CHARSET_FLAG_CP949TOUTF8  },
 	{    "GBK1TOUTF8",    "utf-8",       "GB18030",    CHARSET_FLAG_UTF8|CHARSET_FLAG_GBK1TOUTF8   },
 	{    "ISO1TOUTF8",    "utf-8",       "ISO-8859-1", CHARSET_FLAG_UTF8|CHARSET_FLAG_ISO1TOUTF8   },
 	{    "ISO2TOUTF8",    "utf-8",       "ISO-8859-2", CHARSET_FLAG_UTF8|CHARSET_FLAG_ISO2TOUTF8   },
@@ -93,234 +93,6 @@ struct charset_type charset_table[] =
 	{    "",              "",            "",           0 }
 };
 
-struct config_type config_table[] =
-{
-	{
-		"AUTO TAB",
-		"Buffer lines used for tab completion",
-		"",
-		config_autotab
-	},
-
-	{
-		"BUFFER SIZE",
-		"The size of the scrollback buffer",
-		"",
-		config_buffersize
-	},
-
-	{
-		"CHARSET",
-		"The character set encoding used",
-		"",
-		config_charset
-	},
-
-	{
-		"CHILD LOCK",
-		"TinTin++ is child locked.",
-		"TinTin++ is not child locked.",
-		config_childlock
-	},
-
-	{
-		"COLOR MODE",
-		"The color code encoding used",
-		"",
-		config_colormode
-	},
-
-	{
-		"COLOR PATCH",
-		"Color the start of each line",
-		"Leave color handling up to the server",
-		config_colorpatch
-	},
-
-	{
-		"COMMAND COLOR",
-		"The color of echoed commands",
-		"",
-		config_commandcolor
-	},
-
-	{
-		"COMMAND ECHO",
-		"Commands are echoed in split mode",
-		"Commands are not echoed in split mode",
-		config_commandecho
-	},
-
-	{
-		"CONNECT RETRY",
-		"Seconds sessions try to connect on failure",
-		"",
-		config_connectretry
-	},
-
-	{
-		"CONVERT META",
-		"TinTin++ converts meta characters",
-		"TinTin++ doesn't convert meta characters",
-		config_convertmeta
-	},
-
-	{
-		"DEBUG TELNET",
-		"You see telnet negotiations",
-		"You do not see telnet negotatiations",
-		config_debugtelnet
-	},
-
-	{
-		"HISTORY SIZE",
-		"The size of the command history",
-		"",
-		config_historysize
-	},
-
-	{
-		"INHERITANCE",
-		"The startup session is inherited",
-		"The startup session is not inherited",
-		config_inheritance
-	},
-
-	{
-		"LOG MODE",
-		"The data type mode of log files",
-		"",
-		config_logmode
-	},
-
-	{
-		"LOG LEVEL",
-		"TinTin++ only logs low level server data",
-		"TinTin++ only logs high level server data",
-		config_loglevel
-	},
-
-	{
-		"MCCP",
-		"MCCP is enabled.",
-		"MCCP is disabled.",
-		config_mccp
-	},
-
-	{
-		"MOUSE",
-		"Generate mouse tracking events.",
-		"Do not generate mouse events.",
-		config_mousetracking
-	},
-
-	{
-		"PACKET PATCH",
-		"Seconds to try to patch broken packets",
-		"",
-		config_packetpatch
-	},
-
-	{
-		"RANDOM SEED",
-		"Seed value used for random numbers",
-		"",
-		config_randomseed
-	},
-
-	{
-		"REPEAT CHAR",
-		"Character used for repeating commands",
-		"",
-		config_repeatchar
-	},
-
-	{
-		"REPEAT ENTER",
-		"You send the last command on an enter",
-		"You send a carriage return on an enter",
-		config_repeatenter
-	},
-
-	{
-		"SCREEN READER",
-		"You are using a screen reader",
-		"You are not using a screen reader",
-		config_screenreader
-	},
-
-	{
-		"SCROLL LOCK",
-		"You do not see server output while scrolling",
-		"You see server output while scrolling",
-		config_scrolllock
-	},
-
-	{
-		"SPEEDWALK",
-		"Your input is scanned for speedwalks",
-		"Your input is not scanned for speedwalks",
-		config_speedwalk
-	},
-
-	{
-		"TAB WIDTH",
-		"Number of spaces used for a tab",
-		"",
-		config_tabwidth
-	},
-
-	{
-		"TELNET",
-		"TELNET support is enabled.",
-		"TELNET support is disabled.",
-		config_telnet
-	},
-
-	{
-		"TINTIN CHAR",
-		"Character used for TinTin++ commands",
-		"",
-		config_tintinchar
-	},
-
-	{
-		"VERBATIM",
-		"Keyboard input is send as is",
-		"Keyboard input is parsed by TinTin++",
-		config_verbatim
-	},
-
-	{
-		"VERBATIM CHAR",
-		"Character used for verbatim lines",
-		"",
-		config_verbatimchar
-	},
-
-	{
-		"VERBOSE",
-		"Read script files verbosely",
-		"Read script files quietly",
-		config_verbose
-	},
-
-	{
-		"WORDWRAP",
-		"Server output is word wrapped",
-		"Server output is line wrapped",
-		config_wordwrap
-	},
-
-
-	{
-		"",
-		"",
-		0,
-		0
-	}
-};
-
 char character_table[256] =
 {
 	0, // 0
@@ -644,14 +416,14 @@ struct color_type color_table[] =
 	{    "light cyan",    "<168>", 10 },
 	{    "light white",   "<178>", 11 },
 
-	{    "dark black",    "<208>",  5 },
-	{    "dark red",      "<218>",  4 },
-	{    "dark green",    "<228>",  5 },
-	{    "dark yellow",   "<238>",  6 },
-	{    "dark blue",     "<248>",  4 },
-	{    "dark magenta",  "<258>",  7 },
-	{    "dark cyan",     "<268>",  4 },
-	{    "dark white",    "<278>",  5 },
+	{    "dark black",    "<208>", 10 },
+	{    "dark red",      "<218>",  8 },
+	{    "dark green",    "<228>", 10 },
+	{    "dark yellow",   "<238>", 11 },
+	{    "dark blue",     "<248>",  9 },
+	{    "dark magenta",  "<258>", 12 },
+	{    "dark cyan",     "<268>",  9 },
+	{    "dark white",    "<278>", 10 },
 
 	{    "Azure",         "<acf>",  5 },
 	{    "Ebony",         "<bbb>",  5 },
@@ -1004,6 +776,7 @@ struct event_type event_table[] =
 	{    "CLASS CREATED",                          0, EVENT_FLAG_CLASS,    "CLASS",     "class creation"             },
 	{    "CLASS DEACTIVATED",                      0, EVENT_FLAG_CLASS,    "CLASS",     "class deactivations"        },
 	{    "CLASS DESTROYED",                        0, EVENT_FLAG_CLASS,    "CLASS",     "class destruction"          },
+	{    "CONFIG",                                 0, EVENT_FLAG_SYSTEM,   "SYSTEM",    "config change"              },
 	{    "DAEMON ATTACH TIMEOUT",                  0, EVENT_FLAG_SYSTEM,   "SYSTEM",    "daemon attachment timeout"  },
 	{    "DAEMON ATTACHED",                        0, EVENT_FLAG_SYSTEM,   "SYSTEM",    "daemon attachment"          },
 	{    "DAEMON DETACHED",                        0, EVENT_FLAG_SYSTEM,   "SYSTEM",    "daemon detachment"          },
@@ -1016,6 +789,7 @@ struct event_type event_table[] =
 	{    "END OF PATH",                            0, EVENT_FLAG_MAP,      "MAP",       "walking the last room"      },
 	{    "END OF RUN",                             0, EVENT_FLAG_MAP,      "MAP",       "running the last room"      },
 	{    "GAG ",                                   0, EVENT_FLAG_GAG,      "GAG",       "prefix for gag events"      },
+	{    "HISTORY UPDATE",                         0, EVENT_FLAG_INPUT,    "INPUT",     "command history update"     },
 	{    "HOUR",                                   0, EVENT_FLAG_TIME,     "TIME",      "every hour or given hour"   },
 	{    "IAC ",                                   0, EVENT_FLAG_TELNET,   "TELNET",    "prefix for telnet events"   },
 	{    "LONG-CLICKED ",                          0, EVENT_FLAG_MOUSE,    "MOUSE",     "mouse is long-clicked"      },

+ 1 - 0
src/telopt_client.c

@@ -236,6 +236,7 @@ int client_translate_telopts(struct session *ses, unsigned char *src, int cplen)
 	{
 		gtd->mud_output_max = gtd->mud_output_len + cplen + 1000;
 		gtd->mud_output_buf = (char *) realloc(gtd->mud_output_buf, gtd->mud_output_max);
+		gtd->mud_output_strip_buf = (char *) realloc(gtd->mud_output_strip_buf, gtd->mud_output_max);
 	}
 
 	cpdst = (unsigned char *) gtd->mud_output_buf + gtd->mud_output_len;

+ 2 - 0
src/text.c

@@ -61,6 +61,8 @@ void print_line(struct session *ses, char **str, int prompt)
 		convert_meta(*str, out, TRUE);
 
 		str_cpy(str, out);
+
+		str_cat(str, prompt ? "\\" : "\\n");
 	}
 
 	if (HAS_BIT(ses->flags, SES_FLAG_SPLIT) || HAS_BIT(ses->config_flags, CONFIG_FLAG_WORDWRAP))

+ 73 - 90
src/tintin.h

@@ -212,7 +212,7 @@
 
 
 #define CLIENT_NAME              "TinTin++"
-#define CLIENT_VERSION           "2.02.30 "
+#define CLIENT_VERSION           "2.02.31 "
 
 
 #define XT_E                            0x27
@@ -241,16 +241,22 @@
 */
 
 #define COLOR_BRACE         "\e[38;5;164m" // "<eae>" // magenta
-#define COLOR_COMMAND       "\e[38;5;044m" // "<aee>" // cyan
-#define COLOR_CONFIG        "\e[38;5;208m" // "<fca>" // orange
+#define COLOR_COMMAND       "\e[38;5;044m" // "<aee>" // Cyan
+#define COLOR_CONFIG        "\e[38;5;208m" // "<fca>" // Orange
 #define COLOR_RESET         "\e[0m"        // "<088>" // reset
 #define COLOR_SEPARATOR     "\e[38;5;160m" // "<eaa>" // red
+#define COLOR_SESSION       "\e[38;5;48m"  // "<afc>" // Jade
 #define COLOR_STATEMENT     "\e[38;5;040m" // "<aea>" // green
 #define COLOR_STRING        "\e[38;5;188m" // "<eee>" // white
-//#define COLOR_TEXT          "\e[38;5;122m" // "<cfe>" // pale jade
-#define COLOR_TEXT          "\e[0m" // "<cfe>" // pale jade
+#define COLOR_DEBUG         "\e[38;5;037m" // "<add>" // cyan
+
+#define COLOR_TEXT          "\e[0m"        // "<088>" // reset
 #define COLOR_TINTIN        "\e[38;5;184m" // "<eea>" // yellow
 #define COLOR_REPEAT        "\e[38;5;33m"  // "<acf>" // azure
+#define COLOR_HELP_DIM      "\e[0;37m" 
+#define COLOR_HELP_BOLD     "\e[1;37m"
+#define COLOR_HELP_TITLE    "\e[1;32m"
+#define COLOR_HELP_TABLE    "\e[0;36m"
 
 /*
 	Index for lists used by tintin
@@ -567,9 +573,9 @@ enum operators
 #define SUB_LIT                       BV12 // no soft escaping
 
 /*
-#define SUB_ARG                       BV01
-#define SUB_SEC                       BV02
-#define SUB_BRA                       BV03
+#define SUB_ARG                       BV01 reserved
+#define SUB_SEC                       BV02 reserved
+#define SUB_BRA                       BV03 reserved
 */
 #define EVENT_FLAG_CATCH              BV04
 #define EVENT_FLAG_CLASS              BV05
@@ -619,30 +625,33 @@ enum operators
 #define TINTIN_FLAG_PRESERVEMACRO     BV13
 #define TINTIN_FLAG_WINCHUPDATE       BV14
 #define TINTIN_FLAG_NOHUP             BV15 // fixes tcsetattr crashes with nohup
+#define TINTIN_FLAG_HIBERNATE         BV16
 
 #define CONFIG_FLAG_AUTOPATCH         BV01
 #define CONFIG_FLAG_AUTOPROMPT        BV02
 #define CONFIG_FLAG_COLORPATCH        BV03
-#define CONFIG_FLAG_CONVERTMETA       BV04
-#define CONFIG_FLAG_ECHOCOMMAND       BV05
-#define CONFIG_FLAG_MCCP              BV06
-#define CONFIG_FLAG_MOUSEDEBUG        BV07
-#define CONFIG_FLAG_MOUSEINFO         BV08
-#define CONFIG_FLAG_MOUSEPIXELS       BV09
-#define CONFIG_FLAG_MOUSETRACKING     BV10
-#define CONFIG_FLAG_REPEATENTER       BV11
-#define CONFIG_FLAG_SCREENREADER      BV12
-#define CONFIG_FLAG_SCROLLLOCK        BV13
-#define CONFIG_FLAG_SPEEDWALK         BV14
-#define CONFIG_FLAG_TELNET            BV15
-#define CONFIG_FLAG_VERBATIM          BV16
-#define CONFIG_FLAG_VERBOSE           BV17
-#define CONFIG_FLAG_WORDWRAP          BV18
+#define CONFIG_FLAG_COMPACT           BV04
+#define CONFIG_FLAG_CONVERTMETA       BV05
+#define CONFIG_FLAG_ECHOCOMMAND       BV06
+#define CONFIG_FLAG_MCCP              BV07
+#define CONFIG_FLAG_MOUSEDEBUG        BV08
+#define CONFIG_FLAG_MOUSEINFO         BV09
+#define CONFIG_FLAG_MOUSEPIXELS       BV10
+#define CONFIG_FLAG_MOUSETRACKING     BV11
+#define CONFIG_FLAG_REPEATENTER       BV12
+#define CONFIG_FLAG_SCREENREADER      BV13
+#define CONFIG_FLAG_SCROLLLOCK        BV14
+#define CONFIG_FLAG_SPEEDWALK         BV15
+#define CONFIG_FLAG_TELNET            BV16
+#define CONFIG_FLAG_VERBATIM          BV17
+#define CONFIG_FLAG_VERBOSE           BV18
+#define CONFIG_FLAG_WORDWRAP          BV19
+
 
 #define SES_FLAG_BUFFERUPDATE         BV01
 #define SES_FLAG_CLOSED               BV02
 #define SES_FLAG_CONNECTED            BV03
-#define SES_FLAG_GAG                  BV04
+#define SES_FLAG_GAG                  BV04 // unused
 #define SES_FLAG_PATHMAPPING          BV05
 #define SES_FLAG_PRINTBUFFER          BV06
 #define SES_FLAG_PRINTLINE            BV07
@@ -686,7 +695,8 @@ enum operators
 #define LIST_FLAG_CASE                BV14
 #define LIST_FLAG_DEFAULT             LIST_FLAG_MESSAGE
 
-#define NODE_FLAG_ONESHOT             BV01 // unused
+#define NODE_FLAG_COLOR               BV01
+#define NODE_FLAG_MULTI               BV02
 
 #define LOG_FLAG_NONE                    0
 #define LOG_FLAG_LINEFEED             BV01
@@ -694,13 +704,10 @@ enum operators
 #define LOG_FLAG_APPEND               BV03
 #define LOG_FLAG_NEXT                 BV04
 #define LOG_FLAG_LOW                  BV05
-
 #define LOG_FLAG_HTML                 BV06
 #define LOG_FLAG_PLAIN                BV07
 #define LOG_FLAG_RAW                  BV08
-#define LOG_FLAG_OLD_HTML             BV09
-#define LOG_FLAG_OLD_PLAIN            BV10
-#define LOG_FLAG_OLD_RAW              BV11
+#define LOG_FLAG_STAMP                BV09
 
 
 // Saved in map files, so don't swap around
@@ -1041,6 +1048,7 @@ struct listroot
 	int                     size;
 	int                     used;
 	int                     update;
+	int                     multi_update;
 	short                   type;
 	short                   flags;
 };
@@ -1054,6 +1062,7 @@ struct listnode
 	char                  * arg4;
 	char                  * group;
 	unsigned int            shots;
+	int                     flags;
 	union
 	{
 		pcre              * regex;      // act, alias, gag, highlight, substitute
@@ -1124,6 +1133,9 @@ struct tintin_data
 	char                  * mud_output_buf;
 	int                     mud_output_max;
 	int                     mud_output_len;
+	char                  * mud_output_strip_buf;
+	int                     mud_output_strip_len;
+	char                  * mud_output_line;
 	unsigned char         * mccp_buf;
 	int                     mccp_len;
 	char                    macro_buf[BUFFER_SIZE];
@@ -1276,6 +1288,7 @@ struct level_data
 	unsigned int            debug;
 	unsigned int            grep;
 	unsigned int            ignore;
+	unsigned int            indent;
 	unsigned int            info;
 	unsigned int            input;
 	unsigned int            local;
@@ -1460,8 +1473,8 @@ struct room_data
 	struct exit_data        * exit_grid[11];
 	int                       vnum;
 	long long                 exit_dirs;
-	float                     length;
-	float                     weight;
+	double                    length;
+	double                    weight;
 	unsigned short            exit_size;
 	unsigned short            search_stamp;
 	unsigned short            display_stamp;
@@ -1491,8 +1504,8 @@ struct exit_data
 	int                       dir;
 	int                       grid;
 	int                       flags;
-	float                     weight;
-	float                     delay;
+	double                    weight;
+	double                    delay;
 	char                    * name;
 	char                    * cmd;
 	char                    * color;
@@ -1506,18 +1519,18 @@ struct search_data
 	int                     max;
 	unsigned short          stamp;
 	char                  * arg;
-	pcre                  * name;
+	struct listnode       * area;
+	struct listnode       * desc;
+	struct listnode       * name;
+	struct listnode       * note;
+	struct listnode       * terrain;
 	int                     exit_size;
 	long long               exit_dirs;
 	char                  * exit_list;
-	pcre                  * desc;
-	pcre                  * area;
-	pcre                  * note;
-	pcre                  * terrain;
 	long long               flag;
 	long long               galf;
 	char                  * id;
-	float                   distance;
+	double                  distance;
 };
 
 struct msdp_data
@@ -1624,7 +1637,6 @@ struct window_data
 #define DO_BUFFER(buffer)               void buffer (struct session *ses, char *arg, char *arg1, char *arg2)
 #define DO_CHAT(chat)                     void chat (char *arg1, char *arg2)
 #define DO_COMMAND(command) struct session *command (struct session *ses, char *arg, char *arg1, char *arg2, char *arg3, char *arg4)
-#define DO_CONFIG(config)    struct session *config (struct session *ses, char *arg1, char *arg2, int index)
 #define DO_CURSOR(cursor)               void cursor (struct session *ses, char *arg)
 #define DO_DAEMON(daemon)               void daemon (struct session *ses, char *arg, char *arg1, char *arg2)
 #define DO_EDIT(edit)          struct session *edit (struct session *ses, char *arg, char *arg1, char *arg2)
@@ -1643,7 +1655,6 @@ typedef int             CMPFUNC (const void *a, const void *b);
 
 typedef void            BUFFER  (struct session *ses, char *arg, char *arg1, char *arg2);
 typedef void            CHAT    (char *arg1, char *arg2);
-typedef struct session *CONFIG  (struct session *ses, char *arg1, char *arg2, int index);
 typedef struct session *COMMAND (struct session *ses, char *arg, char *arg1, char *arg2, char *arg3, char *arg4);
 typedef void            CURSOR  (struct session *ses, char *arg);
 typedef void            DAEMON  (struct session *ses, char *arg, char *arg1, char *arg2);
@@ -1699,14 +1710,6 @@ struct command_type
 	int                     type;
 };
 
-struct config_type
-{
-	char                  * name;
-	char                  * msg_on;
-	char                  * msg_off;
-	CONFIG                * config;
-};
-
 struct cursor_type
 {
 	char                  * name;
@@ -2146,38 +2149,6 @@ extern unsigned long long tintou(char *str);
 
 extern DO_COMMAND(do_configure);
 
-extern DO_CONFIG(config_autotab);
-extern DO_CONFIG(config_buffersize);
-extern DO_CONFIG(config_charset);
-extern DO_CONFIG(config_colormode);
-extern DO_CONFIG(config_colorpatch);
-extern DO_CONFIG(config_commandcolor);
-extern DO_CONFIG(config_commandecho);
-extern DO_CONFIG(config_connectretry);
-extern DO_CONFIG(config_childlock);
-extern DO_CONFIG(config_convertmeta);
-extern DO_CONFIG(config_debugtelnet);
-extern DO_CONFIG(config_historysize);
-extern DO_CONFIG(config_inheritance);
-extern DO_CONFIG(config_loglevel);
-extern DO_CONFIG(config_logmode);
-extern DO_CONFIG(config_mccp);
-extern DO_CONFIG(config_mousetracking);
-extern DO_CONFIG(config_packetpatch);
-extern DO_CONFIG(config_randomseed);
-extern DO_CONFIG(config_repeatchar);
-extern DO_CONFIG(config_repeatenter);
-extern DO_CONFIG(config_screenreader);
-extern DO_CONFIG(config_scrolllock);
-extern DO_CONFIG(config_speedwalk);
-extern DO_CONFIG(config_tabwidth);
-extern DO_CONFIG(config_telnet);
-extern DO_CONFIG(config_tintinchar);
-extern DO_CONFIG(config_verbatim);
-extern DO_CONFIG(config_verbatimchar);
-extern DO_CONFIG(config_verbose);
-extern DO_CONFIG(config_wordwrap);
-
 #endif
 
 
@@ -2212,6 +2183,7 @@ extern void show_list(struct listroot *root, int level);
 extern void remove_node_list(struct session *ses, int type, struct listnode *node);
 extern void remove_index_list(struct listroot *root, int index);
 extern void dispose_node(struct listnode *node);
+extern void delete_node(int type, struct listnode *node);
 extern void delete_node_list(struct session *ses, int type, struct listnode *node);
 extern  int delete_node_with_wild(struct session *ses, int index, char *string);
 extern void delete_index_list(struct listroot *root, int index);
@@ -2223,6 +2195,7 @@ extern  int bsearch_priority_list(struct listroot *root, char *text, char *prior
 extern  int nsearch_list(struct listroot *root, char *text);
 extern struct listroot *init_list(struct session *ses, int type, int size);
 extern struct listroot *copy_list(struct session *ses, struct listroot *sourcelist, int type);
+extern struct listnode *create_node(char *arg1, char *arg2, char *arg3, char *arg4);
 extern struct listnode *create_node_list(struct listroot *root, char *arg1, char *arg2, char *arg3, char *arg4);
 extern struct listnode *insert_node_list(struct listroot *root, struct listnode *node);
 extern struct listnode *insert_index_list(struct listroot *root, struct listnode *node, int index);
@@ -2536,6 +2509,7 @@ extern int connect_mud(struct session *ses, char *host, char *port);
 extern void write_line_mud(struct session *ses, char *line, int size);
 extern int read_buffer_mud(struct session *ses);
 extern void readmud(struct session *ses);
+extern void process_more_output(struct session *ses, char *append, int prompt);
 extern void process_mud_output(struct session *ses, char *linebuf, int prompt);
 
 #endif
@@ -2572,7 +2546,9 @@ extern char *get_arg_at_brackets(struct session *ses, char *string, char *result
 extern char *get_arg_in_brackets(struct session *ses, char *string, char *result);
 extern char *get_char(struct session *ses, char *string, char *result);
 extern void write_mud(struct session *ses, char *command, int flags);
-extern void do_one_line(char *line, struct session *ses);
+
+extern void check_one_line_multi(struct session *ses, char *line, char *strip);
+extern void check_one_line(struct session *ses, char *line);
 
 #endif
 
@@ -2587,7 +2563,7 @@ int exit_to_dir(struct session *ses, char *name);
 unsigned char pdir(struct listnode *node);
 char *dir_to_exit(struct session *ses, int dir);
 
-extern void check_append_path(struct session *ses, char *forward, char *backward, float delay, int force, int follow);
+extern void check_append_path(struct session *ses, char *forward, char *backward, double delay, int force, int follow);
 
 extern DO_PATH(path_create);
 extern DO_PATH(path_describe);
@@ -2678,6 +2654,7 @@ extern void erase_top_region(struct session *ses);
 extern void erase_left_region(struct session *ses);
 extern void erase_right_region(struct session *ses);
 extern void erase_square(struct session *ses, int top_row, int top_col, int bot_row, int bot_col);
+extern void fill_scroll_region(struct session *ses, char *arg);
 extern void fill_top_region(struct session *ses, char *arg);
 extern void fill_bot_region(struct session *ses, char *arg);
 extern void fill_left_region(struct session *ses, char *arg);
@@ -2730,18 +2707,20 @@ extern void show_message(struct session *ses, int index, char *format, ...);
 extern void show_error(struct session *ses, int index, char *format, ...);
 extern void show_debug(struct session *ses, int index, char *format, ...);
 extern void show_info(struct session *ses, int index, char *format, ...);
-extern void print_lines(struct session *ses, int flags, char *format, ...);
-extern void show_lines(struct session *ses, char *str);
 extern void tintin_header(struct session *ses, int width, char *format, ...);
 extern void socket_printf(struct session *ses, size_t length, char *format, ...);
 extern void telnet_printf(struct session *ses, int length, char *format, ...);
 
-extern void tintin_printf2(struct session *ses, char *format, ...);
+extern void print_lines(struct session *ses, int flags, char *color, char *format, ...);
+extern void show_lines(struct session *ses, char *color, char *str);
+
 extern void tintin_printf(struct session *ses, char *format, ...);
+extern void tintin_printf2(struct session *ses, char *format, ...);
+extern void tintin_printf3(struct session *ses, char *format, ...);
 
-extern void tintin_puts3(struct session *ses, char *string, int prompt);
-extern void tintin_puts2(struct session *ses, char *string);
 extern void tintin_puts(struct session *ses, char *string);
+extern void tintin_puts2(struct session *ses, char *string);
+extern void tintin_puts3(struct session *ses, char *string, int prompt);
 
 #endif
 
@@ -2814,6 +2793,7 @@ extern char *fuzzy_color_code(struct session *ses, char *pti);
 extern char *dim_color_code(struct session *ses, char *pti, int mod);
 extern char *lit_color_code(struct session *ses, char *pti, int mod);
 extern int color_gradient(char *pti, int low, int max);
+extern int is_tintin_code(char *pti);
 extern int is_color_code(char *str);
 extern int is_color_name(char *str);
 extern int substitute_color(char *input, char *output, int colors);
@@ -2837,7 +2817,7 @@ extern struct chat_type chat_table[];
 extern   char character_table[];
 extern struct color_type color_table[];
 extern struct color_type map_color_table[];
-extern struct config_type config_table[];
+//extern struct config_type config_table[];
 extern struct cursor_type cursor_table[];
 extern struct daemon_type daemon_table[];
 extern struct edit_type edit_table[];
@@ -2863,6 +2843,7 @@ extern struct map_legend_group_type map_legend_group_table[];
 #define __TELOPT_H__
 
 extern void test_gmcp(struct session *ses, char *buf);
+extern int get_mtts_val(struct session *ses);
 extern  int client_translate_telopts(struct session *ses, unsigned char *src, int cplen);
 extern  int client_write_compressed(struct session *ses, char *txt, int length);
 extern  int client_send_sb_naws(struct session *ses, int cplen, unsigned char *cpsrc);
@@ -2949,6 +2930,7 @@ extern DO_COMMAND(do_delay);
 extern DO_COMMAND(do_function);
 
 extern void check_all_actions(struct session *ses, char *original, char *line, char *buf);
+extern void check_all_actions_multi(struct session *ses, char *original, char *line, char *buf);
 extern  int check_all_aliases(struct session *ses, char *input);
 extern void check_all_buttons(struct session *ses, short row, short col, char *arg1, char *arg2, char *word, char *line);
 extern void check_all_gags(struct session *ses, char *original, char *line);
@@ -2961,6 +2943,7 @@ extern void check_all_substitutions(struct session *ses, char *original, char *l
 // update.c
 
 extern void mainloop(void);
+extern void init_cpu(void);
 extern void show_cpu(struct session *ses);
 
 
@@ -2985,7 +2968,7 @@ extern char *str_time(struct session *ses, char *format, time_t time);
 extern unsigned long long generate_rand(struct session *ses);
 extern void seed_rand(struct session *ses, unsigned long long seed);
 extern char *capitalize(char *str);
-extern char *ftos(float number);
+extern char *ftos(double number);
 extern char *ntos(long long number);
 extern char *indent_one(int len);
 extern char *indent(int len);

+ 51 - 6
src/tokenize.c

@@ -68,6 +68,8 @@ void debugtoken(struct session *ses, struct scriptroot *root, struct scriptnode
 
 	if (gtd->level->debug || HAS_BIT(root->ses->list[root->list]->flags, LIST_FLAG_DEBUG) || HAS_BIT(root->ses->list[root->list]->flags, LIST_FLAG_LOG))
 	{
+		gtd->level->indent = token->lvl;
+
 		switch (token->type)
 		{
 			case TOKEN_TYPE_REPEAT:
@@ -75,10 +77,13 @@ void debugtoken(struct session *ses, struct scriptroot *root, struct scriptnode
 				break;
 
 			case TOKEN_TYPE_STRING:
-			case TOKEN_TYPE_SESSION:
 				show_debug(ses, root->list, "%s%s", indent(token->lvl + 1), token->str);
 				break;
 
+			case TOKEN_TYPE_SESSION:
+				show_debug(ses, root->list, "%s" COLOR_TINTIN "%c" COLOR_SESSION "%s", indent(token->lvl + 1), gtd->tintin_char, token->str);
+				break;
+
 			case TOKEN_TYPE_ELSE:
 			case TOKEN_TYPE_END:
 				show_debug(ses, root->list, "%s" COLOR_TINTIN "%c" COLOR_STATEMENT "%s\e[0m", indent(token->lvl + 1), gtd->tintin_char, token->str);
@@ -292,6 +297,7 @@ void handlereturntoken(struct session *ses, struct scriptnode *token)
 
 		SET_BIT(gtd->flags, TINTIN_FLAG_LOCAL);
 	}
+//	show_debug(ses, LIST_FUNCTION, COLOR_DEBUG "#DEBUG RETURN " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", arg);
 }
 
 void handleswitchtoken(struct session *ses, struct scriptnode *token)
@@ -394,6 +400,10 @@ char *addregextoken(struct scriptroot *root, int lvl, int type, int cmd, char *s
 	str = get_arg_in_braces(root->ses, str, arg2, GET_ONE);
 	str = get_arg_in_braces(root->ses, str, arg3, GET_ALL);
 
+	if (*arg3 == 0)
+	{
+		show_error(root->ses, LIST_COMMAND, "#SYNTAX: #REGEXP {string} {expression} {true} {false}");
+	}
 	addtoken(root, lvl, type, cmd, arg1);
 
 	regex = (struct script_regex *) calloc(1, sizeof(struct script_regex));
@@ -616,12 +626,17 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
 						tokenize_script(root, lvl--, line);
 
-						addtoken(root, lvl, TOKEN_TYPE_END, -1, "endif");
+						addtoken(root, lvl, TOKEN_TYPE_END, -1, "endelseif");
 						break;
 
 					case TOKEN_TYPE_FOREACH:
 						str = addforeachtoken(root, lvl++, TOKEN_TYPE_FOREACH, cmd, arg);
 
+						if (*str == 0 || *str == COMMAND_SEPARATOR)
+						{
+							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #FOREACH {list} {variable} {commands}");
+						}
+
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
 						tokenize_script(root, lvl--, line);
 
@@ -632,6 +647,11 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 						str = get_arg_in_braces(root->ses, arg, line, GET_ONE);
 						addtoken(root, lvl++, TOKEN_TYPE_IF, cmd, line);
 
+						if (*str == 0 || *str == COMMAND_SEPARATOR)
+						{
+							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #IF {conditional} {true} {false}");
+						}
+
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
 						tokenize_script(root, lvl--, line);
 
@@ -644,13 +664,18 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 							str = get_arg_in_braces(root->ses, str, line, GET_ALL);
 							tokenize_script(root, lvl--, line);
 
-							addtoken(root, lvl, TOKEN_TYPE_END, -1, "endif");
+							addtoken(root, lvl, TOKEN_TYPE_END, -1, "endelse");
 						}
 						break;
 
 					case TOKEN_TYPE_LOOP:
 						str = addlooptoken(root, lvl++, TOKEN_TYPE_LOOP, cmd, arg);
 
+						if (*str == 0 || *str == COMMAND_SEPARATOR)
+						{
+							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #LOOP {start} {finish} {commands}");
+						}
+
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
 						tokenize_script(root, lvl--, line);
 
@@ -660,7 +685,13 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 					case TOKEN_TYPE_PARSE:
 						str = addparsetoken(root, lvl++, TOKEN_TYPE_PARSE, cmd, arg);
 
+						if (*str == 0 || *str == COMMAND_SEPARATOR)
+						{
+							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #PARSE {string} {variable} {commands}");
+						}
+
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
+
 						tokenize_script(root, lvl--, line);
 
 						addtoken(root, lvl, TOKEN_TYPE_END, -1, "endparse");
@@ -669,8 +700,6 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 					case TOKEN_TYPE_REGEX:
 						str = addregextoken(root, lvl, TOKEN_TYPE_REGEX, cmd, arg);
 
-//						addtoken(root, --lvl, TOKEN_TYPE_END, -1, "endregex");
-
 						if (*str && *str != COMMAND_SEPARATOR)
 						{
 							addtoken(root, lvl++, TOKEN_TYPE_ELSE, -1, "else");
@@ -678,7 +707,7 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 							str = get_arg_in_braces(root->ses, str, line, GET_ALL);
 							tokenize_script(root, lvl--, line);
 
-							addtoken(root, lvl, TOKEN_TYPE_END, -1, "endregex");
+							addtoken(root, lvl, TOKEN_TYPE_END, -1, "endelse");
 						}
 						break;
 
@@ -690,6 +719,11 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 					case TOKEN_TYPE_SWITCH:
 						str = addswitchtoken(root, lvl++, TOKEN_TYPE_SWITCH, cmd, arg);
 
+						if (*str == 0 || *str == COMMAND_SEPARATOR)
+						{
+							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #SWITCH {conditional} {arguments}");
+						}
+
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
 						tokenize_script(root, lvl--, line);
 
@@ -700,6 +734,13 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 						str = get_arg_in_braces(root->ses, arg, line, GET_ONE);
 						addtoken(root, lvl++, TOKEN_TYPE_WHILE, cmd, line);
 
+						if (*str == 0 || *str == COMMAND_SEPARATOR)
+						{
+							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #WHILE {conditional} {commands}");
+							deltoken(root, root->prev);
+							break;
+						}
+
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
 						tokenize_script(root, lvl--, line);
 
@@ -1273,6 +1314,10 @@ struct session *script_driver(struct session *ses, int list, char *str)
 
 	ses = (struct session *) parse_script(root, 0, root->next, root->prev);
 
+	if (list != LIST_COMMAND)
+	{
+		show_debug(ses, list, COLOR_DEBUG "#END%s", list_table[list].name);
+	}
 	gtd->level->input -= list != LIST_COMMAND;
 
 	while (root->prev)

+ 73 - 11
src/trigger.c

@@ -76,9 +76,14 @@ void check_all_actions(struct session *ses, char *original, char *line, char *bu
 	{
 		node = root->list[root->update];
 
+		if (HAS_BIT(node->flags, NODE_FLAG_MULTI))
+		{
+			continue;
+		}
+
 		if (check_one_regexp(ses, node, line, original, 0))
 		{
-			show_debug(ses, LIST_ACTION, "#DEBUG ACTION {%s}", node->arg1);
+			show_debug(ses, LIST_ACTION, COLOR_DEBUG "#DEBUG ACTION " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
 
 			substitute(ses, node->arg2, buf, SUB_ARG|SUB_SEC);
 
@@ -94,6 +99,64 @@ void check_all_actions(struct session *ses, char *original, char *line, char *bu
 	}
 }
 
+void check_all_actions_multi(struct session *ses, char *original, char *stripped, char *buf)
+{
+	struct listroot *root = ses->list[LIST_ACTION];
+	struct listnode *node;
+	char *pto, *pts;
+
+	for (root->multi_update = 0 ; root->multi_update < root->used ; root->multi_update++)
+	{
+		node = root->list[root->multi_update];
+
+		if (!HAS_BIT(node->flags, NODE_FLAG_MULTI))
+		{
+			continue;
+		}
+
+		pto = original;
+		pts = stripped;
+
+		while (pto && pts)
+		{
+			if (!check_one_regexp(ses, node, pts, pto, 0))
+			{
+				break;
+			}
+			show_debug(ses, LIST_ACTION, COLOR_DEBUG "#DEBUG MULTI ACTION " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
+
+			substitute(ses, node->arg2, buf, SUB_ARG|SUB_SEC);
+
+			if (node->shots && --node->shots == 0)
+			{
+				delete_node_list(ses, LIST_ACTION, node);
+
+				pto = pts = NULL;
+			}
+			else
+			{
+				if (*gtd->vars[0])
+				{
+					pto += gtd->match[1];
+					pts += gtd->match[1];
+
+					if (pts[-1] != '\n')
+					{
+						pto = strchr(pto, '\n'); if (pto) pto++;
+						pts = strchr(pts, '\n'); if (pts) pts++;
+					}
+				}
+				else
+				{
+					pto = pts = NULL;
+				}
+			}
+			script_driver(ses, LIST_ACTION, buf);
+		}
+	}
+}
+
+
 /******************************************************************************
 *               (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                  *
 *                                                                             *
@@ -191,14 +254,13 @@ int check_all_aliases(struct session *ses, char *input)
 
 					RESTRING(gtd->vars[i], buf);
 
+					gtd->varc = i + 1;
+
 					if (*arg == 0)
 					{
 						while (++i < 100)
 						{
-							if (*gtd->vars[i])
-							{
-								RESTRING(gtd->vars[i], "");
-							}
+							*gtd->vars[i] = 0;
 						}
 						break;
 					}
@@ -217,7 +279,7 @@ int check_all_aliases(struct session *ses, char *input)
 				sprintf(input, "%s", buf);
 			}
 
-			show_debug(ses, LIST_ALIAS, "#DEBUG ALIAS {%s} {%s}", node->arg1, gtd->vars[0]);
+			show_debug(ses, LIST_ALIAS, COLOR_DEBUG "#DEBUG ALIAS " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1, gtd->vars[0]);
 
 			if (node->shots && --node->shots == 0)
 			{
@@ -358,7 +420,7 @@ void check_all_buttons(struct session *ses, short row, short col, char *arg1, ch
 
 		if (!strcmp(arg4, node->arg4))
 		{
-			show_debug(ses, LIST_BUTTON, "#DEBUG BUTTON {%s}", node->arg1);
+			show_debug(ses, LIST_BUTTON, COLOR_DEBUG "#DEBUG BUTTON " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
 
 			RESTRING(gtd->vars[0], ntos(row));
 			RESTRING(gtd->vars[1], ntos(col));
@@ -593,7 +655,7 @@ DO_COMMAND(do_highlight)
 		if (!is_color_name(arg2))
 		{
 			tintin_printf2(ses, "#HIGHLIGHT: INVALID COLOR {%s}. VALID COLORS ARE:\n", arg2);
-			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.");
+			tintin_printf2(ses, "reset, 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, azure, ebony, jade, lime, orange, pink, silver, tan, violet.");
 		}
 		else
 		{
@@ -673,7 +735,7 @@ void check_all_highlights(struct session *ses, char *original, char *line)
 
 				pto = ptm + len;
 
-				show_debug(ses, LIST_HIGHLIGHT, "#DEBUG HIGHLIGHT {%s}", node->arg1);
+				show_debug(ses, LIST_HIGHLIGHT, COLOR_DEBUG "#DEBUG HIGHLIGHT " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
 			}
 			while (check_one_regexp(ses, node, ptl, pto, 0));
 
@@ -807,7 +869,7 @@ int check_all_prompts(struct session *ses, char *original, char *line)
 				strip_vt102_codes(original, line);
 			}
 
-			show_debug(ses, LIST_PROMPT, "#DEBUG PROMPT {%s}", node->arg1);
+			show_debug(ses, LIST_PROMPT, COLOR_DEBUG "#DEBUG PROMPT " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
 
 			if (strcmp(node->arg3, "0"))
 			{
@@ -933,7 +995,7 @@ void check_all_substitutions(struct session *ses, char *original, char *line)
 
 				pto = ptm + len;
 
-				show_debug(ses, LIST_SUBSTITUTE, "#DEBUG SUBSTITUTE {%s} {%s}", node->arg1, match);
+				show_debug(ses, LIST_SUBSTITUTE, COLOR_DEBUG "#DEBUG SUBSTITUTE " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1, match);
 			}
 			while (*pto && check_one_regexp(ses, node, ptl, pto, 0));
 

+ 67 - 90
src/update.c

@@ -62,22 +62,7 @@
 #define PULSE_UPDATE_PACKETS            10
 #define PULSE_UPDATE_TERMINAL           10
 #define PULSE_UPDATE_MEMORY             10
-#define PULSE_UPDATE_TIME               10
-
-#define TIMER_UPDATE_INPUT               0
-#define TIMER_UPDATE_SESSIONS            1
-#define TIMER_UPDATE_DELAYS              2
-#define TIMER_UPDATE_DAEMON              3
-#define TIMER_UPDATE_CHAT                4
-#define TIMER_UPDATE_PORT                5
-#define TIMER_UPDATE_TICKS               6
-#define TIMER_UPDATE_PATHS               7
-#define TIMER_UPDATE_PACKETS             8
-#define TIMER_UPDATE_TERMINAL            9
-#define TIMER_UPDATE_TIME               10
-#define TIMER_UPDATE_MEMORY             11
-#define TIMER_STALL_PROGRAM             12
-#define TIMER_CPU                       13
+#define PULSE_UPDATE_TIME                5
 
 long long cpu_timer[TIMER_CPU][5];
 
@@ -111,17 +96,19 @@ void mainloop(void)
 	pulse.update_sessions =  0 + PULSE_UPDATE_SESSIONS;
 	pulse.update_delays   =  0 + PULSE_UPDATE_DELAYS;
 	pulse.update_daemon   =  0 + PULSE_UPDATE_DAEMON;
-	pulse.update_chat     =  2 + PULSE_UPDATE_CHAT;
+	pulse.update_chat     =  1 + PULSE_UPDATE_CHAT;
 	pulse.update_port     =  2 + PULSE_UPDATE_PORT;
 	pulse.update_ticks    =  3 + PULSE_UPDATE_TICKS;
-	pulse.update_paths    =  3 + PULSE_UPDATE_PATHS;
-	pulse.update_packets  =  4 + PULSE_UPDATE_PACKETS;
-	pulse.update_terminal =  6 + PULSE_UPDATE_TERMINAL;
-	pulse.update_memory   =  7 + PULSE_UPDATE_MEMORY;
-	pulse.update_time     =  8 + PULSE_UPDATE_TIME;
+	pulse.update_paths    =  5 + PULSE_UPDATE_PATHS;
+	pulse.update_packets  =  6 + PULSE_UPDATE_PACKETS;
+	pulse.update_terminal =  7 + PULSE_UPDATE_TERMINAL;
+	pulse.update_memory   =  8 + PULSE_UPDATE_MEMORY;
+	pulse.update_time     =  9 + PULSE_UPDATE_TIME;
 
 	push_call("mainloop()");
 
+	init_cpu();
+
 	while (TRUE)
 	{
 		start_utime = utime();
@@ -288,7 +275,7 @@ void mainloop(void)
 
 		span_time_val = end_utime - start_utime;
 
-		wait_time_val = 1000000 / PULSE_PER_SECOND - span_time_val;
+		wait_time_val = (HAS_BIT(gtd->flags, TINTIN_FLAG_HIBERNATE) ? 10000000 : 1000000) / PULSE_PER_SECOND - span_time_val;
 
 		if (wait_time_val > 0)
 		{
@@ -313,9 +300,8 @@ void update_input(void)
 
 	if (gtd->time_input < gtd->time)
 	{
-		if (sleep < 10)
+		if (sleep++ < 10)
 		{
-			sleep++;
 			return;
 		}
 		sleep = 0;
@@ -368,12 +354,10 @@ void update_sessions(void)
 	struct session *ses;
 	int rv;
 
-	if (gtd->time_session + 10 < gtd->time)
+	if (gtd->time_session < gtd->time)
 	{
-		if (sleep < 10)
+		if (sleep++ < 10)
 		{
-			sleep++;
-
 			return;
 		}
 		sleep = 0;
@@ -460,10 +444,10 @@ void update_sessions(void)
 					}
 				}
 
-				gtd->time_session = gtd->time;
-
 				if (gtd->mud_output_len)
 				{
+					gtd->time_session = gtd->time + 10;
+
 					readmud(ses);
 				}
 			}
@@ -478,7 +462,7 @@ void update_sessions(void)
 		{
 			gtd->update = ses->next;
 
-			if (HAS_BIT(ses->flags, SES_FLAG_PRINTLINE) && ses->check_output == 0)
+			if (HAS_BIT(ses->flags, SES_FLAG_PRINTLINE))
 			{
 				DEL_BIT(ses->flags, SES_FLAG_PRINTLINE);
 
@@ -541,12 +525,10 @@ void update_daemon(void)
 	socklen_t len;
 	int rv;
 
-	if (gtd->time_daemon + 10 < gtd->time)
+	if (gtd->time_daemon < gtd->time)
 	{
-		if (sleep < 10)
+		if (sleep++ < 10)
 		{
-			sleep++;
-
 			return;
 		}
 		sleep = 0;
@@ -566,7 +548,7 @@ void update_daemon(void)
 			{
 				if (FD_ISSET(gtd->detach_port, &read_fd))
 				{
-					gtd->time_daemon = gtd->time;
+					gtd->time_daemon = gtd->time + 10;
 
 					if (gtd->detach_sock)
 					{
@@ -695,7 +677,7 @@ void update_daemon(void)
 //						gtd->detach_sock = close(gtd->detach_sock); // experimental
 						break;
 					}
-					gtd->time_daemon = gtd->time;
+					gtd->time_daemon = gtd->time + 10;
 
 					process_input();
 				}
@@ -727,7 +709,7 @@ void update_daemon(void)
 			{
 				char buffer[BUFFER_SIZE];
 
-				gtd->time_daemon = gtd->time;
+				gtd->time_daemon = gtd->time + 10;
 
 				rv = read(gtd->attach_sock, buffer, BUFFER_SIZE -1);
 
@@ -924,7 +906,7 @@ void tick_update(void)
 
 				if (!HAS_BIT(root->flags, LIST_FLAG_IGNORE))
 				{
-					show_debug(ses, LIST_TICKER, "#DEBUG TICKER {%s}", node->arg2);
+					show_debug(ses, LIST_TICKER, COLOR_DEBUG "#DEBUG TICKER " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg2);
 
 					if (node->shots && --node->shots == 0)
 					{
@@ -969,7 +951,7 @@ void delay_update(void)
 
 			if (node->val64 <= gtd->utime)
 			{
-				show_debug(ses, LIST_DELAY, "#DEBUG DELAY {%s}", node->arg2);
+				show_debug(ses, LIST_DELAY, COLOR_DEBUG "#DEBUG DELAY " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg2);
 
 				delete_index_list(root, root->update);
 
@@ -999,7 +981,11 @@ void path_update(void)
 
 		root = ses->list[LIST_PATH];
 
-		while (root->update < root->used)
+		if (HAS_BIT(root->flags, LIST_FLAG_IGNORE))
+		{
+			continue;
+		}
+		if (root->update < root->used)
 		{
 			node = root->list[root->update];
 
@@ -1009,16 +995,15 @@ void path_update(void)
 
 				node->val64 = 0;
 
-				show_debug(ses, LIST_COMMAND, "#DEBUG PATH {%s}", node->arg1);
+				show_debug(ses, LIST_PATH, COLOR_DEBUG "#DEBUG PATH " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
 
-				script_driver(ses, LIST_COMMAND, node->arg1);
+				script_driver(ses, LIST_PATH, node->arg1);
 
 				if (root->update == root->used)
 				{
 					check_all_events(ses, EVENT_FLAG_MAP, 0, 0, "END OF RUN");
 				}
 			}
-			break;
 		}
 	}
 }
@@ -1033,37 +1018,7 @@ void packet_update(void)
 
 		if (ses->check_output && gtd->utime > ses->check_output)
 		{
-			char result[STRING_SIZE];
-
-			if (HAS_BIT(ses->flags, SES_FLAG_SPLIT))
-			{
-				save_pos(ses);
-
-				goto_pos(ses, ses->split->bot_row, 1);
-			}
-
-			SET_BIT(ses->flags, SES_FLAG_READMUD);
-
-			strcpy(result, ses->more_output);
-
-			if (HAS_BIT(ses->charset, CHARSET_FLAG_ALL_TOUTF8))
-			{
-				all_to_utf8(ses, ses->more_output, result);
-			}
-			else
-			{
-				strcpy(result, ses->more_output);
-			}
-			str_cpy(&ses->more_output, "");
-
-			process_mud_output(ses, result, TRUE);
-
-			DEL_BIT(ses->flags, SES_FLAG_READMUD);
-
-			if (HAS_BIT(ses->flags, SES_FLAG_SPLIT))
-			{
-				restore_pos(ses);
-			}
+			process_more_output(ses, "", TRUE);
 		}
 
 		if (HAS_BIT(ses->telopts, TELOPT_FLAG_UPDATENAWS))
@@ -1135,12 +1090,12 @@ void time_update(void)
 		return;
 	}
 
-	calendar = *localtime(&gtd->time);
-
 	// Initialize on the first call.
 
 	if (old_calendar.tm_year == 0)
 	{
+		calendar = *localtime(&gtd->time);
+
 		old_calendar.tm_sec  = calendar.tm_sec;
 		old_calendar.tm_min  = calendar.tm_min;
 		old_calendar.tm_hour = calendar.tm_hour;
@@ -1177,7 +1132,13 @@ void time_update(void)
 		}
 	}
 
-	strftime(str_sec, 9, "%S", &calendar);
+	calendar.tm_sec = gtd->time % 60;
+	calendar.tm_min = gtd->time % 3600 / 60;
+
+//	strftime(str_sec, 9, "%S", &calendar);
+
+	str_sec[0] = '0' + calendar.tm_sec / 10;
+	str_sec[1] = '0' + calendar.tm_sec % 10;
 	old_calendar.tm_sec = calendar.tm_sec;
 
 	if (calendar.tm_min == old_calendar.tm_min)
@@ -1185,7 +1146,14 @@ void time_update(void)
 		goto time_event_sec;
 	}
 
-	strftime(str_min, 9, "%M", &calendar);
+	// localtime() is slow, so only update it once a minute
+
+	calendar = *localtime(&gtd->time);
+
+//	strftime(str_min, 9, "%M", &calendar);
+
+	str_min[0] = '0' + calendar.tm_min / 10;
+	str_min[1] = '0' + calendar.tm_min % 10;
 	old_calendar.tm_min = calendar.tm_min;
 
 	if (calendar.tm_hour == old_calendar.tm_hour)
@@ -1286,6 +1254,22 @@ void time_update(void)
 }
 
 
+void init_cpu()
+{
+	struct timeval last_time;
+	long long current_time;
+	int timer;
+
+	gettimeofday(&last_time, NULL);
+
+	current_time = (long long) last_time.tv_usec + 1000000LL * (long long) last_time.tv_sec;
+
+	for (timer = 0 ; timer < TIMER_CPU ; timer++)
+	{
+		cpu_timer[timer][2] = current_time;
+	}
+}
+
 void show_cpu(struct session *ses)
 {
 	long long total_cpu = 0;
@@ -1351,16 +1335,9 @@ void open_timer(int timer)
 
 	current_time = (long long) last_time.tv_usec + 1000000LL * (long long) last_time.tv_sec;
 
-	if (cpu_timer[timer][2] == 0)
-	{
-		cpu_timer[timer][2] = current_time;
-	}
-	else
-	{
-		cpu_timer[timer][3] += current_time - cpu_timer[timer][2];
-		cpu_timer[timer][2]  = current_time;
-		cpu_timer[timer][4] ++;
-	}
+	cpu_timer[timer][3] += current_time - cpu_timer[timer][2];
+	cpu_timer[timer][2]  = current_time;
+	cpu_timer[timer][4] ++;
 }
 
 

+ 1 - 1
src/utils.c

@@ -393,7 +393,7 @@ char *capitalize(char *str)
 	return outbuf;
 }
 
-char *ftos(float number)
+char *ftos(double number)
 {
 	static char outbuf[10][NUMBER_SIZE];
 	static int cnt;

+ 52 - 64
src/variable.c

@@ -55,7 +55,7 @@ DO_COMMAND(do_variable)
 
 				view_nest_node(node, &str_result, 0, TRUE, TRUE);
 
-				print_lines(ses, SUB_NONE, COLOR_TINTIN "%c" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\n" COLOR_BRACE "{\n" COLOR_STRING "%s" COLOR_BRACE "}" COLOR_RESET "\n", gtd->tintin_char, list_table[LIST_VARIABLE].name, path, str_result);
+				print_lines(ses, SUB_NONE, "", COLOR_TINTIN "%c" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\n" COLOR_BRACE "{\n" COLOR_STRING "%s" COLOR_BRACE "}" COLOR_RESET "\n", gtd->tintin_char, list_table[LIST_VARIABLE].name, path, str_result);
 			}
 			else
 			{
@@ -234,9 +234,8 @@ DO_COMMAND(do_unlocal)
 
 DO_COMMAND(do_cat)
 {
-	char *str, name[BUFFER_SIZE];
-	struct listroot *root;
 	struct listnode *node;
+	char *str;
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_NST, SUB_VAR|SUB_FUN);
 
@@ -246,39 +245,22 @@ DO_COMMAND(do_cat)
 	}
 	else
 	{
-		str = str_alloc_stack(strlen(arg));
-
-		if ((node = search_nest_node_ses(ses, arg1)) == NULL)
+		if (!valid_variable(ses, arg1))
 		{
-//			arg = sub_arg_in_braces(ses, arg, str, GET_ALL, SUB_VAR|SUB_FUN);
+			show_error(ses, LIST_VARIABLE, "#CAT: INVALID VARIABLE NAME {%s}.", arg1);
 
-			node = set_nest_node(ses->list[LIST_VARIABLE], arg1, "");
+			return ses;
 		}
 
-		root = search_nest_base_ses(ses, arg1);
-
-		get_arg_to_brackets(ses, arg1, name);
-
-		check_all_events(ses, EVENT_FLAG_VARIABLE, 1, 3, "VARIABLE UPDATE %s", name, name, node->arg2, arg1);
+		str = str_alloc_stack(strlen(arg));
 
-		while (*arg)
+		do
 		{
 			arg = sub_arg_in_braces(ses, arg, str, GET_ALL, SUB_VAR|SUB_FUN);
 
-			if (*str)
-			{
-				if (node->root)
-				{
-					add_nest_node(root, arg1, "%s", str);
-				}
-				else
-				{
-					str_cat(&node->arg2, str);
-				}
-			}
+			node = add_nest_node_ses(ses, arg1, "%s", str);
 		}
-
-		check_all_events(ses, EVENT_FLAG_VARIABLE, 1, 3, "VARIABLE UPDATED %s", name, name, node->arg2, arg1);
+		while (*arg);
 
 		show_nest_node(node, &str, 1);
 
@@ -294,7 +276,7 @@ DO_COMMAND(do_replace)
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_NST, 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);
+	arg = get_arg_in_braces(ses, arg, arg3, GET_ALL);
 
 	if (*arg1 == 0 || *arg2 == 0)
 	{
@@ -316,7 +298,7 @@ DO_COMMAND(do_replace)
 	}
 	else
 	{
-		show_debug(ses, LIST_VARIABLE, "#REPLACE {%s} {%s} {%s}", node->arg2, arg2, arg3);
+//		show_debug(ses, LIST_VARIABLE, "#REPLACE {%s} {%s} {%s}", node->arg2, arg2, arg3);
 
 		pti = node->arg2;
 		str = str_alloc_stack(0);
@@ -332,7 +314,8 @@ DO_COMMAND(do_replace)
 			ptm = pti + gtd->match[0]; *ptm = 0;
 			ptm = pti + gtd->match[1];
 
-			substitute(ses, arg3, tmp, SUB_CMD|SUB_FUN);
+			substitute(ses, arg3, tmp, SUB_CMD);
+			substitute(ses, tmp, tmp, SUB_VAR|SUB_FUN);
 
 			str_cat_printf(&str, "%s%s", pti, tmp);
 
@@ -665,23 +648,11 @@ void reversestring(char *str)
 
 	while (*pts)
 	{
-		switch (*pts)
-		{
-			case '\\':
-				skip = pts[1] ? 2 : 0;
-				break;
-
-			case '\e':
-				skip = skip_vt102_codes(pts);
-				break;
+		skip = is_tintin_code(pts);
 
-			case '<':
-				skip = is_color_code(pts);
-				break;
-
-			default:
-				skip = 0;
-				break;
+		if (skip == 0 && *pts == '\\')
+		{
+			skip = pts[1] ? 2 : 0;
 		}
 
 		if (skip)
@@ -1019,7 +990,7 @@ int string_str_raw_len(struct session *ses, char *str, int start, int end)
 			continue;
 		}
 
-		col_len = is_color_code(&str[raw_cnt]);
+		col_len = is_tintin_code(&str[raw_cnt]);
 
 		if (col_len)
 		{
@@ -1101,7 +1072,7 @@ int string_str_str_len(struct session *ses, char *str, int start, int end)
 			continue;
 		}
 
-		col_len = is_color_code(&str[raw_cnt]);
+		col_len = is_tintin_code(&str[raw_cnt]);
 
 		if (col_len)
 		{
@@ -1184,7 +1155,7 @@ int string_raw_str_len(struct session *ses, char *str, int raw_start, int raw_en
 			continue;
 		}
 
-		col_len = is_color_code(&str[raw_cnt]);
+		col_len = is_tintin_code(&str[raw_cnt]);
 
 		if (col_len)
 		{
@@ -1427,29 +1398,47 @@ void format_string(struct session *ses, char *format, char *arg, char *out)
 								{
 									*ptt++ = *ptn++;
 								}
-		
 								*ptt = 0;
 
+								int snip = atoi(arg2);
+								int strl = stringlength(ses, arglist[i]);
+								int rawl = strlen(arglist[i]);
+
+								if (snip >= 0)
+								{
+									if (snip < strl)
+									{
+									 	int head = string_str_raw_len(ses, arglist[i], 0, snip);
+
+									 	arglist[i][head] = 0;
+									 	strl = snip;
+									 	rawl = head;
+									}
+								}
+								else
+								{
+									snip *= -1;
+
+									if (snip < strl)
+									{
+										int head = string_str_raw_len(ses, arglist[i], 0, strl - snip);
+
+										memmove(arglist[i], arglist[i] + head, rawl - head + 1);
+										strl = snip;
+										rawl -= head;
+									}
+								}
+
 								if (atoi(arg1) < 0)
 								{
-									sprintf(argformat, "%%%d.%d",
-										atoi(arg1) - (string_str_raw_len(ses, arglist[i], 0, atoi(arg2)) - string_str_str_len(ses, arglist[i], 0, atoi(arg2))),
-//										atoi(arg1) - ((int) strlen(arglist[i]) - string_str_raw_len(ses, arglist[i], 0, -1)),
-										string_str_raw_len(ses, arglist[i], 0, atoi(arg2)));
+									sprintf(argformat, "%%%d", atoi(arg1) - (rawl - strl));
 								}
 								else
 								{
-/*									printf("debug: %%%d.%d\n",
-										atoi(arg1) + string_str_raw_len(ses, arglist[i], 0, atoi(arg2)) - string_str_str_len(ses, arglist[i], 0, atoi(arg2)),
-										string_str_raw_len(ses, arglist[i], 0, atoi(arg2)));
-*/
-									sprintf(argformat, "%%%d.%d",
-										atoi(arg1) + string_str_raw_len(ses, arglist[i], 0, atoi(arg2)) - string_str_str_len(ses, arglist[i], 0, atoi(arg2)),
-//										atoi(arg1) + ((int) strlen(arglist[i]) - string_raw_str_len(ses, arglist[i], 0, -1)),
-										string_str_raw_len(ses, arglist[i], 0, atoi(arg2)));
+									sprintf(argformat, "%%%d", atoi(arg1) + (rawl - strl));
 								}
 							}
-		
+
 							ptt = argformat;
 							ptn = pts;
 		
@@ -1457,7 +1446,6 @@ void format_string(struct session *ses, char *format, char *arg, char *out)
 							{
 								*ptn++ = *ptt++;
 							}
-		
 							*ptn = 0;
 						}
 				}

+ 21 - 14
src/vt102.c

@@ -241,7 +241,7 @@ int skip_vt102_codes(char *str)
 					return skip;
 
 				case 'R':
-					return str[3] ? 3 : 2;
+					return 3;
 
 				default:
 					for (skip = 2 ; str[skip] ; skip++)
@@ -497,25 +497,31 @@ int find_escaped_color_code(char *str)
 			return 0;
 	}
 
-	switch (str[2])
+	if (str[2] == '[')
 	{
-		case '[':
-			break;
+		for (skip = 3 ; str[skip] != 0 ; skip++)
+		{
+			if (str[skip] == 'm')
+			{
+				return skip + 1;
+			}
 
-		default:
-			return 0;
+			if (is_csichar(str[skip]))
+			{
+				return 0;
+			}
+		}
+		return 0;
 	}
 
-	for (skip = 3 ; str[skip] != 0 ; skip++)
+	if (str[2] == ']')
 	{
-		if (str[skip] == 'm')
+		for (skip = 3 ; str[skip] != 0 ; skip++)
 		{
-			return skip + 1;
-		}
-
-		if (is_csichar(str[skip]))
-		{
-			return 0;
+			if (str[skip] == '\\' && str[skip + 1] == 'a')
+			{
+				return skip + 2;
+			}
 		}
 	}
 	return 0;
@@ -1312,6 +1318,7 @@ int catch_vt102_codes(struct session *ses, unsigned char *str, int cplen)
 							goto end;
 
 						case 'H':
+						case 'f':
 							if (check_all_events(ses, EVENT_FLAG_CATCH, 0, 2, "CATCH VT100 CURSOR H", ntos(val[0]), ntos(val[1])))
 							{
 								pop_call();

部分文件因为文件数量过多而无法显示