Scandum il y a 5 ans
Parent
commit
0f37d4c785
54 fichiers modifiés avec 3351 ajouts et 1644 suppressions
  1. 2 2
      src/Makefile.in
  2. 31 30
      src/advertise.c
  3. 42 4
      src/buffer.c
  4. 33 11
      src/chat.c
  5. 13 8
      src/class.c
  6. 78 0
      src/confdefs.h
  7. 12 10
      src/config.c
  8. 35 22
      src/cursor.c
  9. 6 5
      src/daemon.c
  10. 122 54
      src/data.c
  11. 37 50
      src/debug.c
  12. 4 5
      src/dict.c
  13. 76 44
      src/draw.c
  14. 24 12
      src/event.c
  15. 44 36
      src/files.c
  16. 156 114
      src/help.c
  17. 82 25
      src/history.c
  18. 40 26
      src/input.c
  19. 83 6
      src/line.c
  20. 3 4
      src/list.c
  21. 106 74
      src/log.c
  22. 66 62
      src/main.c
  23. 239 127
      src/mapper.c
  24. 75 8
      src/math.c
  25. 126 63
      src/memory.c
  26. 26 17
      src/misc.c
  27. 5 5
      src/msdp.c
  28. 20 15
      src/nest.c
  29. 30 19
      src/net.c
  30. 70 13
      src/parse.c
  31. 108 21
      src/path.c
  32. 31 16
      src/port.c
  33. 42 9
      src/regex.c
  34. 0 1
      src/scan.c
  35. 67 61
      src/screen.c
  36. 10 9
      src/session.c
  37. 22 34
      src/show.c
  38. 24 16
      src/split.c
  39. 1 1
      src/ssl.c
  40. 204 0
      src/string.c
  41. 411 105
      src/substitute.c
  42. 5 7
      src/system.c
  43. 161 102
      src/tables.c
  44. 100 74
      src/telopt_client.c
  45. 2 2
      src/telopt_server.c
  46. 3 0
      src/terminal.c
  47. 4 7
      src/text.c
  48. 144 56
      src/tintin.h
  49. 21 4
      src/tokenize.c
  50. 36 49
      src/trigger.c
  51. 24 12
      src/update.c
  52. 145 7
      src/utf8.c
  53. 41 174
      src/variable.c
  54. 59 6
      src/vt102.c

+ 2 - 2
src/Makefile.in

@@ -20,7 +20,7 @@
 
 DEFINES = -D_GNU_SOURCE @DEFS@
 
-CC = @CC@ -g
+CC = @CC@ -g -Wall
 MAKE = @MAKE@
 
 prefix = @prefix@
@@ -64,7 +64,7 @@ system.o mapper.o tables.o buffer.o event.o tokenize.o chat.o utf8.o \
 advertise.o list.o forkpty.o utils.o line.o data.o variable.o msdp.o \
 port.o scan.o telopt_client.o screen.o cursor.o nest.o show.o mccp.o \
 telopt_server.o draw.o log.o path.o session.o class.o config.o ssl.o \
-regex.o substitute.o daemon.o dict.o sort.o base.o
+regex.o substitute.o daemon.o dict.o sort.o base.o string.o
 
 default: all
 

+ 31 - 30
src/advertise.c

@@ -193,6 +193,37 @@ struct advertisement_type advertisement_table[] =
                 "<178>To connect to New Worlds Ateraan enter: #session nwa ateraan.com 4002\n"
                 "\n"
 	},
+
+	{
+		1400000000,
+ 		1800000000,
+		100,
+
+		"\n"
+		"<138>              Realm of Utopian Dreams (RUD)  -  http://rudmud.com\n"
+		"\n"
+		"<078>RUD is a unique ROM-based high-fantasy MUD with character choices for many play\n"
+		"<078>styles from hack-n-slash to roleplay. Each of the races and classes offer\n"
+		"<078>unique spells and skills, unlocked through a tiered remort system with\n"
+		"<078>customization through religion memberships and epic advancements. RUD started\n"
+		"<078>in 1996, always seeking new adventurers to become the next hero, build a home,\n"
+		"<078>start a shop, and eventually become Nobles of the Realm! New players to RUD can\n"
+		"<078>be just as successful as 20+ year veterans. We run quests, plots, and annual\n"
+		"<078>festivals in an ever evolving world. Come build Lantarea with us!\n"
+		"\n"
+		"<178>To connect to Realm of Utopian Dreams enter: #session rud rudmud.com 1701\n"
+		"\n",
+
+		"\n"
+		"<138>Realms of Utopian Dreams (RUD)\n"
+		"<168>http://rudmud.com\n"
+		"\n"
+		"<078>RUD is a unique ROM-based high-fantasy MUD with character choices for many play styles from hack-n-slash to roleplay. Each of the races and classes offer unique spells and skills, unlocked through a tiered remort system with customization through religion memberships and epic advancements. RUD started in 1996, always seeking new adventurers to become the next hero, build a home, start a shop, and eventually become Nobles of the Realm! New players to RUD can be just as successful as 20+ year veterans. We run quests, plots, and annual festivals in an ever evolving world. Come build Lantarea with us!\n"
+		"\n"
+		"<178>To connect to Realm of Utopian Dreams enter: #session rud rudmud.com 1701\n"
+		"\n"
+	},
+
 /*
 	{
 		1400000000,  // 2014
@@ -254,37 +285,7 @@ struct advertisement_type advertisement_table[] =
 	},
 */
 
-/*
-	{
-		1400000000,
- 		1800000000,
-		100,
 
-		"\n"
-		"<138>              Realm of Utopian Dreams (RUD)  -  http://rudmud.com\n"
-		"\n"
-		"<078>RUD is a custom hack'n'slash MUD, with character choices for a range of combat\n"
-		"<078>and roleplay. Every race and class has many unique spells and skills, and many\n"
-		"<078>advanced remort options. We're a fantasy MUD started in 1996 seeking new\n"
-		"<078>adventurers to become the next hero, buy a home, start a shop, and eventually\n"
-		"<078>become Nobles of the Realm! Experience a classic game showcasing the content and\n"
-		"<078>features we've built up. The Immortals are ready to help build quests and new\n"
-		"<078>features for the curious. Come visit Lantarea and explore your dream world. We\n"
-		"<078>have an OLC, auction house, and noble system! Explore class-only areas and more!\n"
-		"\n"
-		"<178>To connect to Realm of Utopian Dreams enter: #session rud rudmud.com 1701\n"
-		"\n",
-
-		"\n"
-		"<138>Realms of Utopian Dreams (RUD)\n"
-		"<168>http://rudmud.com\n"
-		"\n"
-		"<078>RUD is a custom hack'n'slash MUD, with character choices for a range of combat and roleplay. Every race and class has many unique spells and skills, and many advanced remort options. We're a fantasy MUD started in 1996 seeking new adventurers to become the next hero, buy a home, start a shop, and eventually become Nobles of the Realm! Experience a classic game showcasing the content and features we've built up. The Immortals are ready to help build quests and new features for the curious. Come visit Lantarea and explore your dream world. We have an OLC, auction house, and noble system! Explore class-only areas and more!\n"
-		"\n"
-		"<178>To connect to Realm of Utopian Dreams enter: #session rud rudmud.com 1701\n"
-		"\n"
-	},
-*/
 /*
 	{
 		1400000000,

+ 42 - 4
src/buffer.c

@@ -132,6 +132,44 @@ void add_line_buffer(struct session *ses, char *line, int prompt)
 		return;
 	}
 
+	SET_BIT(ses->flags, SES_FLAG_BUFFERUPDATE);
+
+/*
+	strip_vt102_codes(line, temp);
+
+	check_all_events(ses, SUB_ARG|SUB_SEC|SUB_SIL, 0, 2, "ADD LINE BUFFER", line, temp);
+
+	if (check_all_events(ses, SUB_ARG|SUB_SEC|SUB_SIL, 0, 2, "CATCH ADD LINE BUFFER", line, temp))
+	{
+		pop_call();
+		return;
+	}
+
+	if (prompt)
+	{
+		check_all_events(ses, SUB_ARG|SUB_SEC|SUB_SIL, 0, 2, "ADD PROMPT BUFFER", line, temp);
+		
+		if (check_all_events(ses, SUB_ARG|SUB_SEC|SUB_SIL, 0, 2, "CATCH ADD PROMPT BUFFER", line, temp))
+		{
+			pop_call();
+			return;
+		}
+	}
+*/
+	if (ses->line_capturefile)
+	{
+		sprintf(temp, "{%d}{%s}", ses->line_captureindex++, line);
+
+		if (ses->line_captureindex == 1)
+		{
+			set_nest_node_ses(ses, ses->line_capturefile, "%s", temp);
+		}
+		else
+		{
+			add_nest_node_ses(ses, ses->line_capturefile, "%s", temp);
+		}
+	}
+
 	if (HAS_BIT(ses->flags, SES_FLAG_CONVERTMETA))
 	{
 		convert_meta(line, temp, TRUE);
@@ -595,7 +633,6 @@ int show_buffer(struct session *ses)
 
 DO_COMMAND(do_buffer)
 {
-	char arg1[BUFFER_SIZE];
 	int cnt;
 
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
@@ -605,6 +642,8 @@ DO_COMMAND(do_buffer)
 
 	if (*arg1 == 0)
 	{
+		info:
+
 		tintin_header(ses, " BUFFER OPTIONS ");
 
 		for (cnt = 0 ; *buffer_table[cnt].name != 0 ; cnt++)
@@ -628,7 +667,7 @@ DO_COMMAND(do_buffer)
 		return ses;
 	}
 
-	do_buffer(ses, "");
+	goto info;
 
 	return ses;
 }
@@ -884,7 +923,7 @@ DO_BUFFER(buffer_find)
 
 DO_BUFFER(buffer_get)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE];
+	char arg1[BUFFER_SIZE], arg2[STRING_SIZE], arg3[BUFFER_SIZE];
 	int cnt, min, max;
 
 	check_buffer(ses);
@@ -1024,7 +1063,6 @@ DO_BUFFER(buffer_info)
 
 DO_COMMAND(do_grep)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 	int scroll_cnt, grep_cnt, grep_min, grep_max, grep_add, page;
 
 	check_buffer(ses);

+ 33 - 11
src/chat.c

@@ -70,13 +70,15 @@ extern struct chat_data *find_group(char *arg);
 
 DO_COMMAND(do_chat)
 {
-	char cmd[BUFFER_SIZE], arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
+	char cmd[BUFFER_SIZE];
 	int cnt;
 
 	arg = get_arg_in_braces(ses, arg, cmd, GET_ONE);
 
 	if (*cmd == 0)
 	{
+		info:
+
 		tintin_header(ses, " CHAT OPTIONS ");
 
 		for (cnt = 0 ; *chat_table[cnt].name != 0 ; cnt++)
@@ -110,7 +112,7 @@ DO_COMMAND(do_chat)
 		return ses;
 	}
 
-	do_chat(ses, "");
+	goto info;
 
 	return ses;
 }
@@ -204,7 +206,7 @@ DO_CHAT(chat_uninitialize)
 
 	gtd->chat = NULL;
 
-	tintin_printf(NULL, "#OK: Uninitialized chat on port %d.", port);
+	show_message(gtd->ses, LIST_COMMAND, "#OK: UNINITIALIZED CHAT ON PORT %d.", port);
 }
 
 
@@ -242,10 +244,13 @@ int chat_new(int s)
 
 	new_buddy->fd       = fd;
 
+	new_buddy->color    = strdup("");
 	new_buddy->download = strdup("");
 	new_buddy->group    = strdup("");
 	new_buddy->ip       = strdup(inet_ntoa(sock.sin_addr));
 	new_buddy->name     = strdup("Unknown");
+	new_buddy->prefix   = strdup("");
+	new_buddy->reply    = strdup("");
 	new_buddy->version  = strdup("");
 
 	new_buddy->timeout  = gtd->time + CALL_TIMEOUT;
@@ -364,11 +369,14 @@ void *threaded_chat_call(void *arg)
 	new_buddy->fd       = sock;
 	new_buddy->port     = atoi(port);
 
+	new_buddy->color    = strdup("");
+	new_buddy->download = strdup("");
 	new_buddy->group    = strdup("");
 	new_buddy->ip       = strdup(host);
 	new_buddy->name     = strdup("");
+	new_buddy->reply    = strdup("");
+	new_buddy->prefix   = strdup("");
 	new_buddy->version  = strdup("");
-	new_buddy->download = strdup("");
 
 	strip_vt102_codes(gtd->chat->name, name);
 
@@ -654,10 +662,13 @@ void close_chat(struct chat_data *buddy, int unlink)
 
 	close(buddy->fd);
 
+	free(buddy->color);
 	free(buddy->download);
 	free(buddy->group);
 	free(buddy->ip);
 	free(buddy->name);
+	free(buddy->prefix);
+	free(buddy->reply);
 	free(buddy->version);
 
 	free(buddy);
@@ -721,25 +732,32 @@ void chat_socket_printf(struct chat_data *buddy, char *format, ...)
 void chat_printf(char *format, ...)
 {
 	struct chat_data *buddy;
-	char buf[STRING_SIZE], tmp[STRING_SIZE];
+	char *buf, *tmp;
 	va_list args;
 
+	push_call("chat_printf(%p,...)",format);
+
+	buf = str_alloc_stack();
+	tmp = str_alloc_stack();
+
 	va_start(args, format);
 	vsnprintf(buf, BUFFER_SIZE / 3, format, args);
 	va_end(args);
 
+	str_fix(buf);
+
 	if (strncmp(buf, gtd->chat->prefix, strlen(gtd->chat->prefix)))
 	{
-		sprintf(tmp, "%s%s", gtd->chat->prefix, buf);
+		str_cpy_printf(&tmp, "%s%s", gtd->chat->prefix, buf);
 	}
 	else
 	{
-		sprintf(tmp, "%s", buf);
+		str_cpy_printf(&tmp, "%s", buf);
 	}
 
 	strip_vt102_codes_non_graph(tmp, buf);
 
-	sprintf(tmp, "%c%s%c", CHAT_SNOOP_DATA, buf, CHAT_END_OF_COMMAND);
+	str_cpy_printf(&tmp, "%c%s%c", CHAT_SNOOP_DATA, buf, CHAT_END_OF_COMMAND);
 
 	for (buddy = gtd->chat->next ; buddy ; buddy = buddy->next)
 	{
@@ -748,7 +766,7 @@ void chat_printf(char *format, ...)
 			chat_socket_printf(buddy, "%s", tmp);
 		}
 	}
-	sprintf(tmp, "%s%s%s", gtd->chat->color, buf, "\e[0m");
+	str_cpy_printf(&tmp, "%s%s%s", gtd->chat->color, buf, "\e[0m");
 
 	check_all_events(gtd->ses, SUB_ARG|SUB_SEC, 0, 2, "CHAT MESSAGE", tmp, buf);
 
@@ -756,6 +774,8 @@ void chat_printf(char *format, ...)
 	{
 		tintin_puts(NULL, tmp);
 	}
+	pop_call();
+	return;
 }
 
 
@@ -2223,15 +2243,17 @@ DO_CHAT(chat_cancelfile)
 
 DO_CHAT(chat_color)
 {
-	if (*arg1 == 0 || get_color_names(gtd->ses, arg1, arg2) == FALSE)
+	if (*arg1 == 0 || !is_color_name(arg1))
 	{
 		chat_printf("Valid colors are:\n\nreset, bold, dim, light, dark, underscore, blink, reverse, black, red, green, yellow, blue, magenta, cyan, white, b black, b red, b green, b yellow, b blue, b magenta, b cyan, b white");
 
 		return;
 	}
+	get_color_names(gtd->ses, arg1, arg2);
+
 	RESTRING(gtd->chat->color, arg2);
 
-	chat_printf("Color has been set to %s", arg1);
+	chat_printf("Color has been set to %s.", arg1);
 }
 
 DO_CHAT(chat_dnd)

+ 13 - 8
src/class.c

@@ -29,7 +29,6 @@
 
 DO_COMMAND(do_class)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE];
 	int i;
 	struct listroot *root;
 	struct listnode *node;
@@ -67,7 +66,7 @@ DO_COMMAND(do_class)
 
 		if (*class_table[i].name == 0)
 		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: CLASS {name} {OPEN|CLOSE|READ|SIZE|WRITE|KILL}.", arg1, capitalize(arg2));
+			show_error(ses, LIST_COMMAND, "#SYNTAX: CLASS {name} {OPEN|CLEAR|CLOSE|READ|SIZE|WRITE|KILL}.", arg1, capitalize(arg2));
 		}
 		else
 		{
@@ -75,6 +74,8 @@ DO_COMMAND(do_class)
 
 			if (node == NULL)
 			{
+				show_info(ses, LIST_CLASS, "#INFO: CLASS {%s} CREATED", arg1);
+
 				check_all_events(ses, SUB_ARG, 0, 1, "CLASS CREATED", arg1);
 
 				node = update_node_list(ses->list[LIST_CLASS], arg1, "", arg3, "");
@@ -250,7 +251,10 @@ DO_CLASS(class_load)
 
 		return ses;
 	}
-	file = fmemopen(node->data, (size_t) node->val32[1], "r");
+
+	file = fmemopen(node->data, (size_t) atoi(node->arg4), "r");
+
+	show_message(ses, LIST_CLASS, "#CLASS {%s} HAS BEEN LOADED FROM MEMORY.", arg1);
 
 	read_file(ses, file, arg1);
 
@@ -292,7 +296,7 @@ DO_CLASS(class_read)
 {
 	class_open(ses, node, arg1, arg2);
 
-	do_read(ses, arg2);
+	execute(ses, "#READ {%s}", arg2);
 
 	class_close(ses, node, arg1, arg2);
 
@@ -302,11 +306,10 @@ DO_CLASS(class_read)
 DO_CLASS(class_save)
 {
 	FILE *file;
+	size_t len;
 	int list, index;
 
-	str_cpy(&node->arg4, "");
-
-	file = open_memstream(&node->data, (size_t *) &node->val32[1]);
+	file = open_memstream(&node->data, (size_t *) &len);
 
 	fprintf(file, "%cCLASS {%s} OPEN\n\n", gtd->tintin_char, arg1);
 
@@ -330,7 +333,9 @@ DO_CLASS(class_save)
 
 	fclose(file);
 
-	show_message(ses, LIST_CLASS, "#CLASS {%s} HAS BEEN SAVED TO MEMORY (%d BYTES) (%s).", arg1, node->val32[1], node->data);
+	str_cpy_printf(&node->arg4, "%d", len);
+
+	show_message(ses, LIST_CLASS, "#CLASS {%s} HAS BEEN SAVED TO MEMORY.", arg1);
 
 	return ses;
 }	

+ 78 - 0
src/confdefs.h

@@ -0,0 +1,78 @@
+/* confdefs.h */
+#define PACKAGE_NAME ""
+#define PACKAGE_TARNAME ""
+#define PACKAGE_VERSION ""
+#define PACKAGE_STRING ""
+#define PACKAGE_BUGREPORT ""
+#define PACKAGE_URL ""
+#define STDC_HEADERS 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_STDLIB_H 1
+#define HAVE_STRING_H 1
+#define HAVE_MEMORY_H 1
+#define HAVE_STRINGS_H 1
+#define HAVE_INTTYPES_H 1
+#define HAVE_STDINT_H 1
+#define HAVE_UNISTD_H 1
+#define HAVE_ARPA_INET_H 1
+#define HAVE_CTYPE_H 1
+#define HAVE_FCNTL_H 1
+#define HAVE_NETDB_H 1
+#define HAVE_NETINET_IN_H 1
+#define HAVE_PTHREAD_H 1
+#define HAVE_STDLIB_H 1
+#define HAVE_STRING_H 1
+#define HAVE_STRINGS_H 1
+#define HAVE_SYS_IOCTL_H 1
+#define HAVE_SYS_PARAM_H 1
+#define HAVE_SYS_SOCKET_H 1
+#define HAVE_SYS_TERMIO_H 1
+#define HAVE_SYS_TIME_H 1
+#define HAVE_TIME_H 1
+#define HAVE_UNISTD_H 1
+#define HAVE_PTY_H 1
+#define HAVE_ZLIB_H 1
+#define HAVE_PCRE_H 1
+#define HAVE_GNUTLS_GNUTLS_H 1
+#define HAVE_GNUTLS_H /**/
+#define HAVE__BOOL 1
+#define HAVE_STDBOOL_H 1
+#define TIME_WITH_SYS_TIME 1
+#define HAVE_STDLIB_H 1
+#define HAVE_REALLOC 1
+#define HAVE_SYS_SELECT_H 1
+#define HAVE_SYS_SOCKET_H 1
+#define SELECT_TYPE_ARG1 int
+#define SELECT_TYPE_ARG234 (fd_set *)
+#define SELECT_TYPE_ARG5 (struct timeval *)
+#define RETSIGTYPE void
+#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1
+#define HAVE_STRFTIME 1
+#define HAVE_UTIME_H 1
+#define HAVE_UTIME_NULL 1
+#define HAVE_VPRINTF 1
+#define HAVE_GETHOSTBYNAME 1
+#define HAVE_GETHOSTNAME 1
+#define HAVE_GETTIMEOFDAY 1
+#define HAVE_INET_NTOA 1
+#define HAVE_MEMSET 1
+#define HAVE_SELECT 1
+#define HAVE_SOCKET 1
+#define HAVE_STRCASECMP 1
+#define HAVE_STRCHR 1
+#define HAVE_STRDUP 1
+#define HAVE_STRERROR 1
+#define HAVE_STRFTIME 1
+#define HAVE_STRNCASECMP 1
+#define HAVE_STRSTR 1
+#define HAVE_UTIME 1
+#define HAVE_GETADDRINFO 1
+#define HAVE_FORKPTY 1
+#define HAVE_POPEN 1
+#define HAVE_LIBZ 1
+#define HAVE_LIBPTHREAD 1
+#define HAVE_LIBUTIL 1
+#define HAVE_LIBPCRE 1
+#define HAVE_LIBGNUTLS 1
+#define HAVE_LIBM 1

+ 12 - 10
src/config.c

@@ -29,12 +29,11 @@
 
 DO_COMMAND(do_configure)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 	struct listnode *node;
 	int index;
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
-	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
+	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
 
 	if (*arg1 == 0)
 	{
@@ -200,6 +199,11 @@ DO_CONFIG(config_charset)
 			DEL_BIT(ses->charset, CHARSET_FLAG_ALL);
 			SET_BIT(ses->charset, CHARSET_FLAG_UTF8|CHARSET_FLAG_BIG5TOUTF8);
 		}
+		else if (is_abbrev(arg2, "CP1251TOUTF8"))
+		{
+			DEL_BIT(ses->charset, CHARSET_FLAG_ALL);
+			SET_BIT(ses->charset, CHARSET_FLAG_UTF8|CHARSET_FLAG_CP1251TOUTF8);
+		}
 		else if (is_abbrev(arg2, "FANSI"))
 		{
 			DEL_BIT(ses->charset, CHARSET_FLAG_ALL);
@@ -227,7 +231,7 @@ DO_CONFIG(config_charset)
 		}
 		else
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <AUTO|ASCII|BIG-5|BIG5TOUTF8|FANSI|GBK-1|GBK1TOUTF8|KOI8TOUTF8|UTF-8>", config_table[index].name);
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <AUTO|ASCII|BIG-5|BIG5TOUTF8|CP1251TOUTF8|FANSI|GBK-1|GBK1TOUTF8|KOI8TOUTF8|UTF-8>", config_table[index].name);
 
 			return NULL;
 		}
@@ -247,6 +251,9 @@ DO_CONFIG(config_charset)
 		case CHARSET_FLAG_UTF8|CHARSET_FLAG_BIG5TOUTF8:
 			strcpy(arg2, "BIG5TOUTF8");
 			break;
+	        case CHARSET_FLAG_UTF8|CHARSET_FLAG_CP1251TOUTF8:
+	        	strcpy(arg2, "CP1251TOUTF8");
+	        	break;
 		case CHARSET_FLAG_UTF8|CHARSET_FLAG_FANSITOUTF8:
 			strcpy(arg2, "FANSI");
 			break;
@@ -354,12 +361,8 @@ DO_CONFIG(config_commandcolor)
 {
 	if (*arg2)
 	{
-		if (!get_color_names(ses, arg2, arg1))
-		{
-			show_error(ses, LIST_CONFIG, "#CONFIG COMMAND COLOR: INVALID COLOR CODE {%s}", arg2);
+		get_color_names(ses, arg2, arg1);
 
-			return NULL;
-		}
 		RESTRING(ses->cmd_color, arg1);
 	}
 	convert_meta(ses->cmd_color, arg2, SUB_EOL);
@@ -597,7 +600,6 @@ DO_CONFIG(config_mccp)
 	return ses;
 }
 
-
 DO_CONFIG(config_mousetracking)
 {
 	if (*arg2)
@@ -677,7 +679,7 @@ DO_CONFIG(config_packetpatch)
 {
 	if (*arg2)
 	{
-		if (is_abbrev(arg2, "AUTO"))
+		if (is_abbrev(arg2, "AUTO PROMPT") || is_abbrev(arg2, "AUTO TELNET") || is_abbrev(arg2, "AUTO OFF"))
 		{
 			ses->packet_patch = 0;
 

+ 35 - 22
src/cursor.c

@@ -27,13 +27,12 @@
 
 DO_COMMAND(do_cursor)
 {
-	char all[BUFFER_SIZE], arg1[BUFFER_SIZE], temp[BUFFER_SIZE];
+	char all[BUFFER_SIZE], temp[BUFFER_SIZE];
 	int cnt;
 
 	get_arg_in_braces(ses, arg, all, GET_ALL);
 
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
-//	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
 
 	if (*arg1 == 0)
 	{
@@ -45,7 +44,7 @@ DO_COMMAND(do_cursor)
 			{
 				convert_meta(cursor_table[cnt].code, temp, FALSE);
 
-				tintin_printf2(ses, "  [%-18s] [%-6s] %s", cursor_table[cnt].name, temp, cursor_table[cnt].desc);
+				tintin_printf2(ses, "  [%-18s] [%-7s] %s", cursor_table[cnt].name, temp, cursor_table[cnt].desc);
 			}
 		}
 		tintin_header(ses, "");
@@ -82,6 +81,8 @@ DO_COMMAND(do_cursor)
 	return ses;
 }
 
+// strlen with offset.
+
 int inputline_str_str_len(int start, int end)
 {
 	int raw_cnt, str_cnt, ret_cnt, width;
@@ -325,27 +326,27 @@ DO_CURSOR(cursor_brace_close)
 
 DO_CURSOR(cursor_buffer_down)
 {
-	do_buffer(ses, "DOWN");
+	buffer_down(ses, "");
 }
 
 DO_CURSOR(cursor_buffer_end)
 {
-	do_buffer(ses, "END");
+	buffer_end(ses, "");
 }
 
 DO_CURSOR(cursor_buffer_home)
 {
-	do_buffer(ses, "HOME");
+	buffer_home(ses, "");
 }
 
 DO_CURSOR(cursor_buffer_lock)
 {
-	do_buffer(ses, "LOCK");
+	buffer_lock(ses, "");
 }
 
 DO_CURSOR(cursor_buffer_up)
 {
-	do_buffer(ses, "UP");
+	buffer_up(ses, "");
 }
 
 
@@ -687,7 +688,7 @@ DO_CURSOR(cursor_exit)
 {
 	if (ses == gts)
 	{
-		do_end(ses, "");
+		execute(ses, "#END");
 	}
 	else
 	{
@@ -1095,6 +1096,15 @@ DO_CURSOR(cursor_paste_buffer)
 	modified_input();
 }
 
+DO_CURSOR(cursor_preserve_macro)
+{
+	SET_BIT(gtd->flags, TINTIN_FLAG_PRESERVEMACRO);
+}
+
+DO_CURSOR(cursor_reset_macro)
+{
+	gtd->macro_buf[0] = 0;
+}
 
 DO_CURSOR(cursor_redraw_input)
 {
@@ -1276,7 +1286,10 @@ DO_CURSOR(cursor_set)
 
 DO_CURSOR(cursor_suspend)
 {
-	do_suspend(ses, "");
+	if (!HAS_BIT(gtd->flags, TINTIN_FLAG_CHILDLOCK))
+	{
+		do_suspend(ses, arg, NULL, NULL, NULL, NULL);
+	}
 }
 
 DO_CURSOR(cursor_info)
@@ -1321,9 +1334,9 @@ int cursor_tab_add(int input_now, int stop_after_first)
 				{
 					continue;
 				}
-				insert_node_list(gtd->ses->list[LIST_COMMAND], tab, "", "", "");
+				create_node_list(gtd->ses->list[LIST_COMMAND], tab, "", "", "");
 
-				if (HAS_BIT(node->flags, NODE_FLAG_ONESHOT))
+				if (node->shots && --node->shots == 0)
 				{
 					delete_node_list(gtd->ses, LIST_TAB, node);
 				}
@@ -1383,7 +1396,7 @@ int cursor_auto_tab_add(int input_now, int stop_after_first)
 				{
 					continue;
 				}
-				insert_node_list(gtd->ses->list[LIST_COMMAND], tab, "", "", "");
+				create_node_list(gtd->ses->list[LIST_COMMAND], tab, "", "", "");
 
 				if (stop_after_first)
 				{
@@ -1529,7 +1542,7 @@ DO_CURSOR(cursor_tab)
 	{
 		if (!HAS_BIT(flags, TAB_FLAG_LIST|TAB_FLAG_SCROLLBACK))
 		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB <LIST|SCROLLBACK> FORWARD");
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB {LIST|SCROLLBACK} FORWARD");
 		}
 		else
 		{
@@ -1552,7 +1565,7 @@ DO_CURSOR(cursor_tab)
 	{
 		if (!HAS_BIT(flags, TAB_FLAG_LIST|TAB_FLAG_SCROLLBACK))
 		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB <LIST|SCROLLBACK> BACKWARD");
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB {LIST|SCROLLBACK} BACKWARD");
 		}
 		else
 		{
@@ -1573,7 +1586,7 @@ DO_CURSOR(cursor_tab)
 	}
 	else
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB <LIST|SCROLLBACK> <BACKWARD|FORWARD>");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB {LIST|SCROLLBACK} <BACKWARD|FORWARD>");
 	}
 }
 
@@ -1596,7 +1609,7 @@ DO_CURSOR(cursor_tab_forward)
 
 	if (!root->list[0])
 	{
-		insert_node_list(root, &gtd->ses->input->buf[gtd->ses->input->tab], "", "", "");
+		create_node_list(root, &gtd->ses->input->buf[gtd->ses->input->tab], "", "", "");
 	}
 	tab_found = cursor_tab_add(gtd->ses->input->tab, TRUE);
 
@@ -1626,7 +1639,7 @@ DO_CURSOR(cursor_tab_backward)
 
 	if (!root->list[0])
 	{
-		insert_node_list(root, &gtd->ses->input->buf[gtd->ses->input->tab], "", "", "");
+		create_node_list(root, &gtd->ses->input->buf[gtd->ses->input->tab], "", "", "");
 
 		cursor_tab_add(gtd->ses->input->tab, FALSE);
 	}
@@ -1652,7 +1665,7 @@ DO_CURSOR(cursor_auto_tab_forward)
 
 	if (!root->list[0])
 	{
-		insert_node_list(root, &gtd->ses->input->buf[gtd->ses->input->tab], "", "", "");
+		create_node_list(root, &gtd->ses->input->buf[gtd->ses->input->tab], "", "", "");
 	}
 
 	tab_found = cursor_auto_tab_add(gtd->ses->input->tab, TRUE);
@@ -1683,7 +1696,7 @@ DO_CURSOR(cursor_auto_tab_backward)
 
 	if (!root->list[0])
 	{
-		insert_node_list(root, &gtd->ses->input->buf[gtd->ses->input->tab], "", "", "");
+		create_node_list(root, &gtd->ses->input->buf[gtd->ses->input->tab], "", "", "");
 
 		cursor_auto_tab_add(gtd->ses->input->tab, FALSE);
 	}
@@ -1711,7 +1724,7 @@ DO_CURSOR(cursor_mixed_tab_forward)
 
 	if (!root->list[0])
 	{
-		insert_node_list(root, &gtd->ses->input->buf[gtd->ses->input->tab], "", "", "");
+		create_node_list(root, &gtd->ses->input->buf[gtd->ses->input->tab], "", "", "");
 	}
 	tab_found = cursor_tab_add(gtd->ses->input->tab, TRUE) || cursor_auto_tab_add(gtd->ses->input->tab, TRUE);
 
@@ -1741,7 +1754,7 @@ DO_CURSOR(cursor_mixed_tab_backward)
 
 	if (!root->list[0])
 	{
-		insert_node_list(root, &gtd->ses->input->buf[gtd->ses->input->tab], "", "", "");
+		create_node_list(root, &gtd->ses->input->buf[gtd->ses->input->tab], "", "", "");
 
 		cursor_tab_add(gtd->ses->input->tab, FALSE);
 		cursor_auto_tab_add(gtd->ses->input->tab, FALSE);

+ 6 - 5
src/daemon.c

@@ -41,13 +41,14 @@ int get_daemon_dir(struct session *ses, char *filename);
 
 DO_COMMAND(do_daemon)
 {
-	char arg1[BUFFER_SIZE];
 	int cnt;
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 
 	if (*arg1 == 0)
 	{
+		info:
+
 		tintin_header(ses, " DAEMON OPTIONS ");
 
 		for (cnt = 0 ; *daemon_table[cnt].fun != NULL ; cnt++)
@@ -73,7 +74,7 @@ DO_COMMAND(do_daemon)
 
 		if (*daemon_table[cnt].name == 0)
 		{
-			do_daemon(ses, "");
+			goto info;
 		}
 		else
 		{
@@ -185,7 +186,7 @@ DO_DAEMON(daemon_attach)
 		return;
 	}
 
-	sprintf(sock_file, "%s/%s.s", filename, arg2);
+	sprintf(sock_file, "%.*s/%.*s.s", PATH_SIZE, filename, PATH_SIZE, arg2);
 
 	if (access(sock_file, F_OK) == -1)
 	{
@@ -537,7 +538,7 @@ DO_DAEMON(daemon_kill)
 				{
 					pid = atoi(arg + 1);
 
-					sprintf(sock_file, "%s/%s.s", filename, arg2);
+					sprintf(sock_file, "%.*s/%.*s.s", PATH_SIZE, filename, PATH_SIZE, arg2);
 
 					show_message(ses, LIST_COMMAND, "#DAEMON {%s} KILLED.", sock_file, pid);
 
@@ -607,7 +608,7 @@ DO_DAEMON(daemon_list)
 				{
 					pid = atoi(arg + 1);
 
-					sprintf(sock_file, "%s/%s.s", filename, arg2);
+					sprintf(sock_file, "%.*s/%.*s.s", PATH_SIZE, filename, PATH_SIZE, arg2);
 
 					tintin_printf2(ses, "%-40s [%6d]", sock_file, pid);
 				}

+ 122 - 54
src/data.c

@@ -84,7 +84,7 @@ struct listroot *copy_list(struct session *ses, struct listroot *sourcelist, int
 			node->arg2  = str_dup_clone(sourcelist->list[i]->arg2);
 			node->arg3  = str_dup_clone(sourcelist->list[i]->arg3);
 			node->arg4  = str_dup_clone(sourcelist->list[i]->arg4);
-			node->flags = sourcelist->list[i]->flags;
+			node->shots = sourcelist->list[i]->shots;
 			node->group = strdup(sourcelist->list[i]->group);
 
 			switch (type)
@@ -122,10 +122,8 @@ struct listroot *copy_list(struct session *ses, struct listroot *sourcelist, int
 	return ses->list[type];
 }
 
-
-struct listnode *insert_node_list(struct listroot *root, char *arg1, char *arg2, char *arg3, char *arg4)
+struct listnode *create_node_list(struct listroot *root, char *arg1, char *arg2, char *arg3, char *arg4)
 {
-	int index;
 	struct listnode *node;
 
 	node = (struct listnode *) calloc(1, sizeof(struct listnode));
@@ -147,9 +145,9 @@ struct listnode *insert_node_list(struct listroot *root, char *arg1, char *arg2,
 	node->arg3 = str_dup(arg3);
 	node->arg4 = str_dup(arg4);
 
-	if (gtd->level->oneshot)
+	if (gtd->level->shots)
 	{
-		SET_BIT(node->flags, NODE_FLAG_ONESHOT);
+		node->shots = gtd->level->mshot;
 	}
 
 	node->group = HAS_BIT(root->flags, LIST_FLAG_CLASS) ? strdup(root->ses->group) : strdup("");
@@ -169,7 +167,14 @@ struct listnode *insert_node_list(struct listroot *root, char *arg1, char *arg2,
 			break;
 	}
 
-	index = locate_index_list(root, arg1, arg3);
+	return insert_node_list(root, node);
+}
+
+struct listnode *insert_node_list(struct listroot *root, struct listnode *node)
+{
+	int index;
+
+	index = locate_index_list(root, node->arg1, node->arg3);
 
 	return insert_index_list(root, node, index);
 }
@@ -186,19 +191,19 @@ struct listnode *update_node_list(struct listroot *root, char *arg1, char *arg2,
 	{
 		if (list_table[root->type].mode == SORT_DELAY && is_number(arg1))
 		{
-			return insert_node_list(root, arg1, arg2, arg3, arg4);
+			return create_node_list(root, arg1, arg2, arg3, arg4);
 		}
 
 		node = root->list[index];
 
-		if (gtd->level->oneshot)
+		if (gtd->level->shots)
 		{
-			SET_BIT(node->flags, NODE_FLAG_ONESHOT);
+			node->shots = gtd->level->mshot;
 		}
 
 		if (strcmp(node->arg2, arg2) != 0)
 		{
-			node->arg2 = str_cpy(&node->arg2, arg2);
+			str_cpy(&node->arg2, arg2);
 		}
 
 		switch (root->type)
@@ -214,38 +219,44 @@ struct listnode *update_node_list(struct listroot *root, char *arg1, char *arg2,
 			strcpy(arg3, "5");
 		}
 
+		if (strcmp(node->arg3, arg3) != 0)
+		{
+			str_cpy(&node->arg3, arg3);
+		}
+
+		if (strcmp(node->arg4, arg4) != 0)
+		{
+			str_cpy(&node->arg4, arg4);
+		}
+
 		switch (list_table[root->type].mode)
 		{
 			case SORT_PRIORITY:
 				if (atof(node->arg3) != atof(arg3))
 				{
-					delete_index_list(root, index);
-					return insert_node_list(root, arg1, arg2, arg3, arg4);
+					remove_index_list(root, index);
+					insert_node_list(root, node);
 				}
 				break;
 
 			case SORT_APPEND:
-				delete_index_list(root, index);
-				return insert_node_list(root, arg1, arg2, arg3, arg4);
+				remove_index_list(root, index);
+				insert_node_list(root, node);
 				break;
 
 			case SORT_ALPHA:
 			case SORT_DELAY:
-				if (strcmp(node->arg3, arg3) != 0)
-				{
-					str_cpy(&node->arg3, arg3);
-				}
 				break;
 
 			default:
-				tintin_printf2(root->ses, "#BUG: update_node_list: unknown mode: %d", list_table[root->type].mode);
+				tintin_printf2(root->ses, "#BUG: update_node_list: unknown sort: %d", list_table[root->type].mode);
 				break;
 		}
 		return node;
 	}
 	else
 	{
-		return insert_node_list(root, arg1, arg2, arg3, arg4);
+		return create_node_list(root, arg1, arg2, arg3, arg4);
 	}
 }
 
@@ -267,6 +278,27 @@ struct listnode *insert_index_list(struct listroot *root, struct listnode *node,
 	return node;
 }
 
+void remove_node_list(struct session *ses, int type, struct listnode *node)
+{
+	int index = search_index_list(ses->list[type], node->arg1, node->arg3);
+
+	remove_index_list(ses->list[type], index);
+}
+
+void remove_index_list(struct listroot *root, int index)
+{
+	if (index <= root->update)
+	{
+		root->update--;
+	}
+
+	memmove(&root->list[index], &root->list[index + 1], (root->used - index) * sizeof(struct listnode *));
+
+	root->used--;
+
+	return;
+}
+
 void delete_node_list(struct session *ses, int type, struct listnode *node)
 {
 	int index = search_index_list(ses->list[type], node->arg1, node->arg3);
@@ -283,11 +315,6 @@ void delete_index_list(struct listroot *root, int index)
 		free_list(node->root);
 	}
 
-	if (index <= root->update)
-	{
-		root->update--;
-	}
-
 	str_free(node->arg1);
 	str_free(node->arg2);
 	str_free(node->arg3);
@@ -306,6 +333,7 @@ void delete_index_list(struct listroot *root, int index)
 	switch (root->type)
 	{
 		case LIST_TERRAIN:
+			delete_room_data(node->room);
 			free(node->room);
 			break;
 
@@ -316,14 +344,9 @@ void delete_index_list(struct listroot *root, int index)
 			}
 			break;
 	}
-
 	free(node);
 
-	memmove(&root->list[index], &root->list[index + 1], (root->used - index) * sizeof(struct listnode *));
-
-	root->used--;
-
-	return;
+	remove_index_list(root, index);
 }
 
 struct listnode *search_node_list(struct listroot *root, char *text)
@@ -602,14 +625,26 @@ void show_list(struct listroot *root, int level)
 int show_node_with_wild(struct session *ses, char *text, struct listroot *root)
 {
 	struct listnode *node;
-	int i, found = FALSE;
+	int index, found = FALSE;
 
 	push_call("show_node_with_wild(%p,%p,%p)",ses,text,root);
 
-	node = search_node_list(root, text);
+	switch (list_table[root->type].mode)
+	{
+		case SORT_ALPHA:
+		case SORT_DELAY:
+			index = bsearch_alpha_list(root, text, 0);
+			break;
+
+		default:
+			index = nsearch_list(root, text);
+			break;
+	}
 
-	if (node)
+	if (index != -1)
 	{
+		node = root->list[index];
+
 		if (list_table[root->type].script_arg == 2)
 		{
 			if (list_table[root->type].args == 2)
@@ -674,11 +709,11 @@ int show_node_with_wild(struct session *ses, char *text, struct listroot *root)
 		return TRUE;
 	}
 
-	for (i = 0 ; i < root->used ; i++)
+	for (index = 0 ; index < root->used ; index++)
 	{
-		if (match(ses, root->list[i]->arg1, text, SUB_VAR|SUB_FUN))
+		if (match(ses, root->list[index]->arg1, text, SUB_VAR|SUB_FUN))
 		{
-			show_node(root, root->list[i], 0);
+			show_node(root, root->list[index], 0);
 
 			found = TRUE;
 		}
@@ -692,28 +727,40 @@ int delete_node_with_wild(struct session *ses, int type, char *text)
 	struct listroot *root = ses->list[type];
 	struct listnode *node;
 	char arg1[BUFFER_SIZE];
-	int i, found = FALSE;
+	int index, found = FALSE;
 
 	sub_arg_in_braces(ses, text, arg1, GET_ALL, SUB_VAR|SUB_FUN);
 
-	node = search_node_list(root, arg1);
+	switch (list_table[type].mode)
+	{
+		case SORT_ALPHA:
+		case SORT_DELAY:
+			index = bsearch_alpha_list(root, arg1, 0);
+			break;
+
+		default:
+			index = nsearch_list(root, arg1);
+			break;
+	}
 
-	if (node)
+	if (index != -1)
 	{
+		node = root->list[index];
+
 		show_message(ses, type, "#OK. {%s} IS NO LONGER %s %s.", node->arg1, (*list_table[type].name == 'A' || *list_table[type].name == 'E') ? "AN" : "A", list_table[type].name);
 
-		delete_node_list(ses, type, node);
+		delete_index_list(root, index);
 
 		return TRUE;
 	}
 
-	for (i = root->used - 1 ; i >= 0 ; i--)
+	for (index = root->used - 1 ; index >= 0 ; index--)
 	{
-		if (match(ses, root->list[i]->arg1, arg1, SUB_VAR|SUB_FUN))
+		if (match(ses, root->list[index]->arg1, arg1, SUB_VAR|SUB_FUN))
 		{
-			show_message(ses, type, "#OK. {%s} IS NO LONGER %s %s.", root->list[i]->arg1, (*list_table[type].name == 'A' || *list_table[type].name == 'E') ? "AN" : "A", list_table[type].name);
+			show_message(ses, type, "#OK. {%s} IS NO LONGER %s %s.", root->list[index]->arg1, is_vowel(list_table[type].name) ? "AN" : "A", list_table[type].name);
 
-			delete_index_list(root, i);
+			delete_index_list(root, index);
 
 			found = TRUE;
 		}
@@ -733,14 +780,13 @@ DO_COMMAND(do_killall)
 {
 	tintin_printf2(ses, "\e[1;31m#NOTICE: PLEASE CHANGE #KILLALL TO #KILL ALL.");
 
-	do_kill(ses, arg);
+	do_kill(ses, arg, arg1, arg2, arg3, arg4);
 
 	return ses;
 }
 
 DO_COMMAND(do_kill)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 	int index;
 
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
@@ -790,7 +836,6 @@ DO_COMMAND(do_kill)
 
 DO_COMMAND(do_message)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 	int index, found = FALSE;
 
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
@@ -858,7 +903,6 @@ DO_COMMAND(do_message)
 
 DO_COMMAND(do_ignore)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 	int index, found = FALSE;
 
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
@@ -926,7 +970,6 @@ DO_COMMAND(do_ignore)
 
 DO_COMMAND(do_debug)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 	int index, found = FALSE;
 
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
@@ -998,7 +1041,7 @@ DO_COMMAND(do_debug)
 
 DO_COMMAND(do_info)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], name[BUFFER_SIZE];
+	char name[BUFFER_SIZE];
 	int cnt, index, found = FALSE;
 	struct listroot *root;
 
@@ -1059,7 +1102,7 @@ DO_COMMAND(do_info)
 				{
 					for (cnt = 0 ; cnt < root->used ; cnt++)
 					{
-						tintin_printf2(ses, "#INFO %s %4d {arg1}{%s} {arg2}{%s} {arg3}{%s} {arg4}{%s} {class}{%s} {flags}{%d}", list_table[index].name, cnt, root->list[cnt]->arg1, root->list[cnt]->arg2, root->list[cnt]->arg3, root->list[cnt]->arg4, root->list[cnt]->group, root->list[cnt]->flags);
+						tintin_printf2(ses, "#INFO %s %4d {arg1}{%s} {arg2}{%s} {arg3}{%s} {arg4}{%s} {class}{%s} {shots}{%u}", list_table[index].name, cnt, root->list[cnt]->arg1, root->list[cnt]->arg2, root->list[cnt]->arg3, root->list[cnt]->arg4, root->list[cnt]->group, root->list[cnt]->shots);
 					}
 				}
 				else if (is_abbrev(arg2, "SAVE"))
@@ -1071,7 +1114,7 @@ DO_COMMAND(do_info)
 					{
 						sprintf(name, "info[%s][%d]", list_table[index].name, cnt);
 
-						set_nest_node_ses(ses, name, "{arg1}{%s}{arg2}{%s}{arg3}{%s}{arg4}{%s}{class}{%s}{flags}{%d}", root->list[cnt]->arg1, root->list[cnt]->arg2, root->list[cnt]->arg3, root->list[cnt]->arg4, root->list[cnt]->group, root->list[cnt]->flags);
+						set_nest_node_ses(ses, name, "{arg1}{%s}{arg2}{%s}{arg3}{%s}{arg4}{%s}{class}{%s}{shots}{%u}", root->list[cnt]->arg1, root->list[cnt]->arg2, root->list[cnt]->arg3, root->list[cnt]->arg4, root->list[cnt]->group, root->list[cnt]->shots);
 					}
 					show_message(ses, LIST_COMMAND, "#INFO: DATA WRITTEN TO {info[%s]}", list_table[index].name);
 				}
@@ -1103,6 +1146,29 @@ DO_COMMAND(do_info)
 					tintin_printf2(ses, "#INFO MCCP3: TOTAL IN: %9ull TOTAL OUT: %9ull RATIO: %3d", ses->mccp3->total_in, ses->mccp3->total_out, 100 * ses->mccp3->total_out / ses->mccp3->total_in);
 				}
 			}
+			else if (is_abbrev(arg1, "MEMORY"))
+			{
+				long long quan, used, max;
+				struct str_data *str;
+
+				max  = 0;
+				quan = 0;
+				used = 0;
+
+				for (str = gtd->memory->alloc->next ; str ; str = str->next)
+				{
+					max++;
+					quan += str->max;
+					used += str->len;
+				}
+
+				tintin_printf2(ses, "#INFO MEMORY: ALLOC  MAX: %d", max);
+				tintin_printf2(ses, "#INFO MEMORY: ALLOC QUAN: %d", quan);
+				tintin_printf2(ses, "#INFO MEMORY: ALLOC USED: %d", used);
+
+				tintin_printf2(ses, "#INFO MEMORY: STACK  MAX: %d", gtd->memory->stack_max);
+				tintin_printf2(ses, "#INFO MEMORY: STACK  LEN: %d", gtd->memory->stack_len);
+			}
 			else if (is_abbrev(arg1, "SESSION"))
 			{
 				if (is_abbrev(arg2, "SAVE"))
@@ -1110,6 +1176,7 @@ DO_COMMAND(do_info)
 					sprintf(name, "info[SESSION]");
 
 					set_nest_node_ses(ses, name, "{SESSION_NAME}{%s}", ses->name);
+					add_nest_node_ses(ses, name, "{SESSION_ACTIVE}{%d}", gtd->ses == ses);
 					add_nest_node_ses(ses, name, "{SESSION_CLASS}{%s}", ses->group);
 					add_nest_node_ses(ses, name, "{SESSION_CREATED}{%d}", ses->created);
 					add_nest_node_ses(ses, name, "{SESSION_HOST} {%s}", ses->session_host);
@@ -1121,6 +1188,7 @@ DO_COMMAND(do_info)
 				else
 				{
 					tintin_printf2(ses, "{SESSION_NAME}{%s}", ses->name);
+					tintin_printf2(ses, "{SESSION_ACTIVE}{%d}", gtd->ses == ses);
 					tintin_printf2(ses, "{SESSION_CLASS}{%s}", ses->group);
 					tintin_printf2(ses, "{SESSION_CREATED}{%d}", ses->created);
 					tintin_printf2(ses, "{SESSION_HOST} {%s}", ses->session_host);

+ 37 - 50
src/debug.c

@@ -26,27 +26,33 @@
 
 #include "tintin.h"
 
-#define MAX_STACK_SIZE     100
-#define MAX_DEBUG_SIZE     400
-
-char debug_stack[MAX_STACK_SIZE][MAX_DEBUG_SIZE];
-
-int debug_index = 0;
-
-int push_call(char *f, ...)
+int push_call(char *format, ...)
 {
+	int len;
 	va_list ap;
 
-	if (debug_index < MAX_STACK_SIZE)
+	len = gtd->memory->debug_len;
+
+	if (len == gtd->memory->debug_max)
 	{
-		va_start(ap, f);
+		gtd->memory->debug_max++;
 
-		vsnprintf(debug_stack[debug_index], MAX_DEBUG_SIZE - 1, f, ap);
+		gtd->memory->debug = (struct stack_data **) realloc(gtd->memory->debug, sizeof(struct str_data *) * gtd->memory->debug_max);
 
-		va_end(ap);
+		gtd->memory->debug[len] = calloc(1, sizeof(struct stack_data));
+
+		gtd->memory->debug[len]->name = str_alloc(NAME_SIZE);
 	}
 
-	if (++debug_index == 10000)
+	va_start(ap, format);
+
+	vsnprintf(gtd->memory->debug[len]->name, NAME_SIZE - 1, format, ap);
+
+	va_end(ap);
+
+	gtd->memory->debug[len]->index = gtd->memory->stack_len;
+
+	if (gtd->memory->debug_len++ == 1000)
 	{
 		dump_stack();
 
@@ -58,59 +64,40 @@ int push_call(char *f, ...)
 
 void pop_call(void)
 {
-	if (debug_index > 0)
+	if (gtd->memory->debug_len > 0)
 	{
-		debug_index--;
+		gtd->memory->debug_len--;
+		gtd->memory->stack_len = gtd->memory->debug[gtd->memory->debug_len]->index;
 	}
 	else
 	{
 		tintin_printf2(gtd->ses, "pop_call: index is zero.");
-		dump_full_stack();
-	}
-}
 
-void dump_stack(void)
-{
-	unsigned char i;
+		unsigned char i;
 
-	if (gtd && gtd->ses)
-	{
-		for (i = 0 ; i < debug_index && i < MAX_STACK_SIZE ; i++)
-		{
-			tintin_printf2(gtd->ses, "\e[1;32mDEBUG_STACK[\e[1;31m%03d\e[1;32m] = \e[1;31m%s\e[0m", i, debug_stack[i]);
-		}
-	}
-	else
-	{
-		for (i = 0 ; i < debug_index && i < MAX_STACK_SIZE ; i++)
+		tintin_header(gtd->ses, " DEBUG STACK ");
+
+		for (i = 0 ; i < 100 ; i++)
 		{
-			tintin_printf2(gtd->ses, "\e[1;32mDEBUG_STACK[\e[1;31m%03d\e[1;32m] = \e[1;31m%s\e[0m\n", i, debug_stack[i]);
+			if (i < gtd->memory->debug_max)
+			{
+				tintin_printf2(gtd->ses, "\e[1;31mDEBUG_STACK[%03d] = %s", i, gtd->memory->debug[i]->name);
+			}
 		}
+		tintin_header(gtd->ses, "");
 	}
 }
 
-void dump_stack_fatal(void)
-{
-	unsigned char i;
-
-	for (i = 0 ; i < debug_index && i < MAX_STACK_SIZE ; i++)
-	{
-		print_stdout("\e[1;32mDEBUG_STACK[\e[1;31m%03d\e[1;32m] = \e[1;31m%s\e[0m\n", i, debug_stack[i]);
-	}
-}
-
-void dump_full_stack(void)
+void dump_stack(void)
 {
-	unsigned char i;
-
-	tintin_header(gtd->ses, " FULL DEBUG STACK ");
+	unsigned int i;
 
-	for (i = 0 ; i < MAX_STACK_SIZE ; i++)
+	if (gtd)
 	{
-		if (*debug_stack[i])
+		for (i = 0 ; i < gtd->memory->debug_len ; i++)
 		{
-			tintin_printf2(gtd->ses, "\e[1;31mDEBUG_STACK[%03d] = %s", i, debug_stack[i]);
+			tintin_printf2(gtd->ses, "\e[1;32mDEBUG_STACK[\e[1;31m%03d\e[1;32m] [%03d] = \e[1;31m%s\e[0m", i, gtd->memory->debug[i]->index, gtd->memory->debug[i]->name);
 		}
 	}
-	tintin_header(gtd->ses, "");
 }
+

+ 4 - 5
src/dict.c

@@ -91,7 +91,7 @@ void dictionary_lowerstring(char *in, char *out)
 
 	while (*pti)
 	{
-		if (isalpha(*pti))
+		if (isalpha((int) *pti))
 		{
 			*pto++ = tolower(*pti++);
 		}
@@ -117,7 +117,7 @@ int spellcheck_count(struct session *ses, char *in)
 
 		dictionary_lowerstring(arg1, arg2);
 
-		if (isalpha(*arg2))
+		if (isalpha((int) *arg2))
 		{
 			hash = *arg2 - 'a';
 
@@ -139,12 +139,11 @@ int spellcheck_count(struct session *ses, char *in)
 
 DO_COMMAND(do_dictionary)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE];
 	int hash, size, index;
 
 	sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
 
-	if (*arg1 == 0 || !isalpha(*arg1))
+	if (*arg1 == 0 || !isalpha((int) *arg1))
 	{
 		show_message(ses, LIST_COMMAND, "#SYNTAX: #DICTIONARY {WORD}");
 
@@ -159,7 +158,7 @@ DO_COMMAND(do_dictionary)
 
 		dictionary_lowerstring(arg2, arg3);
 
-		if (isalpha(*arg3))
+		if (isalpha((int) *arg3))
 		{
 			hash = *arg3 - 'a';
 

+ 76 - 44
src/draw.c

@@ -30,7 +30,7 @@ static int  draw_cnt;
 
 DO_COMMAND(do_draw)
 {
-	char *sub_arg, arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], color[BUFFER_SIZE], code[BUFFER_SIZE], arg3[BUFFER_SIZE], input[BUFFER_SIZE];
+	char color[BUFFER_SIZE], code[BUFFER_SIZE], input[BUFFER_SIZE];
 	long long flags;
 	int index, top_row, top_col, bot_row, bot_col, rows, cols;
 
@@ -69,11 +69,11 @@ DO_COMMAND(do_draw)
 
 				SET_BIT(flags, DRAW_FLAG_COLOR);
 			}
-			else if (!HAS_BIT(flags, DRAW_FLAG_COLOR) && strip_vt102_strlen(ses, arg1) == 0)
+/*			else if (!HAS_BIT(flags, DRAW_FLAG_COLOR) && strip_vt102_strlen(ses, arg1) == 0)
 			{
 				strcpy(color, arg1);
 				SET_BIT(flags, DRAW_FLAG_COLOR);
-			}
+			}*/
 			else if (is_abbrev(arg1, "ASCII"))
 			{
 				DEL_BIT(flags, DRAW_FLAG_UTF8);
@@ -86,6 +86,10 @@ DO_COMMAND(do_draw)
 			{
 				SET_BIT(flags, DRAW_FLAG_BOT);
 			}
+			else if (!strcasecmp(arg1, "BOXED"))
+			{
+				SET_BIT(flags, DRAW_FLAG_BOXED|DRAW_FLAG_LEFT|DRAW_FLAG_RIGHT|DRAW_FLAG_TOP|DRAW_FLAG_BOT);
+			}
 			else if (is_abbrev(arg1, "BUMPED"))
 			{
 				SET_BIT(flags, DRAW_FLAG_BUMP);
@@ -202,32 +206,14 @@ DO_COMMAND(do_draw)
 			if (is_abbrev(arg1, draw_table[index].name))
 			{
 				arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
-
-				sub_arg = get_arg_in_braces(ses, arg1, arg3, GET_ONE);
-
-				if (*sub_arg)
-				{
-					strcpy(arg1, arg3);
-					sub_arg = get_arg_in_braces(ses, sub_arg, arg2, GET_ONE);
-				}
-				else
-				{
-					arg = get_arg_in_braces(ses, arg, arg2, GET_ONE);
-				}
+				arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
 
 				top_row = get_row_index_arg(ses, arg1);
 				top_col = get_col_index_arg(ses, arg2);
 
-				if (*sub_arg)
-				{
-					sub_arg = get_arg_in_braces(ses, sub_arg, arg1, GET_ONE);
-					sub_arg = get_arg_in_braces(ses, sub_arg, arg2, GET_ONE);
-				}
-				else
-				{
-					arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
-					arg = get_arg_in_braces(ses, arg, arg2, GET_ONE);
-				}
+				arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
+				arg = get_arg_in_braces(ses, arg, arg2, GET_ONE);
+
 				bot_row = get_row_index_arg(ses, arg1);
 				bot_col = get_col_index_arg(ses, arg2);
 
@@ -248,7 +234,7 @@ DO_COMMAND(do_draw)
 				{
 					if (ses != gtd->ses)
 					{
-						show_error(ses, LIST_COMMAND, "#ERROR: #DRAW %s %d %d %d %d: SESSION IS IN THE BACKGROUND.", draw_table[index].name, top_row, top_col, bot_row, bot_col);
+						show_message(ses, LIST_COMMAND, "#WARNING: #DRAW %s %d %d %d %d: SESSION IS IN THE BACKGROUND.", draw_table[index].name, top_row, top_col, bot_row, bot_col);
 
 						return ses;
 					}
@@ -1024,6 +1010,29 @@ DO_DRAW(draw_bot_side)
 	}
 }
 
+DO_DRAW(draw_arg)
+{
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
+	top_row = get_row_index_arg(ses, arg1);
+
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
+	top_col = get_col_index_arg(ses, arg1);
+
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
+	bot_row = get_row_index_arg(ses, arg1);
+
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
+	bot_col = get_col_index_arg(ses, arg1);
+
+	rows = URANGE(1, 1 + bot_row - top_row, gtd->screen->rows);
+	cols = URANGE(1, 1 + bot_col - top_col, gtd->screen->cols);
+
+	save_pos(ses);
+
+	draw_text(ses, top_row, top_col, bot_row, bot_col, rows, cols, flags, color, arg2, arg1, arg);
+
+	restore_pos(ses);
+}
 
 DO_DRAW(draw_box)
 {
@@ -1107,27 +1116,50 @@ DO_DRAW(draw_line)
 
 DO_DRAW(draw_map)
 {
-	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
-	top_row = get_row_index_arg(ses, arg1);
+	int map_rows = rows;
+	int map_cols = cols;
 
-	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
-	top_col = get_col_index_arg(ses, arg1);
+	if (HAS_BIT(flags, DRAW_FLAG_BOXED|DRAW_FLAG_TOP|DRAW_FLAG_PRUNED))
+	{
+		map_rows--;
+	}
 
-	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
-	bot_row = get_row_index_arg(ses, arg1);
+	if (HAS_BIT(flags, DRAW_FLAG_BOXED|DRAW_FLAG_BOT|DRAW_FLAG_PRUNED))
+	{
+		map_rows--;
+	}
 
-	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
-	bot_col = get_col_index_arg(ses, arg1);
+	if (HAS_BIT(flags, DRAW_FLAG_BOXED|DRAW_FLAG_LEFT|DRAW_FLAG_PRUNED))
+	{
+		map_cols--;
+	}
 
-	rows = URANGE(1, 1 + bot_row - top_row, gtd->screen->rows);
-	cols = URANGE(1, 1 + bot_col - top_col, gtd->screen->cols);
+	if (HAS_BIT(flags, DRAW_FLAG_BOXED|DRAW_FLAG_RIGHT|DRAW_FLAG_PRUNED))
+	{
+		map_cols--;
+	}
 
-	save_pos(ses);
+	if (ses->map && ses->map->in_room)
+	{
+		sprintf(arg, "{%d} {%d} {SAVE}", map_rows, map_cols);
 
-	draw_text(ses, top_row, top_col, bot_row, bot_col, rows, cols, flags, color, arg2, arg1, arg);
+		map_map(ses, arg, arg1, arg2);
+	}
+	else
+	{
+		str_cpy(&gtd->buf, "{}");
+	}
 
-	restore_pos(ses);
+	if (HAS_BIT(flags, DRAW_FLAG_TOP|DRAW_FLAG_BOT))
+	{
+		draw_box(ses, top_row, top_col, bot_row, bot_col, rows, cols, flags, color, gtd->buf, arg1, arg2);
+	}
+	else
+	{
+		draw_text(ses, top_row, top_col, bot_row, bot_col, rows, cols, flags, color, gtd->buf, arg1, arg2);
+	}
 }
+
 char *rain_symbols = "ロヲアウエオカキケコサシスセソタツテナニヌネハヒホマミムメモヤユラリワ01SԐ45789Z=*+-¦|_ʺ╌";
 char *braille_symbols = "⠁⠂⠃⠄⠅⠆⠇⠈⠊⠌⠎⠐⠑⠔⠕⠘⠜⠠⠡⠢⠣⠨⠪⠰⠱⠸⡀⡁⡂⡃⡄⡅⡆⡇⡈⡊⡌⡎⡐⡑⡔⡕⡘⡜⡠⡡⡢⡣⡨⡪⡰⡱⡸⢀⢁⢂⢃⢄⢅⢆⢇⢈⢉⢊⢌⢎⢐⢑⢔⢕⢘⢜⢠⢡⢢⢣⢨⢪⢰⢱";
 
@@ -1643,7 +1675,7 @@ DO_DRAW(draw_text)
 	{
 		while (*arg)
 		{
-			arg = sub_arg_in_braces(ses, arg, buf1, GET_ALL, SUB_COL|SUB_ESC|SUB_VAR|SUB_FUN);
+			arg = sub_arg_in_braces(ses, arg, buf1, GET_ALL, SUB_COL|SUB_ESC|SUB_VAR|SUB_FUN|SUB_LIT);
 
 			txt += sprintf(txt, "%s\n", buf1);
 
@@ -1655,25 +1687,25 @@ DO_DRAW(draw_text)
 		string_to_font(ses, flags, buf2, buf2);
 	}
 
-	if (HAS_BIT(flags, DRAW_FLAG_BOXED) /*|| HAS_BIT(flags, DRAW_FLAG_LINED)*/ || HAS_BIT(flags, DRAW_FLAG_TOP) || HAS_BIT(flags, DRAW_FLAG_PRUNED))
+	if (HAS_BIT(flags, DRAW_FLAG_BOXED|DRAW_FLAG_TOP|DRAW_FLAG_PRUNED))
 	{
 		top_row++;
 		rows--;
 	}
 
-	if (HAS_BIT(flags, DRAW_FLAG_BOXED) /*|| HAS_BIT(flags, DRAW_FLAG_LINED)*/ || HAS_BIT(flags, DRAW_FLAG_BOT) || HAS_BIT(flags, DRAW_FLAG_PRUNED))
+	if (HAS_BIT(flags, DRAW_FLAG_BOXED|DRAW_FLAG_BOT|DRAW_FLAG_PRUNED))
 	{
 		bot_row--;
 		rows--;
 	}
 
-	if (HAS_BIT(flags, DRAW_FLAG_BOXED) || HAS_BIT(flags, DRAW_FLAG_LEFT) || HAS_BIT(flags, DRAW_FLAG_PRUNED))
+	if (HAS_BIT(flags, DRAW_FLAG_BOXED|DRAW_FLAG_LEFT|DRAW_FLAG_PRUNED))
 	{
 		strcpy(side1, " ");
 		cols--;
 	}
 
-	if (HAS_BIT(flags, DRAW_FLAG_BOXED) || HAS_BIT(flags, DRAW_FLAG_RIGHT) || HAS_BIT(flags, DRAW_FLAG_PRUNED))
+	if (HAS_BIT(flags, DRAW_FLAG_BOXED|DRAW_FLAG_RIGHT|DRAW_FLAG_PRUNED))
 	{
 		if (!HAS_BIT(flags, DRAW_FLAG_GRID) || HAS_BIT(flags, DRAW_FLAG_RIGHT))
 		{

+ 24 - 12
src/event.c

@@ -28,7 +28,6 @@
 
 DO_COMMAND(do_event)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 	struct listnode *node;
 	int cnt;
 
@@ -113,7 +112,10 @@ int check_all_events(struct session *ses, int flags, int args, int vars, char *f
 	{
 		if (!HAS_BIT(ses_ptr->list[LIST_EVENT]->flags, LIST_FLAG_IGNORE))
 		{
-			show_info(ses_ptr, LIST_EVENT, "#INFO EVENT {%s}", name);
+			if (!HAS_BIT(flags, SUB_SIL))
+			{
+				show_info(ses_ptr, LIST_EVENT, "#INFO EVENT {%s} ARGUMENTS {%d}", name, vars);
+			}
 
 			node = search_node_list(ses_ptr->list[LIST_EVENT], name);
 
@@ -137,18 +139,22 @@ int check_all_events(struct session *ses, int flags, int args, int vars, char *f
 
 				substitute(ses_ptr, node->arg2, buf, flags);
 
-				if (HAS_BIT(ses_ptr->list[LIST_EVENT]->flags, LIST_FLAG_DEBUG))
+				if (!HAS_BIT(flags, SUB_SIL) && 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);
 				}
 
-				if (HAS_BIT(node->flags, NODE_FLAG_ONESHOT))
+				if (node->shots && --node->shots == 0)
 				{
 					delete_node_list(ses, LIST_EVENT, node);
 				}
 
+				gtd->level->quiet += HAS_BIT(flags, SUB_SIL) ? 1 : 0;
+
 				script_driver(ses_ptr, LIST_EVENT, buf);
 
+				gtd->level->quiet -= HAS_BIT(flags, SUB_SIL) ? 1 : 0;
+
 				if (ses)
 				{
 					free(name);
@@ -175,7 +181,7 @@ int check_all_events(struct session *ses, int flags, int args, int vars, char *f
 
 void mouse_handler(struct session *ses, int flags, int row, int col)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], line[BUFFER_SIZE];
+	char *arg1, *arg2, line[BUFFER_SIZE];
 	static char word[BUFFER_SIZE];
 	static char last[100], dir[10];
 	static long long click[3];
@@ -183,11 +189,16 @@ void mouse_handler(struct session *ses, int flags, int row, int col)
 	int debug, info, rev_row, rev_col, link;
 
 	push_call("mouse_handler(%p,%d,%d,%d,%c)",ses,flags,row,col);
+
+	arg1 = str_alloc_stack();
+	arg2 = str_alloc_stack();
+
 /*
 	if (!HAS_BIT(ses->event_flags, EVENT_FLAG_MOUSE))
 	{
 		if (!HAS_BIT(ses->flags, SES_FLAG_MOUSEINFO) && !HAS_BIT(ses->list[LIST_EVENT]->flags, LIST_FLAG_INFO))
 		{
+			pop_call();
 			return;
 		}
 	}
@@ -308,12 +319,13 @@ void mouse_handler(struct session *ses, int flags, int row, int col)
 		case 1:
 			check_all_events(ses, SUB_ARG, 2, 6, "%s LINK %s", arg1, arg2, ntos(row), ntos(col), ntos(rev_row), ntos(-1 - (gtd->screen->cols - col)), word, line);
 			break;
+
 		case 2:
 			if (flags == 0)
 			{
 				tintin_printf2(ses, "\e[1;32m         %s\n", capitalize(word));
-				
-				do_help(ses, word);
+
+				execute(ses, "#HELP {%s}", word);
 			}
 			break;
 	}
@@ -324,7 +336,7 @@ void mouse_handler(struct session *ses, int flags, int row, int col)
 
 	check_all_events(ses, SUB_ARG, 3, 6, "%s %s %d", arg1, arg2, rev_row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
 
-	map_mouse_handler(ses, arg1, arg2, col, row, 0, 0);
+	map_mouse_handler(ses, arg1, arg2, row, col, rev_row, rev_col, 0, 0);
 
 	if (!strcmp(arg1, "PRESSED"))
 	{
@@ -361,7 +373,7 @@ void mouse_handler(struct session *ses, int flags, int row, int col)
 
 					check_all_events(ses, SUB_ARG, 2, 6, "TRIPLE-CLICKED %s %d", arg2, rev_row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
 
-					map_mouse_handler(ses, "TRIPPLE-CLICKED", arg2, col, row, 0, 0);
+					map_mouse_handler(ses, "TRIPPLE-CLICKED", arg2, row, col, rev_row, rev_col, 0, 0);
 
 					strcpy(last, "");
 				}
@@ -383,7 +395,7 @@ void mouse_handler(struct session *ses, int flags, int row, int col)
 
 					check_all_events(ses, SUB_ARG, 2, 6, "DOUBLE-CLICKED %s %d", arg2, rev_row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
 
-					map_mouse_handler(ses, "DOUBLE-CLICKED", arg2, col, row, 0, 0);
+					map_mouse_handler(ses, "DOUBLE-CLICKED", arg2, row, col, rev_row, rev_col, 0, 0);
 				}
 			}
 		}
@@ -443,7 +455,7 @@ void mouse_handler(struct session *ses, int flags, int row, int col)
 
 			check_all_events(ses, SUB_ARG, 2, 6, "LONG-CLICKED %s %d", arg2, rev_row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
 
-			map_mouse_handler(ses, "LONG-CLICKED", arg2, col, row, 0, 0);
+			map_mouse_handler(ses, "LONG-CLICKED", arg2, row, col, rev_row, rev_col, 0, 0);
 		}
 		else if (click[0] - click[1] >= 500000)
 		{
@@ -464,7 +476,7 @@ void mouse_handler(struct session *ses, int flags, int row, int col)
 
 				check_all_events(ses, SUB_ARG, 2, 6, "SHORT-CLICKED %s %d", arg2, rev_row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
 
-				map_mouse_handler(ses, "SHORT-CLICKED", arg2, col, row, 0, 0);
+				map_mouse_handler(ses, "SHORT-CLICKED", arg2, row, col, rev_row, rev_col, 0, 0);
 			}
 		}
 	}

+ 44 - 36
src/files.c

@@ -31,28 +31,26 @@
 
 DO_COMMAND(do_read)
 {
-	char filename[BUFFER_SIZE];
 	FILE *fp;
 
-	sub_arg_in_braces(ses, arg, filename, GET_ONE, SUB_VAR|SUB_FUN);
+	sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 
-	if ((fp = fopen(filename, "r")) == NULL)
+	if ((fp = fopen(arg1, "r")) == NULL)
 	{
-		check_all_events(ses, SUB_ARG, 0, 2, "READ ERROR", filename, "FILE NOT FOUND.");
+		check_all_events(ses, SUB_ARG, 0, 2, "READ ERROR", arg1, "FILE NOT FOUND.");
 
-		tintin_printf(ses, "#READ {%s} - FILE NOT FOUND.", filename);
+		tintin_printf(ses, "#READ {%s} - FILE NOT FOUND.", arg1);
 
 		return ses;
 	}
 
-	return read_file(ses, fp, filename);
+	return read_file(ses, fp, arg1);
 }
 
 struct session *read_file(struct session *ses, FILE *fp, char *filename)
 {
-	struct stat filedata;
 	char *bufi, *bufo, temp[INPUT_SIZE], *pti, *pto, last = 0;
-	int lvl, cnt, com, lnc, fix, ok, verbose;
+	int lvl, cnt, com, lnc, fix, ok, verbose, size;
 	int counter[LIST_MAX];
 
 	temp[0] = getc(fp);
@@ -78,13 +76,17 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 		}
 	}
 
-	stat(filename, &filedata);
+	fseek(fp, 0, SEEK_END);
 
-	if ((bufi = (char *) calloc(1, filedata.st_size + 2)) == NULL || (bufo = (char *) calloc(1, filedata.st_size + 2)) == NULL)
+	size = ftell(fp);
+
+	fseek(fp, 0, SEEK_SET);
+
+	if ((bufi = (char *) calloc(1, size + 2)) == NULL || (bufo = (char *) calloc(1, size + 2)) == NULL)
 	{
 		check_all_events(ses, SUB_ARG, 0, 2, "READ ERROR", filename, "FAILED TO ALLOCATE MEMORY");
 
-		tintin_printf(ses, "#ERROR: #READ {%s} - FAILED TO ALLOCATE MEMORY.", filename);
+		tintin_printf(ses, "#ERROR: #READ {%s} - FAILED TO ALLOCATE %d BYTES OF MEMORY.", filename, size + 2);
 
 		fclose(fp);
 
@@ -92,7 +94,7 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 	}
 
 
-	fread(bufi, 1, filedata.st_size, fp);
+	fread(bufi, 1, size, fp);
 
 	pti = bufi;
 	pto = bufo;
@@ -197,6 +199,14 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 
 						}
 
+						if (last == 0)
+						{
+							if (*pti != DEFAULT_OPEN && *pti != DEFAULT_CLOSE)
+							{
+								show_error(ses, LIST_COMMAND, "#WARNING: #READ {%s} MISSING SEMICOLON ON LINE %d.", filename, lnc - 1);
+							}
+						}
+
 						if (*pti != DEFAULT_CLOSE && last == 0)
 						{
 							*pto++ = ' ';
@@ -278,7 +288,6 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 	*pto   = '\0';
 
 
-
 	if (lvl)
 	{
 		check_all_events(ses, SUB_ARG, 0, 2, "READ ERROR", filename, "MISSING BRACE OPEN OR CLOSE");
@@ -307,9 +316,9 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 		return ses;
 	}
 
-	sprintf(temp, "{TINTIN CHAR} {%c}", bufo[0]);
+	sprintf(temp, "#CONFIG {TINTIN CHAR} {%c}", bufo[0]);
 
-	if (bufo[0] != '#')
+	if (bufo[0] != gtd->tintin_char)
 	{
 		gtd->level->verbose++;
 		gtd->level->debug++;
@@ -318,6 +327,12 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 
 		gtd->level->debug--;
 		gtd->level->verbose--;
+
+		gtd->level->quiet++;
+
+		script_driver(ses, LIST_COMMAND, temp);
+
+		gtd->level->quiet--;
 	}
 
 	verbose = HAS_BIT(ses->flags, SES_FLAG_VERBOSE) ? 1 : 0;
@@ -326,12 +341,6 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 
 	gtd->level->verbose += verbose;
 
-	gtd->level->quiet++;
-
-	do_configure(ses, temp);
-
-	gtd->level->quiet--;
-
 	lvl = 0;
 	lnc = 0;
 	pti = bufo;
@@ -347,9 +356,9 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 		lnc++;
 		*pto = 0;
 
-		if (strlen(bufi) >= BUFFER_SIZE)
+		if (pto - bufi >= BUFFER_SIZE)
 		{
-			tintin_printf(ses, "#ERROR: #READ {%s} - BUFFER OVERFLOW AT COMMAND: %.30s", filename, bufi);
+			show_debug(ses, LIST_COMMAND, "#WARNING: #READ {%s} - POSSIBLE BUFFER OVERFLOW AT COMMAND: %.30s", filename, bufi);
 		}
 
 		if (bufi[0])
@@ -398,37 +407,36 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 DO_COMMAND(do_write)
 {
 	FILE *file;
-	char filename[BUFFER_SIZE], forceful[BUFFER_SIZE];
 	struct listroot *root;
 	struct listnode *node;
 
 	int i, j, fix, cnt = 0;
 
-	arg = get_arg_in_braces(ses, arg, filename, GET_ONE);
-	arg = get_arg_in_braces(ses, arg, forceful, GET_ONE);
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+	arg = get_arg_in_braces(ses, arg, arg2, GET_ONE);
 
-	if (*filename == 0)
+	if (*arg1 == 0)
 	{
-		check_all_events(ses, SUB_ARG, 0, 2, "WRITE ERROR", filename, "INVALID FILE NAME");
+		check_all_events(ses, SUB_ARG, 0, 2, "WRITE ERROR", arg1, "INVALID FILE NAME");
 
 		tintin_printf2(ses, "#SYNTAX: #WRITE {<filename>} {[FORCE]}");
 
 		return ses;
 	}
 	
-	if (!str_suffix(filename, ".map") && !is_abbrev(forceful, "FORCE"))
+	if (!str_suffix(arg1, ".map") && !is_abbrev(arg2, "FORCE"))
 	{
-		check_all_events(ses, SUB_ARG, 0, 2, "WRITE ERROR", filename, "INVALID FILE EXTENSION");
-		tintin_printf2(ses, "#WRITE {%s}: USE {FORCE} TO OVERWRITE .map FILES.", filename);
+		check_all_events(ses, SUB_ARG, 0, 2, "WRITE ERROR", arg1, "INVALID FILE EXTENSION");
+		tintin_printf2(ses, "#WRITE {%s}: USE {FORCE} TO OVERWRITE .map FILES.", arg1);
 
 		return ses;
 	}
 
-	if ((file = fopen(filename, "w")) == NULL)
+	if ((file = fopen(arg1, "w")) == NULL)
 	{
-		check_all_events(ses, SUB_ARG, 0, 2, "WRITE ERROR", filename, "FAILED TO OPEN");
+		check_all_events(ses, SUB_ARG, 0, 2, "WRITE ERROR", arg1, "FAILED TO OPEN");
 
-		tintin_printf(ses, "#ERROR: #WRITE: COULDN'T OPEN {%s} TO WRITE.", filename);
+		tintin_printf(ses, "#ERROR: #WRITE: COULDN'T OPEN {%s} TO WRITE.", arg1);
 
 		return ses;
 	}
@@ -448,7 +456,7 @@ DO_COMMAND(do_write)
 		{
 			node = root->list[j];
 
-			if (HAS_BIT(node->flags, NODE_FLAG_ONESHOT))
+			if (node->shots)//HAS_BIT(node->flags, NODE_FLAG_ONESHOT))
 			{
 				continue;
 			}
@@ -470,7 +478,7 @@ DO_COMMAND(do_write)
 
 	fclose(file);
 
-	show_message(ses, LIST_COMMAND, "#WRITE: %d COMMANDS WRITTEN TO {%s}.", cnt, filename);
+	show_message(ses, LIST_COMMAND, "#WRITE: %d COMMANDS WRITTEN TO {%s}.", cnt, arg1);
 
 	return ses;
 }

Fichier diff supprimé car celui-ci est trop grand
+ 156 - 114
src/help.c


+ 82 - 25
src/history.c

@@ -27,14 +27,17 @@
 
 DO_COMMAND(do_history)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 	int cnt;
 
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
-	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
+	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
+	arg = sub_arg_in_braces(ses, arg, arg3, GET_ONE, SUB_VAR|SUB_FUN);
+	arg = sub_arg_in_braces(ses, arg, arg4, GET_ALL, SUB_VAR|SUB_FUN);
 
 	if (*arg1 == 0)
 	{
+		info:
+
 		tintin_header(ses, " HISTORY COMMANDS ");
 
 		for (cnt = 0 ; *history_table[cnt].name != 0 ; cnt++)
@@ -53,12 +56,12 @@ DO_COMMAND(do_history)
 			continue;
 		}
 
-		history_table[cnt].fun(ses, arg2);
+		history_table[cnt].fun(ses, arg2, arg3, arg4);
 
 		return ses;
 	}
 
-	do_history(ses, "");
+	goto info;
 
 	return ses;
 }
@@ -120,7 +123,7 @@ void search_line_history(struct session *ses, char *line)
 
 DO_HISTORY(history_character)
 {
-	gtd->repeat_char = *arg;
+	gtd->repeat_char = *arg1;
 
 	show_message(ses, LIST_HISTORY, "#HISTORY CHARACTER SET TO {%c}.", gtd->repeat_char);
 }
@@ -137,19 +140,77 @@ DO_HISTORY(history_delete)
 
 DO_HISTORY(history_insert)
 {
-	add_line_history(ses, arg);
+	add_line_history(ses, arg1);
 }
 
-DO_HISTORY(history_list)
+DO_HISTORY(history_get)
 {
-	struct listroot *root;
-	int i, cnt = 1;
+	struct listroot *root = ses->list[LIST_HISTORY];
+	int cnt, min, max;
 
-	root = ses->list[LIST_HISTORY];
+	if (*arg1 == 0)
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #HISTORY GET <VARIABLE> [LOWER BOUND] [UPPER BOUND]");
 
-	for (i = 0 ; i < root->used ; i++)
+		return;
+	}
+
+	min = get_number(ses, arg2);
+
+	if (min < 0)
+	{
+		min = root->used + min;
+	}
+
+	min = URANGE(0, min, root->used - 1);
+
+	if (*arg3 == 0)
+	{
+		set_nest_node_ses(ses, arg1, "%s", root->list[min]->arg1);
+
+		return;
+	}
+
+	max = get_number(ses, arg3);
+
+	if (max < 0)
+	{
+		max = root->used + max;
+	}
+	max = URANGE(0, max, root->used - 1);
+
+	if (min > max)
+	{
+		show_error(ses, LIST_COMMAND, "#ERROR: #HISTORY GET {%s} {%d} {%d} LOWER BOUND EXCEEDS UPPER BOUND.", arg1, min, max);
+
+		return;
+	}
+
+	cnt = 0;
+
+	set_nest_node_ses(ses, arg1, "");
+
+	while (min <= max)
+	{
+		sprintf(arg2, "%s[%d]", arg1, ++cnt);
+
+		set_nest_node_ses(ses, arg2, "%s", root->list[min++]->arg1);
+	}
+
+	show_message(ses, LIST_COMMAND, "#HISTORY GET: %d LINES SAVED TO {%s}.", cnt, arg1);
+
+	return;
+}
+
+DO_HISTORY(history_list)
+{
+	if (*arg1 == 0)
+	{
+		show_list(ses->list[LIST_HISTORY], 0);
+	}
+	else
 	{
-		tintin_printf2(ses, "%6d - %s", cnt++, root->list[i]->arg1);
+		show_node_with_wild(ses, arg1, ses->list[LIST_HISTORY]);
 	}
 	return;
 }
@@ -159,11 +220,11 @@ DO_HISTORY(history_read)
 	FILE *file;
 	char *cptr, buffer[BUFFER_SIZE];
 
-	file = fopen(arg, "r");
+	file = fopen(arg1, "r");
 
 	if (file == NULL)
 	{
-		show_message(ses, LIST_HISTORY, "#HISTORY: COULDN'T OPEN FILE {%s} TO READ.", arg);
+		show_message(ses, LIST_HISTORY, "#HISTORY: COULDN'T OPEN FILE {%s} TO READ.", arg1);
 		return;
 	}
 
@@ -179,21 +240,17 @@ DO_HISTORY(history_read)
 
 			if (*buffer)
 			{
-				insert_node_list(ses->list[LIST_HISTORY], buffer, "", "", "");
+				create_node_list(ses->list[LIST_HISTORY], buffer, "", "", "");
 			}
 		}
 	}
-	insert_node_list(ses->list[LIST_HISTORY], "", "", "", "");
+	create_node_list(ses->list[LIST_HISTORY], "", "", "", "");
 
 	fclose(file);
 
 	if (ses->list[LIST_HISTORY]->used > gtd->history_size) 
 	{
-		char buf[BUFFER_SIZE];
-
-		sprintf(buf, "{HISTORY SIZE} {%d}", UMIN(ses->list[LIST_HISTORY]->used, 9999));
-
-		do_configure(gts, buf);
+		execute(gts, "#CONFIG {HISTORY SIZE} {%d}", UMIN(ses->list[LIST_HISTORY]->used, 9999));
 	}
 
 	return;
@@ -201,13 +258,13 @@ DO_HISTORY(history_read)
 
 DO_HISTORY(history_size)
 {
-	if (atoi(arg) < 1 || atoi(arg) > 100000)
+	if (atoi(arg1) < 1 || atoi(arg1) > 100000)
 	{
 		show_error(ses, LIST_COMMAND, "#ERROR: #HISTORY SIZE: PROVIDE A NUMBER BETWEEN 1 and 100,000");
 	}
 	else
 	{
-		gtd->history_size = atoi(arg);
+		gtd->history_size = atoi(arg1);
 	}
 	return;
 }
@@ -218,11 +275,11 @@ DO_HISTORY(history_write)
 	FILE *file;
 	int i;
 
-	file = fopen(arg, "w");
+	file = fopen(arg1, "w");
 
 	if (file == NULL)
 	{
-		tintin_printf2(ses, "#HISTORY: COULDN'T OPEN FILE {%s} TO WRITE.", arg);
+		tintin_printf2(ses, "#HISTORY: COULDN'T OPEN FILE {%s} TO WRITE.", arg1);
 
 		return;
 	}

+ 40 - 26
src/input.c

@@ -154,7 +154,7 @@ void process_input(void)
 
 	if (HAS_BIT(gtd->flags, TINTIN_FLAG_CHILDLOCK))
 	{
-		write_mud(gtd->ses, gtd->ses->input->buf, SUB_EOL);
+		parse_input(gtd->ses, gtd->ses->input->buf);
 	}
 	else
 	{
@@ -193,10 +193,7 @@ void read_line(char *input, int len)
 		strcat(gtd->macro_buf, input);
 	}
 
-	if (check_key(input, len))
-	{
-		return;
-	}
+	get_utf8_index(input, &index);
 
 	if (HAS_BIT(gtd->ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(gtd->macro_buf))
 	{
@@ -206,23 +203,25 @@ void read_line(char *input, int len)
 		}
 	}
 
-	if (gtd->macro_buf[0] == ASCII_ESC)
-	{
-		strcpy(input, gtd->macro_buf);
+	check_all_events(gtd->ses, SUB_ARG|SUB_SIL, 0, 2, "RECEIVED KEYPRESS", input, ntos(index));
 
-		convert_meta(input, gtd->macro_buf, FALSE);
+	if (check_all_events(gtd->ses, SUB_ARG|SUB_SIL, 0, 2, "CATCH RECEIVED KEYPRESS", input, ntos(index)) == 1)
+	{
+		return;
 	}
 
-	get_utf8_index(gtd->macro_buf, &index);
-
-	check_all_events(gtd->ses, SUB_ARG, 0, 2, "RECEIVED KEYPRESS", gtd->macro_buf, ntos(index));
-
-	if (check_all_events(gtd->ses, SUB_ARG, 0, 2, "CATCH RECEIVED KEYPRESS", gtd->macro_buf, ntos(index)) == 1)
+	if (check_key(input, len))
 	{
-		gtd->macro_buf[0] = 0;
 		return;
 	}
 
+	if (gtd->macro_buf[0] == ASCII_ESC)
+	{
+		strcpy(input, gtd->macro_buf);
+
+		convert_meta(input, gtd->macro_buf, FALSE);
+	}
+
 	while (gtd->macro_buf[0])
 	{
 		switch (gtd->macro_buf[0])
@@ -390,7 +389,7 @@ int check_key(char *input, int len)
 	char buf[BUFFER_SIZE];
 	struct listroot *root;
 	struct listnode *node;
-	int cnt, val[5];
+	int cnt, val[5], partial;
 
 	push_call("check_key(%p,%d)",input,len);
 
@@ -398,10 +397,12 @@ int check_key(char *input, int len)
 
 	if (!HAS_BIT(gtd->ses->flags, SES_FLAG_CONVERTMETA))
 	{
-		root  = gtd->ses->list[LIST_MACRO];
+		root = gtd->ses->list[LIST_MACRO];
 
 		if (!HAS_BIT(root->flags, LIST_FLAG_IGNORE))
 		{
+			partial = 0;
+
 			for (root->update = 0 ; root->update < root->used ; root->update++)
 			{
 				node = root->list[root->update];
@@ -410,29 +411,42 @@ int check_key(char *input, int len)
 				{
 					continue;
 				}
-				else if (!strcmp(gtd->macro_buf, node->arg3))
+				else if (!strcmp(gtd->macro_buf, node->arg4))
 				{
 					strcpy(buf, node->arg2);
 
-					if (HAS_BIT(node->flags, NODE_FLAG_ONESHOT))
+					if (node->shots && --node->shots == 0)
 					{
 						delete_node_list(gtd->ses, LIST_MACRO, node);
 					}
 
 					script_driver(gtd->ses, LIST_MACRO, buf);
 
-					gtd->macro_buf[0] = 0;
+					if (HAS_BIT(gtd->flags, TINTIN_FLAG_PRESERVEMACRO))
+					{
+						DEL_BIT(gtd->flags, TINTIN_FLAG_PRESERVEMACRO);
+					}
+					else
+					{
+						gtd->macro_buf[0] = 0;
+					}
+
 					pop_call();
 					return TRUE;
 				}
-				else if (!strncmp(gtd->macro_buf, node->arg3, strlen(gtd->macro_buf)))
+				else if (!strncmp(gtd->macro_buf, node->arg4, strlen(gtd->macro_buf)))
 				{
-					pop_call();
-					return TRUE;
+					partial = TRUE;
 				}
 			}
 		}
 
+		if (partial)
+		{
+			pop_call();
+			return TRUE;
+		}
+
 		if (!HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_SGA) || HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_ECHO) || gtd->ses->input->buf[0] == gtd->tintin_char)
 		{
 			for (cnt = 0 ; *cursor_table[cnt].fun != NULL ; cnt++)
@@ -466,7 +480,7 @@ int check_key(char *input, int len)
 
 					for (len = 3 ; gtd->macro_buf[len] ; len++)
 					{
-						if (isdigit(gtd->macro_buf[len]))
+						if (isdigit((int) gtd->macro_buf[len]))
 						{
 							cat_sprintf(input, "%c", gtd->macro_buf[len]);
 						}
@@ -514,7 +528,7 @@ int check_key(char *input, int len)
 							return FALSE;
 						}
 
-						if (isdigit(gtd->macro_buf[len]))
+						if (isdigit((int) gtd->macro_buf[len]))
 						{
 							cat_sprintf(input, "%c", gtd->macro_buf[len]);
 						}
@@ -794,7 +808,7 @@ void echo_command(struct session *ses, char *line)
 		sprintf(buffer, "\e[0m");
 	}
 
-	if (ses->wrap == gtd->screen->cols)
+//	if (ses->wrap == gtd->screen->cols)
 	{
 		gtd->level->scroll++;
 

+ 83 - 6
src/line.c

@@ -27,13 +27,16 @@
 
 DO_COMMAND(do_line)
 {
-	char arg1[BUFFER_SIZE];
 	int cnt;
 
+	push_call("do_line(%p,%p)",ses,arg);
+
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
 
 	if (*arg1 == 0)
 	{
+		info:
+
 		tintin_header(ses, " LINE OPTIONS ");
 
 		for (cnt = 0 ; *line_table[cnt].fun != NULL ; cnt++)
@@ -45,6 +48,7 @@ DO_COMMAND(do_line)
 		}
 		tintin_header(ses, "");
 
+		pop_call();
 		return ses;
 	}
 	else
@@ -59,13 +63,14 @@ DO_COMMAND(do_line)
 
 		if (*line_table[cnt].name == 0)
 		{
-			do_line(ses, "");
+			goto info;
 		}
 		else
 		{
 			ses = line_table[cnt].fun(ses, arg);
 		}
 	}
+	pop_call();
 	return ses;
 }
 
@@ -197,9 +202,25 @@ DO_LINE(line_gag)
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 
-	show_debug(ses, LIST_GAG, "#DEBUG LINE GAG");
+	switch (*arg1)
+	{
+		case '-':
+			ses->gagline -= get_number(ses, arg1+1);
+			break;
+		case '+':
+			ses->gagline += get_number(ses, arg1+1);
+			break;
+		case 0:
+			ses->gagline = 1;
+			break;
+		default:
+			ses->gagline = get_number(ses, arg1);
+			break;
+	}
+
+	show_debug(ses, LIST_GAG, "#DEBUG LINE GAG {%s}", arg1);
 
-	SET_BIT(ses->flags, SES_FLAG_GAG);
+//	SET_BIT(ses->flags, SES_FLAG_GAG);
 
 	return ses;
 }
@@ -226,6 +247,30 @@ DO_LINE(line_ignore)
 	return ses;
 }
 
+DO_LINE(line_local)
+{
+	char arg1[BUFFER_SIZE];
+
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
+
+	if (*arg1 == 0)
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {LOCAL} {command}.");
+
+		return ses;
+	}
+
+	gtd->level->local++;
+
+	SET_BIT(gtd->flags, TINTIN_FLAG_LOCAL);
+
+	ses = script_driver(ses, LIST_COMMAND, arg1);
+
+	gtd->level->local--;
+
+	return ses;
+}
+
 // Without an argument mark next line to be logged, otherwise log the given line to file.
 
 DO_LINE(line_log)
@@ -428,6 +473,36 @@ DO_LINE(line_logverbatim)
 	return ses;
 }
 
+DO_LINE(line_multishot)
+{
+	unsigned int shots;
+	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
+
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
+	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
+
+	shots = (unsigned int) get_number(ses, arg1);
+
+	if (!is_math(ses, arg1) || *arg2 == 0)
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {MULTISHOT} {number} {command}.");
+		
+		return ses;
+	}
+
+	gtd->level->shots++;
+
+	gtd->level->mshot = shots;
+
+	ses = script_driver(ses, LIST_COMMAND, arg2);
+
+	gtd->level->mshot = 1;
+
+	gtd->level->shots--;
+
+	return ses;
+}
+
 DO_LINE(line_oneshot)
 {
 	char arg1[BUFFER_SIZE];
@@ -441,11 +516,13 @@ DO_LINE(line_oneshot)
 		return ses;
 	}
 
-	gtd->level->oneshot++;
+	gtd->level->shots++;
+
+	gtd->level->mshot = 1;
 
 	ses = script_driver(ses, LIST_COMMAND, arg1);
 
-	gtd->level->oneshot--;
+	gtd->level->shots--;
 
 	return ses;
 }

+ 3 - 4
src/list.c

@@ -30,7 +30,6 @@
 
 DO_COMMAND(do_list)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 	struct listnode *node;
 	int index, cnt;
 
@@ -39,6 +38,8 @@ DO_COMMAND(do_list)
 
 	if (*arg1 == 0)
 	{
+		info:
+
 		tintin_header(ses, " LIST OPTIONS ");
 
 		for (index = 0 ; *array_table[index].fun ; index++)
@@ -66,7 +67,7 @@ DO_COMMAND(do_list)
 
 		if (*array_table[cnt].name == 0)
 		{
-			return do_list(ses, "");
+			goto info;
 		}
 		else
 		{
@@ -400,8 +401,6 @@ DO_ARRAY(array_insert)
 
 	set_nest_node(list->root, ntos(index + 1), "%s", arg2);
 
-//	insert_node_list(list->root, ntos(index + 1), arg2, "");
-
 	return ses;
 }
 

+ 106 - 74
src/log.c

@@ -25,6 +25,112 @@
 
 #include "tintin.h"
 
+DO_COMMAND(do_log)
+{
+	int cnt;
+
+	push_call("do_log(%p,%p)",ses,arg);
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN|SUB_ESC);
+
+	if (*arg1 == 0)
+	{
+		info:
+
+		tintin_header(ses, " LOG OPTIONS ");
+
+		for (cnt = 0 ; *log_table[cnt].fun != NULL ; cnt++)
+		{
+			if (*log_table[cnt].desc)
+			{
+				tintin_printf2(ses, "  [%-13s] %s", log_table[cnt].name, log_table[cnt].desc);
+			}
+		}
+		pop_call();
+		return ses;
+	}
+	else
+	{
+		for (cnt = 0 ; *log_table[cnt].name ; cnt++)
+		{
+			if (is_abbrev(arg1, log_table[cnt].name))
+			{
+				break;
+			}
+		}
+
+		if (*log_table[cnt].name == 0)
+		{
+			goto info;
+		}
+		else
+		{
+			log_table[cnt].fun(ses, arg, arg1, arg2);
+		}
+	}
+	pop_call();
+	return ses;
+}
+
+DO_LOG(log_append)
+{
+	if (ses->logfile)
+	{
+		fclose(ses->logfile);
+	}
+
+	if ((ses->logfile = fopen(arg2, "a")))
+	{
+		SET_BIT(ses->logmode, LOG_FLAG_APPEND);
+
+		loginit(ses, ses->logfile, ses->logmode);
+
+		show_message(ses, LIST_COMMAND, "#LOG: LOGGING OUTPUT TO '%s' FILESIZE: %ld", arg2, ftell(ses->logfile));
+	}
+	else
+	{
+		show_error(ses, LIST_COMMAND, "#ERROR: #LOG {%s} {%s} - COULDN'T OPEN FILE.", arg1, arg2);
+	}
+}
+
+DO_LOG(log_overwrite)
+{
+	if (ses->logfile)
+	{
+		fclose(ses->logfile);
+	}
+
+	if ((ses->logfile = fopen(arg2, "w")))
+	{
+		SET_BIT(ses->logmode, LOG_FLAG_OVERWRITE);
+
+		loginit(ses, ses->logfile, ses->logmode);
+
+		show_message(ses, LIST_COMMAND, "#LOG: LOGGING OUTPUT TO '%s'", arg2);
+	}
+	else
+	{
+		show_error(ses, LIST_COMMAND, "#ERROR: #LOG {%s} {%s} - COULDN'T OPEN FILE.", arg1, arg2);
+	}
+}
+
+DO_LOG(log_off)
+{
+	if (ses->logfile)
+	{
+		DEL_BIT(ses->logmode, LOG_FLAG_APPEND|LOG_FLAG_OVERWRITE);
+
+		fclose(ses->logfile);
+		ses->logfile = NULL;
+
+		show_message(ses, LIST_COMMAND, "#LOG {OFF}: LOGGING TURNED OFF.");
+	}
+	else
+	{
+		show_message(ses, LIST_COMMAND, "#LOG: LOGGING ALREADY TURNED OFF.");
+	}
+}
 
 void logit(struct session *ses, char *txt, FILE *file, int flags)
 {
@@ -84,80 +190,6 @@ void loginit(struct session *ses, FILE *file, int flags)
 	return;
 }
 
-DO_COMMAND(do_log)
-{
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
-
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
-
-	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN|SUB_ESC);
-
-	if (*arg1 == 0)
-	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #LOG {APPEND|OVERWRITE|OFF} {<FILENAME>}");
-	}
-	else if (is_abbrev(arg1, "APPEND") && *arg2 != 0)
-	{
-		if (ses->logfile)
-		{
-			fclose(ses->logfile);
-		}
-
-		if ((ses->logfile = fopen(arg2, "a")))
-		{
-			SET_BIT(ses->logmode, LOG_FLAG_APPEND);
-
-			loginit(ses, ses->logfile, ses->logmode);
-
-			show_message(ses, LIST_COMMAND, "#LOG: LOGGING OUTPUT TO '%s' FILESIZE: %ld", arg2, ftell(ses->logfile));
-		}
-		else
-		{
-			show_error(ses, LIST_COMMAND, "#ERROR: #LOG {%s} {%s} - COULDN'T OPEN FILE.", arg1, arg2);
-		}
-	}
-	else if (is_abbrev(arg1, "OVERWRITE") && *arg2)
-	{
-		if (ses->logfile)
-		{
-			fclose(ses->logfile);
-		}
-
-		if ((ses->logfile = fopen(arg2, "w")))
-		{
-			SET_BIT(ses->logmode, LOG_FLAG_OVERWRITE);
-
-			loginit(ses, ses->logfile, ses->logmode);
-
-			show_message(ses, LIST_COMMAND, "#LOG: LOGGING OUTPUT TO '%s'", arg2);
-		}
-		else
-		{
-			show_error(ses, LIST_COMMAND, "#ERROR: #LOG {%s} {%s} - COULDN'T OPEN FILE.", arg1, arg2);
-		}
-	}
-	else if (is_abbrev(arg1, "OFF"))
-	{
-		if (ses->logfile)
-		{
-			DEL_BIT(ses->logmode, LOG_FLAG_APPEND|LOG_FLAG_OVERWRITE);
-
-			fclose(ses->logfile);
-			ses->logfile = NULL;
-			show_message(ses, LIST_COMMAND, "#LOG: LOGGING TURNED OFF.");
-		}
-		else
-		{
-			show_message(ses, LIST_COMMAND, "#LOG: LOGGING ALREADY TURNED OFF.");
-		}
-	}
-	else
-	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #LOG {APPEND|OVERWRITE|OFF} {<FILENAME>}");
-	}
-	return ses;
-}
-
 void write_html_header(struct session *ses, FILE *fp)
 {
 	char header[BUFFER_SIZE];

+ 66 - 62
src/main.c

@@ -288,7 +288,7 @@ int main(int argc, char **argv)
 
 		if (access(filename, F_OK ) != -1)
 		{
-			history_read(gts, filename);
+			history_read(gts, filename, "", "");
 		}
 	}
 
@@ -319,12 +319,12 @@ int main(int argc, char **argv)
 					break;
 
 				case 'M':
-					do_test(gts, optarg ? optarg : "");
+					execute(gts, "#TEST %s", optarg ? optarg : "");
 					break;
 
 				case 'r':
 //					gtd->level->input++;
-					gtd->ses = do_read(gtd->ses, optarg);
+					gtd->ses = execute(gtd->ses, "#READ %s", optarg);
 //					gtd->level->input--;
 					break;
 
@@ -358,9 +358,9 @@ int main(int argc, char **argv)
 
 	if (!HAS_BIT(greeting, STARTUP_FLAG_NOTITLE))
 	{
-		do_screen(gts, "LOAD BOTH");
-		do_screen(gts, "SAVE BOTH");
-		do_screen(gts, "SET BOTH TinTin++");
+		execute(gts, "#SCREEN LOAD BOTH");
+		execute(gts, "#SCREEN SAVE BOTH");
+		execute(gts, "#SCREEN SET BOTH TinTin++");
 	}
 
 	gtd->exec = strdup(argv[0]);
@@ -400,13 +400,13 @@ int main(int argc, char **argv)
 	{
 		if (!strncasecmp(argv[optind], "telnet://", 9))
 		{
-			do_session(gts, argv[optind]);
+			gtd->ses = execute(gts, "#SESSION %s", argv[optind]);
 		}
 		else
 		{
 			gtd->level->input++;
 
-			gtd->ses = do_read(gtd->ses, argv[optind]);
+			gtd->ses = execute(gtd->ses, "#READ %s", argv[optind]);
 
 			gtd->level->input--;
 		}
@@ -423,16 +423,19 @@ void init_tintin(int greeting)
 {
 	int ref, index;
 
-	push_call("init_tintin(%d)",greeting);
+	gtd                    = (struct tintin_data *) calloc(1, sizeof(struct tintin_data));
 
-	gtd                 = (struct tintin_data *) calloc(1, sizeof(struct tintin_data));
+	gtd->memory            = calloc(1, sizeof(struct memory_data));
+	gtd->memory->debug     = calloc(1, sizeof(struct stack_data *));
+	gtd->memory->stack     = calloc(1, sizeof(struct str_data *));
+	gtd->memory->alloc     = calloc(1, sizeof(struct str_data));
 
-	gtd->level          = (struct level_data *) calloc(1, sizeof(struct level_data));
+	push_call("init_tintin(%d)",greeting);
 
-	gtd->memory         = calloc(1, sizeof(struct str_data));
+	gtd->level             = (struct level_data *) calloc(1, sizeof(struct level_data));
 
-	gtd->buf            = str_alloc(STRING_SIZE);
-	gtd->out            = str_alloc(STRING_SIZE);
+	gtd->buf               = str_alloc(STRING_SIZE);
+	gtd->out               = str_alloc(STRING_SIZE);
 
 	gtd->flags          = TINTIN_FLAG_INHERITANCE;
 
@@ -442,8 +445,6 @@ void init_tintin(int greeting)
 	gtd->mud_output_max = 16384;
 	gtd->mud_output_buf = (char *) calloc(1, gtd->mud_output_max);
 
-
-
 	gtd->os             = strdup(getenv("OS")   ? getenv("OS")   : "UNKNOWN");
 	gtd->home           = strdup(getenv("HOME") ? getenv("HOME") : "~/");
 	gtd->lang           = strdup(getenv("LANG") ? getenv("LANG") : "UNKNOWN");
@@ -452,6 +453,8 @@ void init_tintin(int greeting)
 	gtd->detach_file    = strdup("");
 	gtd->attach_file    = strdup("");
 
+	gtd->tintin_char    = '#';
+
 	gtd->time           = time(NULL);
 	gtd->calendar       = *localtime(&gtd->time);
 
@@ -509,6 +512,7 @@ void init_tintin(int greeting)
 
 	gts = (struct session *) calloc(1, sizeof(struct session));
 
+	gts->created        = gtd->time;
 	gts->name           = strdup("gts");
 	gts->group          = strdup("");
 	gts->session_host   = strdup("");
@@ -549,42 +553,42 @@ void init_tintin(int greeting)
 
 	gtd->level->input++;
 
-	do_configure(gts, "{AUTO TAB}         {5000}");
-	do_configure(gts, "{BUFFER SIZE}     {10000}");
-	do_configure(gts, "{COLOR MODE}         {ON}");
-	do_configure(gts, "{COLOR PATCH}       {OFF}");
-	do_configure(gts, "{COMMAND COLOR}   {<078>}");
-	do_configure(gts, "{COMMAND ECHO}       {ON}");
-	do_configure(gts, "{CONNECT RETRY}       {0}");
-	do_configure(gts, "{CHARSET}          {AUTO}");
-	do_configure(gts, "{HISTORY SIZE}     {1000}");
-	do_configure(gts, "{LOG MODE}          {RAW}");
-	do_configure(gts, "{MOUSE TRACKING}    {OFF}");
-	do_configure(gts, "{PACKET PATCH}     {AUTO}");
-	do_configure(gts, "{RANDOM SEED}      {AUTO}");
-	do_configure(gts, "{REPEAT CHAR}         {!}");
-	do_configure(gts, "{REPEAT ENTER}      {OFF}");
-	do_configure(gts, HAS_BIT(greeting, STARTUP_FLAG_SCREENREADER) ? "{SCREEN READER} {ON}" : "{SCREEN READER} {OFF}");
-	do_configure(gts, "{SCROLL LOCK}        {ON}");
-	do_configure(gts, "{SPEEDWALK}         {OFF}");
-	do_configure(gts, "{TAB WIDTH}        {AUTO}");
-	do_configure(gts, "{TELNET}             {ON}");
-	do_configure(gts, "{TINTIN CHAR}         {#}");
-	do_configure(gts, "{VERBATIM}          {OFF}");
-	do_configure(gts, "{VERBATIM CHAR}      {\\}");
-	do_configure(gts, HAS_BIT(greeting, STARTUP_FLAG_VERBOSE) ? "{VERBOSE} {ON}" : "{VERBOSE} {OFF}");
-	do_configure(gts, "{WORDWRAP}           {ON}");
-
-	do_pathdir(gts, " n  s  1");
-	do_pathdir(gts, " e  w  2");
-	do_pathdir(gts, " s  n  4");
-	do_pathdir(gts, " w  e  8");
-	do_pathdir(gts, " u  d 16");
-	do_pathdir(gts, " d  u 32");
-	do_pathdir(gts, "ne sw  3");
-	do_pathdir(gts, "nw se  9");
-	do_pathdir(gts, "se nw  6");
-	do_pathdir(gts, "sw ne 12");
+	execute(gts, "#CONFIG {AUTO TAB}         {5000}");
+	execute(gts, "#CONFIG {BUFFER SIZE}     {10000}");
+	execute(gts, "#CONFIG {COLOR MODE}         {ON}");
+	execute(gts, "#CONFIG {COLOR PATCH}       {OFF}");
+	execute(gts, "#CONFIG {COMMAND COLOR}   {<078>}");
+	execute(gts, "#CONFIG {COMMAND ECHO}       {ON}");
+	execute(gts, "#CONFIG {CONNECT RETRY}       {0}");
+	execute(gts, "#CONFIG {CHARSET}          {AUTO}");
+	execute(gts, "#CONFIG {HISTORY SIZE}     {1000}");
+	execute(gts, "#CONFIG {LOG MODE}          {RAW}");
+	execute(gts, "#CONFIG {MOUSE TRACKING}    {OFF}");
+	execute(gts, "#CONFIG {PACKET PATCH}     {AUTO}");
+	execute(gts, "#CONFIG {RANDOM SEED}      {AUTO}");
+	execute(gts, "#CONFIG {REPEAT CHAR}         {!}");
+	execute(gts, "#CONFIG {REPEAT ENTER}      {OFF}");
+	execute(gts, "#CONFIG {SCREEN READER}      {%s}", HAS_BIT(greeting, STARTUP_FLAG_SCREENREADER) ? "ON" : "OFF");
+	execute(gts, "#CONFIG {SCROLL LOCK}        {ON}");
+	execute(gts, "#CONFIG {SPEEDWALK}         {OFF}");
+	execute(gts, "#CONFIG {TAB WIDTH}        {AUTO}");
+	execute(gts, "#CONFIG {TELNET}             {ON}");
+	execute(gts, "#CONFIG {TINTIN CHAR}         {#}");
+	execute(gts, "#CONFIG {VERBATIM}          {OFF}");
+	execute(gts, "#CONFIG {VERBATIM CHAR}      {\\}");
+	execute(gts, "#CONFIG {VERBOSE}            {%s}", HAS_BIT(greeting, STARTUP_FLAG_VERBOSE) ? "ON" : "OFF");
+	execute(gts, "#CONFIG {WORDWRAP}           {ON}");
+
+	execute(gts, "#PATHDIR  n  s  1");
+	execute(gts, "#PATHDIR  e  w  2");
+	execute(gts, "#PATHDIR  s  n  4");
+	execute(gts, "#PATHDIR  w  e  8");
+	execute(gts, "#PATHDIR  u  d 16");
+	execute(gts, "#PATHDIR  d  u 32");
+	execute(gts, "#PATHDIR ne sw  3");
+	execute(gts, "#PATHDIR nw se  9");
+	execute(gts, "#PATHDIR se nw  6");
+	execute(gts, "#PATHDIR sw ne 12");
 
 	gtd->level->input--;
 
@@ -603,7 +607,7 @@ void init_tintin(int greeting)
 		{
 			tintin_printf2(gts, "Welcome to TinTin Plus Plus. Don't know which MUD to play? How about the following MUD.");
 
-			do_advertise(gts, "");
+			execute(gts, "ADVERTISE");
 
 			tintin_printf2(gts, "You're using TinTin Plus Plus written by Peter Unold, Bill Reis, and Igor van den Hoven.", CLIENT_VERSION);
 
@@ -611,11 +615,11 @@ void init_tintin(int greeting)
 		}
 		else
 		{
-			do_advertise(gts, "");
+			execute(gts, "#ADVERTISE");
 
 			if (gtd->screen->cols >= 80)
 			{
-				do_help(gts, "GREETING");
+				execute(gts, "#HELP GREETING");
 			}
 			else
 			{
@@ -666,7 +670,7 @@ void quitmsg(char *message)
 
 		sprintf(filename, "%s/%s/%s", gtd->home, TINTIN_DIR, HISTORY_FILE);
 
-		history_write(gts, filename);
+		history_write(gts, filename, "", "");
 	}
 
 	reset_daemon();
@@ -737,7 +741,7 @@ void syserr_signal(int signal, char *msg)
 
 	if (crashed++)
 	{
-		print_stdout("\ecsyserr_signal(crashed)\n");
+		print_stdout("syserr_signal(crashed)\n");
 
 		fflush(NULL);
 
@@ -750,7 +754,7 @@ void syserr_signal(int signal, char *msg)
 
 	fflush(NULL);
 
-	dump_stack_fatal();
+	dump_stack();
 
 	sprintf(buf, "\e[1;31mFATAL SIGNAL FROM (%s): %s\e[0m\n", msg, strsignal(signal));
 
@@ -758,7 +762,7 @@ void syserr_signal(int signal, char *msg)
 
 	fflush(NULL);
 
-	exit(0);
+	abort();
 }
 
 void syserr_fatal(int signal, char *msg)
@@ -768,7 +772,7 @@ void syserr_fatal(int signal, char *msg)
 
 	if (crashed++)
 	{
-		print_stdout("\ecsyserr_fatal(crashed)");
+		print_stdout("syserr_fatal(crashed)");
 
 		fflush(NULL);
 
@@ -795,7 +799,7 @@ void syserr_fatal(int signal, char *msg)
 
 	print_stdout("\e[r");
 
-	dump_stack_fatal();
+	dump_stack();
 
 	sprintf(buf, "\n\e[1;31mFATAL ERROR \e[1;32m%s %s\e[0m\n", msg, errstr);
 
@@ -805,5 +809,5 @@ void syserr_fatal(int signal, char *msg)
 
 	fflush(NULL);
 
-	exit(0);
+	abort();
 }

+ 239 - 127
src/mapper.c

@@ -77,7 +77,6 @@ extern void update_terrain(struct session *ses);
 DO_COMMAND(do_map)
 {
 	int cnt;
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 
 	push_call("do_map(%p,%p)",ses,arg);
 
@@ -85,6 +84,8 @@ DO_COMMAND(do_map)
 
 	if (*arg1 == 0)
 	{
+		info:
+
 		tintin_header(ses, " MAP OPTIONS ");
 
 		for (cnt = 0 ; *map_table[cnt].fun != NULL ; cnt++)
@@ -129,10 +130,6 @@ DO_COMMAND(do_map)
 						SET_BIT(ses->flags, SES_FLAG_UPDATEVTMAP);
 					}
 				}
-				pop_call();
-
-				push_call("MAP_%s(%p,%p,%p,%p,%p)",map_table[cnt].name,ses,arg,arg1,arg2);
-
 				map_table[cnt].fun (ses, arg, arg1, arg2);
 
 				pop_call();
@@ -140,7 +137,7 @@ DO_COMMAND(do_map)
 			}
 		}
 
-		do_map(ses, "");
+		goto info;
 	}
 	pop_call();
 	return ses;
@@ -184,12 +181,12 @@ void create_map(struct session *ses, char *arg)
 		ses->map->global_exit->weight = 1;
 		ses->map->global_exit->color  = strdup("");
 
-	do_map(ses, "{COLOR} {RESET}");
+	execute(ses, "#MAP {COLOR} {RESET}");
 
 	ses->map->display_stamp = 1;
 	ses->map->search->stamp = 1;
 
-	do_map(ses, "TERRAIN {} { }");
+	execute(ses, "#MAP TERRAIN {} { }");
 /*
 	do_map(ses, "TERRAIN BEACH        <eea>~");
 	do_map(ses, "TERRAIN CITY         <ebf>-");
@@ -240,7 +237,7 @@ void create_map(struct session *ses, char *arg)
 	}
 
 	gtd->level->quiet++;
-	do_map(ses, "LEGEND RESET");
+	execute(ses, "#MAP LEGEND RESET");
 	gtd->level->quiet--;
 
 	pop_call();
@@ -267,10 +264,17 @@ int delete_map(struct session *ses)
 		del_undo(ses, ses->map->undo_head);
 	}
 
+//	delete_exit(ses, 0, ses->map->global_exit);
+
 	free(ses->map->global_exit->name);
 	free(ses->map->global_exit->cmd);
 	free(ses->map->global_exit->data);
+	free(ses->map->global_exit->color);
+
+	free(ses->map->grid_rooms);
+	free(ses->map->grid_vnums);
 	free(ses->map->global_exit);
+	free(ses->map->search);
 
 	free(ses->map);
 
@@ -357,6 +361,21 @@ struct room_data *create_room(struct session *ses, char *format, ...)
 	return newroom;
 }
 
+void delete_room_data(struct room_data *room)
+{
+	free(room->area);
+	free(room->color);
+	free(room->id);
+	free(room->name);
+	free(room->symbol);
+	free(room->desc);
+	free(room->note);
+	free(room->terrain);
+	free(room->data); 
+
+	return;
+}
+	
 void delete_room(struct session *ses, int room, int exits)
 {
 	struct exit_data *exit, *exit_next;
@@ -369,15 +388,7 @@ void delete_room(struct session *ses, int room, int exits)
 		delete_exit(ses, room, ses->map->room_list[room]->f_exit);
 	}
 
-	free(ses->map->room_list[room]->area);
-	free(ses->map->room_list[room]->color);
-	free(ses->map->room_list[room]->id);
-	free(ses->map->room_list[room]->name);
-	free(ses->map->room_list[room]->symbol);
-	free(ses->map->room_list[room]->desc);
-	free(ses->map->room_list[room]->note);
-	free(ses->map->room_list[room]->terrain);
-	free(ses->map->room_list[room]->data); 
+	delete_room_data(ses->map->room_list[room]);
 
 	free(ses->map->room_list[room]);
 
@@ -429,6 +440,7 @@ struct exit_data *create_exit(struct session *ses, int vnum, char *format, ...)
 	{
 		free(newexit);
 
+		pop_call();
 		return find_exit(ses, vnum, buf);
 	}
 	newexit->name = strdup(buf);
@@ -465,12 +477,16 @@ struct exit_data *create_exit(struct session *ses, int vnum, char *format, ...)
 
 	show_message(ses, LIST_COMMAND, "#MAP CREATE EXIT {%s} {%s} TO ROOM %d.", newexit->name, newexit->cmd, newexit->vnum);
 
+	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 4, "MAP CREATE EXIT", ntos(room->vnum), newexit->name,newexit->cmd, ntos(newexit->vnum));
+
 	pop_call();
 	return newexit;
 }
 
 void delete_exit(struct session *ses, int room, struct exit_data *exit)
 {
+	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 4, "MAP DELETE EXIT", ntos(room), exit->name, exit->cmd, ntos(exit->vnum));
+
 	free(exit->name);
 	free(exit->cmd);
 	free(exit->data);
@@ -552,11 +568,8 @@ char *get_exit_color(struct session *ses, int room, struct exit_data *exit)
 		pop_call();
 		return ses->map->color[MAP_COLOR_EXIT];
 	}
-	else
-	{
-		pop_call();
-		return "";
-	}
+	pop_call();
+	return "";
 }
 
 int revdir_to_grid(int dir)
@@ -1774,7 +1787,7 @@ int follow_map(struct session *ses, char *argument)
 
 			vnum = tunnel_void(ses, in_room, exit->vnum, exit->dir);
 
-			check_all_events(ses, SUB_ARG, 0, 5, "MAP FOLLOW MAP", ntos(in_room), ntos(vnum), exit->name);
+			check_all_events(ses, SUB_ARG, 0, 4, "MAP FOLLOW MAP", ntos(in_room), ntos(vnum), exit->name, ntos(ses->map->nofollow));
 		}
 		pop_call();
 		return 0;
@@ -1815,7 +1828,7 @@ int follow_map(struct session *ses, char *argument)
 			}
 		}
 
-		check_all_events(ses, SUB_ARG, 0, 5, "MAP FOLLOW MAP", ntos(in_room), ntos(vnum), exit->name);
+		check_all_events(ses, SUB_ARG, 0, 4, "MAP FOLLOW MAP", ntos(in_room), ntos(vnum), exit->name, ntos(ses->map->nofollow));
 
 		add_undo(ses, "%d %d %d", vnum, in_room, MAP_UNDO_MOVE);
 
@@ -3735,7 +3748,7 @@ void map_search_compile(struct session *ses, char *arg, char *var)
 
 		ptb = buf;
 
-		while (*buf)
+		while (*ptb)
 		{
 			ptb = sub_arg_in_braces(ses, ptb, flags, GET_ONE, SUB_NONE);
 
@@ -4826,20 +4839,20 @@ void explore_path(struct session *ses, int run, char *arg1, char *arg2)
 	}
 }
 
-void map_mouse_handler(struct session *ses, char *arg1, char *arg2, int x, int y, int height, int width)
+void map_mouse_handler(struct session *ses, char *arg1, char *arg2, int row, int col, int rev_row, int rev_col, int height, int width)
 {
 	char exit[10];
-	int max_x, max_y;
-	int top_row, top_col, bot_row, bot_col, rows, cols, char_height;
+	int x, y, max_x, max_y;
+	int top_row, top_col, bot_row, bot_col, rows, cols, char_height, vnum = 0;
 
-	push_call("map_mouse_handler(%p,%p,%p,%d,%d)",ses,arg1,arg2,x,y);
+	push_call("map_mouse_handler(%p,%p,%p,%d,%d)",ses,arg1,arg2,row,col);
 
 	if (ses->map == NULL || !HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP) || ses->map->room_list[ses->map->in_room] == NULL)
 	{
 		pop_call();
 		return;
 	}
-
+/*
 	if (!HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
 	{
 		if (arg1 && arg2)
@@ -4847,6 +4860,10 @@ void map_mouse_handler(struct session *ses, char *arg1, char *arg2, int x, int y
 //			do_screen(ses, "{RAISE} {SCREEN MOUSE LOCATION}");
 		}
 	}
+*/
+
+	x = col;
+	y = row;
 
 	exit[0] = 0;
 
@@ -4975,17 +4992,26 @@ void map_mouse_handler(struct session *ses, char *arg1, char *arg2, int x, int y
 		return;
 	}
 
-	if (ses->map->grid_rooms[x + 1 + max_x * (y - 1)])
+	vnum = ses->map->grid_rooms[x + 1 + max_x * (y - 1)] ? ses->map->grid_rooms[x + 1 + max_x * (y - 1)]->vnum : 0;
+
+	if (arg1 && arg2)
+	{
+		check_all_events(ses, SUB_ARG, 2, 6, "MAP REGION %s %s", arg1, arg2, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), ntos(vnum), exit);
+	}
+
+	if (vnum)
 	{
 		if (arg1 && arg2)
 		{
-			check_all_events(ses, SUB_ARG, 2, 2, "MAP %s %s", arg1, arg2, ntos(ses->map->grid_rooms[x + 1 + max_x * (y - 1)]->vnum), exit);
+			check_all_events(ses, SUB_ARG, 2, 6, "MAP %s %s", arg1, arg2, ntos(vnum), exit, ntos(rev_row), ntos(rev_col), ntos(vnum), exit);
+			check_all_events(ses, SUB_ARG, 2, 6, "MAP ROOM %s %s", arg1, arg2, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), ntos(vnum), exit);
 		}
 		else
 		{
-			check_all_events(ses, SUB_ARG, 0, 2, "MAP MOUSE LOCATION", ntos(ses->map->grid_rooms[x + 1 + max_x * (y - 1)]->vnum), exit);
+			check_all_events(ses, SUB_ARG, 0, 2, "MAP MOUSE LOCATION", ntos(vnum), exit, ntos(rev_row), ntos(rev_col), ntos(vnum), exit);
 		}
 	}
+		
 	pop_call();
 	return;
 }
@@ -5026,7 +5052,10 @@ DO_MAP(map_at)
 
 	if (new_room == 0)
 	{
-		new_room = find_location(ses, arg1);
+		if (ses->map->in_room)
+		{
+			new_room = find_location(ses, arg1);
+		}
 
 		if (new_room == 0)
 		{
@@ -5043,6 +5072,7 @@ DO_MAP(map_at)
 	if (ses->map)
 	{
 		ses->map->in_room = ses->map->at_room;
+		ses->map->at_room = 0;
 	}
 }
 
@@ -5196,7 +5226,7 @@ DO_MAP(map_delete)
 			return;
 		}
 	}
-	else
+	else if (ses->map->in_room)
 	{
 		exit = find_exit(ses, ses->map->in_room, arg1);
 
@@ -5207,17 +5237,23 @@ DO_MAP(map_delete)
 
 		if (exit == NULL)
 		{
-			show_error(ses, LIST_COMMAND, "#MAP: No exit with that name found");
+			show_error(ses, LIST_COMMAND, "#MAP DELETE: No exit with that name found");
 			
 			return;
 		}
 
 		room = exit->vnum;
 	}
+	else
+	{
+		show_error(ses, LIST_COMMAND, "#MAP DELETE: You must first enter the map");
+
+		return;
+	}
 
-	if (room == ses->map->in_room)
+	if (room == ses->map->in_room || room == ses->map->at_room)
 	{
-		show_error(ses, LIST_COMMAND, "#MAP: You must first leave the room you're trying to delete");
+		show_error(ses, LIST_COMMAND, "#MAP DELETE: You must first leave the room you're trying to delete");
 		
 		return;
 	}
@@ -5427,17 +5463,19 @@ void exit_edit(struct session *ses, struct exit_data *exit, char *arg, char *arg
 	{
 		tintin_printf2(ses, "      color: %s", str_convert_meta(exit->color, TRUE));
 		tintin_printf2(ses, "    command: %s", exit->cmd);
+		tintin_printf2(ses, "       data: %s", exit->data);
 		tintin_printf2(ses, "destination: %d", tunnel_void(ses, ses->map->in_room, exit->vnum, exit->dir));
 		tintin_printf2(ses, "  direction: %d", exit->dir);
 		tintin_printf2(ses, "      flags: %d", exit->flags);
-		tintin_printf2(ses, "    get/set: %s", exit->data);
 		tintin_printf2(ses, "       name: %s", exit->name);
 		tintin_printf2(ses, "       vnum: %d", exit->vnum);
 		tintin_printf2(ses, "     weight: %.3f", exit->weight);
 	}
 	else if (is_abbrev(arg2, "COLOR"))
 	{
-		RESTRING(exit->color, arg3);
+		translate_color_names(ses, arg3, arg2);
+
+		RESTRING(exit->color, arg2);
 
 		show_message(ses, LIST_COMMAND, "#MAP %s {%s} : COLOR SET TO {%s}.", arg, arg1, exit->color);
 	}
@@ -5495,7 +5533,7 @@ void exit_edit(struct session *ses, struct exit_data *exit, char *arg, char *arg
 	{
 		if (*arg3)
 		{
-			set_nest_node_ses(ses, arg3, "{command}{%s}{destination}{%d}{dir}{%d}{flags}{%d}{name}{%s}{vnum}{%d}{weight}{%.3f}", exit->cmd, tunnel_void(ses, ses->map->in_room, exit->vnum, exit->dir), exit->dir, exit->flags, exit->name, exit->vnum, exit->weight);
+			set_nest_node_ses(ses, arg3, "{color}{%s}{command}{%s}{destination}{%d}{dir}{%d}{flags}{%d}{name}{%s}{vnum}{%d}{weight}{%.3f}", exit->color, exit->cmd, tunnel_void(ses, ses->map->in_room, exit->vnum, exit->dir), exit->dir, exit->flags, exit->name, exit->vnum, exit->weight);
 		}
 		else
 		{
@@ -6431,8 +6469,8 @@ void map_legend_index(struct session *ses, char *arg, int head, int tail)
 		{
 			numbertocharacter(ses, esc);
 		}
-		snprintf(ses->map->legend[cnt],     LEGEND_SIZE - 1, "%s", esc);
-		snprintf(ses->map->legend_raw[cnt], LEGEND_SIZE - 1, "%s", raw);
+		sprintf(ses->map->legend[cnt],     "%.*s", LEGEND_SIZE - 1, esc);
+		sprintf(ses->map->legend_raw[cnt], "%.*s", LEGEND_SIZE - 1, raw);
 
 		if (*arg == 0)
 		{
@@ -6786,8 +6824,16 @@ DO_MAP(map_map)
 
 				logfile = fopen(arg4, "a");
 
-				loginit(ses, logfile, LOG_FLAG_APPEND | HAS_BIT(ses->logmode, LOG_FLAG_HTML));
-
+				if (logfile)
+				{
+					loginit(ses, logfile, LOG_FLAG_APPEND | HAS_BIT(ses->logmode, LOG_FLAG_HTML));
+				}
+				else
+				{
+					show_error(ses, LIST_COMMAND, "#ERROR: #MAP MAP {%s} {%s} {%s} FAILED TO OPEN FILE {%s}", arg1, arg2, arg3, arg4);
+					pop_call();
+					return;
+				}
 				break;
 
 			case 'd':
@@ -6797,6 +6843,7 @@ DO_MAP(map_map)
 				if (*arg4 == 0)
 				{
 					show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP MAP {%s} {%s} {%s} {square}", arg1, arg2, arg3);
+
 					pop_call();
 					return;
 				}
@@ -6808,8 +6855,16 @@ DO_MAP(map_map)
 
 				logfile = fopen(arg4, "w");
 
-				loginit(ses, logfile, LOG_FLAG_OVERWRITE | HAS_BIT(ses->logmode, LOG_FLAG_HTML));
-
+				if (logfile)
+				{
+					loginit(ses, logfile, LOG_FLAG_OVERWRITE | HAS_BIT(ses->logmode, LOG_FLAG_HTML));
+				}
+				else
+				{
+					show_error(ses, LIST_COMMAND, "#ERROR: #MAP MAP {%s} {%s} {%s} FAILED TO OPEN FILE {%s}", arg1, arg2, arg3, arg4);
+					pop_call();
+					return;
+				}
 				break;
 
 			case 'l':
@@ -6817,6 +6872,12 @@ DO_MAP(map_map)
 				strcpy(arg3, "LIST");
 				break;
 
+			case 's':
+			case 'S':
+				strcpy(arg3, "SAVE");
+				strcpy(arg4, "SAVE");
+				break;
+
 			case 'v':
 			case 'V':
 				strcpy(arg3, "VARIABLE");
@@ -6887,7 +6948,7 @@ DO_MAP(map_map)
 		{
 			for (line = 1 ; line <= 3 ; line++)
 			{
-				str_cpy(&gtd->buf, ses->map->color[MAP_COLOR_BACK]);
+				gtd->buf = str_cpy_printf(&gtd->buf, "\e[m%s", ses->map->color[MAP_COLOR_BACK]);
 
 				for (x = 1 ; x < map_grid_x - 1 ; x++)
 				{
@@ -6896,23 +6957,31 @@ DO_MAP(map_map)
 
 				str_clone(&gtd->out, gtd->buf);
 
-				substitute(ses, gtd->buf, gtd->out, SUB_COL|SUB_CMP|SUB_LIT);
+				substitute(ses, gtd->buf, gtd->out, SUB_COL|SUB_CMP|SUB_SEC);
 
-				if (logfile)
-				{
-					logit(ses, gtd->out, logfile, LOG_FLAG_LINEFEED);
-				}
-				else if (*arg3 == 'L')
-				{
-					cat_sprintf(arg1, "{%02d}{%s}", ++row, gtd->out);
-				}
-				else if (*arg3 == 'V' || *arg3 == 'D')
+				switch (*arg3)
 				{
-					cat_sprintf(arg1, "%s\n", gtd->out);
-				}
-				else
-				{
-					tintin_puts2(ses, gtd->out);
+					case 'A':
+					case 'O':
+						logit(ses, gtd->out, logfile, LOG_FLAG_LINEFEED);
+						break;
+					
+					case 'L':
+						cat_sprintf(arg1, "{%02d}{%s}", ++row, gtd->out);
+						break;
+
+					case 'S':
+						cat_sprintf(arg1, "\n%s", gtd->out);
+						break;
+
+					case 'D':
+					case 'V':
+						cat_sprintf(arg1, "%s\n", gtd->out);
+						break;
+
+					default:
+						tintin_puts2(ses, gtd->out);
+						break;
 				}
 			}
 		}
@@ -6923,7 +6992,7 @@ DO_MAP(map_map)
 		{
 			for (line = 1 ; line <= 2 ; line++)
 			{
-				str_cpy(&gtd->buf, ses->map->color[MAP_COLOR_BACK]);
+				str_cpy_printf(&gtd->buf, "\e[m%s", ses->map->color[MAP_COLOR_BACK]);
 
 				for (x = 1 ; x < map_grid_x - 1 ; x++)
 				{
@@ -6937,28 +7006,35 @@ DO_MAP(map_map)
 					{
 						str_cat(&gtd->buf, draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], line, x, y));
 					}
-//					str_cat(&gtd->buf, draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], line, x, y));
 				}
 
 				str_clone(&gtd->out, gtd->buf);
 
 				substitute(ses, gtd->buf, gtd->out, SUB_COL|SUB_CMP|SUB_LIT);
 
-				if (logfile)
-				{
-					fprintf(logfile, "%s\n", gtd->out);
-				}
-				else if (*arg3 == 'L')
+				switch (*arg3)
 				{
-					cat_sprintf(arg1, "{%02d}{%s\e[0m}", ++row, gtd->out);
-				}
-				else if (*arg3 == 'V' || *arg3 == 'D')
-				{
-					cat_sprintf(arg1, "%s\e[0m\n", gtd->out);
-				}
-				else
-				{
-					tintin_puts2(ses, gtd->out);
+					case 'A':
+					case 'O':
+						fprintf(logfile, "%s\n", gtd->out);
+						break;
+
+					case 'L':
+						cat_sprintf(arg1, "{%02d}{%s\e[0m}", ++row, gtd->out);
+						break;
+
+					case 'S':
+						cat_sprintf(arg1, "\n%s\e[0m", gtd->out);
+						break;
+
+					case 'D':
+					case 'V':
+						cat_sprintf(arg1, "%s\e[0m\n", gtd->out);
+						break;
+
+					default:
+						tintin_puts2(ses, gtd->out);
+						break;
 				}
 			}
 		}
@@ -6969,7 +7045,7 @@ DO_MAP(map_map)
 		{
 			for (line = 1 ; line <= 2 ; line++)
 			{
-				str_cpy(&gtd->buf, ses->map->color[MAP_COLOR_BACK]);
+				str_cpy_printf(&gtd->buf, "\e[m%s", ses->map->color[MAP_COLOR_BACK]);
 
 				for (x = 1 ; x < map_grid_x - 1 ; x++)
 				{
@@ -6980,21 +7056,29 @@ DO_MAP(map_map)
 
 				substitute(ses, gtd->buf, gtd->out, SUB_COL|SUB_CMP|SUB_LIT);
 
-				if (logfile)
-				{
-					fprintf(logfile, "%s\n", gtd->out);
-				}
-				else if (*arg3 == 'L')
+				switch (*arg3)
 				{
-					cat_sprintf(arg1, "{%02d}{%s\e[0m}", ++row, gtd->out);
-				}
-				else if (*arg3 == 'V' || *arg3 == 'D')
-				{
-					cat_sprintf(arg1, "%s\e[0m\n", gtd->out);
-				}
-				else
-				{
-					tintin_puts2(ses, gtd->out);
+					case 'A':
+					case 'O':
+						fprintf(logfile, "%s\n", gtd->out);
+						break;
+
+					case 'L':
+						cat_sprintf(arg1, "{%02d}{%s\e[0m}", ++row, gtd->out);
+						break;
+
+					case 'S':
+						cat_sprintf(arg1, "\n%s\e[0m", gtd->out);
+						break;
+
+					case 'D':
+					case 'V':
+						cat_sprintf(arg1, "%s\e[0m\n", gtd->out);
+						break;
+
+					default:
+						tintin_puts2(ses, gtd->out);
+						break;
 				}
 			}
 		}
@@ -7003,7 +7087,7 @@ DO_MAP(map_map)
 	{
 		for (y = map_grid_y - 2 ; y >= 1 ; y--)
 		{
-			str_cpy(&gtd->buf, ses->map->color[MAP_COLOR_BACK]);
+			str_cpy_printf(&gtd->buf, "\e[m%s", ses->map->color[MAP_COLOR_BACK]);
 
 			for (x = 1 ; x < map_grid_x - 1 ; x++)
 			{
@@ -7012,40 +7096,55 @@ DO_MAP(map_map)
 
 			substitute(ses, gtd->buf, gtd->out, SUB_COL|SUB_CMP|SUB_LIT);
 
-			if (logfile)
-			{
-				fprintf(logfile, "%s\n", gtd->out);
-			}
-			else if (*arg3 == 'L')
-			{
-				cat_sprintf(arg1, "{%02d}{%s}", ++row, gtd->out);
-			}
-			else if (*arg3 == 'V' || *arg3 == 'D')
-			{
-				cat_sprintf(arg1, "%s\n", gtd->out);
-			}
-			else
+			switch (*arg3)
 			{
-				tintin_puts2(ses, gtd->out);
+				case 'A':
+				case 'O':
+					fprintf(logfile, "%s\n", gtd->out);
+					break;
+				
+				case 'L':
+					cat_sprintf(arg1, "{%02d}{%s}", ++row, gtd->out);
+					break;
+
+				case 'S':
+					cat_sprintf(arg1, "\n%s", gtd->out);
+					break;
+
+				case 'D':
+				case 'V':
+					cat_sprintf(arg1, "%s\n", gtd->out);
+					break;
+				
+				default:
+					tintin_puts2(ses, gtd->out);
+					break;
 			}
 		}
 	}
 
-	if (logfile)
-	{
-		fclose(logfile);
-	}
-	else if (*arg3 == 'D')
-	{
-		draw_map(ses, 1, 2, 3, 4, 5, 6, 7, "", arg4, arg2, arg1);
-	}
-	else if (*arg3 == 'L')
-	{
-		set_nest_node_ses(ses, arg4, "%s", arg1);
-	}
-	else if (*arg3 == 'V')
+	switch (*arg3)
 	{
-		set_nest_node_ses(ses, arg4, "%s", arg1);
+		case 'A':
+		case 'O':
+			fclose(logfile);
+			break;
+
+		case 'D':
+			draw_arg(ses, 1, 2, 3, 4, 5, 6, 7, "", arg4, arg2, arg1);
+			break;
+
+		case 'S':
+			str_cpy(&gtd->buf, arg1);
+			break;
+
+		case 'L':
+			set_nest_node_ses(ses, arg4, "%s", arg1);
+			break;
+
+		case 'V':
+			set_nest_node_ses(ses, arg4, "%s", arg1);
+			break;
 	}
 
 	pop_call();
@@ -8171,6 +8270,8 @@ DO_MAP(map_unlink)
 
 DO_MAP(map_update)
 {
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+
 	if (ses->map == NULL)
 	{
 		show_message(ses, LIST_COMMAND, "#MAP UPDATE: NO MAP DATA.");
@@ -8189,9 +8290,20 @@ DO_MAP(map_update)
 	}
 	else
 	{
-		show_message(ses, LIST_COMMAND, "#MAP UPDATE: OK.");
-		
-		SET_BIT(ses->flags, SES_FLAG_UPDATEVTMAP);
+		if (is_abbrev(arg1, "NOW"))
+		{
+			show_message(ses, LIST_COMMAND, "#MAP UPDATE: MAP UPDATING NOW.");
+
+			DEL_BIT(ses->flags, SES_FLAG_UPDATEVTMAP);
+
+			show_vtmap(ses);
+		}
+		else
+		{
+			show_message(ses, LIST_COMMAND, "#MAP UPDATE: MAP SCHEDULED FOR UPDATE.");
+
+			SET_BIT(ses->flags, SES_FLAG_UPDATEVTMAP);
+		}
 	}
 }
 

+ 75 - 8
src/math.c

@@ -54,7 +54,6 @@ int precision;
 
 DO_COMMAND(do_math)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 	struct listnode *node;
 	long double result;
 
@@ -299,8 +298,53 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 						break;
 
 					case '!':
+						if (pta != buf3)
+						{
+							MATH_NODE(FALSE, EXP_PR_VAR, EXP_OPERATOR);
+						}
+						else
+						{
+							add_math_node(ntos(level), ntos(EXP_PR_VAR), "0");
+							add_math_node(ntos(level), ntos(EXP_PR_LOGCOMP), "==");
+
+							*pta++ = *pti++;
+
+							pta = buf3;
+						}
+						break;
+
 					case '~':
+						if (pta != buf3)
+						{
+							MATH_NODE(FALSE, EXP_PR_VAR, EXP_OPERATOR);
+						}
+						else
+						{
+							add_math_node(ntos(level), ntos(EXP_PR_VAR), "-1");
+							add_math_node(ntos(level), ntos(EXP_PR_INTADD), "-");
+
+							*pta++ = *pti++;
+
+							pta = buf3;
+						}
+						break;
+
 					case '+':
+						if (pta != buf3)
+						{
+							MATH_NODE(FALSE, EXP_PR_VAR, EXP_OPERATOR);
+						}
+						else
+						{
+							add_math_node(ntos(level), ntos(EXP_PR_VAR), "1");
+							add_math_node(ntos(level), ntos(EXP_PR_INTMUL), "*");
+
+							*pta++ = *pti++;
+
+							pta = buf3;
+						}
+						break;
+
 					case '-':
 						if (pta != buf3)
 						{
@@ -308,7 +352,12 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 						}
 						else
 						{
+							add_math_node(ntos(level), ntos(EXP_PR_VAR), "-1");
+							add_math_node(ntos(level), ntos(EXP_PR_INTMUL), "*");
+
 							*pta++ = *pti++;
+
+							pta = buf3;
 						}
 						break;
 
@@ -349,8 +398,11 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 							}
 							return FALSE;
 						}
-						*pta++ = *pti++;
-						MATH_NODE(FALSE, EXP_PR_LVL, EXP_VARIABLE);
+						else
+						{
+							*pta++ = *pti++;
+							MATH_NODE(FALSE, EXP_PR_LVL, EXP_VARIABLE);
+						}
 						level++;
 						break;
 
@@ -399,6 +451,15 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 					case '^':
 					case '|':
 					case '=':
+						if (pti == str)
+						{
+							if (debug)
+							{
+								show_debug(ses, LIST_VARIABLE, "#MATH EXP: EXPRESSION STARTED WITH AN OPERATOR.");
+							}
+							return FALSE;
+						}
+
 						if (pta != buf3)
 						{
 							MATH_NODE(FALSE, EXP_PR_VAR, EXP_OPERATOR);
@@ -925,15 +986,18 @@ void mathexp_compute(struct session *ses, struct link_data *node)
 		case '-':
 			value = tintoi(node->prev->str3) - tintoi(node->next->str3);
 			break;
+
 		case '<':
 			switch (node->str3[1])
 			{
 				case '=':
 					value = tincmp(node->prev->str3, node->next->str3) <= 0;
 					break;
+
 				case '<':
-					value = atoll(node->prev->str3) << atoll(node->next->str3);
+					value = (long long) tintoi(node->prev->str3) << (long long) tintoi(node->next->str3);
 					break;
+
 				default:
 					value = tincmp(node->prev->str3, node->next->str3) < 0;
 					break;
@@ -945,9 +1009,11 @@ void mathexp_compute(struct session *ses, struct link_data *node)
 				case '=':
 					value = tincmp(node->prev->str3, node->next->str3) >= 0;
 					break;
+
 				case '>':
-					value = atoll(node->prev->str3) >> atoll(node->next->str3);
+					value = (long long) tintoi(node->prev->str3) >> (long long) tintoi(node->next->str3);
 					break;
+
 				default:
 					value = tincmp(node->prev->str3, node->next->str3) > 0;
 					break;
@@ -960,8 +1026,9 @@ void mathexp_compute(struct session *ses, struct link_data *node)
 				case '&':
 					value = tintoi(node->prev->str3) && tintoi(node->next->str3);
 					break;
+
 				default:
-					value = atoll(node->prev->str3) & atoll(node->next->str3);
+					value = (long long) tintoi(node->prev->str3) & (long long) tintoi(node->next->str3);
 					break;
 			}
 			break;
@@ -973,7 +1040,7 @@ void mathexp_compute(struct session *ses, struct link_data *node)
 					break;
 
 				default:
-					value = atoll(node->prev->str3) ^ atoll(node->next->str3);
+					value = (long long) tintoi(node->prev->str3) ^ (long long) tintoi(node->next->str3);
 					break;
 			}
 			break;
@@ -985,7 +1052,7 @@ void mathexp_compute(struct session *ses, struct link_data *node)
 					break;
 
 				default:
-					value = atoll(node->prev->str3) | atoll(node->next->str3);
+					value = (long long) tintoi(node->prev->str3) | (long long) tintoi(node->next->str3);
 					break;
 			}
 			break;

+ 126 - 63
src/memory.c

@@ -57,45 +57,78 @@ char *restringf(char *point, char *fmt, ...)
 	str_ functions
 */
 
-char *str_alloc(int size)
+struct str_data *str_calloc(int size)
 {
-	char *str;
-
 	struct str_data *str_ptr = (struct str_data *) calloc(1, sizeof(struct str_data) + size + 1);
 
-	LINK(str_ptr, gtd->memory->next, gtd->memory->prev);
-
-	gtd->memory->max++;
+	LINK(str_ptr, gtd->memory->alloc->next, gtd->memory->alloc->prev);
 
 	str_ptr->max = size + 1;
 	str_ptr->len = 0;
 
-	str = (char *) str_ptr + sizeof(struct str_data);
+	return str_ptr;
+}
+
+char *str_alloc(int size)
+{
+	struct str_data *str_ptr;
+	char *str;
 
-	*str = 0;
+	str_ptr = str_calloc(size);
+
+	str = (char *) str_ptr + sizeof(struct str_data);
 
 	return str;
 }
 
 struct str_data *str_realloc(struct str_data *str_ptr, int size)
 {
+	struct str_data *new_ptr;
+
+	push_call("str_realloc(%p,%d) (%d,%d,%p,%p)",str_ptr,size, str_ptr->len, str_ptr->max, str_ptr->next, str_ptr->prev);
+
+	if (str_ptr->max <= str_ptr->len)
+	{
+		tintin_printf2(gtd->ses, "\e[1;35mstr_realloc: we got problem\n");
+	}
+
 	if (str_ptr->max <= size)
 	{
-		int len = str_ptr->len;
+//		int len = str_ptr->len;
 
-		UNLINK(str_ptr, gtd->memory->next, gtd->memory->prev);
+		UNLINK(str_ptr, gtd->memory->alloc->next, gtd->memory->alloc->prev);
 
-		str_ptr = (struct str_data *) realloc(str_ptr, sizeof(struct str_data) + size + 1);
+		new_ptr = (struct str_data *) realloc(str_ptr, sizeof(struct str_data) + size + 1);
 
-		LINK(str_ptr, gtd->memory->next, gtd->memory->prev);
+		if (new_ptr == NULL)
+		{
+			printf("str_realloc: failed to realloc mem.\n");
+		}
+		else
+		{
+			str_ptr = new_ptr;
+		}
+
+		LINK(str_ptr, gtd->memory->alloc->next, gtd->memory->alloc->prev);
 
 		str_ptr->max = size + 1;
-		str_ptr->len = len;
+//		str_ptr->len = len;
 	}
+	pop_call();
 	return str_ptr;
 }
 
-struct str_data *str_resize(struct str_data *str_ptr, int add)
+struct str_data *get_str_ptr(char *str)
+{
+	return (struct str_data *) (str - sizeof(struct str_data));
+}
+
+char *get_str_str(struct str_data *str_ptr)
+{
+	return (char *) str_ptr + sizeof(struct str_data);
+}
+
+struct str_data *str_ptr_resize(struct str_data *str_ptr, int add)
 {
 	int len = str_ptr->len;
 
@@ -106,6 +139,18 @@ struct str_data *str_resize(struct str_data *str_ptr, int add)
 	return str_ptr;
 }
 
+char *str_resize(char **str, int add)
+{
+	struct str_data *str_ptr = get_str_ptr(*str);
+
+	str_ptr = str_ptr_resize(str_ptr, add);
+
+	*str = get_str_str(str_ptr);
+
+	return *str;
+}
+
+
 // like str_dup but return an empty string
 
 char *str_mim(char *original)
@@ -121,14 +166,15 @@ char *str_mim(char *original)
 
 void str_clone(char **clone, char *original)
 {
-	struct str_data *clo_ptr = (struct str_data *) (*clone - sizeof(struct str_data));
+	struct str_data *clo_ptr = get_str_ptr(*clone);
+
 	int len = str_len(original);
 
 	if (clo_ptr->max < len)
 	{
 		clo_ptr = str_realloc(clo_ptr, len * 2);
 
-		*clone = (char *) clo_ptr + sizeof(struct str_data);
+		*clone = get_str_str(clo_ptr);
 	}
 }
 
@@ -147,18 +193,23 @@ char *str_dup_clone(char *original)
 
 // call after a non str_ function alters *str to set the correct length.
 
-void str_fix(char *original)
+int str_fix(char *original)
 {
-	struct str_data *str_ptr = (struct str_data *) (original - sizeof(struct str_data));
+	struct str_data *str_ptr = get_str_ptr(original);
 
 	str_ptr->len = strlen(original);
+
+	return str_ptr->len;
 }
 
 int str_len(char *str)
 {
-	struct str_data *str_ptr = (struct str_data *) (str - sizeof(struct str_data));
+	return get_str_ptr(str)->len;
+}
 
-	return str_ptr->len;
+int str_max(char *str)
+{
+	return get_str_ptr(str)->max;
 }
 
 char *str_dup(char *original)
@@ -196,13 +247,13 @@ char *str_cpy(char **str, char *buf)
 
 	buf_len = strlen(buf);
 
-	str_ptr = (struct str_data *) (*str - sizeof(struct str_data));
+	str_ptr = get_str_ptr(*str);
 
 	if (str_ptr->max <= buf_len)
 	{
 		str_ptr = str_realloc(str_ptr, buf_len);
 
-		*str = (char *) str_ptr + sizeof(struct str_data);
+		*str = get_str_str(str_ptr);
 	}
 	str_ptr->len = buf_len;
 
@@ -211,20 +262,20 @@ char *str_cpy(char **str, char *buf)
 	return *str;
 }
 
-char *str_cpy_printf(char **ptr, char *fmt, ...)
+char *str_cpy_printf(char **str, char *fmt, ...)
 {
-	char *str;
+	char *arg;
 	va_list args;
 
 	va_start(args, fmt);
-	vasprintf(&str, fmt, args);
+	vasprintf(&arg, fmt, args);
 	va_end(args);
 
-	str_cpy(ptr, str);
+	str_cpy(str, arg);
 
-	free(str);
+	free(arg);
 
-	return *ptr;
+	return *str;
 }
 
 // unused
@@ -245,20 +296,15 @@ char *str_ncpy(char **str, char *buf, int len)
 	int buf_len;
 	struct str_data *str_ptr;
 
-	buf_len = strlen(buf);
-
-	if (buf_len > len)
-	{
-		buf_len = len;
-	}
+	buf_len = strnlen(buf, len);
 
-	str_ptr = (struct str_data *) (*str - sizeof(struct str_data));
+	str_ptr = get_str_ptr(*str);
 
 	if (str_ptr->max <= buf_len)
 	{
 		str_ptr = str_realloc(str_ptr, len);
 
-		*str = (char *) str_ptr + sizeof(struct str_data);
+		*str = get_str_str(str_ptr);
 	}
 
 	str_ptr->len = UMIN(buf_len, len);
@@ -270,42 +316,40 @@ char *str_ncpy(char **str, char *buf, int len)
 	return *str;
 }
 
-char *str_cat(char **str, char *buf)
+char *str_cat(char **str, char *arg)
 {
-	int buf_len;
+	int arg_len;
 	struct str_data *str_ptr;
 
-	buf_len = strlen(buf);
+	arg_len = strlen(arg);
 
-	str_ptr = (struct str_data *) (*str - sizeof(struct str_data));
+	str_ptr = get_str_ptr(*str);
 
-	if (str_ptr->max <= str_ptr->len + buf_len)
+	if (str_ptr->max <= str_ptr->len + arg_len)
 	{
-		str_ptr = str_resize(str_ptr, buf_len);
+		str_ptr = str_ptr_resize(str_ptr, arg_len);
 
-		*str = (char *) str_ptr + sizeof(struct str_data);
+		*str = get_str_str(str_ptr);
 	}
 
-	strcpy(&(*str)[str_ptr->len], buf);
+	strcpy(&(*str)[str_ptr->len], arg);
 
-	str_ptr->len += buf_len;
+	str_ptr->len += arg_len;
 
 	return *str;
 }
 
-// Unused
-
 char *str_cat_chr(char **ptr, char chr)
 {
 	struct str_data *str_ptr;
 
-	str_ptr = (struct str_data *) (*ptr - sizeof(struct str_data));
+	str_ptr = get_str_ptr(*ptr);
 
 	if (str_ptr->max <= str_ptr->len + 1)
 	{
-		str_ptr = str_resize(str_ptr, 1);
+		str_ptr = str_ptr_resize(str_ptr, 1);
 
-		*ptr = (char *) str_ptr + sizeof(struct str_data);
+		*ptr = get_str_str(str_ptr);
 	}
 
 	(*ptr)[str_ptr->len++] = chr;
@@ -316,20 +360,20 @@ char *str_cat_chr(char **ptr, char chr)
 }
 	
 
-char *str_cat_printf(char **ptr, char *fmt, ...)
+char *str_cat_printf(char **str, char *fmt, ...)
 {
-	char *str;
+	char *arg;
 	va_list args;
 
 	va_start(args, fmt);
-	vasprintf(&str, fmt, args);
+	vasprintf(&arg, fmt, args);
 	va_end(args);
 
-	str_cat(ptr, str);
+	str_cat(str, arg);
 
-	free(str);
+	free(arg);
 
-	return *ptr;
+	return *str;
 }
 
 char *str_ins(char **str, int index, char *buf)
@@ -339,13 +383,13 @@ char *str_ins(char **str, int index, char *buf)
 
 	buf_len = strlen(buf);
 
-	str_ptr = (struct str_data *) (*str - sizeof(struct str_data));
+	str_ptr = get_str_ptr(*str);
 
 	if (str_ptr->max <= str_ptr->len + buf_len)
 	{
-		str_ptr = str_resize(str_ptr, buf_len);
+		str_ptr = str_ptr_resize(str_ptr, buf_len);
 
-		*str = (char *) str_ptr + sizeof(struct str_data);
+		*str = get_str_str(str_ptr);
 	}
 
 	if (index >= str_ptr->len)
@@ -381,11 +425,30 @@ char *str_ins(char **str, int index, char *buf)
 
 void str_free(char *ptr)
 {
-	struct str_data *str_ptr = (struct str_data *) (ptr - sizeof(struct str_data));
+	struct str_data *str_ptr = get_str_ptr(ptr);
 
-	UNLINK(str_ptr, gtd->memory->next, gtd->memory->prev);
-
-	gtd->memory->max--;
+	UNLINK(str_ptr, gtd->memory->alloc->next, gtd->memory->alloc->prev);
 
 	free(str_ptr);
 }
+
+// stack handling
+
+char *str_alloc_stack()
+{
+	struct str_data *str_ptr;
+
+	if (gtd->memory->stack_len == gtd->memory->stack_max)
+	{
+		gtd->memory->stack_max++;
+
+		gtd->memory->stack = (struct str_data **) realloc(gtd->memory->stack, sizeof(struct str_data *) * gtd->memory->stack_max);
+
+		gtd->memory->stack[gtd->memory->stack_len] = str_calloc(BUFFER_SIZE);
+	}
+	str_ptr = gtd->memory->stack[gtd->memory->stack_len++];
+
+	str_ptr->len = 0;
+
+	return get_str_str(str_ptr);
+}

+ 26 - 17
src/misc.c

@@ -29,8 +29,6 @@
 
 DO_COMMAND(do_bell)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
-
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
 
@@ -109,7 +107,7 @@ DO_COMMAND(do_bell)
 
 DO_COMMAND(do_commands)
 {
-	char buf[BUFFER_SIZE] = { 0 }, add[BUFFER_SIZE];
+	char buf[BUFFER_SIZE] = { 0 };
 	int cmd;
 
 	tintin_header(ses, " %s ", "COMMANDS");
@@ -120,20 +118,25 @@ DO_COMMAND(do_commands)
 		{
 			continue;
 		}
-		if ((int) strlen(buf) + 20 > gtd->screen->cols)
+
+		if (strip_vt102_strlen(ses, buf) + 20 > gtd->screen->cols)
 		{
 			tintin_puts2(ses, buf);
 			buf[0] = 0;
 		}
-		sprintf(add, "%20s", command_table[cmd].name);
-		strcat(buf, add);
+		if (command_table[cmd].type == TOKEN_TYPE_COMMAND)
+		{
+			cat_sprintf(buf, "%s%20s", COLOR_COMMAND, command_table[cmd].name);
+		}
+		else
+		{
+			cat_sprintf(buf, "%s%20s", COLOR_STATEMENT, command_table[cmd].name);
+		}
 	}
 	if (buf[0])
 	{
 		tintin_puts2(ses, buf);
 	}
-	tintin_header(ses, "");
-
 	return ses;
 }
 
@@ -214,8 +217,6 @@ DO_COMMAND(do_echo)
 
 DO_COMMAND(do_end)
 {
-	char arg1[BUFFER_SIZE];
-
 	if (*arg)
 	{
 		sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN|SUB_COL|SUB_ESC|SUB_LNF);
@@ -238,8 +239,6 @@ DO_COMMAND(do_nop)
 
 DO_COMMAND(do_send)
 {
-	char arg1[BUFFER_SIZE];
-
 	push_call("do_send(%p,%p)",ses,arg);
 
 	get_arg_in_braces(ses, arg, arg1, GET_ALL);
@@ -252,24 +251,34 @@ DO_COMMAND(do_send)
 
 
 
-
 DO_COMMAND(do_test)
 {
-	char arg1[BUFFER_SIZE], arg2[100], arg3[100], arg4[100];
+	if (!strcmp(arg, "string"))
+	{
+		char *test = str_dup("\e[32m0 2 4 6 8 A C E");
+
+		test = str_ins_str(ses, &test, "\e[33mbli bli", 4, 11);
+
+		printf("test: [%s]\n", test);
+
+		str_free(test);
+		
+		return ses;
+	}
 
 	strcpy(arg2, "9");
 	strcpy(arg3, "<f0b8>");
 	strcpy(arg4, "1 9");
 
-	if (isdigit(arg[0]))
+	if (isdigit((int) arg[0]))
 	{
 		sprintf(arg2, "%d", (arg[0] - '0') * (arg[0] - '0'));
 
-		if ((isxdigit(arg[1]) && isxdigit(arg[2]) && isxdigit(arg[3])) || (arg[1] == '?' && arg[2] == '?' && arg[3] == '?'))
+		if ((isxdigit((int) arg[1]) && isxdigit((int) arg[2]) && isxdigit((int) arg[3])) || (arg[1] == '?' && arg[2] == '?' && arg[3] == '?'))
 		{
 			sprintf(arg3, "<f%c%c%c>", arg[1], arg[2], arg[3]);
 
-			if (isdigit(arg[4]) && isdigit(arg[5]))
+			if (isdigit((int) arg[4]) && isdigit((int) arg[5]))
 			{
 				sprintf(arg4, "%f %d %s", (arg[4] - '0') * (arg[4] - '0') / 10.0, (arg[5] - '0') * (arg[5] - '0'), &arg[6]);
 

+ 5 - 5
src/msdp.c

@@ -176,7 +176,7 @@ void msdp_update_varf(struct session *ses, struct port_data *buddy, char *var, c
 
 void msdp_update_var_instant(struct session *ses, struct port_data *buddy, char *var, char *fmt, ...)
 {
-	char buf[STRING_SIZE];
+	char buf[BUFFER_SIZE], out[STRING_SIZE];
 	int index, length;
 	va_list args;
 
@@ -200,9 +200,9 @@ void msdp_update_var_instant(struct session *ses, struct port_data *buddy, char
 
 	if (HAS_BIT(buddy->msdp_data[index]->flags, MSDP_FLAG_REPORTED))
 	{
-		length = sprintf(buf, "%c%c%c%c%s%c%s%c%c", IAC, SB, TELOPT_MSDP, MSDP_VAR, msdp_table[index].name, MSDP_VAL, buf, IAC, SE);
+		length = sprintf(out, "%c%c%c%c%s%c%s%c%c", IAC, SB, TELOPT_MSDP, MSDP_VAR, msdp_table[index].name, MSDP_VAL, buf, IAC, SE);
 
-		write_msdp_to_descriptor(ses, buddy, buf, length);
+		write_msdp_to_descriptor(ses, buddy, out, length);
 	}
 }
 
@@ -683,9 +683,9 @@ struct msdp_type msdp_table[] =
 	{    "SCREEN_COLS",                   MSDP_FLAG_SENDABLE|MSDP_FLAG_REPORTABLE,  PORT_RANK_SPY,   NULL },
 	{    "SCREEN_FOCUS",                  MSDP_FLAG_SENDABLE|MSDP_FLAG_REPORTABLE,  PORT_RANK_SPY,   NULL },
 	{    "SCREEN_HEIGHT",                 MSDP_FLAG_SENDABLE|MSDP_FLAG_REPORTABLE,  PORT_RANK_SPY,   NULL },
+	{    "SCREEN_LOCATION_HEIGHT",        MSDP_FLAG_SENDABLE|MSDP_FLAG_REPORTABLE,  PORT_RANK_SPY,   NULL },
+	{    "SCREEN_LOCATION_WIDTH",         MSDP_FLAG_SENDABLE|MSDP_FLAG_REPORTABLE,  PORT_RANK_SPY,   NULL },
 	{    "SCREEN_MINIMIZED",              MSDP_FLAG_SENDABLE|MSDP_FLAG_REPORTABLE,  PORT_RANK_SPY,   NULL },
-	{    "SCREEN_POSITION_HEIGHT",        MSDP_FLAG_SENDABLE|MSDP_FLAG_REPORTABLE,  PORT_RANK_SPY,   NULL },
-	{    "SCREEN_POSITION_WIDTH",         MSDP_FLAG_SENDABLE|MSDP_FLAG_REPORTABLE,  PORT_RANK_SPY,   NULL },
 	{    "SCREEN_ROWS",                   MSDP_FLAG_SENDABLE|MSDP_FLAG_REPORTABLE,  PORT_RANK_SPY,   NULL },
 	{    "SCREEN_WIDTH",                  MSDP_FLAG_SENDABLE|MSDP_FLAG_REPORTABLE,  PORT_RANK_SPY,   NULL },
 	{    "SEND",                                                MSDP_FLAG_COMMAND,  PORT_RANK_SPY,   msdp_command_send },

+ 20 - 15
src/nest.c

@@ -671,7 +671,7 @@ struct listnode *get_nest_node_key(struct listroot *root, char *variable, char *
 	{
 		str_cpy_printf(result, "%s", node->arg1);
 
-		if (HAS_BIT(node->flags, NODE_FLAG_ONESHOT))
+		if (node->shots && --node->shots == 0)
 		{
 			delete_nest_node(root, variable);
 		}
@@ -691,8 +691,6 @@ struct listnode *get_nest_node_key(struct listroot *root, char *variable, char *
 	return NULL;
 }
 
-// Has ONESHOT check
-
 struct listnode *get_nest_node_val(struct listroot *root, char *variable, char **result, int def)
 {
 	struct listnode *node;
@@ -711,7 +709,7 @@ struct listnode *get_nest_node_val(struct listroot *root, char *variable, char *
 	{
 		show_nest_node(node, result, TRUE);
 
-		if (HAS_BIT(node->flags, NODE_FLAG_ONESHOT))
+		if (node->shots && --node->shots == 0)
 		{
 			delete_nest_node(root, variable);
 		}
@@ -753,7 +751,7 @@ int get_nest_index(struct listroot *root, char *variable, char **result, int def
 	{
 		str_cpy_printf(result, "%d", index + 1);
 
-		if (HAS_BIT(node->flags, NODE_FLAG_ONESHOT))
+		if (node->shots && --node->shots == 0)
 		{
 			delete_index_list(root, index);
 		}
@@ -884,7 +882,14 @@ struct listnode *set_nest_node_ses(struct session *ses, char *arg1, char *format
 
 	if (root == NULL)
 	{
-		root = ses->list[LIST_VARIABLE];
+		if (gtd->level->local)
+		{
+			root = local_list(ses);
+		}
+		else
+		{
+			root = ses->list[LIST_VARIABLE];
+		}
 		node = NULL;
 	}
 	else
@@ -926,9 +931,9 @@ struct listnode *set_nest_node_ses(struct session *ses, char *arg1, char *format
 		node = update_node_list(root, name, arg2, "", "");
 	}
 
-	if (gtd->level->oneshot)
+	if (gtd->level->shots)
 	{
-		SET_BIT(node->flags, NODE_FLAG_ONESHOT);
+		node->shots = gtd->level->mshot;
 	}
 
 	check_all_events(root->ses, SUB_ARG, 1, 1, "VARIABLE UPDATED %s", name, name, arg2);
@@ -1006,9 +1011,9 @@ struct listnode *add_nest_node_ses(struct session *ses, char *arg1, char *format
 		node = update_node_list(root, name, arg2, "", "");
 	}
 
-	if (gtd->level->oneshot)
+	if (gtd->level->shots)
 	{
-		SET_BIT(node->flags, NODE_FLAG_ONESHOT);
+		node->shots = gtd->level->mshot;
 	}
 
 	check_all_events(root->ses, SUB_ARG, 1, 1, "VARIABLE UPDATED %s", name, name, arg2);
@@ -1081,9 +1086,9 @@ struct listnode *set_nest_node(struct listroot *root, char *arg1, char *format,
 		node = update_node_list(root, name, arg2, "", "");
 	}
 
-	if (gtd->level->oneshot)
+	if (gtd->level->shots)
 	{
-		SET_BIT(node->flags, NODE_FLAG_ONESHOT);
+		node->shots = gtd->level->mshot;
 	}
 
 	check_all_events(root->ses, SUB_ARG, 1, 1, "VARIABLE UPDATED %s", name, name, arg2);
@@ -1160,9 +1165,9 @@ struct listnode *add_nest_node(struct listroot *root, char *arg1, char *format,
 		node = update_node_list(root, name, arg2, "", "");
 	}
 
-	if (gtd->level->oneshot)
+	if (gtd->level->shots)
 	{
-		SET_BIT(node->flags, NODE_FLAG_ONESHOT);
+		node->shots = gtd->level->mshot;
 	}
 
 	check_all_events(root->ses, SUB_ARG, 1, 1, "VARIABLE UPDATED %s", name, name, arg2);
@@ -1187,7 +1192,7 @@ void copy_nest_node(struct listroot *dst_root, struct listnode *dst, struct list
 
 	for (index = 0 ; index < src->root->used ; index++)
 	{
-		dst = insert_node_list(dst_root, src->root->list[index]->arg1, src->root->list[index]->arg2, src->root->list[index]->arg3, src->root->list[index]->arg4);
+		dst = create_node_list(dst_root, src->root->list[index]->arg1, src->root->list[index]->arg2, src->root->list[index]->arg3, src->root->list[index]->arg4);
 
 		if (src->root->list[index]->root)
 		{

+ 30 - 19
src/net.c

@@ -201,6 +201,14 @@ void write_line_mud(struct session *ses, char *line, int size)
 
 	push_call("write_line_mud(%p,%p)",line,ses);
 
+	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "SEND OUTPUT", line, ntos(size));
+
+	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "CATCH SEND OUTPUT", line, ntos(size)))
+	{
+		pop_call();
+		return;
+	}
+
 	if (ses == gts)
 	{
 		if (HAS_BIT(gtd->flags, TINTIN_FLAG_CHILDLOCK))
@@ -223,18 +231,18 @@ void write_line_mud(struct session *ses, char *line, int size)
 		return;
 	}
 
+
 	if (!HAS_BIT(ses->telopts, TELOPT_FLAG_TELNET) && HAS_BIT(ses->charset, CHARSET_FLAG_ALL_TOUTF8))
 	{
 		char buf[BUFFER_SIZE];
 
 		size = utf8_to_all(ses, line, buf);
 
-		strcpy(line, buf);
-	}
+		memcpy(line, buf, size);
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "SEND OUTPUT", line, ntos(size));
+		line[size] = 0;
+	}
 
-	if (!check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "CATCH SEND OUTPUT", line, ntos(size)))
 	{
 		if (ses->mccp3)
 		{
@@ -350,12 +358,18 @@ void readmud(struct session *ses)
 
 	push_call("readmud(%p)", ses);
 
+	gtd->mud_output_len = 0;
+
 	if (gtd->mud_output_len < BUFFER_SIZE)
 	{
 		check_all_events(ses, SUB_ARG|SUB_SEC, 0, 1, "RECEIVED OUTPUT", gtd->mud_output_buf);
-	}
 
-	gtd->mud_output_len = 0;
+		if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 1, "CATCH RECEIVED OUTPUT", gtd->mud_output_buf))
+		{
+			pop_call();
+			return;
+		}
+	}
 
 	/* separate into lines and print away */
 
@@ -484,12 +498,14 @@ void readmud(struct session *ses)
 void process_mud_output(struct session *ses, char *linebuf, int prompt)
 {
 	char line[STRING_SIZE];
+	int str_len, raw_len;
 
 	push_call("process_mud_output(%p,%p,%d)",ses,linebuf,prompt);
 
 	ses->check_output = 0;
 
-	strip_vt102_codes(linebuf, line);
+	raw_len = strlen(linebuf);
+	str_len = strip_vt102_codes(linebuf, line);
 
 	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "RECEIVED LINE", linebuf, line);
 
@@ -499,11 +515,11 @@ void process_mud_output(struct session *ses, char *linebuf, int prompt)
 		return;
 	}
 
-	if (prompt)
+	if (str_len && prompt)
 	{
-		check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "RECEIVED PROMPT", linebuf, line);
+		check_all_events(ses, SUB_ARG|SUB_SEC, 0, 4, "RECEIVED PROMPT", linebuf, line, ntos(raw_len), ntos(str_len));
 
-		if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "CATCH RECEIVED PROMPT", linebuf, line))
+		if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 4, "CATCH RECEIVED PROMPT", linebuf, line, ntos(raw_len), ntos(str_len)))
 		{
 			pop_call();
 			return;
@@ -525,9 +541,9 @@ void process_mud_output(struct session *ses, char *linebuf, int prompt)
 		Take care of gags, vt102 support still goes
 	*/
 
-	if (HAS_BIT(ses->flags, SES_FLAG_GAG))
+	if (ses->gagline > 0)
 	{
-		DEL_BIT(ses->flags, SES_FLAG_GAG);
+		ses->gagline--;
 
 		strip_non_vt102_codes(linebuf, line);
 
@@ -535,18 +551,13 @@ void process_mud_output(struct session *ses, char *linebuf, int prompt)
 
 		strip_vt102_codes(linebuf, line);
 
-		show_debug(ses, LIST_GAG, "#DEBUG GAG {%s}", line);
+		show_debug(ses, LIST_GAG, "#DEBUG GAG {%d} {%s}", ses->gagline + 1, line);
 
 		pop_call();
 		return;
 	}
 
-	if (!check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "CATCH BUFFERED LINE", linebuf, line))
-	{
-		add_line_buffer(ses, linebuf, prompt);
-	}
-
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "BUFFERED LINE", linebuf, line);
+	add_line_buffer(ses, linebuf, prompt);
 
 	if (ses == gtd->ses)
 	{

+ 70 - 13
src/parse.c

@@ -113,6 +113,46 @@ int is_suffix(char *str1, char *str2)
 	return FALSE;
 }
 
+int is_vowel(char *str)
+{
+	switch (case_table[(int) *str])
+	{
+		case 'a':
+		case 'e':
+		case 'i':
+		case 'o':
+		case 'u':
+			return TRUE;
+	}
+	return FALSE;
+}
+
+struct session *execute(struct session *ses, char *format, ...)
+{
+	char *buffer;
+	va_list args;
+
+	va_start(args, format);
+	vasprintf(&buffer, format, args);
+	va_end(args);
+
+	if (*buffer)
+	{
+		if (*buffer != gtd->tintin_char)
+		{
+			*buffer = gtd->tintin_char;
+		}
+		get_arg_all(ses, buffer, buffer, FALSE);
+	}
+
+	ses = script_driver(ses, LIST_COMMAND, buffer);
+
+	free(buffer);
+
+	return ses;
+}
+
+
 struct session *parse_input(struct session *ses, char *input)
 {
 	char *line;
@@ -131,12 +171,16 @@ struct session *parse_input(struct session *ses, char *input)
 	{
 		line = (char *) malloc(BUFFER_SIZE);
 
-		strcpy(line, input);
+		sub_arg_all(ses, input, line, 1, SUB_SEC);
 
 		if (check_all_aliases(ses, line))
 		{
 			ses = script_driver(ses, LIST_ALIAS, line);
 		}
+		else if (HAS_BIT(ses->flags, SES_FLAG_SPEEDWALK) && is_speedwalk(ses, line))
+		{
+			process_speedwalk(ses, line);
+		}
 		else
 		{
 			write_mud(ses, line, SUB_EOL);
@@ -162,7 +206,7 @@ struct session *parse_input(struct session *ses, char *input)
 	{
 		input = space_out(input);
 
-		input = get_arg_all(ses, input, line, GET_ONE);
+		input = get_arg_all(ses, input, line, 0);
 
 		if (parse_command(ses, line))
 		{
@@ -232,16 +276,16 @@ char *substitute_speedwalk(struct session *ses, char *input, char *output)
 
 	while (*pti && pto - output < INPUT_SIZE)
 	{
-		while (isspace(*pti))
+		while (isspace((int) *pti))
 		{
 			pti++;
 		}
 
-		if (isdigit(*pti))
+		if (isdigit((int) *pti))
 		{
 			ptn = num;
 
-			while (isdigit(*pti))
+			while (isdigit((int) *pti))
 			{
 				if (ptn - num < 4)
 				{
@@ -286,7 +330,7 @@ char *substitute_speedwalk(struct session *ses, char *input, char *output)
 
 	return output;
 }
-	
+
 int is_speedwalk(struct session *ses, char *input)
 {
 	int digit = 0, flag = FALSE;
@@ -450,7 +494,6 @@ int cnt_arg_all(struct session *ses, char *string, int flag)
 	get all arguments - only check for unescaped command separators
 */
 
-
 char *get_arg_all(struct session *ses, char *string, char *result, int verbatim)
 {
 	char *pto, *pti;
@@ -522,6 +565,18 @@ char *get_arg_all(struct session *ses, char *string, char *result, int verbatim)
 	return pti;
 }
 
+char *sub_arg_all(struct session *ses, char *string, char *result, int verbatim, int sub)
+{
+	char *buffer = str_alloc(UMAX(strlen(string), BUFFER_SIZE));
+
+	string = get_arg_all(ses, string, buffer, verbatim);
+
+	substitute(ses, buffer, result, sub);
+
+	str_free(buffer);
+
+	return string;
+}
 
 /*
 	Braces are stripped in braced arguments leaving all else as is.
@@ -601,7 +656,7 @@ char *get_arg_in_braces(struct session *ses, char *string, char *result, int fla
 
 char *sub_arg_in_braces(struct session *ses, char *string, char *result, int flag, int sub)
 {
-	char *buffer = str_alloc(UMAX(strlen(string), BUFFER_SIZE));
+	char *buffer = str_alloc(strlen(string) + BUFFER_SIZE);
 
 	string = get_arg_in_braces(ses, string, buffer, flag);
 
@@ -765,7 +820,6 @@ char *get_arg_stop_digits(struct session *ses, char *string, char *result, int f
 		}
 		else if (isdigit((int) *pti) && nest == 0)
 		{
-			pti++;
 			break;
 		}
 		else if (*pti == DEFAULT_OPEN)
@@ -1010,7 +1064,7 @@ void write_mud(struct session *ses, char *command, int flags)
 
 	size = substitute(ses, command, output, flags);
 
-	if (HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING))
+	if (gtd->level->ignore == 0 && HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING))
 	{
 		if (ses->map == NULL || ses->map->nofollow == 0)
 		{
@@ -1018,7 +1072,7 @@ void write_mud(struct session *ses, char *command, int flags)
 		}
 	}
 
-	if (ses->map && ses->map->in_room && ses->map->nofollow == 0)
+	if (gtd->level->ignore == 0 && ses->map && ses->map->in_room && ses->map->nofollow == 0)
 	{
 		if (follow_map(ses, command))
 		{
@@ -1036,9 +1090,9 @@ void write_mud(struct session *ses, char *command, int flags)
 
 void do_one_line(char *line, struct session *ses)
 {
-	char strip[BUFFER_SIZE];
+	char *strip;
 
-	push_call("[%s] do_one_line(%s)",ses->name,line);
+	push_call("do_one_line(%s,%p)",ses->name,line);
 
 	if (gtd->level->ignore)
 	{
@@ -1046,6 +1100,8 @@ void do_one_line(char *line, struct session *ses)
 		return;
 	}
 
+	strip = str_alloc_stack();
+
 	strip_vt102_codes(line, strip);
 
 	if (!HAS_BIT(ses->list[LIST_ACTION]->flags, LIST_FLAG_IGNORE))
@@ -1079,6 +1135,7 @@ void do_one_line(char *line, struct session *ses)
 
 		DEL_BIT(ses->logmode, LOG_FLAG_NEXT);
 	}
+
 	pop_call();
 	return;
 }

+ 108 - 21
src/path.c

@@ -30,13 +30,14 @@
 
 DO_COMMAND(do_path)
 {
-	char arg1[BUFFER_SIZE];
 	int cnt;
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 
 	if (*arg1 == 0)
 	{
+		info:
+
 		tintin_header(ses, " PATH OPTIONS ");
 
 		for (cnt = 0 ; *path_table[cnt].fun != NULL ; cnt++)
@@ -62,7 +63,7 @@ DO_COMMAND(do_path)
 
 		if (*path_table[cnt].name == 0)
 		{
-			do_path(ses, "");
+			goto info;
 		}
 		else
 		{
@@ -261,6 +262,40 @@ DO_PATH(path_map)
 	}
 }
 
+DO_PATH(path_get)
+{
+	struct listroot *root = ses->list[LIST_PATH];
+	char result[STRING_SIZE], arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
+
+	if (*arg2 == 0)
+	{
+		tintin_printf2(ses, "  length: %d", root->used);
+		tintin_printf2(ses, "position: %d", root->update + 1);
+	}
+	else if (is_abbrev(arg1, "LENGTH"))
+	{
+		sprintf(result, "%d", root->used);
+
+		set_nest_node_ses(ses, arg2, "%s", result);
+
+		show_message(ses, LIST_COMMAND, "#PATH GET: PATH LENGTH {%s} SAVED TO {%s}", result, arg2);
+	}
+	else if (is_abbrev(arg1, "POSITION"))
+	{
+		sprintf(result, "%d", root->update + 1);
+
+		set_nest_node_ses(ses, arg2, "%s", result);
+
+		show_message(ses, LIST_COMMAND, "#PATH GET: PATH POSITION {%s} SAVED TO {%s}", result, arg2);
+	}
+	else
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH GET <LENGTH|POSITION> <VARIABLE NAME>");
+	}
+}
 
 DO_PATH(path_save)
 {
@@ -277,7 +312,7 @@ DO_PATH(path_save)
 	}
 	else if (*arg2 == 0)
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH SAVE <BACKWARD|FORWARD|LENGTH|POSITION> <VARIABLE NAME>");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH SAVE <BACKWARD|FORWARD> <VARIABLE NAME>");
 	}
 	else if (is_abbrev(arg1, "BACKWARDS"))
 	{
@@ -331,7 +366,7 @@ DO_PATH(path_save)
 	}
 	else
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH SAVE <BACKWARD|FORWARD|LENGTH|POSITION> <VARIABLE NAME>");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH SAVE <BACKWARD|FORWARD> <VARIABLE NAME>");
 	}
 }
 
@@ -368,11 +403,11 @@ DO_PATH(path_load)
 
 		if ((node = search_node_list(root, temp)))
 		{
-			insert_node_list(root, node->arg1, node->arg2, "0", "");
+			create_node_list(root, node->arg1, node->arg2, "0", "");
 		}
 		else
 		{
-			insert_node_list(root, temp, temp, "0", "");
+			create_node_list(root, temp, temp, "0", "");
 		}
 	}
 	show_message(ses, LIST_COMMAND, "#PATH LOAD: PATH WITH %d NODES LOADED.", root->used);
@@ -414,7 +449,7 @@ DO_PATH(path_insert)
 	}
 	else
 	{
-		insert_node_list(root, arg1, arg2, "0", "");
+		create_node_list(root, arg1, arg2, "0", "");
 
 		show_message(ses, LIST_COMMAND, "#PATH INSERT: FORWARD {%s} BACKWARD {%s}.", arg1, arg2);
 
@@ -639,7 +674,7 @@ DO_PATH(path_zip)
 
 	kill_list(root);
 
-	insert_node_list(root, arg1, arg2, "0", "");
+	create_node_list(root, arg1, arg2, "0", "");
 
 	show_message(ses, LIST_COMMAND, "#PATH ZIP: THE PATH HAS BEEN ZIPPED TO {%s} {%s}.", arg1, arg2);
 }
@@ -647,8 +682,10 @@ DO_PATH(path_zip)
 DO_PATH(path_unzip)
 {
 	struct listroot *root = ses->list[LIST_PATH];
-	char arg1[BUFFER_SIZE], temp[BUFFER_SIZE], *str;
 	struct listnode *node;
+	char name[BUFFER_SIZE], num[NUMBER_SIZE], *ptn;
+	char arg1[BUFFER_SIZE];
+	int cnt, max;
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 
@@ -667,11 +704,63 @@ DO_PATH(path_unzip)
 
 	while (*arg)
 	{
-		if (*arg == ';')
+		switch (*arg)
 		{
-			arg++;
+			case ';':
+			case ' ':
+				arg++;
+				continue;
 		}
 
+		if (isdigit((int) *arg))
+		{
+			ptn = num;
+
+			while (isdigit((int) *arg))
+			{
+				if (ptn - num < 5)
+				{
+					*ptn++ = *arg++;
+				}
+				else
+				{
+					arg++;
+				}
+			}
+			*ptn = 0;
+
+			max = atoi(num);
+		}
+		else
+		{
+			max = 1;
+		}
+
+		arg = get_arg_stop_digits(ses, arg, name, GET_ONE);
+
+		if (*name == 0)
+		{
+			break;
+		}
+
+		node = search_node_list(ses->list[LIST_PATHDIR], name);
+
+		if (node)
+		{
+			for (cnt = 0 ; cnt < max ; cnt++)
+			{
+				create_node_list(root, node->arg1, node->arg2, "0", "");
+			}
+		}
+		else
+		{
+			for (cnt = 0 ; cnt < max ; cnt++)
+			{
+				create_node_list(root, name, name, "0", "");
+			}
+		}
+	}
+/*
 		arg = get_arg_in_braces(ses, arg, temp, GET_ALL);
 
 		if (is_speedwalk(ses, temp))
@@ -702,11 +791,11 @@ DO_PATH(path_unzip)
 				{
 					if ((node = search_node_list(ses->list[LIST_PATHDIR], dir)))
 					{
-						insert_node_list(root, node->arg1, node->arg2, "0", "");
+						create_node_list(root, node->arg1, node->arg2, "0", "");
 					}
 					else
 					{
-						insert_node_list(root, dir, dir, "0", "");
+						create_node_list(root, dir, dir, "0", "");
 					}
 				}
 			}
@@ -715,14 +804,15 @@ DO_PATH(path_unzip)
 		{
 			if ((node = search_node_list(ses->list[LIST_PATHDIR], temp)))
 			{
-				insert_node_list(root, node->arg1, node->arg2, "0", "");
+				create_node_list(root, node->arg1, node->arg2, "0", "");
 			}
 			else
 			{
-				insert_node_list(root, temp, temp, "0", "");
+				create_node_list(root, temp, temp, "0", "");
 			}
 		}
 	}
+*/
 	show_message(ses, LIST_COMMAND, "#PATH UNZIP: PATH WITH %d NODES UNZIPPED.", root->used);
 }
 
@@ -853,7 +943,7 @@ void check_append_path(struct session *ses, char *forward, char *backward, int f
 	{
 		if ((node = search_node_list(ses->list[LIST_PATHDIR], forward)))
 		{
-			insert_node_list(root, node->arg1, node->arg2, "0", "");
+			create_node_list(root, node->arg1, node->arg2, "0", "");
 
 			root->update = root->used;
 		}
@@ -862,11 +952,11 @@ void check_append_path(struct session *ses, char *forward, char *backward, int f
 	{
 		if ((node = search_node_list(ses->list[LIST_PATHDIR], forward)))
 		{
-			insert_node_list(root, node->arg1, node->arg2, "0", "");
+			create_node_list(root, node->arg1, node->arg2, "0", "");
 		}
 		else
 		{
-			insert_node_list(root, forward, backward, "0", "");
+			create_node_list(root, forward, backward, "0", "");
 		}
 	}
 }
@@ -874,7 +964,6 @@ void check_append_path(struct session *ses, char *forward, char *backward, int f
 
 DO_COMMAND(do_pathdir)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE];
 	struct listnode *node;
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
@@ -925,8 +1014,6 @@ DO_COMMAND(do_pathdir)
 
 DO_COMMAND(do_unpathdir)
 {
-	char arg1[BUFFER_SIZE];
-
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 
 	do

+ 31 - 16
src/port.c

@@ -36,13 +36,15 @@
 
 DO_COMMAND(do_port)
 {
-	char cmd[BUFFER_SIZE], arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
+	char cmd[BUFFER_SIZE];
 	int cnt;
 
 	arg = get_arg_in_braces(ses, arg, cmd, GET_ONE);
 
 	if (*cmd == 0)
 	{
+		info:
+
 		tintin_header(ses, " PORT OPTIONS ");
 
 		for (cnt = 0 ; *port_table[cnt].name != 0 ; cnt++)
@@ -77,7 +79,7 @@ DO_COMMAND(do_port)
 		return ses;
 	}
 
-	do_port(ses, "");
+	goto info;
 
 	return ses;
 }
@@ -115,7 +117,7 @@ DO_PORT(port_initialize)
 
 	tintin_printf(ses, "#TRYING TO LAUNCH '%s' ON PORT '%s'.", arg1, arg2);
 
-	sprintf(temp, "{localport} {%d} {%s}", atoi(arg2), file);
+	sprintf(temp, "{localport} {%d} {%.*s}", atoi(arg2), PATH_SIZE, file);
 
 	port = atoi(arg2);
 
@@ -184,7 +186,12 @@ DO_PORT(port_initialize)
 	ses->port->ip       = strdup("<Unknown>");
 	ses->port->prefix   = strdup("<PORT> ");
 
-	tintin_printf(ses, "#PORT INITIALIZE: SESSION {%s} IS LISTENING ON PORT %d.", ses->name, ses->port->port);
+	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "PORT INITIALIZED", ses->name, ntos(ses->port->port));
+
+	if (!check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "GAG PORT INITIALIZED", ses->name, ntos(ses->port->port)))
+	{
+		tintin_printf(ses, "#PORT INITIALIZE: SESSION {%s} IS LISTENING ON PORT %d.", ses->name, ses->port->port);
+	}
 
 	return ses;
 }
@@ -202,7 +209,12 @@ DO_PORT(port_uninitialize)
 
 	ses->port = NULL;
 
-	tintin_printf(ses, "#PORT UNINITIALIZE: CLOSED PORT {%d}.", port);
+	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "PORT UNINITIALIZED", ses->name, ntos(port));
+
+	if (!check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "GAG PORT UNINITIALIZED", ses->name, ntos(port)))
+	{
+		tintin_printf(ses, "#PORT UNINITIALIZE: CLOSED PORT {%d}.", port);
+	}
 
 	return ses;
 }
@@ -408,12 +420,13 @@ void port_socket_printf(struct session *ses, struct port_data *buddy, char *form
 {
 	char buf[BUFFER_SIZE];
 	va_list args;
+	int len;
 
 	va_start(args, format);
-	vsnprintf(buf, BUFFER_SIZE / 3, format, args);
+	len = vsnprintf(buf, BUFFER_SIZE / 3, format, args);
 	va_end(args);
 
-	port_socket_write(ses, buddy, buf, strlen(buf));
+	port_socket_write(ses, buddy, buf, len);
 }
 
 void port_telnet_printf(struct session *ses, struct port_data *buddy, size_t length, char *format, ...)
@@ -441,14 +454,14 @@ void port_printf(struct session *ses, char *format, ...)
 	va_list args;
 
 	va_start(args, format);
-	vsnprintf(buf, BUFFER_SIZE / 3, format, args);
+	vsnprintf(buf, BUFFER_SIZE, format, args);
 	va_end(args);
 
-	sprintf(tmp, "%s%s", ses->port->prefix, buf);
+	sprintf(tmp, "%s%.*s", ses->port->prefix, BUFFER_SIZE, buf);
 
 	strip_vt102_codes_non_graph(tmp, buf);
 
-	sprintf(tmp, "%s%s%s", ses->port->color, buf, "\e[0m");
+	sprintf(tmp, "%s%.*s%s", ses->port->color, BUFFER_SIZE, buf, "\e[0m");
 
 	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "PORT MESSAGE", tmp, buf);
 
@@ -464,14 +477,14 @@ void port_log_printf(struct session *ses, struct port_data *buddy, char *format,
 	va_list args;
 
 	va_start(args, format);
-	vsnprintf(buf, BUFFER_SIZE / 3, format, args);
+	vsnprintf(buf, BUFFER_SIZE, format, args);
 	va_end(args);
 
-	sprintf(tmp, "%s%s@%s %s", ses->port->prefix, buddy->name, buddy->ip, buf);
+	sprintf(tmp, "%s%s@%s %.*s", ses->port->prefix, buddy->name, buddy->ip, BUFFER_SIZE, buf);
 
 	strip_vt102_codes_non_graph(tmp, buf);
 
-	sprintf(tmp, "%s%s\e[0m", ses->port->color, buf);
+	sprintf(tmp, "%s%.*s\e[0m", ses->port->color, BUFFER_SIZE, buf);
 
 	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 5, "PORT LOG MESSAGE", buddy->name, buddy->ip, ntos(buddy->fd), tmp, buf);
 
@@ -592,13 +605,13 @@ void get_port_commands(struct session *ses, struct port_data *buddy, char *buf,
 
 	strip_vt102_codes(buf, txt);
 
+	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 5, "PORT RECEIVED MESSAGE", buddy->name, buddy->ip, ntos(buddy->port), buf, txt);
+
 	if (!check_all_events(ses, SUB_ARG|SUB_SEC, 0, 5, "CATCH PORT RECEIVED MESSAGE", buddy->name, buddy->ip, ntos(buddy->port), buf, txt))
 	{
 		port_receive_message(ses, buddy, buf);
 	}
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 5, "PORT RECEIVED MESSAGE", buddy->name, buddy->ip, ntos(buddy->port), buf, txt);
-
 	pop_call();
 	return;
 }
@@ -917,12 +930,14 @@ DO_PORT(port_zap)
 
 DO_PORT(port_color)
 {
-	if (*arg1 == 0 || get_color_names(gtd->ses, arg1, arg2) == FALSE)
+	if (*arg1 == 0 || !is_color_name(arg1))
 	{
 		port_printf(ses, "Valid colors are:\n\nreset, bold, dim, light, dark, underscore, blink, reverse, black, red, green, yellow, blue, magenta, cyan, white, b black, b red, b green, b yellow, b blue, b magenta, b cyan, b white");
 
 		return ses;
 	}
+	get_color_names(gtd->ses, arg1, arg2);
+
 	RESTRING(ses->port->color, arg2);
 
 	port_printf(ses, "Color has been set to %s", arg1);

+ 42 - 9
src/regex.c

@@ -59,14 +59,12 @@ int find(struct session *ses, char *str, char *exp, int sub, int flag)
 
 DO_COMMAND(do_regexp)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], is_t[BUFFER_SIZE], is_f[BUFFER_SIZE];
-
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
-	arg = get_arg_in_braces(ses, arg, is_t, GET_ALL);
-	arg = get_arg_in_braces(ses, arg, is_f, GET_ALL);
+	arg = get_arg_in_braces(ses, arg, arg3, GET_ALL);
+	arg = get_arg_in_braces(ses, arg, arg4, GET_ALL);
 
-	if (*is_t == 0)
+	if (*arg3 == 0)
 	{
 		show_error(ses, LIST_COMMAND, "SYNTAX: #REGEXP {string} {expression} {true} {false}.");
 	}
@@ -74,13 +72,13 @@ DO_COMMAND(do_regexp)
 	{
 		if (tintin_regexp(ses, NULL, arg1, arg2, 0, REGEX_FLAG_CMD))
 		{
-			substitute(ses, is_t, is_t, SUB_CMD);
+			substitute(ses, arg3, arg3, SUB_CMD);
 
-			ses = script_driver(ses, LIST_COMMAND, is_t);
+			ses = script_driver(ses, LIST_COMMAND, arg3);
 		}
-		else if (*is_f)
+		else if (*arg4)
 		{
-			ses = script_driver(ses, LIST_COMMAND, is_f);
+			ses = script_driver(ses, LIST_COMMAND, arg4);
 		}
 	}
 	return ses;
@@ -1164,6 +1162,11 @@ void tintin_macro_compile(char *input, char *output)
 						pti    += 2;
 						break;
 
+					case 'n':
+						*pto++ = ASCII_LF;
+						*pti += 2;
+						break;
+
 					case 'r':
 						*pto++ = ASCII_CR;
 						pti   += 2;
@@ -1185,6 +1188,36 @@ void tintin_macro_compile(char *input, char *output)
 							*pto++ = *pti++;
 						}
 						break;
+
+					case 'u':
+						if (pti[2] && pti[3] && pti[4] && pti[5])
+						{
+							pto += unicode_16_bit(&pti[2], pto);
+							pti += 6;
+						}
+						else
+						{
+							*pto++ = *pti++;
+						}
+						break;
+
+					case 'U':
+						if (pti[2] && pti[3] && pti[4] && pti[5] && pti[6] && pti[7])
+						{
+							pto += unicode_21_bit(&pti[2], pto);
+							pti += 8;
+						}
+						else
+						{
+							*pto++ = *pti++;
+						}
+						break;
+
+					case 'v':
+						*pto++ = ASCII_VTAB;
+						pti   += 2;
+						break;
+
 					default:
 						*pto++ = *pti++;
 						break;

+ 0 - 1
src/scan.c

@@ -375,7 +375,6 @@ struct session *scan_txt_file(struct session *ses, FILE *fp, char *filename)
 DO_COMMAND(do_scan)
 {
 	FILE *fp;
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);

+ 67 - 61
src/screen.c

@@ -32,7 +32,6 @@ void screen_csit(struct session *ses, char *arg1, char *arg2, char *tc);
 
 DO_COMMAND(do_screen)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 	int cnt;
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
@@ -202,30 +201,41 @@ DO_SCREEN(screen_clear)
 	}
 }
 
-DO_SCREEN(screen_fill)
+DO_SCREEN(screen_dump)
 {
-	char buf[BUFFER_SIZE];
+	int cnt;
+
+	for (cnt = 0 ; cnt < gtd->screen->max_row ; cnt++)
+	{
+		save_pos(ses);
+
+		goto_pos(ses, cnt + 1, 1);
 
+		printf("[%02d] %s", cnt + 1, gtd->screen->grid[cnt]->str);
+
+		restore_pos(ses);
+	}
+}
+
+DO_SCREEN(screen_fill)
+{
 	if (is_abbrev(arg1, "DEFAULT"))
 	{
 		if (ses->split->sav_top_col || ses->split->sav_bot_col)
 		{
-			sprintf(buf, "CLEAR SPLIT");
-
-			do_screen(ses, buf);
+			execute(ses, "#SCREEN CLEAR SPLIT");
 		}
 
 		if (ses->split->sav_top_row > 0)
 		{
 			if (ses->split->sav_top_row == 1)
 			{
-				sprintf(buf, "%s LINE %d %d %d %d", arg2, 1, 1, ses->split->top_row - 1, gtd->screen->cols);
+				execute(ses, "#DRAW %s LINE %d %d %d %d", arg2, 1, 1, ses->split->top_row - 1, gtd->screen->cols);
 			}
 			else
 			{
-				sprintf(buf, "%s BOX %d %d %d %d {}", arg2, 1, 1, ses->split->top_row - 1, gtd->screen->cols);
+				execute(ses, "#DRAW %s BOX %d %d %d %d {}", arg2, 1, 1, ses->split->top_row - 1, gtd->screen->cols);
 			}
-			do_draw(ses, buf);
 		}
 
 		// bottom split
@@ -236,13 +246,12 @@ DO_SCREEN(screen_fill)
 			{
 				if (ses->split->sav_bot_row - inputline_max_row() == 0)
 				{
-					sprintf(buf, "%s LINE %d %d %d %d", arg2, ses->split->bot_row + 1, 1, gtd->screen->rows - 1, gtd->screen->cols);
+					execute(ses, "#DRAW %s LINE %d %d %d %d", arg2, ses->split->bot_row + 1, 1, gtd->screen->rows - 1, gtd->screen->cols);
 				}
 				else
 				{
-					sprintf(buf, "%s BOX %d %d %d %d {}", arg2, ses->split->bot_row + 1, 1, gtd->screen->rows - inputline_max_row(), gtd->screen->cols);
+					execute(ses, "#DRAW %s BOX %d %d %d %d {}", arg2, ses->split->bot_row + 1, 1, gtd->screen->rows - inputline_max_row(), gtd->screen->cols);
 				}
-				do_draw(ses, buf);
 			}
 		}
 
@@ -250,28 +259,24 @@ DO_SCREEN(screen_fill)
 		{
 			if (ses->split->sav_top_col)
 			{
-				sprintf(buf, "%s TEED VERTICAL LINE %d %d %d %d", arg2, ses->split->top_row - 1, ses->split->top_col - 1, ses->split->bot_row + 1, ses->split->top_col - 1);
-				do_draw(ses, buf);
+				execute(ses, "#DRAW %s TEED VERTICAL LINE %d %d %d %d", arg2, ses->split->top_row - 1, ses->split->top_col - 1, ses->split->bot_row + 1, ses->split->top_col - 1);
 			}
 
 			if (ses->split->sav_bot_col)
 			{
-				sprintf(buf, "%s TEED VERTICAL LINE %d %d %d %d", arg2, ses->split->top_row - 1, ses->split->bot_col + 1, ses->split->bot_row + 1, ses->split->bot_col + 1);
-				do_draw(ses, buf);
+				execute(ses, "#DRAW %s TEED VERTICAL LINE %d %d %d %d", arg2, ses->split->top_row - 1, ses->split->bot_col + 1, ses->split->bot_row + 1, ses->split->bot_col + 1);
 			}
 		}
 		else
 		{
 			if (ses->split->sav_top_col)
 			{
-				sprintf(buf, "%s VERTICAL LINE %d %d %d %d", arg2, ses->split->top_row, ses->split->top_col - 1, ses->split->bot_row, ses->split->top_col - 1);
-				do_draw(ses, buf);
+				execute(ses, "#DRAW %s VERTICAL LINE %d %d %d %d", arg2, ses->split->top_row, ses->split->top_col - 1, ses->split->bot_row, ses->split->top_col - 1);
 			}
 
 			if (ses->split->sav_bot_col)
 			{
-				sprintf(buf, "%s VERTICAL LINE %d %d %d %d", arg2, ses->split->top_row, ses->split->bot_col + 1, ses->split->bot_row, ses->split->bot_col + 1);
-				do_draw(ses, buf);
+				execute(ses, "#DRAW %s VERTICAL LINE %d %d %d %d", arg2, ses->split->top_row, ses->split->bot_col + 1, ses->split->bot_row, ses->split->bot_col + 1);
 			}
 		}
 	}
@@ -611,7 +616,7 @@ DO_SCREEN(screen_scrollregion)
 
 	if ((top_row|top_col|bot_row|bot_col) == 0)
 	{
-		do_unsplit(ses, "");
+		execute(ses, "#UNSPLIT");
 
 		return;
 	}
@@ -939,17 +944,17 @@ void csit_handler(int ind, int var1, int var2)
 	switch (ind)
 	{
 		case 1:
-			gtd->screen->minimized = 1;
-			check_all_events(NULL, SUB_ARG, 0, 1, "SCREEN MINIMIZED", "1");
-			msdp_update_all("SCREEN_MINIMIZED", "1");
-			break;
-
-		case 2:
 			gtd->screen->minimized = 0;
 			check_all_events(NULL, SUB_ARG, 0, 1, "SCREEN MINIMIZED", "0");
 			msdp_update_all("SCREEN_MINIMIZED", "0");
 			break;
 
+		case 2:
+			gtd->screen->minimized = 1;
+			check_all_events(NULL, SUB_ARG, 0, 1, "SCREEN MINIMIZED", "1");
+			msdp_update_all("SCREEN_MINIMIZED", "1");
+			break;
+
 		case 3:
 			gtd->screen->pos_height = UMAX(0, var2);
 			gtd->screen->pos_width  = UMAX(0, var1);
@@ -1030,7 +1035,7 @@ void rqlp_handler(int event, int button, int height, int width)
 
 	check_all_events(gtd->ses, SUB_ARG, 0, 9, "SCREEN MOUSE LOCATION", ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), ntos(char_height), ntos(char_width), ntos(rev_char_height), ntos(rev_char_width), grid[grid_val]);
 
-	map_mouse_handler(gtd->ses, NULL, NULL, col, row, char_height, char_width);
+	map_mouse_handler(gtd->ses, NULL, NULL, row, col, -1 - (gtd->screen->rows - row), -1 - (gtd->screen->cols - col), char_height, char_width);
 
 	gtd->level->debug -= debug;
 	gtd->level->info  -= info;
@@ -1057,8 +1062,6 @@ void screen_csi(char *cmd, char *num1, char *num2, char *num3, char *tc)
 		*num2 ? XT_S : XT_V, *num2 && *num2 != ' ' ? num2 : "",
 		num3,
 		tc);
-
-	SET_BIT(gtd->flags, TINTIN_FLAG_FLUSH);
 }
 
 void screen_csit(struct session *ses, char *arg1, char *arg2, char *arg3)
@@ -1088,9 +1091,6 @@ void screen_csit(struct session *ses, char *arg1, char *arg2, char *arg3)
 //	convert_meta(buf, debug, FALSE);
 
 //	tintin_printf2(gtd->ses, "\e[1;32m[%s] num1 (%s) num2 (%s) %s %s", num1, num2, debug, buf);
-
-
-	SET_BIT(gtd->flags, TINTIN_FLAG_FLUSH);
 }
 
 
@@ -1385,6 +1385,10 @@ DO_SCREEN(screen_info)
 	tintin_printf2(ses, "gtd->screen->desk_height: %4d", gtd->screen->desk_height);
 	tintin_printf2(ses, "gtd->screen->desk_width:  %4d", gtd->screen->desk_width);
 
+	tintin_printf2(ses, "");
+
+	tintin_printf2(ses, "gtd->screen->minimized:   %4d", gtd->screen->minimized);
+
 	if (!HAS_BIT(ses->flags, SES_FLAG_READMUD) && IS_SPLIT(ses))
 	{
 		tintin_printf2(ses, "SPLIT mode detected.");
@@ -1429,12 +1433,12 @@ int inside_scroll_region(struct session *ses, int row, int col)
 void add_row_screen(int index)
 {
 	gtd->screen->lines[index] = (struct row_data *) calloc(1, sizeof(struct row_data));
-	gtd->screen->lines[index]->str = strdup("");
+	gtd->screen->lines[index]->str = str_dup("");
 }
 
 void del_row_screen(int index)
 {
-	free(gtd->screen->lines[index]->str);
+	str_free(gtd->screen->lines[index]->str);
 	free(gtd->screen->lines[index]);
 }
 
@@ -1442,6 +1446,8 @@ void init_screen(int rows, int cols, int height, int width)
 {
 	int cnt;
 
+	push_call("init_screen(%d,%d)",rows,cols);
+
 	gtd->screen->rows        = UMAX(1, rows);
 	gtd->screen->cols        = UMAX(1, cols);
 	gtd->screen->height      = UMAX(1, height);
@@ -1460,15 +1466,18 @@ void init_screen(int rows, int cols, int height, int width)
 	gtd->screen->sav_row[0] = gtd->screen->cur_row = rows;
 	gtd->screen->sav_col[0] = gtd->screen->cur_col = 1;
 
-	push_call("init_screen(%d,%d)",rows,cols);
-
 	if (gtd->screen->max_row < rows)
 	{
 		gtd->screen->lines = (struct row_data **) realloc(gtd->screen->lines, rows * sizeof(struct row_data *));
+		gtd->screen->grid  = (struct row_data **) realloc(gtd->screen->grid,  rows * sizeof(struct row_data *));
 
 		for (cnt = gtd->screen->max_row ; cnt < rows ; cnt++)
 		{
-			add_row_screen(cnt);
+			gtd->screen->lines[cnt]      = (struct row_data *) calloc(1, sizeof(struct row_data));
+			gtd->screen->lines[cnt]->str = str_dup("");
+
+			gtd->screen->grid[cnt]       = (struct row_data *) calloc(1, sizeof(struct row_data));
+			gtd->screen->grid[cnt]->str  = str_dup("");
 		}
 		gtd->screen->max_row = rows;
 	}
@@ -1527,6 +1536,7 @@ int get_link_screen(struct session *ses, char *result, int flags, int row, int c
 	int skip, width, len, start, opt;
 
 	ptl     = NULL;
+	start   = 0;
 	len     = 0;
 	opt     = 0;
 	*result = 0;
@@ -1539,9 +1549,10 @@ int get_link_screen(struct session *ses, char *result, int flags, int row, int c
 	}
 	else
 	{
-//		tintin_printf2(ses, "debug: scroll region only for now.");
-
-		return 0;
+		col -= 1;
+		pts = gtd->screen->grid[row - 1]->str;
+		ptw = pts;
+//		tintin_printf2(ses, "split: (%s)", pts);
 	}
 
 	while (*pts)
@@ -1563,7 +1574,7 @@ int get_link_screen(struct session *ses, char *result, int flags, int row, int c
 
 				opt = 0;
 
-				while (isdigit(*pts))
+				while (isdigit((int) *pts))
 				{
 					opt = opt * 10 + (*pts++ - '0');
 				}
@@ -1748,7 +1759,7 @@ int get_link_screen(struct session *ses, char *result, int flags, int row, int c
 								strcpy(result, var);
 							}
 							pts++;
-//							tintin_printf2(gtd->ses, "link debug: %s", result);
+//							tintin_printf2(gtd->ses, "link osc: %s opt: %d", result, opt);
 							goto start;
 							break;
 
@@ -1801,16 +1812,15 @@ int get_link_screen(struct session *ses, char *result, int flags, int row, int c
 			}
 			else if (pts[1] == '[' && pts[2] == '2' && pts[3] == '4' && pts[4] == 'm')
 			{
+//				tintin_printf2(gtd->ses, "\e[1;32mfound link: (%d,%d,%d) [%s]", start,col, len, result);
+
 				if (ptl && col >= start && col < len)
 				{
 					if (*result == 0)
 					{
 						sprintf(result, "%.*s", (int) (pts - ptl), ptl);
 					}
-
-//					tintin_printf2(gtd->ses, "\e[1;32mfound link: (%d,%d) [%s]", col, len, result);
-
-					return opt ? opt : TRUE;
+					return opt ? opt : 1;
 				}
 				else
 				{
@@ -1839,19 +1849,13 @@ int get_link_screen(struct session *ses, char *result, int flags, int row, int c
 	return FALSE;
 }
 
-void set_line_screen(char *str, int row, int col)
+void set_line_screen(struct session *ses, char *ins, int row, int col)
 {
-	char buf[BUFFER_SIZE];
-
-	push_call("set_line_screen(%p,%d)",str,row,col);
-
-	strcpy(buf, gtd->screen->lines[row]->str);
+	push_call("set_line_screen(%p,%d,%d)",ins,row,col);
 
-	free(gtd->screen->lines[row]->str);
+//	tintin_printf2(ses, "set_line_screen(%s,%d,%d,%d)",ins,row,col,strip_vt102_strlen(ses, ins));
 
-	strcpy(&buf[col], str);
-
-	gtd->screen->lines[row]->str = strdup(buf);
+	str_ins_str(ses, &gtd->screen->grid[row]->str, ins, col, col + strip_vt102_strlen(ses, ins));
 
 	pop_call();
 	return;
@@ -1889,7 +1893,7 @@ void print_screen()
 
 void add_line_screen(char *str)
 {
-	char *ptr;
+	char *ptr, *tmp;
 	int cnt;
 
 	push_call("add_line_screen(%p)",str);
@@ -1911,7 +1915,7 @@ void add_line_screen(char *str)
 			tintin_printf2(gtd->ses, "add_line_screen debug: cnt = %d", cnt);
 		}
 
-		free(gtd->screen->lines[cnt]->str);
+		tmp = gtd->screen->lines[cnt]->str;
 
 		while (cnt < gtd->ses->split->bot_row - 2)
 		{
@@ -1920,17 +1924,19 @@ void add_line_screen(char *str)
 			cnt++;
 		}
 
+		gtd->screen->lines[cnt]->str = tmp;
+
 		ptr = strchr(str, '\n');
 
 		if (ptr)
 		{
-			gtd->screen->lines[cnt]->str = strndup(str, ptr - str);
+			str_ncpy(&gtd->screen->lines[cnt]->str, str, ptr - str);
 
 			str = ptr + 1;
 		}
 		else
 		{
-			gtd->screen->lines[cnt]->str = strdup(str);
+			str_cpy(&gtd->screen->lines[cnt]->str, str);
 
 			str = NULL;
 		}

+ 10 - 9
src/session.c

@@ -28,7 +28,6 @@
 
 DO_COMMAND(do_all)
 {
-	char arg1[BUFFER_SIZE];
 	struct session *sesptr;
 
 	if (gts->next)
@@ -55,7 +54,7 @@ DO_COMMAND(do_all)
 
 DO_COMMAND(do_session)
 {
-	char temp[BUFFER_SIZE], arg1[BUFFER_SIZE];
+	char temp[BUFFER_SIZE];
 	struct session *sesptr;
 	int cnt;
 
@@ -138,7 +137,6 @@ DO_COMMAND(do_session)
 DO_COMMAND(do_snoop)
 {
 	struct session *sesptr = ses;
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
@@ -194,7 +192,6 @@ DO_COMMAND(do_snoop)
 DO_COMMAND(do_zap)
 {
 	struct session *sesptr;
-	char arg1[BUFFER_SIZE];
 
 	push_call("do_zap(%p,%p)",ses,arg);
 
@@ -224,7 +221,8 @@ DO_COMMAND(do_zap)
 	if (sesptr == gts)
 	{
 		pop_call();
-		return do_end(NULL, "");
+		return execute(ses, "#END");
+//		do_end(NULL, "");
 	}
 
 	if (ses == sesptr)
@@ -519,7 +517,7 @@ struct session *new_session(struct session *ses, char *name, char *arg, int desc
 
 	if (*file)
 	{
-		newses = do_read(newses, file);
+		newses = execute(newses, "#READ %s", file);
 	}
 	check_all_events(newses, SUB_ARG, 0, 4, "SESSION CREATED", newses->name, newses->session_host, newses->session_ip, newses->session_port);
 
@@ -671,6 +669,9 @@ void cleanup_session(struct session *ses)
 
 	SET_BIT(ses->flags, SES_FLAG_CLOSED);
 
+	client_end_mccp2(ses);
+	client_end_mccp3(ses);
+
 	if (HAS_BIT(ses->flags, SES_FLAG_PORT) || HAS_BIT(ses->flags, SES_FLAG_CONNECTED))
 	{
 		DEL_BIT(ses->flags, SES_FLAG_CONNECTED);
@@ -747,9 +748,6 @@ void dispose_session(struct session *ses)
 		free_list(ses->list[index]);
 	}
 
-	client_end_mccp2(ses);
-	client_end_mccp3(ses);
-
 	init_buffer(ses, 0);
 
 	free(ses->name);
@@ -762,6 +760,9 @@ void dispose_session(struct session *ses)
 	free(ses->lognext_name);
 	free(ses->logline_name);
 	free(ses->split);
+	str_free(ses->input->buf);
+	str_free(ses->input->tmp);
+	free(ses->input);
 
 	free(ses);
 

+ 22 - 34
src/show.c

@@ -30,31 +30,33 @@
 
 DO_COMMAND(do_showme)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE], temp[STRING_SIZE], *output;
+	char *out, *tmp;
 	int lnf;
 
+	push_call("do_showme(%p,%p)",ses,arg);
+
+	out = str_alloc_stack();
+	tmp = str_alloc_stack();
+
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
 
 	lnf = !str_suffix(arg1, "\\");
 
-	substitute(ses, arg1, temp, SUB_VAR|SUB_FUN);
-	substitute(ses, temp, arg1, SUB_COL|SUB_ESC);
+	substitute(ses, arg1, tmp, SUB_VAR|SUB_FUN);
+	substitute(ses, tmp, arg1, SUB_COL|SUB_ESC);
 
 	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 (HAS_BIT(ses->flags, SES_FLAG_GAG))
+	if (ses->gagline > 0)
 	{
-		DEL_BIT(ses->flags, SES_FLAG_GAG);
-
-//		gtd->level->ignore++;
+		ses->gagline--;
 
-		show_debug(ses, LIST_GAG, "#DEBUG GAG {%s}", arg1);
-
-//		gtd->level->ignore--;
+		show_debug(ses, LIST_GAG, "#DEBUG GAG {%d} {%s}", ses->gagline + 1, arg1);
 
+		pop_call();
 		return ses;
 	}
 
@@ -62,19 +64,20 @@ DO_COMMAND(do_showme)
 	{
 		split_show(ses, arg1, (int) get_number(ses, arg2), (int) get_number(ses, arg3));
 
+		pop_call();
 		return ses;
 	}
 
 	if (strip_vt102_strlen(ses, ses->more_output) != 0)
 	{
-		output = str_dup_printf("\n%s%s%s", COLOR_TEXT, arg1, COLOR_TEXT);
+		str_cpy_printf(&out, "\n%s%s%s", COLOR_TEXT, arg1, COLOR_TEXT);
 	}
 	else
 	{
-		output = str_dup_printf("%s%s%s", COLOR_TEXT, arg1, COLOR_TEXT);
+		str_cpy_printf(&out, "%s%s%s", COLOR_TEXT, arg1, COLOR_TEXT);
 	}
 
-	add_line_buffer(ses, output, lnf);
+	add_line_buffer(ses, out, lnf);
 
 	if (ses == gtd->ses)
 	{
@@ -85,7 +88,7 @@ DO_COMMAND(do_showme)
 			goto_pos(ses, ses->split->bot_row, ses->split->top_col);
 		}
 
-		print_line(ses, &output, lnf);
+		print_line(ses, &out, lnf);
 
 		if (!HAS_BIT(ses->flags, SES_FLAG_READMUD) && IS_SPLIT(ses))
 		{
@@ -93,8 +96,7 @@ DO_COMMAND(do_showme)
 		}
 	}
 
-	str_free(output);
-
+	pop_call();
 	return ses;
 }
 
@@ -435,13 +437,13 @@ void tintin_puts(struct session *ses, char *string)
 
 	do_one_line(string, ses);
 
-	if (HAS_BIT(ses->flags, SES_FLAG_GAG))
+	if (ses->gagline)
 	{
-		DEL_BIT(ses->flags, SES_FLAG_GAG);
+		ses->gagline--;
 
 		gtd->level->ignore++;
 
-		show_debug(ses, LIST_GAG, "#DEBUG GAG {%s}", string);
+		show_debug(ses, LIST_GAG, "#DEBUG GAG {%d} {%s}", ses->gagline + 1, string);
 
 		gtd->level->ignore--;
 	}
@@ -479,7 +481,7 @@ void tintin_puts2(struct session *ses, char *string)
 
 void tintin_puts3(struct session *ses, char *string)
 {
-	char *output, temp[STRING_SIZE];
+	char *output;
 
 	push_call("tintin_puts3(%p,%p)",ses,string);
 
@@ -488,20 +490,6 @@ void tintin_puts3(struct session *ses, char *string)
 		ses = gtd->ses;
 	}
 
-	if (ses->line_capturefile)
-	{
-		sprintf(temp, "{%d}{%s}", ses->line_captureindex++, string);
-
-		if (ses->line_captureindex == 1)
-		{
-			set_nest_node_ses(ses, ses->line_capturefile, "%s", temp);
-		}
-		else
-		{
-			add_nest_node_ses(ses, ses->line_capturefile, "%s", temp);
-		}
-	}
-
 	if (gtd->level->quiet && gtd->level->verbose == 0)
 	{
 		pop_call();

+ 24 - 16
src/split.c

@@ -29,8 +29,6 @@
 
 DO_COMMAND(do_split)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
-
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
 
@@ -168,13 +166,21 @@ void init_split(struct session *ses, int top_row, int top_col, int bot_row, int
 		SET_BIT(ses->flags, SES_FLAG_UPDATEVTMAP);
 	}
 
-	if (!HAS_BIT(ses->flags, SES_FLAG_SCROLLSPLIT))
+
+	check_all_events(ses, SUB_ARG, 0, 4, "SCREEN SPLIT FILL", ntos(ses->split->top_row), ntos(ses->split->top_col), ntos(ses->split->bot_row), ntos(ses->split->bot_col));
+
+	if (!check_all_events(ses, SUB_ARG, 0, 4, "CATCH SCREEN SPLIT FILL", ntos(ses->split->top_row), ntos(ses->split->top_col), ntos(ses->split->bot_row), ntos(ses->split->bot_col)))
 	{
-		if (HAS_BIT(ses->flags, SES_FLAG_VERBOSE) || gtd->level->verbose || gtd->level->quiet == 0)
+		if (!HAS_BIT(ses->flags, SES_FLAG_SCROLLSPLIT))
 		{
-			do_screen(ses, "FILL DEFAULT");
+			if (HAS_BIT(ses->flags, SES_FLAG_VERBOSE) || gtd->level->verbose || gtd->level->quiet == 0)
+			{
+				execute(ses, "#SCREEN FILL DEFAULT");
+			}
 		}
+
 	}
+
 	check_all_events(ses, SUB_ARG, 0, 4, "SCREEN SPLIT", ntos(ses->split->top_row), ntos(ses->split->top_col), ntos(ses->split->bot_row), ntos(ses->split->bot_col));
 
 	pop_call();
@@ -272,13 +278,11 @@ void split_show(struct session *ses, char *prompt, int row, int col)
 		return;
 	}
 
-	if (row > ses->split->top_row && row <= ses->split->bot_row)
+	if (inside_scroll_region(ses, row, col))
 	{
-		if (col >= ses->split->top_col && col <= ses->split->bot_col)
-		{
-			show_error(ses, LIST_PROMPT, "#ERROR: PROMPT ROW IS INSIDE THE SCROLLING REGION: {%s} {%d}.", prompt, original_row);
-			return;
-		}
+		show_error(ses, LIST_PROMPT, "#ERROR: PROMPT ROW IS INSIDE THE SCROLLING REGION: {%s} {%d}.", prompt, original_row);
+
+		return;
 	}
 
 	if (ses != gtd->ses)
@@ -286,13 +290,15 @@ void split_show(struct session *ses, char *prompt, int row, int col)
 		return;
 	}
 
-	len = strip_vt102_strlen(ses, prompt);
+	len = strip_color_strlen(ses, prompt);
 
-	if (len == 0)
+/*	if (len == 0)
 	{
 		sprintf(buf1, "%.*s", gtd->screen->cols + 4, "\e[0m--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
 	}
-	else if (col - 1 + len <= gtd->screen->cols)
+	else */
+
+	if (col - 1 + len <= gtd->screen->cols)
 	{
 		sprintf(buf1, "%s", prompt);
 	}
@@ -300,7 +306,9 @@ void split_show(struct session *ses, char *prompt, int row, int col)
 	{
 		show_debug(ses, LIST_PROMPT, "#DEBUG PROMPT {%s}", prompt);
 
-		sprintf(buf1, "#PROMPT SIZE (%d) LONGER THAN ROW SIZE (%d)", len, gtd->screen->cols);
+		show_debug(ses, LIST_PROMPT, "#PROMPT SIZE %d WITH OFFSET %d LONGER THAN ROW SIZE %d.", len, col, gtd->screen->cols);
+
+		sprintf(buf1, "#PROMPT SIZE %d WITH OFFSET %d LONGER THAN ROW SIZE %d.", len, col, gtd->screen->cols);
 	}
 
 	save_pos(ses);
@@ -325,7 +333,7 @@ void split_show(struct session *ses, char *prompt, int row, int col)
 		print_stdout("%s%s", clear ? "\e[2K" : "", buf1);
 	}
 
-//	set_line_screen(buf1, row - 1, col - 1);
+	set_line_screen(ses, buf1, row - 1, col - 1);
 
 	restore_pos(ses);
 }

+ 1 - 1
src/ssl.c

@@ -35,7 +35,7 @@ static int ssl_check_cert(struct session *ses, gnutls_session_t sslses);
 
 DO_COMMAND(do_ssl)
 {
-	char temp[BUFFER_SIZE], arg1[BUFFER_SIZE];
+	char temp[BUFFER_SIZE];
 
 	substitute(ses, arg, temp, SUB_VAR|SUB_FUN);
 

+ 204 - 0
src/string.c

@@ -0,0 +1,204 @@
+/******************************************************************************
+*   This file is part of TinTin++                                             *
+*                                                                             *
+*   Copyright (C) 2004-2020 Igor van den Hoven                                *
+*                                                                             *
+*   TinTin++ is free software; you can redistribute it and/or modify          *
+*   it under the terms of the GNU General Public License as published by      *
+*   the Free Software Foundation; either version 3 of the License, or         *
+*   (at your option) any later version.                                       *
+*                                                                             *
+*   This program is distributed in the hope that it will be useful,           *
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of            *
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
+*   GNU General Public License for more details.                              *
+*                                                                             *
+*   You should have received a copy of the GNU General Public License         *
+*   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
+******************************************************************************/
+
+/******************************************************************************
+*                               T I N T I N + +                               *
+*                                                                             *
+*                      coded by Igor van den Hoven 2020                       *
+******************************************************************************/
+
+#include "tintin.h"
+
+int str_len_str(struct session *ses, char *str, int start, int end)
+{
+	int raw_cnt, str_cnt, ret_cnt, width, raw_len, tmp_cnt;
+
+	raw_cnt = 0;
+	str_cnt = 0;
+	ret_cnt = 0;
+
+	raw_len = str_len(str);
+
+	while (raw_cnt < raw_len)
+	{
+		if (end >= 0 && str_cnt >= end)
+		{
+			break;
+		}
+
+		tmp_cnt = skip_vt102_codes(&str[raw_cnt]);
+
+		if (tmp_cnt)
+		{
+			raw_cnt += tmp_cnt;
+		}
+		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&str[raw_cnt]))
+		{
+			raw_cnt += get_utf8_width(&str[raw_cnt], &width);
+
+			if (str_cnt >= start)
+			{
+				ret_cnt += width;
+			}
+			str_cnt += width;
+		}
+		else
+		{
+			if (str_cnt >= start)
+			{
+				ret_cnt++;
+			}
+			raw_cnt++;
+			str_cnt++;
+		}
+	}
+	return ret_cnt;
+}
+
+int str_len_raw(struct session *ses, char *str, int start, int end)
+{
+	int raw_cnt, ret_cnt, width, raw_len, tmp_cnt;
+
+	raw_cnt = start;
+	ret_cnt = 0;
+	raw_len = str_len(str);
+
+	while (raw_cnt < raw_len)
+	{
+		if (raw_cnt >= end)
+		{
+			break;
+		}
+
+		tmp_cnt = skip_vt102_codes(&str[raw_cnt]);
+
+		if (tmp_cnt)
+		{
+			// can go past end, but shouldn't be an issue
+			raw_cnt += tmp_cnt;
+		}
+		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&str[raw_cnt]))
+		{
+			raw_cnt += get_utf8_width(&str[raw_cnt], &width);
+			ret_cnt += width;
+		}
+		else
+		{
+			raw_cnt++;
+			ret_cnt++;
+		}
+	}
+	return ret_cnt;
+}
+
+int raw_len_str(struct session *ses, char *str, int start, int end)
+{
+	int raw_cnt, str_cnt, ret_cnt, width, tmp_cnt, raw_len;
+
+	raw_cnt = 0;
+	str_cnt = 0;
+	ret_cnt = 0;
+	raw_len = strlen(str);
+
+	while (raw_cnt < raw_len)
+	{
+		tmp_cnt = skip_vt102_codes(&str[raw_cnt]);
+
+		if (tmp_cnt)
+		{
+			raw_cnt += tmp_cnt;
+
+			if (str_cnt >= start)
+			{
+				ret_cnt += tmp_cnt;
+			}
+			width = 0;
+		}
+		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&str[raw_cnt]))
+		{    
+			tmp_cnt = get_utf8_width(&str[raw_cnt], &width);
+
+			if (str_cnt >= start)
+			{
+				ret_cnt += tmp_cnt;
+			}
+			raw_cnt += tmp_cnt;
+		}
+		else
+		{
+			if (str_cnt >= start)
+			{
+				ret_cnt++;
+			}
+			raw_cnt++;
+			width = 1;
+		}
+		if (end >= 0 && str_cnt + width > end)
+		{
+			break;
+		}
+		str_cnt += width;
+	}
+	return ret_cnt;
+}
+
+int raw_len_raw(struct session *ses, char *str, int start, int end)
+{
+	if (start >= end)
+	{
+		return 0;
+	}
+	return end - start;
+}
+
+char *str_ins_str(struct session *ses, char **str, char *ins, int str_start, int str_end)
+{
+	int len, raw_start, raw_end, raw_len, ins_raw_len;
+
+	len = str_len_str(ses, *str, 0, str_end);
+
+	if (len < str_end)
+	{
+		str_cat_printf(str, "%*s", str_end - len, "");
+	}
+
+	ins_raw_len = raw_len_str(ses, ins, 0, str_end - str_start);
+
+	raw_start = raw_len_str(ses, *str, 0, str_start);
+	raw_len   = raw_len_str(ses, *str, 0, -1);
+	raw_end   = raw_len_str(ses, *str, 0, str_end);
+
+	if (raw_len < raw_end + ins_raw_len)
+	{
+		str_resize(str, ins_raw_len);
+
+		memmove(*str + raw_start + ins_raw_len, *str + raw_end, raw_len - raw_end + 1);
+
+		memcpy(*str + raw_start, ins, ins_raw_len);
+	}
+	else
+	{
+		memcpy(*str + raw_start, ins, ins_raw_len);
+
+		(*str)[raw_start + ins_raw_len] = 0;
+	}
+	str_fix(*str);
+
+	return *str;
+}

+ 411 - 105
src/substitute.c

@@ -267,6 +267,33 @@ char *c32_fg_bold[26] =
 	"", "<ff80>", "<ff08>", "", "<ff00>", "<fddd>", "<fdb0>", "", "<f80f>", "<ffff>", "", "<fff0>", ""
 };
 
+int valid_escape(struct session *ses, char *str)
+{
+	switch (*str)
+	{
+		case '0':
+		case 'a':
+		case 'c':
+		case 'e':
+		case 'f':
+		case 'n':
+		case 'r':
+		case 't':
+		case 'x':
+		case 'u':
+		case 'U':
+		case 'v':
+		case ';':
+		case '$':
+		case '@':
+		case '*':
+		case '&':
+		case '\\':
+			return TRUE;
+	}
+	return FALSE;
+}
+
 int is_variable(struct session *ses, char *str)
 {
 	struct listroot *root;
@@ -354,84 +381,6 @@ int is_function(struct session *ses, char *str)
 	return TRUE;
 }
 
-int is_color_code(char *pti)
-{
-	if (pti[0] == '<')
-	{
-		if (pti[1] == 0 || pti[2] == 0 || pti[3] == 0 || pti[4] == 0)
-		{
-			return 0;
-		}
-
-		if (pti[4] == '>')
-		{
-
-			if (isdigit(pti[1]) && isdigit(pti[2]) && isdigit(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')
-			{
-				return 5;
-			}
-
-			if (pti[1] == 'g' || pti[1] == 'G')
-			{
-				if (isdigit((int) pti[2]) && isdigit((int) pti[3]))
-				{
-					return 5;
-				}
-				return 0;
-			}
-
-			return 0;
-		}
-
-		if (pti[5] == 0)
-		{
-			return 0;
-		}
-
-		if (toupper((int) pti[1]) == 'F')
-		{
-			if (isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && pti[5] == '>')
-			{
-				return 6;
-			}
-			else if (pti[2] == '?' && pti[3] == '?' && pti[4] == '?' && pti[5] == '>')
-			{
-				return 6;
-			}
-			else if (isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && isxdigit(pti[5]) && isxdigit(pti[6]) && isxdigit(pti[7]) && pti[8] == '>')
-			{
-				return 9;
-			}
-			return 0;
-		}
-
-		if (toupper(pti[1]) == 'B')
-		{
-			if (isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && pti[5] == '>')
-			{
-				return 6;
-			}
-			if (toupper(pti[1]) == 'B' && pti[2] == '?' && pti[3] == '?' && pti[4] == '?' && pti[5] == '>')
-			{
-				return 6;
-			}
-			if (toupper(pti[1]) == 'B' && isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && isxdigit(pti[5]) && isxdigit(pti[6]) && isxdigit(pti[7]) && pti[8] == '>')
-			{
-				return 9;
-			}
-			return 0;
-		}
-	}
-	return 0;
-}
 
 
 char *fuzzy_char(struct session *ses, char val1, char val2, int mode)
@@ -515,7 +464,7 @@ char *fuzzy_color_code(struct session *ses, char *in)
 
 			if (pti[4] == '>')
 			{
-				if (isdigit(pti[1]) && isdigit(pti[2]) && isdigit(pti[3]))
+				if (isdigit((int) pti[1]) && isdigit((int) pti[2]) && isdigit((int) pti[3]))
 				{
 					pto += sprintf(pto, "<%c%c%c>", pti[1], pti[2], pti[3]);
 				}
@@ -541,7 +490,7 @@ char *fuzzy_color_code(struct session *ses, char *in)
 			}
 			else if (toupper((int) pti[1]) == 'F')
 			{
-				if (isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && pti[5] == '>')
+				if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && pti[5] == '>')
 				{
 					pto += sprintf(pto, "<F%s%s%s>", fuzzy_char(ses, 0, pti[2], 12), fuzzy_char(ses, 0, pti[3], 12), fuzzy_char(ses, 0, pti[4], 12));
 
@@ -555,7 +504,7 @@ char *fuzzy_color_code(struct session *ses, char *in)
 
 					pti += 6;
 				}
-				else if (isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && isxdigit(pti[5]) && isxdigit(pti[6]) && isxdigit(pti[7]) && pti[8] == '>')
+				else if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && isxdigit((int) pti[5]) && isxdigit((int) pti[6]) && isxdigit((int) pti[7]) && pti[8] == '>')
 				{
 					pto += sprintf(pto, "<F%s%s%s>", fuzzy_char(ses, pti[3], pti[4], 24), fuzzy_char(ses, pti[4], pti[5], 24), fuzzy_char(ses, pti[7], pti[7], 24));
 
@@ -566,9 +515,9 @@ char *fuzzy_color_code(struct session *ses, char *in)
 					return out[cnt];
 				}
 			}
-			else if (toupper(pti[1]) == 'B')
+			else if (toupper((int) pti[1]) == 'B')
 			{
-				if (isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && pti[5] == '>')
+				if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && pti[5] == '>')
 				{
 					pto += sprintf(pto, "<B%s%s%s>", fuzzy_char(ses, 0, pti[2], 12), fuzzy_char(ses, 0, pti[3], 12), fuzzy_char(ses, 0, pti[4], 12));
 
@@ -582,7 +531,7 @@ char *fuzzy_color_code(struct session *ses, char *in)
 
 					pti += 6;
 				}
-				else if (isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && isxdigit(pti[5]) && isxdigit(pti[6]) && isxdigit(pti[7]) && pti[8] == '>')
+				else if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && isxdigit((int) pti[5]) && isxdigit((int) pti[6]) && isxdigit((int) pti[7]) && pti[8] == '>')
 				{
 					pto += sprintf(pto, "<B%s%s%s>", fuzzy_char(ses, pti[2], pti[3], 24), fuzzy_char(ses, pti[4], pti[5], 24), fuzzy_char(ses, pti[6], pti[7], 24));
 
@@ -696,7 +645,7 @@ char *dim_color_code(struct session *ses, char *in, int mod)
 
 			if (pti[4] == '>')
 			{
-				if (isdigit(pti[1]) && isdigit(pti[2]) && isdigit(pti[3]))
+				if (isdigit((int) pti[1]) && isdigit((int) pti[2]) && isdigit((int) pti[3]))
 				{
 					pto += sprintf(pto, "<%c%c%c>", pti[1], pti[2], pti[3]);
 				}
@@ -727,13 +676,13 @@ char *dim_color_code(struct session *ses, char *in, int mod)
 					c4096_rnd(ses, &pti[2]);
 				}
 
-				if (isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && pti[5] == '>')
+				if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && pti[5] == '>')
 				{
 					pto += sprintf(pto, "<F%s%s%s>", dim_char(ses, 0, pti[2], mod, 12), dim_char(ses, 0, pti[3], mod, 12), dim_char(ses, 0, pti[4], mod, 12));
 
 					pti += 6;
 				}
-				else if (isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && isxdigit(pti[5]) && isxdigit(pti[6]) && isxdigit(pti[7]) && pti[8] == '>')
+				else if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && isxdigit((int) pti[5]) && isxdigit((int) pti[6]) && isxdigit((int) pti[7]) && pti[8] == '>')
 				{
 					pto += sprintf(pto, "<F%s%s%s>", dim_char(ses, pti[2], pti[3], mod, 24), dim_char(ses, pti[4], pti[5], mod, 24), dim_char(ses, mod, pti[6], pti[7], 24));
 
@@ -744,20 +693,20 @@ char *dim_color_code(struct session *ses, char *in, int mod)
 					return out[cnt];
 				}
 			}
-			else if (toupper(pti[1]) == 'B')
+			else if (toupper((int) pti[1]) == 'B')
 			{
 				if (pti[2] == '?' && pti[3] == '?' && pti[4] == '?' && pti[5] == '>')
 				{
 					c4096_rnd(ses, &pti[2]);
 				}
 
-				if (isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && pti[5] == '>')
+				if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && pti[5] == '>')
 				{
 					pto += sprintf(pto, "<B%s%s%s>", dim_char(ses, 0, pti[2], mod, 12), dim_char(ses, 0, pti[3], mod, 12), dim_char(ses, 0, pti[4], mod, 12));
 
 					pti += 6;
 				}
-				else if (toupper(pti[1]) == 'B' && isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && isxdigit(pti[5]) && isxdigit(pti[6]) && isxdigit(pti[7]) && pti[8] == '>')
+				else if (toupper((int) pti[1]) == 'B' && isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && isxdigit((int) pti[5]) && isxdigit((int) pti[6]) && isxdigit((int) pti[7]) && pti[8] == '>')
 				{
 					pto += sprintf(pto, "<B%s%s%s>", dim_char(ses, pti[2], pti[3], mod, 24), dim_char(ses, pti[4], pti[5], mod, 24), dim_char(ses, pti[6], pti[7], mod, 24));
 
@@ -816,7 +765,7 @@ char *lit_color_code(struct session *ses, char *pti, int mod)
 
 		if (pti[4] == '>')
 		{
-			if (isdigit(pti[1]) && isdigit(pti[2]) && isdigit(pti[3]))
+			if (isdigit((int) pti[1]) && isdigit((int) pti[2]) && isdigit((int) pti[3]))
 			{
 				sprintf(fuzzy[cnt], "<%c%c%c>%.9s", pti[1], pti[2], pti[3], &pti[5]);
 
@@ -862,7 +811,7 @@ char *lit_color_code(struct session *ses, char *pti, int mod)
 
 		if (toupper((int) pti[1]) == 'F')
 		{
-			if (isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && pti[5] == '>')
+			if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && pti[5] == '>')
 			{
 				sprintf(fuzzy[cnt], "<F%c%c%c>%.9s", lit_char(ses, 'F', pti[2], mod, 12), lit_char(ses, 'F', pti[3], mod, 12), lit_char(ses, 'F', pti[4], mod, 12), &pti[6]);
 
@@ -876,7 +825,7 @@ char *lit_color_code(struct session *ses, char *pti, int mod)
 
 				return dim_color_code(ses, fuzzy[cnt], mod);
 			}
-			else if (isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && isxdigit(pti[5]) && isxdigit(pti[6]) && isxdigit(pti[7]) && pti[8] == '>')
+			else if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && isxdigit((int) pti[5]) && isxdigit((int) pti[6]) && isxdigit((int) pti[7]) && pti[8] == '>')
 			{
 				sprintf(fuzzy[cnt], "<F%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]);
 
@@ -885,15 +834,15 @@ char *lit_color_code(struct session *ses, char *pti, int mod)
 			return "";
 		}
 
-		if (toupper(pti[1]) == 'B')
+		if (toupper((int) pti[1]) == 'B')
 		{
-			if (isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && pti[5] == '>')
+			if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && pti[5] == '>')
 			{
 				sprintf(fuzzy[cnt], "<B%c%c%c>%.9s", lit_char(ses, 'F', pti[2], mod, 12), lit_char(ses, 'F', pti[3], mod, 12), lit_char(ses, 'F', pti[4], mod, 12), &pti[6]);
 
 				return fuzzy[cnt];
 			}
-			if (toupper(pti[1]) == 'B' && pti[2] == '?' && pti[3] == '?' && pti[4] == '?' && pti[5] == '>')
+			if (toupper((int) pti[1]) == 'B' && pti[2] == '?' && pti[3] == '?' && pti[4] == '?' && pti[5] == '>')
 			{
 				sprintf(fuzzy[cnt], "<B??%c>%.9s", '?', &pti[6]);
 
@@ -901,7 +850,7 @@ char *lit_color_code(struct session *ses, char *pti, int mod)
 
 				return dim_color_code(ses, fuzzy[cnt], mod);
 			}
-			if (toupper(pti[1]) == 'B' && isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && isxdigit(pti[5]) && isxdigit(pti[6]) && isxdigit(pti[7]) && pti[8] == '>')
+			if (toupper((int) pti[1]) == 'B' && isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && isxdigit((int) pti[5]) && isxdigit((int) pti[6]) && isxdigit((int) pti[7]) && pti[8] == '>')
 			{
 				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]);
 
@@ -1079,7 +1028,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 
 					substitute(ses, node->arg2, buf, SUB_ARG);
 
-					if (HAS_BIT(node->flags, NODE_FLAG_ONESHOT))
+					if (node->shots && --node->shots == 0)
 					{
 						delete_node_list(ses, LIST_FUNCTION, node);
 					}
@@ -1559,7 +1508,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 					}
 					else if (pti[1] && pti[2] && pti[3] && pti[4] == '>')
 					{
-						if (isdigit(pti[1]) && isdigit(pti[2]) && isdigit(pti[3]))
+						if (isdigit((int) pti[1]) && isdigit((int) pti[2]) && isdigit((int) pti[3]))
 						{
 							if (pti[1] != '8' || pti[2] != '8' || pti[3] != '8')
 							{
@@ -1665,7 +1614,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 							*pto++ = *pti++;
 						}
 					}
-					else if (toupper((int) pti[1]) == 'F' && isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && pti[5] == '>')
+					else if (toupper((int) pti[1]) == 'F' && isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && pti[5] == '>')
 					{
 						if (ses->color == 4096)
 						{
@@ -1681,7 +1630,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(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]);
 
@@ -1699,7 +1648,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' && isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && isxdigit(pti[5]) && isxdigit(pti[6]) && isxdigit(pti[7]) && pti[8] == '>')
+					else if (toupper((int) pti[1]) == 'F' && isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && isxdigit((int) pti[5]) && isxdigit((int) pti[6]) && isxdigit((int) pti[7]) && pti[8] == '>')
 					{
 						if (ses->color == 4096)
 						{
@@ -1715,7 +1664,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 						}
 						pti += sprintf(old, "<F%c%c%c%c%c%c>", pti[2], pti[3], pti[4], pti[5], pti[6], pti[7]);
 					}
-					else if (toupper(pti[1]) == 'B' && isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && pti[5] == '>')
+					else if (toupper((int) pti[1]) == 'B' && isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && pti[5] == '>')
 					{
 						if (ses->color == 4096)
 						{
@@ -1731,7 +1680,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(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]);
 
@@ -1749,7 +1698,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(pti[1]) == 'B' && isxdigit(pti[2]) && isxdigit(pti[3]) && isxdigit(pti[4]) && isxdigit(pti[5]) && isxdigit(pti[6]) && isxdigit(pti[7]) && pti[8] == '>')
+					else if (toupper((int) pti[1]) == 'B' && isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && isxdigit((int) pti[5]) && isxdigit((int) pti[6]) && isxdigit((int) pti[7]) && pti[8] == '>')
 					{
 						if (ses->color == 4096)
 						{
@@ -1837,6 +1786,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 								pti += 4;
 							}
 							break;
+
 						case 'U':
 							if (pti[1] && pti[2] && pti[3] && pti[4] && pti[5] && pti[6])
 							{
@@ -1953,3 +1903,359 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 	pop_call();
 	return 0;
 }
+
+int is_color_code(char *pti)
+{
+	if (pti[0] == '<')
+	{
+		if (pti[1] == 0 || pti[2] == 0 || pti[3] == 0 || pti[4] == 0)
+		{
+			return 0;
+		}
+
+		if (pti[4] == '>')
+		{
+
+			if (isdigit((int) pti[1]) && isdigit((int) pti[2]) && isdigit((int) 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')
+			{
+				return 5;
+			}
+
+			if (pti[1] == 'g' || pti[1] == 'G')
+			{
+				if (isdigit((int) pti[2]) && isdigit((int) pti[3]))
+				{
+					return 5;
+				}
+				return 0;
+			}
+
+			return 0;
+		}
+
+		if (pti[5] == 0)
+		{
+			return 0;
+		}
+
+		if (toupper((int) pti[1]) == 'F')
+		{
+			if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && pti[5] == '>')
+			{
+				return 6;
+			}
+			else if (pti[2] == '?' && pti[3] == '?' && pti[4] == '?' && pti[5] == '>')
+			{
+				return 6;
+			}
+			else if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && isxdigit((int) pti[5]) && isxdigit((int) pti[6]) && isxdigit((int) pti[7]) && pti[8] == '>')
+			{
+				return 9;
+			}
+			return 0;
+		}
+
+		if (toupper((int) pti[1]) == 'B')
+		{
+			if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) 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' && isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && isxdigit((int) pti[5]) && isxdigit((int) pti[6]) && isxdigit((int) pti[7]) && pti[8] == '>')
+			{
+				return 9;
+			}
+			return 0;
+		}
+	}
+	return 0;
+}
+
+int is_color_name(char *string)
+{
+	int cnt, skip;
+
+	while (*string)
+	{
+		switch (*string)
+		{
+			case ' ':
+			case ';':
+			case ',':
+				string++;
+				continue;
+
+			case '<':
+				skip = is_color_code(string);
+
+				if (skip == 0)
+				{
+					return FALSE;
+				}
+				string += skip;
+				continue;
+
+			case '\\':
+				skip = find_escaped_color_code(string);
+
+				if (skip == 0)
+				{
+					return FALSE;
+				}
+				string += skip;
+				continue;
+
+			case '\e':
+				skip = find_color_code(string);
+
+				if (skip == 0)
+				{
+					return FALSE;
+				}
+				string += skip;
+				continue;
+		}
+
+		if (isalpha((int) *string))
+		{
+			for (cnt = 0 ; *color_table[cnt].name ; cnt++)
+			{
+				if (!strncmp(color_table[cnt].name, string, color_table[cnt].len))
+				{
+					break;
+				}
+			}
+
+			if (*color_table[cnt].name == 0)
+			{
+				for (cnt = 0 ; *color_table[cnt].name ; cnt++)
+				{
+					if (!strncasecmp(color_table[cnt].name, string, color_table[cnt].len))
+					{
+						break;
+					}
+				}
+
+				if (*color_table[cnt].name == 0)
+				{
+					return FALSE;
+				}
+			}
+			string += strlen(color_table[cnt].name);
+		}
+		else
+		{
+			return FALSE;
+		}
+	}
+	return TRUE;
+}
+
+int translate_color_names(struct session *ses, char *string, char *result)
+{
+	int cnt, skip;
+
+	*result = 0;
+
+	while (*string)
+	{
+		switch (*string)
+		{
+			case ' ':
+			case ';':
+			case ',':
+				string++;
+				continue;
+
+			case '<':
+				skip = is_color_code(string);
+
+				if (skip == 0)
+				{
+					return FALSE;
+				}
+				result += sprintf(result, "%.*s", skip, string);
+
+				string += skip;
+				continue;
+
+			case '\\':
+				skip = find_escaped_color_code(string);
+
+				if (skip == 0)
+				{
+					return FALSE;
+				}
+				result += sprintf(result, "%.*s", skip, string);
+
+				string += skip;
+				continue;
+
+			case '\e':
+				skip = find_color_code(string);
+
+				if (skip == 0)
+				{
+					return FALSE;
+				}
+				result += sprintf(result, "%.*s", skip, string);
+
+				string += skip;
+				continue;
+		}
+
+		if (isalpha((int) *string))
+		{
+			for (cnt = 0 ; *color_table[cnt].name ; cnt++)
+			{
+				if (!strncmp(color_table[cnt].name, string, color_table[cnt].len))
+				{
+					result += sprintf(result, "%s", color_table[cnt].code);
+
+					break;
+				}
+			}
+
+			if (*color_table[cnt].name == 0)
+			{
+				for (cnt = 0 ; *color_table[cnt].name ; cnt++)
+				{
+					if (!strncasecmp(color_table[cnt].name, string, color_table[cnt].len))
+					{
+						result += sprintf(result, "%s", color_table[cnt].code);
+
+						break;
+					}
+				}
+
+				if (*color_table[cnt].name == 0)
+				{
+					return FALSE;
+				}
+			}
+			string += strlen(color_table[cnt].name);
+		}
+		else
+		{
+			return FALSE;
+		}
+	}
+	return TRUE;
+}
+
+int get_color_names(struct session *ses, char *string, char *result)
+{
+	int cnt, skip;
+
+	*result = 0;
+
+	while (*string)
+	{
+		switch (*string)
+		{
+			case ' ':
+			case ';':
+			case ',':
+				string++;
+				continue;
+
+			case '<':
+				skip = is_color_code(string);
+
+				if (skip == 0)
+				{
+					return FALSE;
+				}
+				string += sprintf(result, "%.*s", skip, string);
+
+				result += substitute(ses, result, result, SUB_COL);
+
+				continue;
+			
+			case '\\':
+				skip = find_escaped_color_code(string);
+
+				if (skip == 0)
+				{
+					string++;
+					if (*string)
+					{
+						*result++ = *string++;
+					}
+				}
+				string += sprintf(result, "%.*s", skip, string);
+
+				result += substitute(ses, result, result, SUB_ESC);
+
+				continue;
+
+			case '\e':
+				skip = find_color_code(string);
+
+				if (skip == 0)
+				{
+					return FALSE;
+				}
+				result += sprintf(result, "%.*s", skip, string);
+
+				string += skip;
+
+				continue;
+		}
+
+		if (isalpha((int) *string))
+		{
+			for (cnt = 0 ; *color_table[cnt].name ; cnt++)
+			{
+				if (!strncmp(color_table[cnt].name, string, color_table[cnt].len))
+				{
+					substitute(ses, color_table[cnt].code, result, SUB_COL);
+
+					result += strlen(result);
+
+					break;
+				}
+			}
+
+			if (*color_table[cnt].name == 0)
+			{
+				for (cnt = 0 ; *color_table[cnt].name ; cnt++)
+				{
+					if (!strncasecmp(color_table[cnt].name, string, color_table[cnt].len))
+					{
+						substitute(ses, color_table[cnt].code, result, SUB_COL);
+
+						result += strlen(result);
+
+						break;
+					}
+				}
+
+				if (*color_table[cnt].name == 0)
+				{
+					return FALSE;
+				}
+			}
+			string += strlen(color_table[cnt].name);
+		}
+		else
+		{
+			return FALSE;
+		}
+	}
+	*result = 0;
+
+	return TRUE;
+}

+ 5 - 7
src/system.c

@@ -42,7 +42,7 @@
 
 DO_COMMAND(do_run)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], temp[BUFFER_SIZE], file[BUFFER_SIZE];
+	char temp[BUFFER_SIZE];
 	int desc, pid;
 	struct winsize size;
 
@@ -50,7 +50,7 @@ DO_COMMAND(do_run)
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
-	arg = sub_arg_in_braces(ses, arg, file, GET_ONE, SUB_VAR|SUB_FUN);
+	arg = sub_arg_in_braces(ses, arg, arg3, GET_ONE, SUB_VAR|SUB_FUN);
 
 	if (*arg1 == 0 || *arg2 == 0)
 	{
@@ -79,7 +79,7 @@ DO_COMMAND(do_run)
 			break;
 
 		default:
-			sprintf(temp, "{%s} {%d} {%s}", arg2, pid, file);
+			sprintf(temp, "{%s} {%d} {%s}", arg2, pid, arg3);
 			ses = new_session(ses, arg1, temp, desc, 0);
 			break;
 	}
@@ -89,7 +89,7 @@ DO_COMMAND(do_run)
 
 DO_COMMAND(do_script)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], *cptr, buf[BUFFER_SIZE], var[BUFFER_SIZE], tmp[BUFFER_SIZE];
+	char *cptr, buf[BUFFER_SIZE], var[BUFFER_SIZE], tmp[BUFFER_SIZE];
 	FILE *script;
 	int index;
 
@@ -272,8 +272,6 @@ DO_COMMAND(do_system)
 
 DO_COMMAND(do_system)
 {
-	char arg1[BUFFER_SIZE];
-
 	sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
 
 	if (*arg1 == 0)
@@ -308,7 +306,7 @@ DO_COMMAND(do_system)
 DO_COMMAND(do_textin)
 {
 	FILE *fp;
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], buffer[BUFFER_SIZE], *cptr;
+	char buffer[BUFFER_SIZE], *cptr;
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);

+ 161 - 102
src/tables.c

@@ -30,104 +30,104 @@
 
 struct command_type command_table[] =
 {
-	{    "action",            do_action,            TOKEN_TYPE_COMMAND },
-	{    "advertise",         do_advertise,         TOKEN_TYPE_COMMAND },
-	{    "alias",             do_alias,             TOKEN_TYPE_COMMAND },
-	{    "all",               do_all,               TOKEN_TYPE_COMMAND },
-	{    "bell",              do_bell,              TOKEN_TYPE_COMMAND },
-	{    "break",             do_nop,               TOKEN_TYPE_BREAK   },
-	{    "buffer",            do_buffer,            TOKEN_TYPE_COMMAND },
-	{    "button",            do_button,            TOKEN_TYPE_COMMAND },
-	{    "case",              do_nop,               TOKEN_TYPE_CASE    },
-	{    "cat",               do_cat,               TOKEN_TYPE_COMMAND },
-	{    "chat",              do_chat,              TOKEN_TYPE_COMMAND },
-	{    "class",             do_class,             TOKEN_TYPE_COMMAND },
-	{    "commands",          do_commands,          TOKEN_TYPE_COMMAND },
-	{    "config",            do_configure,         TOKEN_TYPE_COMMAND },
-	{    "continue",          do_nop,               TOKEN_TYPE_CONTINUE},
-	{    "cr",                do_cr,                TOKEN_TYPE_COMMAND },
-	{    "cursor",            do_cursor,            TOKEN_TYPE_COMMAND },
-	{    "daemon",            do_daemon,            TOKEN_TYPE_COMMAND },
-	{    "debug",             do_debug,             TOKEN_TYPE_COMMAND },
-	{    "default",           do_nop,               TOKEN_TYPE_DEFAULT },
-	{    "delay",             do_delay,             TOKEN_TYPE_COMMAND },
-	{    "dictionary",        do_dictionary,        TOKEN_TYPE_COMMAND },
-	{    "draw",              do_draw,              TOKEN_TYPE_COMMAND },
-	{    "echo",              do_echo,              TOKEN_TYPE_COMMAND },
-	{    "else",              do_nop,               TOKEN_TYPE_ELSE    },
-	{    "elseif",            do_nop,               TOKEN_TYPE_ELSEIF  },
-	{    "end",               do_end,               TOKEN_TYPE_COMMAND },
-	{    "event",             do_event,             TOKEN_TYPE_COMMAND },
-	{    "foreach",           do_nop,               TOKEN_TYPE_FOREACH },
-	{    "format",            do_format,            TOKEN_TYPE_COMMAND },
-	{    "function",          do_function,          TOKEN_TYPE_COMMAND },
-	{    "gag",               do_gag,               TOKEN_TYPE_COMMAND },
-	{    "grep",              do_grep,              TOKEN_TYPE_COMMAND },
-	{    "help",              do_help,              TOKEN_TYPE_COMMAND },
-	{    "highlight",         do_highlight,         TOKEN_TYPE_COMMAND },
-	{    "history",           do_history,           TOKEN_TYPE_COMMAND },
-	{    "if",                do_nop,               TOKEN_TYPE_IF      },
-	{    "ignore",            do_ignore,            TOKEN_TYPE_COMMAND },
-	{    "info",              do_info,              TOKEN_TYPE_COMMAND },
-	{    "kill",              do_kill,              TOKEN_TYPE_COMMAND },
-	{    "killall",           do_killall,           TOKEN_TYPE_COMMAND },
-	{    "line",              do_line,              TOKEN_TYPE_COMMAND },
-	{    "list",              do_list,              TOKEN_TYPE_COMMAND },
-	{    "local",             do_local,             TOKEN_TYPE_COMMAND },
-	{    "log",               do_log,               TOKEN_TYPE_COMMAND },
-	{    "loop",              do_nop,               TOKEN_TYPE_LOOP    },
-	{    "macro",             do_macro,             TOKEN_TYPE_COMMAND },
-	{    "map",               do_map,               TOKEN_TYPE_COMMAND },
-	{    "math",              do_math,              TOKEN_TYPE_COMMAND },
-	{    "message",           do_message,           TOKEN_TYPE_COMMAND },
-	{    "nop",               do_nop,               TOKEN_TYPE_COMMAND },
-	{    "parse",             do_nop,               TOKEN_TYPE_PARSE   },
-	{    "path",              do_path,              TOKEN_TYPE_COMMAND },
-	{    "pathdir",           do_pathdir,           TOKEN_TYPE_COMMAND },
-	{    "port",              do_port,              TOKEN_TYPE_COMMAND },
-	{    "prompt",            do_prompt,            TOKEN_TYPE_COMMAND },
-	{    "read",              do_read,              TOKEN_TYPE_COMMAND },
-	{    "regexp",            do_regexp,            TOKEN_TYPE_REGEX   },
-	{    "replace",           do_replace,           TOKEN_TYPE_COMMAND },
-	{    "return",            do_nop,               TOKEN_TYPE_RETURN  },
-	{    "run",               do_run,               TOKEN_TYPE_COMMAND },
-	{    "scan",              do_scan,              TOKEN_TYPE_COMMAND },
-	{    "screen",            do_screen,            TOKEN_TYPE_COMMAND },
-	{    "script",            do_script,            TOKEN_TYPE_COMMAND },
-	{    "send",              do_send,              TOKEN_TYPE_COMMAND },
-	{    "session",           do_session,           TOKEN_TYPE_COMMAND },
-	{    "showme",            do_showme,            TOKEN_TYPE_COMMAND },
-	{    "snoop",             do_snoop,             TOKEN_TYPE_COMMAND },
-	{    "split",             do_split,             TOKEN_TYPE_COMMAND },
-	{    "ssl",               do_ssl,               TOKEN_TYPE_COMMAND },
-	{    "substitute",        do_substitute,        TOKEN_TYPE_COMMAND },
-	{    "switch",            do_nop,               TOKEN_TYPE_SWITCH  },
-	{    "system",            do_system,            TOKEN_TYPE_COMMAND },
-	{    "tab",               do_tab,               TOKEN_TYPE_COMMAND },
-	{    "test",              do_test,              TOKEN_TYPE_COMMAND },
-	{    "textin",            do_textin,            TOKEN_TYPE_COMMAND },
-	{    "ticker",            do_tick,              TOKEN_TYPE_COMMAND },
-	{    "unaction",          do_unaction,          TOKEN_TYPE_COMMAND },
-	{    "unalias",           do_unalias,           TOKEN_TYPE_COMMAND },
-	{    "unbutton",          do_unbutton,          TOKEN_TYPE_COMMAND },
-	{    "undelay",           do_undelay,           TOKEN_TYPE_COMMAND },
-	{    "unevent",           do_unevent,           TOKEN_TYPE_COMMAND },
-	{    "unfunction",        do_unfunction,        TOKEN_TYPE_COMMAND },
-	{    "ungag",             do_ungag,             TOKEN_TYPE_COMMAND },
-	{    "unhighlight",       do_unhighlight,       TOKEN_TYPE_COMMAND },
-	{    "unmacro",           do_unmacro,           TOKEN_TYPE_COMMAND },
-	{    "unpathdir",         do_unpathdir,         TOKEN_TYPE_COMMAND },
-	{    "unprompt",          do_unprompt,          TOKEN_TYPE_COMMAND },
-	{    "unsplit",           do_unsplit,           TOKEN_TYPE_COMMAND },
-	{    "unsubstitute",      do_unsubstitute,      TOKEN_TYPE_COMMAND },
-	{    "untab",             do_untab,             TOKEN_TYPE_COMMAND },
-	{    "unticker",          do_untick,            TOKEN_TYPE_COMMAND },
-	{    "unvariable",        do_unvariable,        TOKEN_TYPE_COMMAND },
-	{    "variable",          do_variable,          TOKEN_TYPE_COMMAND },
-	{    "while",             do_nop,               TOKEN_TYPE_WHILE   },
-	{    "write",             do_write,             TOKEN_TYPE_COMMAND },
-	{    "zap",               do_zap,               TOKEN_TYPE_COMMAND },
-	{    "",                  NULL,                 TOKEN_TYPE_COMMAND }
+	{    "action",            do_action,            3, TOKEN_TYPE_COMMAND },
+	{    "advertise",         do_advertise,         0, TOKEN_TYPE_COMMAND },
+	{    "alias",             do_alias,             3, TOKEN_TYPE_COMMAND },
+	{    "all",               do_all,               1, TOKEN_TYPE_COMMAND },
+	{    "bell",              do_bell,              2, TOKEN_TYPE_COMMAND },
+	{    "break",             do_nop,               0, TOKEN_TYPE_BREAK   },
+	{    "buffer",            do_buffer,            1, TOKEN_TYPE_COMMAND },
+	{    "button",            do_button,            3, TOKEN_TYPE_COMMAND },
+	{    "case",              do_nop,               0, TOKEN_TYPE_CASE    },
+	{    "cat",               do_cat,               1, TOKEN_TYPE_COMMAND },
+	{    "chat",              do_chat,              2, TOKEN_TYPE_COMMAND },
+	{    "class",             do_class,             3, TOKEN_TYPE_COMMAND },
+	{    "commands",          do_commands,          0, TOKEN_TYPE_COMMAND },
+	{    "config",            do_configure,         2, TOKEN_TYPE_COMMAND },
+	{    "continue",          do_nop,               0, TOKEN_TYPE_CONTINUE},
+	{    "cr",                do_cr,                0, TOKEN_TYPE_COMMAND },
+	{    "cursor",            do_cursor,            1, TOKEN_TYPE_COMMAND },
+	{    "daemon",            do_daemon,            1, TOKEN_TYPE_COMMAND },
+	{    "debug",             do_debug,             2, TOKEN_TYPE_COMMAND },
+	{    "default",           do_nop,               0, TOKEN_TYPE_DEFAULT },
+	{    "delay",             do_delay,             3, TOKEN_TYPE_COMMAND },
+	{    "dictionary",        do_dictionary,        3, TOKEN_TYPE_COMMAND },
+	{    "draw",              do_draw,              3, TOKEN_TYPE_COMMAND },
+	{    "echo",              do_echo,              3, TOKEN_TYPE_COMMAND },
+	{    "else",              do_nop,               0, TOKEN_TYPE_ELSE    },
+	{    "elseif",            do_nop,               0, TOKEN_TYPE_ELSEIF  },
+	{    "end",               do_end,               1, TOKEN_TYPE_COMMAND },
+	{    "event",             do_event,             2, TOKEN_TYPE_COMMAND },
+	{    "foreach",           do_nop,               3, TOKEN_TYPE_FOREACH },
+	{    "format",            do_format,            3, TOKEN_TYPE_COMMAND },
+	{    "function",          do_function,          2, TOKEN_TYPE_COMMAND },
+	{    "gag",               do_gag,               1, TOKEN_TYPE_COMMAND },
+	{    "grep",              do_grep,              2, TOKEN_TYPE_COMMAND },
+	{    "help",              do_help,              1, TOKEN_TYPE_COMMAND },
+	{    "highlight",         do_highlight,         3, TOKEN_TYPE_COMMAND },
+	{    "history",           do_history,           4, TOKEN_TYPE_COMMAND },
+	{    "if",                do_nop,               0, TOKEN_TYPE_IF      },
+	{    "ignore",            do_ignore,            2, TOKEN_TYPE_COMMAND },
+	{    "info",              do_info,              2, TOKEN_TYPE_COMMAND },
+	{    "kill",              do_kill,              2, TOKEN_TYPE_COMMAND },
+	{    "killall",           do_killall,           2, TOKEN_TYPE_COMMAND },
+	{    "line",              do_line,              1, TOKEN_TYPE_COMMAND },
+	{    "list",              do_list,              2, TOKEN_TYPE_COMMAND },
+	{    "local",             do_local,             1, TOKEN_TYPE_COMMAND },
+	{    "log",               do_log,               2, TOKEN_TYPE_COMMAND },
+	{    "loop",              do_nop,               3, TOKEN_TYPE_LOOP    },
+	{    "macro",             do_macro,             4, TOKEN_TYPE_COMMAND },
+	{    "map",               do_map,               2, TOKEN_TYPE_COMMAND },
+	{    "math",              do_math,              2, TOKEN_TYPE_COMMAND },
+	{    "message",           do_message,           2, TOKEN_TYPE_COMMAND },
+	{    "nop",               do_nop,               0, TOKEN_TYPE_COMMAND },
+	{    "parse",             do_nop,               3, TOKEN_TYPE_PARSE   },
+	{    "path",              do_path,              1, TOKEN_TYPE_COMMAND },
+	{    "pathdir",           do_pathdir,           3, TOKEN_TYPE_COMMAND },
+	{    "port",              do_port,              2, TOKEN_TYPE_COMMAND },
+	{    "prompt",            do_prompt,            4, TOKEN_TYPE_COMMAND },
+	{    "read",              do_read,              1, TOKEN_TYPE_COMMAND },
+	{    "regexp",            do_regexp,            4, TOKEN_TYPE_REGEX   },
+	{    "replace",           do_replace,           3, TOKEN_TYPE_COMMAND },
+	{    "return",            do_nop,               0, TOKEN_TYPE_RETURN  },
+	{    "run",               do_run,               3, TOKEN_TYPE_COMMAND },
+	{    "scan",              do_scan,              2, TOKEN_TYPE_COMMAND },
+	{    "screen",            do_screen,            2, TOKEN_TYPE_COMMAND },
+	{    "script",            do_script,            2, TOKEN_TYPE_COMMAND },
+	{    "send",              do_send,              1, TOKEN_TYPE_COMMAND },
+	{    "session",           do_session,           1, TOKEN_TYPE_COMMAND },
+	{    "showme",            do_showme,            3, TOKEN_TYPE_COMMAND },
+	{    "snoop",             do_snoop,             2, TOKEN_TYPE_COMMAND },
+	{    "split",             do_split,             2, TOKEN_TYPE_COMMAND },
+	{    "ssl",               do_ssl,               3, TOKEN_TYPE_COMMAND },
+	{    "substitute",        do_substitute,        3, TOKEN_TYPE_COMMAND },
+	{    "switch",            do_nop,               0, TOKEN_TYPE_SWITCH  },
+	{    "system",            do_system,            1, TOKEN_TYPE_COMMAND },
+	{    "tab",               do_tab,               1, TOKEN_TYPE_COMMAND },
+	{    "test",              do_test,              4, TOKEN_TYPE_COMMAND },
+	{    "textin",            do_textin,            2, TOKEN_TYPE_COMMAND },
+	{    "ticker",            do_tick,              3, TOKEN_TYPE_COMMAND },
+	{    "unaction",          do_unaction,          0, TOKEN_TYPE_COMMAND },
+	{    "unalias",           do_unalias,           0, TOKEN_TYPE_COMMAND },
+	{    "unbutton",          do_unbutton,          0, TOKEN_TYPE_COMMAND },
+	{    "undelay",           do_undelay,           1, TOKEN_TYPE_COMMAND },
+	{    "unevent",           do_unevent,           0, TOKEN_TYPE_COMMAND },
+	{    "unfunction",        do_unfunction,        0, TOKEN_TYPE_COMMAND },
+	{    "ungag",             do_ungag,             0, TOKEN_TYPE_COMMAND },
+	{    "unhighlight",       do_unhighlight,       0, TOKEN_TYPE_COMMAND },
+	{    "unmacro",           do_unmacro,           0, TOKEN_TYPE_COMMAND },
+	{    "unpathdir",         do_unpathdir,         1, TOKEN_TYPE_COMMAND },
+	{    "unprompt",          do_unprompt,          0, TOKEN_TYPE_COMMAND },
+	{    "unsplit",           do_unsplit,           0, TOKEN_TYPE_COMMAND },
+	{    "unsubstitute",      do_unsubstitute,      0, TOKEN_TYPE_COMMAND },
+	{    "untab",             do_untab,             0, TOKEN_TYPE_COMMAND },
+	{    "unticker",          do_untick,            0, TOKEN_TYPE_COMMAND },
+	{    "unvariable",        do_unvariable,        1, TOKEN_TYPE_COMMAND },
+	{    "variable",          do_variable,          1, TOKEN_TYPE_COMMAND },
+	{    "while",             do_nop,               0, TOKEN_TYPE_WHILE   },
+	{    "write",             do_write,             2, TOKEN_TYPE_COMMAND },
+	{    "zap",               do_zap,               1, TOKEN_TYPE_COMMAND },
+	{    "",                  NULL,                 0, TOKEN_TYPE_COMMAND }
 };
 
 
@@ -170,6 +170,7 @@ struct substitution_type substitution_table[] =
 	{    "LNF",                256  },
 //	{    "FIX",                512  },
         {    "COMPRESS",          1024  },
+        {    "LITERAL",           2048  },
 	{    "",                  0     }
 };
 
@@ -550,6 +551,7 @@ struct color_type map_color_table[] =
 struct class_type class_table[] =
 {
 	{    "OPEN",              class_open             },
+	{    "CLEAR",             class_clear            },
 	{    "CLOSE",             class_close            },
 	{    "KILL",              class_kill             },
 	{    "LIST",              class_list             },
@@ -664,7 +666,7 @@ struct array_type array_table[] =
 
 struct map_type map_table[] =
 {
-	{     "AT",               map_at,              0,              2, "Execute command at given location"    },
+	{     "AT",               map_at,              0,              1, "Execute command at given location"    },
 	{     "CENTER",           map_center,          MAP_FLAG_VTMAP, 2, "Set the center of the map display"    },
 	{     "COLOR",            map_color,           MAP_FLAG_VTMAP, 1, "Set the color for given field"        },
 	{     "CREATE",           map_create,          MAP_FLAG_VTMAP, 0, "Creates the initial map"              },
@@ -940,6 +942,14 @@ struct cursor_type cursor_table[] =
 		CURSOR_FLAG_GET_ALL,
 		cursor_paste_buffer
 	},
+	{
+		"PRESERVE MACRO",
+		"Preserve the current macro state",
+		"",
+		CURSOR_FLAG_GET_ALL,
+		cursor_preserve_macro
+	},
+
 	{
 		"PREV WORD",
 		"Move cursor to the previous word",
@@ -954,6 +964,13 @@ struct cursor_type cursor_table[] =
 		CURSOR_FLAG_GET_ALL,
 		cursor_redraw_input
 	},
+	{
+		"RESET MACRO",
+		"Reset the current macro state",
+		"",
+		CURSOR_FLAG_GET_ALL,
+		cursor_reset_macro
+	},
 	{
 		"SCREEN FOCUS IN",
 		"Window is focussed in event",
@@ -1128,10 +1145,17 @@ struct draw_type draw_table[] =
 		draw_line
 	},
 
+	{
+		"MAP",
+		"Draw the map.",
+		0,
+		draw_map
+	},
+
 	{
 		"RAIN",
 		"Draw digital rain.",
-		DRAW_FLAG_NONE,
+		0,
 		draw_rain
 	},
 
@@ -1191,6 +1215,15 @@ struct screen_type screen_table[] =
 		screen_cursor
 	},
 
+	{
+		"DUMP",
+		"Dump the screen buffer.",
+		SCREEN_FLAG_GET_ONE,
+		SCREEN_FLAG_GET_ONE,
+		SCREEN_FLAG_CSIP,
+		screen_dump
+	},
+
 	{
 		"FILL",
 		"Fill given region with given character.",
@@ -1373,6 +1406,9 @@ struct timer_type timer_table[] =
 
 struct event_type event_table[] =
 {
+//	{    "ADD LINE BUFFER",                        EVENT_FLAG_OUTPUT,   "Triggers when output is added to buffer."},
+//	{    "ADD PROMPT BUFFER",                      EVENT_FLAG_OUTPUT,   "Triggers when output is added to buffer."},
+	{    "BUFFER UPDATE",                          EVENT_FLAG_OUTPUT,   "Trigers when scroll buffer is updated."  },	
 	{    "CATCH ",                                 EVENT_FLAG_CATCH,    "Triggers on catch events."               },
 	{    "CHAT MESSAGE",                           EVENT_FLAG_PORT,     "Triggers on any chat related message."   },
 	{    "CLASS ACTIVATED",                        EVENT_FLAG_CLASS,    "Triggers on class activations."          },
@@ -1381,6 +1417,7 @@ struct event_type event_table[] =
 	{    "CLASS DESTROYED",                        EVENT_FLAG_CLASS,    "Triggers on class destruction."          },
 	{    "DATE",                                   EVENT_FLAG_TIME,     "Triggers on the given date."             },
 	{    "DAY",                                    EVENT_FLAG_TIME,     "Triggers each day or given day."         },
+	{    "DISPLAY UPDATE",                         EVENT_FLAG_OUTPUT,   "Trigers when display is updated."        },
 	{    "DOUBLE-CLICKED ",                        EVENT_FLAG_MOUSE,    "Triggers when mouse is double-clicked"   },
 	{    "END OF PATH",                            EVENT_FLAG_MAP,      "Triggers when walking the last room."    },
 	{    "GAG ",                                   EVENT_FLAG_GAG,      "Triggers on gag events."                 },
@@ -1398,19 +1435,26 @@ struct event_type event_table[] =
 	{    "MAP LOCATION",                           EVENT_FLAG_MOUSE,    "Triggers on vt map click."               },
 	{    "MAP LONG-CLICKED ",                      EVENT_FLAG_MOUSE,    "Triggers on vt map click."               },
 	{    "MAP MOUSE LOCATION",                     EVENT_FLAG_MOUSE,    "Triggers when called by #screen raise."  }, 
+	{    "MAP MOVED ",                             EVENT_FLAG_MOUSE,    "Triggers on vt map mouse move."          },
 	{    "MAP PRESSED ",                           EVENT_FLAG_MOUSE,    "Triggers on vt map click."               },
+	{    "MAP REGION ",                            EVENT_FLAG_MOUSE,    "Triggers on vt map mouse events."        },
 	{    "MAP RELEASED ",                          EVENT_FLAG_MOUSE,    "Triggers on vt map click."               },
+	{    "MAP ROOM ",                              EVENT_FLAG_MOUSE,    "Triggers on vt map room mouse events."   },
+	{    "MAP SCROLLED ",                          EVENT_FLAG_MOUSE,    "Triggers on vt map scroll."              },
 	{    "MAP SHORT-CLICKED ",                     EVENT_FLAG_MOUSE,    "Triggers on vt map click."               },
 	{    "MAP TRIPLE-CLICKED ",                    EVENT_FLAG_MOUSE,    "Triggers on vt map click."               },
 	{    "MAP UPDATED VTMAP",                      EVENT_FLAG_MAP,      "Triggers on vt map update."              },
+
 	{    "MINUTE",                                 EVENT_FLAG_TIME,     "Triggers each minute or given minute."   },
 	{    "MONTH",                                  EVENT_FLAG_TIME,     "Triggers each month or given month."     },
 	{    "MOVED ",                                 EVENT_FLAG_MOUSE,    "Triggers when mouse is moved."           },
 	{    "PORT CONNECTION",                        EVENT_FLAG_PORT,     "Triggers when socket connects."          },
 	{    "PORT DISCONNECTION",                     EVENT_FLAG_PORT,     "Triggers when socket disconnects."       },
+	{    "PORT INITIALIZED",                       EVENT_FLAG_PORT,     "Triggers when port is initialized."      },
 	{    "PORT LOG MESSAGE",                       EVENT_FLAG_PORT,     "Triggers on local port log messages."    },
 	{    "PORT MESSAGE",                           EVENT_FLAG_PORT,     "Triggers on local port messages."        },
 	{    "PORT RECEIVED MESSAGE",                  EVENT_FLAG_PORT,     "Triggers when socket data is received."  },
+	{    "PORT UNINITIALIZED",                     EVENT_FLAG_PORT,     "Triggers when port is uninitialized."    },
 	{    "PRESSED ",                               EVENT_FLAG_MOUSE,    "Triggers when mouse button is pressed."  },
 	{    "PROGRAM START",                          EVENT_FLAG_SYSTEM,   "Triggers when main session starts."      },
 	{    "PROGRAM TERMINATION",                    EVENT_FLAG_SYSTEM,   "Triggers when main session exists."      },
@@ -1428,6 +1472,7 @@ struct event_type event_table[] =
 	{    "SCREEN DESKTOP DIMENSIONS",              EVENT_FLAG_SCREEN,   "Triggers when called by #screen raise."  },
 	{    "SCREEN DESKTOP SIZE",                    EVENT_FLAG_SCREEN,   "Triggers when called by #screen raise."  },
 	{    "SCREEN DIMENSIONS",                      EVENT_FLAG_SCREEN,   "Triggers when called by #screen raise."  },
+	{    "SCREEN FILL",                            EVENT_FLAG_SCREEN,   "Triggers when split bars are filled."    },
 	{    "SCREEN FOCUS",                           EVENT_FLAG_SCREEN,   "Triggers when focus changes.",           },
 	{    "SCREEN LOCATION",                        EVENT_FLAG_SCREEN,   "Triggers when called by #screen raise."  },
 	{    "SCREEN MINIMIZED",                       EVENT_FLAG_SCREEN,   "Triggers when called by #screen raise."  },
@@ -1438,6 +1483,7 @@ struct event_type event_table[] =
 	{    "SCREEN ROTATE PORTRAIT",                 EVENT_FLAG_SCREEN,   "Triggers when the screen is rotated."    },
 	{    "SCREEN SIZE",                            EVENT_FLAG_SCREEN,   "Triggers when called by #screen raise."  },
 	{    "SCREEN SPLIT",                           EVENT_FLAG_SCREEN,   "Triggers when the screen is split."      },
+	{    "SCREEN SPLIT FILL",                      EVENT_FLAG_SCREEN,   "Triggers when split region is filled."   },
 	{    "SCREEN UNSPLIT",                         EVENT_FLAG_SCREEN,   "Triggers when the screen is unsplit."    },
 	{    "SCROLLED ",                              EVENT_FLAG_MOUSE,    "Triggers when mouse wheel is scrolled."  },
 	{    "SECOND",                                 EVENT_FLAG_TIME,     "Triggers each second or given second."   },
@@ -1476,6 +1522,7 @@ struct path_type path_table[] =
 	{    "DESCRIBE",          path_describe,       "Describe the path and current position."        },
 	{    "DESTROY",           path_destroy,        "Clear the path and stop path mapping."          },
 	{    "END",               path_end,            ""                                               },
+	{    "GET",               path_get,            "Store a path value into a variable."            },
 	{    "GOTO",              path_goto,           "Move position to given index."                  },
 	{    "INSERT",            path_insert,         "Insert a command to the end of the path."       },
 	{    "LOAD",              path_load,           "Load a path from a variable."                   },
@@ -1504,9 +1551,11 @@ struct line_type line_table[] =
 	{    "DEBUG",             line_debug,          "Execute line in debug mode."                    },
 	{    "GAG",               line_gag,            "Gag the next line."                             },
 	{    "IGNORE",            line_ignore,         "Execute line with triggers ignored."            },
+	{    "LOCAL",             line_local,          "Execute line with local scope."                 },
 	{    "LOG",               line_log,            "Log the next line or given line."               },
 	{    "LOGMODE",           line_logmode,        "Execute line with given log mode."              },
 	{    "LOGVERBATIM",       line_logverbatim,    "Log the line as plain text verbatim."           },
+	{    "MULTISHOT",         line_multishot,      "Execute line creating multishot triggers."      },
 	{    "ONESHOT",           line_oneshot,        "Execute line creating oneshot triggers."        },
 	{    "QUIET",             line_quiet,          "Execute line with all system messages off."     },
 	{    "STRIP",             line_strip,          "Execute line with escape codes stripped."       },
@@ -1516,14 +1565,23 @@ struct line_type line_table[] =
 	{    "",                  NULL,                ""                                               }
 };
 
+struct log_type log_table[] =
+{
+	{    "APPEND",            log_append,          "Start logging, apending to give file."          },
+	{    "OFF",               log_off,             "Stop logging."                                  },
+	{    "OVERWRITE",         log_overwrite,       "Start logging, overwriting the given file."     },
+	{    "",                  NULL,                ""                                               }
+};
+
 struct history_type history_table[] =
 {
-/*	{    "CHARACTER",         history_character,   "Set the character used for repeating commands." }, */
+//	{    "CHARACTER",         history_character,   "Set the character used for repeating commands." },
 	{    "DELETE",            history_delete,      "Delete last command history entry."             },
+	{    "GET",               history_get,         "Store in geven variable a given line or range." },
 	{    "INSERT",            history_insert,      "Insert a new command history entry."            },
 	{    "LIST",              history_list,        "Display command history list."                  },
 	{    "READ",              history_read,        "Read a command history list from file."         },
-/*	{    "SIZE",              history_size,        "The size of the command history."               }, */
+//	{    "SIZE",              history_size,        "The size of the command history."               },
 	{    "WRITE",             history_write,       "Write a command history list to file."          },
 	{    "",                  NULL,                ""                                               }
 };
@@ -2088,6 +2146,7 @@ struct map_group_type map_group_table[] =
 	{ "MUDFONT CURVED BRAILLE",	"MUDFONT CURVED",	1, 2,	1, 2,	0, 0,	"{\\u2818} {\\u28A0} {\\u2844} {\\u2803} {} {} {} {}" },
 
 	{ "UNICODE GRAPHICS",           "UNICODE GRAPHICS",     2, 5,   2, 5,   0, 0,   "{ } {\\u2E0C} {\\u2E1D} {>} {\\u2E0D} {\\u2E0C\\u2E0D} {\\uFF0F} {>\\u2E0D} {\\u2E1C} {\\uFF3C} {\\u2E1D\\u2E1C} {>\\u2E1C} {<} {\\u2E0C<} {\\u2E1D<} {><} {-} {\\u2191} {\\u2193} {\\u2502} {+} {\\U01F806} {\\U01F804} {\\u2500} {[} {(} {]} {)}" },
+//	{ "UNICODE GRAPHICS",           "UNICODE GRAPHICS",     2, 5,   2, 5,   0, 0,   "{ } {\\u2E0C} {\\u2E1D} {>} {\\u2E0D} {\\u2E0C\\u2E0D} {\\uFF0F} {>\\u2E0D} {\\u2E1C} {\\uFF3C} {\\u2E1D\\u2E1C} {>\\u2E1C} {<} {\\u2E0C<} {\\u2E1D<} {><} {-} {\\u2191} {\\u2193} {\\u2502} {+} {\\u2192} {\\u2190} {\\u2500} {[} {(} {]} {)}" },
 
 	{ NULL,				NULL,			0, 0,	0, 0,	0, 0,	"" }
 };

+ 100 - 74
src/telopt_client.c

@@ -494,8 +494,16 @@ int client_translate_telopts(struct session *ses, unsigned char *src, int cplen)
 								cplen -= 3;
 								continue;
 							}
+
 							if (cplen >= 4)
 							{
+								if (cpsrc[2] == '0' && cpsrc[3] == 'c')
+								{
+									check_all_events(ses, SUB_ARG, 0, 0, "VT100 DA");
+									cpsrc += 4;
+									cplen -= 4;
+									continue;
+								}
 								if (cpsrc[2] >= '5' && cpsrc[2] <= '6' && cpsrc[3] == 'n')
 								{
 									if (cpsrc[2] == '5')
@@ -579,13 +587,13 @@ int client_translate_telopts(struct session *ses, unsigned char *src, int cplen)
 
 int client_recv_will_sga(struct session *ses, int cplen, unsigned char *cpsrc)
 {
+	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC WILL SGA");
+
 	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "CATCH IAC WILL SGA"))
 	{
 		return 3;
 	}
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC WILL SGA");
-
 	SET_BIT(ses->telopts, TELOPT_FLAG_SGA);
 
 	if (!HAS_BIT(ses->telopt_flag[TELOPT_SGA / 32], 1 << TELOPT_SGA % 32))
@@ -601,13 +609,13 @@ int client_recv_will_sga(struct session *ses, int cplen, unsigned char *cpsrc)
 
 int client_recv_do_sga(struct session *ses, int cplen, unsigned char *cpsrc)
 {
+	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC DO SGA");
+
 	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "CATCH IAC DO SGA"))
 	{
 		return 3;
 	}
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC DO SGA");
-
 	SET_BIT(ses->telopts, TELOPT_FLAG_SGA);
 
 	if (!HAS_BIT(ses->telopt_flag[TELOPT_SGA / 32], 1 << TELOPT_SGA % 32))
@@ -643,13 +651,13 @@ int client_mark_prompt(struct session *ses, int cplen, unsigned char *cpsrc)
 
 int client_recv_dont_ttype(struct session *ses, int cplen, unsigned char *cpsrc)
 {
+	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC DONT TTYPE");
+
 	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "CATCH IAC DONT TTYPE"))
 	{
 		return 3;
 	}
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC DONT TTYPE");
-
 	DEL_BIT(ses->telopts, TELOPT_FLAG_TTYPE);
 
 	DEL_BIT(ses->telopt_flag[cpsrc[2] / 32], 1 << cpsrc[2] % 32);
@@ -659,13 +667,13 @@ int client_recv_dont_ttype(struct session *ses, int cplen, unsigned char *cpsrc)
 
 int client_recv_sb_ttype(struct session *ses, int cplen, unsigned char *cpsrc)
 {
+	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 1, "IAC SB TTYPE", ntos(cpsrc[3]));
+
 	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 1, "CATCH IAC SB TTYPE", ntos(cpsrc[3])))
 	{
 		return 6;
 	}
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 1, "IAC SB TTYPE", ntos(cpsrc[3]));
-
 	if (HAS_BIT(ses->telopts, TELOPT_FLAG_MTTS))
 	{
 		char mtts[BUFFER_SIZE];
@@ -708,13 +716,13 @@ int client_recv_sb_ttype(struct session *ses, int cplen, unsigned char *cpsrc)
 
 int client_recv_sb_tspeed(struct session *ses, int cplen, unsigned char *cpsrc)
 {
+	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 1, "IAC SB TSPEED", ntos(cpsrc[3]));
+
 	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 1, "CATCH IAC SB TSPEED", ntos(cpsrc[3])))
 	{
 		return 6;
 	}
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 1, "IAC SB TSPEED", ntos(cpsrc[3]));
-
 	SET_BIT(ses->telopts, TELOPT_FLAG_TSPEED);
 
 	telnet_printf(ses, 17, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TSPEED, 0, "38400,38400", IAC, SE);
@@ -731,13 +739,13 @@ int client_recv_sb_tspeed(struct session *ses, int cplen, unsigned char *cpsrc)
 
 int client_recv_do_naws(struct session *ses, int cplen, unsigned char *cpsrc)
 {
+	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC DO NAWS");
+
 	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "CATCH IAC DO NAWS"))
 	{
 		return 3;
 	}
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC DO NAWS");
-
 	SET_BIT(ses->telopts, TELOPT_FLAG_NAWS);
 
 	if (!HAS_BIT(ses->telopt_flag[TELOPT_NAWS / 32], 1 << TELOPT_NAWS % 32))
@@ -761,6 +769,13 @@ int client_send_sb_naws(struct session *ses, int cplen, unsigned char *cpsrc)
 
 	cols = get_scroll_cols(ses);
 
+	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "IAC SB NAWS", ntos(rows), ntos(cols));
+
+	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "CATCH IAC SB NAWS", ntos(rows), ntos(cols)))
+	{
+		return 3;
+	}
+
 	// Properly handle row and colum size of 255
 
 	if (cols % 256 == IAC && gtd->screen->rows % 256 == IAC)
@@ -789,13 +804,13 @@ int client_send_sb_naws(struct session *ses, int cplen, unsigned char *cpsrc)
 
 int client_recv_wont_echo(struct session *ses, int cplen, unsigned char *cpsrc)
 {
+	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC WONT ECHO");
+
 	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "CATCH IAC WONT ECHO"))
 	{
 		return 3;
 	}
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC WONT ECHO");
-
 	SET_BIT(ses->telopts, TELOPT_FLAG_ECHO);
 
 	if (HAS_BIT(ses->telopt_flag[TELOPT_ECHO / 32], 1 << TELOPT_ECHO % 32))
@@ -818,13 +833,13 @@ int client_recv_wont_echo(struct session *ses, int cplen, unsigned char *cpsrc)
 
 int client_recv_will_echo(struct session *ses, int cplen, unsigned char *cpsrc)
 {
+	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC WILL ECHO");
+
 	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "CATCH IAC WILL ECHO"))
 	{
 		return 3;
 	}
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC WILL ECHO");
-
 	DEL_BIT(ses->telopts, TELOPT_FLAG_ECHO);
 
 	if (!HAS_BIT(ses->telopt_flag[TELOPT_ECHO / 32], 1 << TELOPT_ECHO % 32))
@@ -846,13 +861,13 @@ int client_recv_will_echo(struct session *ses, int cplen, unsigned char *cpsrc)
 
 int client_recv_do_echo(struct session *ses, int cplen, unsigned char *cpsrc)
 {
+	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC DO ECHO");
+
 	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "CATCH IAC DO ECHO"))
 	{
 		return 3;
 	}
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC DO ECHO");
-
 	DEL_BIT(ses->telopts, TELOPT_FLAG_ECHO);
 
 	if (!HAS_BIT(ses->telopt_flag[TELOPT_ECHO / 32], 1 << TELOPT_ECHO % 32))
@@ -1358,7 +1373,7 @@ int client_recv_sb_charset(struct session *ses, int cplen, unsigned char *src)
 		return cplen + 1;
 	}
 
-	client_telopt_debug(ses, "IAC SB CHARSET %d %d", src[3], src[4]);
+//	client_telopt_debug(ses, "RCVD IAC SB CHARSET %d %d", src[3], src[4]);
 
 	i = 5;
 
@@ -1390,7 +1405,7 @@ int client_recv_sb_charset(struct session *ses, int cplen, unsigned char *src)
 				break;
 		}
 
-		client_telopt_debug(ses, "IAC SB CHARSET %s %s", buf, var);
+		client_telopt_debug(ses, "RCVD IAC SB CHARSET %s %s", buf, var);
 
 		check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "IAC SB CHARSET", buf, var);
 		check_all_events(ses, SUB_ARG|SUB_SEC, 2, 2, "IAC SB CHARSET %s %s", buf, var, buf, var);
@@ -1418,13 +1433,13 @@ int client_recv_sb_charset(struct session *ses, int cplen, unsigned char *src)
 				{
 					if (HAS_BIT(ses->charset, CHARSET_FLAG_BIG5) || HAS_BIT(ses->charset, CHARSET_FLAG_BIG5TOUTF8))
 					{
-						telnet_printf(ses, 11, "%c%c%c%c BIG-5%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_ACCEPTED, IAC, SE);
+						telnet_printf(ses, 12, "%c%c%c%c BIG-5%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_ACCEPTED, IAC, SE);
 
 						client_telopt_debug(ses, "SENT IAC SB CHARSET ACCEPTED BIG-5");
 					}
 					else
 					{
-						telnet_printf(ses, 11, "%c%c%c%c BIG-5%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_REJECTED, IAC, SE);
+						telnet_printf(ses, 12, "%c%c%c%c BIG-5%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_REJECTED, IAC, SE);
 
 						client_telopt_debug(ses, "SENT IAC SB CHARSET REJECTED BIG-5");
 					}
@@ -1435,13 +1450,13 @@ int client_recv_sb_charset(struct session *ses, int cplen, unsigned char *src)
 					{
 						if (HAS_BIT(ses->charset, CHARSET_FLAG_FANSITOUTF8))
 						{
-							telnet_printf(ses, 11, "%c%c%c%c FANSI%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_ACCEPTED, IAC, SE);
+							telnet_printf(ses, 12, "%c%c%c%c FANSI%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_ACCEPTED, IAC, SE);
 
 							client_telopt_debug(ses, "SENT IAC SB CHARSET ACCEPTED FANSI");
 						}
 						else
 						{
-							telnet_printf(ses, 11, "%c%c%c%c FANSI%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_REJECTED, IAC, SE);
+							telnet_printf(ses, 12, "%c%c%c%c FANSI%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_REJECTED, IAC, SE);
 
 							client_telopt_debug(ses, "SENT IAC SB CHARSET REJECTED FANSI");
 						}
@@ -1453,13 +1468,13 @@ int client_recv_sb_charset(struct session *ses, int cplen, unsigned char *src)
 					{
 						if (HAS_BIT(ses->charset, CHARSET_FLAG_ISO1TOUTF8))
 						{
-							telnet_printf(ses, 11, "%c%c%c%c %s%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_ACCEPTED, var, IAC, SE);
+							telnet_printf(ses, -1, "%c%c%c%c %s%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_ACCEPTED, var, IAC, SE);
 							
 							client_telopt_debug(ses, "SENT IAC SB CHARSET ACCEPTED %s", var);
 						}
 						else
 						{
-							telnet_printf(ses, 11, "%c%c%c%c %s%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_REJECTED, var, IAC, SE);
+							telnet_printf(ses, -1, "%c%c%c%c %s%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_REJECTED, var, IAC, SE);
 
 							client_telopt_debug(ses, "SENT IAC SB CHARSET REJECTED %s", var);
 						}
@@ -1471,13 +1486,13 @@ int client_recv_sb_charset(struct session *ses, int cplen, unsigned char *src)
 					{
 						if (HAS_BIT(ses->charset, CHARSET_FLAG_ISO2TOUTF8))
 						{
-							telnet_printf(ses, 11, "%c%c%c%c %s%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_ACCEPTED, var, IAC, SE);
+							telnet_printf(ses, -1, "%c%c%c%c %s%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_ACCEPTED, var, IAC, SE);
 							
 							client_telopt_debug(ses, "SENT IAC SB CHARSET ACCEPTED %s", var);
 						}
 						else
 						{
-							telnet_printf(ses, 11, "%c%c%c%c %s%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_REJECTED, var, IAC, SE);
+							telnet_printf(ses, -1, "%c%c%c%c %s%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_REJECTED, var, IAC, SE);
 
 							client_telopt_debug(ses, "SENT IAC SB CHARSET REJECTED %s", var);
 						}
@@ -1489,13 +1504,13 @@ int client_recv_sb_charset(struct session *ses, int cplen, unsigned char *src)
 					{
 						if (HAS_BIT(ses->charset, CHARSET_FLAG_GBK1TOUTF8))
 						{
-							telnet_printf(ses, 11, "%c%c%c%c GBK-1%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_ACCEPTED, IAC, SE);
+							telnet_printf(ses, 12, "%c%c%c%c GBK-1%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_ACCEPTED, IAC, SE);
 
 							client_telopt_debug(ses, "SENT IAC SB CHARSET ACCEPTED GBK-1");
 						}
 						else
 						{
-							telnet_printf(ses, 11, "%c%c%c%c GB-18030%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_REJECTED, IAC, SE);
+							telnet_printf(ses, 16, "%c%c%c%c GB-18030%c%c", IAC, SB, TELOPT_CHARSET, CHARSET_REJECTED, IAC, SE);
 
 							client_telopt_debug(ses, "SENT IAC SB CHARSET REJECTED GBK-1");
 						}
@@ -1506,7 +1521,7 @@ int client_recv_sb_charset(struct session *ses, int cplen, unsigned char *src)
 		i++;
 	}
 
-	client_telopt_debug(ses, "IAC SB CHARSET IAC SE");
+	client_telopt_debug(ses, "RCVD IAC SB CHARSET IAC SE");
 
 	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC SB CHARSET IAC SE");
 
@@ -1550,7 +1565,7 @@ int client_recv_sb_new_environ(struct session *ses, int cplen, unsigned char *sr
 		return cplen + 1;
 	}
 
-	client_telopt_debug(ses, "IAC SB NEW-ENVIRON %d %d", src[3], src[4]);
+//	client_telopt_debug(ses, "RCVD IAC SB NEW-ENVIRON %d %d", src[3], src[4]);
 
 	switch (src[3])
 	{
@@ -1570,7 +1585,7 @@ int client_recv_sb_new_environ(struct session *ses, int cplen, unsigned char *sr
 
 	i = 4;
 
-	while (i < cplen && src[i] != SE)
+	while (i < cplen && src[i] != IAC)
 	{
 		switch (src[i])
 		{
@@ -1605,52 +1620,61 @@ int client_recv_sb_new_environ(struct session *ses, int cplen, unsigned char *sr
 
 				if (src[3] == ENV_SEND)
 				{
-					client_telopt_debug(ses, "IAC SB NEW-ENVIRON SEND %s", sub2);
+					client_telopt_debug(ses, "RCVD IAC SB NEW-ENVIRON SEND %s %s", sub2, var);
+
+					check_all_events(ses, SUB_ARG|SUB_SEC, 0, 4, "IAC SB NEW-ENVIRON", sub1, sub2, var, "");
 
 					if (!check_all_events(ses, SUB_ARG|SUB_SEC, 0, 4, "CATCH IAC SB NEW-ENVIRON", sub1, sub2, var, ""))
 					{
-						check_all_events(ses, SUB_ARG|SUB_SEC, 0, 4, "IAC SB NEW-ENVIRON", sub1, sub2, var, "");
+						check_all_events(ses, SUB_ARG|SUB_SEC, 1, 4, "IAC SB NEW-ENVIRON SEND %s", var, sub1, sub2, var, "");
 
 						if (!check_all_events(ses, SUB_ARG|SUB_SEC, 1, 4, "CATCH IAC SB NEW-ENVIRON SEND %s", var, sub1, sub2, var, ""))
 						{
-							check_all_events(ses, SUB_ARG|SUB_SEC, 1, 4, "IAC SB NEW-ENVIRON SEND %s", var, sub1, sub2, var, "");
-
-							if (*var == 0)
+							if (!strcmp(var, ""))
 							{
-								telnet_printf(ses, -1, "%c%c%c" "%c%c%s%c%s" "%c%c%s%c%s" "%c%c%s%c%s" "%c%c%s%c%s" "%c%c%s%c%s" "%c%c",
-									IAC, SB, TELOPT_NEW_ENVIRON,
-									ENV_IS, ENV_VAR, "CHARSET", ENV_VAL, get_charset(ses),
-									ENV_IS, ENV_VAR, "CLIENT_NAME", ENV_VAL, CLIENT_NAME,
-									ENV_IS, ENV_VAR, "CLIENT_VERSION", ENV_VAL, CLIENT_VERSION,
-									ENV_IS, ENV_VAR, "MTTS", ENV_VAL, get_mtts_val(ses),
-									ENV_IS, ENV_VAR, "TERMINAL_TYPE", ENV_VAL, gtd->term,
-									IAC, SE);
+								if (!strcmp(sub2, "VAR"))
+								{
+									client_telopt_debug(ses, "SENT IAC SB NEW-ENVIRON IS VAR %s VAL %s", "CHARSET", get_charset(ses));
+									client_telopt_debug(ses, "SENT IAC SB NEW-ENVIRON IS VAR %s VAL %s", "CLIENT_NAME", CLIENT_NAME);
+									client_telopt_debug(ses, "SENT IAC SB NEW-ENVIRON IS VAR %s VAL %s", "CLIENT_VERSION", CLIENT_VERSION);
+									client_telopt_debug(ses, "SENT IAC SB NEW-ENVIRON IS VAR MTTS VAL %d", get_mtts_val(ses));
+									client_telopt_debug(ses, "SENT IAC SB NEW-ENVIRON IS VAR TERMINAL_TYPE VAL %s", gtd->term);
+
+									telnet_printf(ses, -1, "%c%c%c" "%c%c%s%c%s" "%c%c%s%c%s" "%c%c%s%c%s" "%c%c%s%c%d" "%c%c%s%c%s" "%c%c",
+										IAC, SB, TELOPT_NEW_ENVIRON,
+										ENV_IS, ENV_VAR, "CHARSET", ENV_VAL, get_charset(ses),
+										ENV_IS, ENV_VAR, "CLIENT_NAME", ENV_VAL, CLIENT_NAME,
+										ENV_IS, ENV_VAR, "CLIENT_VERSION", ENV_VAL, CLIENT_VERSION,
+										ENV_IS, ENV_VAR, "MTTS", ENV_VAL, get_mtts_val(ses),
+										ENV_IS, ENV_VAR, "TERMINAL_TYPE", ENV_VAL, gtd->term,
+										IAC, SE);
+								}
 							}
-							else if (!strcasecmp(var, "CHARSET"))
+							else if (!strcmp(var, "CHARSET"))
 							{
 								telnet_printf(ses, -1, "%c%c%c%c%c%s%c%s%c%c", IAC, SB, TELOPT_NEW_ENVIRON, ENV_IS, ENV_VAR, "CHARSET", ENV_VAL, get_charset(ses), IAC, SE);
 
 								client_telopt_debug(ses, "SENT IAC SB NEW-ENVIRON IS VAR %s VAL %s", "CHARSET", get_charset(ses));
 							}
-							else if (!strcasecmp(var, "CLIENT_NAME"))
+							else if (!strcmp(var, "CLIENT_NAME"))
 							{
 								telnet_printf(ses, -1, "%c%c%c%c%c%s%c%s%c%c", IAC, SB, TELOPT_NEW_ENVIRON, ENV_IS, ENV_VAR, "CLIENT_NAME", ENV_VAL, CLIENT_NAME, IAC, SE);
 
 								client_telopt_debug(ses, "SENT IAC SB NEW-ENVIRON IS VAR %s VAL %s", "CLIENT_NAME", CLIENT_NAME);
 							}
-							else if (!strcasecmp(var, "CLIENT_VERSION"))
+							else if (!strcmp(var, "CLIENT_VERSION"))
 							{
 								telnet_printf(ses, -1, "%c%c%c%c%c%s%c%s%c%c", IAC, SB, TELOPT_NEW_ENVIRON, ENV_IS, ENV_VAR, "CLIENT_VERSION", ENV_VAL, CLIENT_VERSION, IAC, SE);
 
 								client_telopt_debug(ses, "SENT IAC SB NEW-ENVIRON IS VAR %s VAL %s", "CLIENT_VERSION", CLIENT_VERSION);
 							}
-							else if (!strcasecmp(var, "MTTS") || *var == 0)
+							else if (!strcmp(var, "MTTS") || *var == 0)
 							{
 								telnet_printf(ses, -1, "%c%c%c%c%c%s%c%d%c%c", IAC, SB, TELOPT_NEW_ENVIRON, ENV_IS, ENV_VAR, "MTTS", ENV_VAL, get_mtts_val(ses), IAC, SE);
 
 								client_telopt_debug(ses, "SENT IAC SB NEW-ENVIRON IS VAR MTTS VAL %d", get_mtts_val(ses));
 							}
-							else if (!strcasecmp(var, "TERMINAL_TYPE"))
+							else if (!strcmp(var, "TERMINAL_TYPE"))
 							{
 								telnet_printf(ses, -1, "%c%c%c%c%c%s%c%s%c%c", IAC, SB, TELOPT_NEW_ENVIRON, ENV_IS, ENV_VAR, "TERMINAL_TYPE", ENV_VAL, gtd->term, IAC, SE);
 
@@ -1673,29 +1697,24 @@ int client_recv_sb_new_environ(struct session *ses, int cplen, unsigned char *sr
 
 				substitute(ses, buf, val, SUB_SEC);
 
-				client_telopt_debug(ses, "IAC SB NEW-ENVIRON %s %s", sub1, sub2);
+				client_telopt_debug(ses, "RCVD IAC SB NEW-ENVIRON %s %s VAR %s VAL %s", sub1, sub2, var, val);
 
 				check_all_events(ses, SUB_ARG|SUB_SEC, 0, 4, "IAC SB NEW-ENVIRON", sub1, sub2, var, val);
 				check_all_events(ses, SUB_ARG|SUB_SEC, 2, 4, "IAC SB NEW-ENVIRON %s %s", sub1, sub2, sub1, sub2, var, val);
 				break;
 
-			case IAC:
-				client_telopt_debug(ses, "IAC SB NEW-ENVIRON (ERROR) %s %s (%s) (%s)", sub1, sub2, var, val);
-				i++;
-				break;
-
 			default:
-				client_telopt_debug(ses, "IAC SB NEW-ENVIRON (ERROR) %03d %c", src[i], src[i]);
+				client_telopt_debug(ses, "RCVD IAC SB NEW-ENVIRON %s (ERROR) %03d %c", sub1, src[i], src[i]);
 				i++;
 				break;
 		}
 	}
 
-	client_telopt_debug(ses, "IAC SB NEW-ENVIRON IAC SE");
+	client_telopt_debug(ses, "RCVD IAC SB NEW-ENVIRON IAC SE");
 
 	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC SB NEW-ENVIRON IAC SE");
 
-	return i + 1;
+	return i + 2;
 }
 
 int client_recv_sb_zmp(struct session *ses, int cplen, unsigned char *src)
@@ -2014,13 +2033,13 @@ int client_recv_sb_gmcp(struct session *ses, int cplen, unsigned char *src)
 
 int client_recv_will_mccp2(struct session *ses, int cplen, unsigned char *cpsrc)
 {
+	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC WILL MCCP2");
+
 	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "CATCH IAC WILL MCCP2"))
 	{
 		return 3;
 	}
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC WILL MCCP2");
-
 	if (HAS_BIT(ses->flags, SES_FLAG_MCCP))
 	{
 		telnet_printf(ses, 3, "%c%c%c", IAC, DO, TELOPT_MCCP2);
@@ -2050,6 +2069,7 @@ int client_init_mccp2(struct session *ses, int cplen, unsigned char *cpsrc)
 {
 	if (ses->mccp2)
 	{
+		client_telopt_debug(ses, "INFO MCCP2 ALREADY INITIALIZED");
 		return 5;
 	}
 
@@ -2069,7 +2089,7 @@ int client_init_mccp2(struct session *ses, int cplen, unsigned char *cpsrc)
 	}
 	else
 	{
-		client_telopt_debug(ses, "MCCP2: INITIALIZED");
+		client_telopt_debug(ses, "INFO MCCP2 INITIALIZED");
 	}
 	return 5;
 }
@@ -2081,9 +2101,15 @@ void client_end_mccp2(struct session *ses)
 		return;
 	}
 
-	if (deflateEnd(ses->mccp2) != Z_OK)
+	ses->mccp2->next_in     = NULL;
+	ses->mccp2->avail_in    = 0;
+
+	ses->mccp2->next_out    = gtd->mccp_buf;
+	ses->mccp2->avail_out   = gtd->mccp_len;
+
+	if (deflateEnd(ses->mccp2) == Z_STREAM_ERROR)
 	{
-		tintin_printf2(ses, "MCCP2: FAILED TO DEFLATE_END");
+		client_telopt_debug(ses, "MCCP2: deflateEnd failed:");
 	}
 
 	free(ses->mccp2);
@@ -2100,13 +2126,13 @@ void client_end_mccp2(struct session *ses)
 
 int client_recv_will_mccp3(struct session *ses, int cplen, unsigned char *cpsrc)
 {
+	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC WILL MCCP3");
+
 	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "CATCH IAC WILL MCCP3"))
 	{
 		return 3;
 	}
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC WILL MCCP3");
-
 	if (HAS_BIT(ses->flags, SES_FLAG_MCCP))
 	{
 		telnet_printf(ses, 3, "%c%c%c", IAC, DO, TELOPT_MCCP3);
@@ -2127,13 +2153,13 @@ int client_recv_will_mccp3(struct session *ses, int cplen, unsigned char *cpsrc)
 
 int client_recv_dont_mccp3(struct session *ses, int cplen, unsigned char *cpsrc)
 {
+	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC DONT MCCP3");
+
 	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "CATCH IAC DONT MCCP3"))
 	{
 	 	return 3;
 	}
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC DONT MCCP3");
-
 	if (ses->mccp3)
 	{
 		client_end_mccp3(ses);
@@ -2143,13 +2169,13 @@ int client_recv_dont_mccp3(struct session *ses, int cplen, unsigned char *cpsrc)
 
 int client_recv_wont_mccp3(struct session *ses, int cplen, unsigned char *cpsrc)
 {
+	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC WONT MCCP3");
+
 	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "CATCH IAC WONT MCCP3"))
 	{
 	 	return 3;
 	}
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC WONT MCCP3");
-
 	if (ses->mccp3)
 	{
 		client_end_mccp3(ses);
@@ -2163,7 +2189,7 @@ int client_init_mccp3(struct session *ses)
 
 	if (ses->mccp3)
 	{
-		client_telopt_debug(ses, "MCCP3: ALREADY INITIALIZED");
+		client_telopt_debug(ses, "INFO MCCP3 ALREADY INITIALIZED");
 
 		return TRUE;
 	}
@@ -2183,7 +2209,7 @@ int client_init_mccp3(struct session *ses)
 
 	if (deflateInit(stream, Z_BEST_COMPRESSION) != Z_OK)
 	{
-		client_telopt_debug(ses, "MCCP3: FAILED TO INITIALIZE");
+		client_telopt_debug(ses, "INFO MCCP3 FAILED TO INITIALIZE");
 
 		free(stream);
 
@@ -2194,7 +2220,7 @@ int client_init_mccp3(struct session *ses)
 
 	client_telopt_debug(ses, "SENT IAC SB MCCP3 IAC SE");
 
-	client_telopt_debug(ses, "MCCP3: INITIALIZED");
+	client_telopt_debug(ses, "INFO MCCP3 INITIALIZED");
 
 	ses->mccp3 = stream;
 

+ 2 - 2
src/telopt_server.c

@@ -808,8 +808,8 @@ int process_do_msdp(struct session *ses, struct port_data *buddy, unsigned char
 	msdp_update_varf(ses, buddy, "SCREEN_HEIGHT",   "%d", gtd->screen->height);
 	msdp_update_varf(ses, buddy, "SCREEN_WIDTH",    "%d", gtd->screen->width);
 
-	msdp_update_varf(ses, buddy, "SCREEN_POSITION_HEIGHT", "%d", gtd->screen->pos_height);
-	msdp_update_varf(ses, buddy, "SCREEN_POSITION_WIDTH",  "%d", gtd->screen->pos_width);
+	msdp_update_varf(ses, buddy, "SCREEN_LOCATION_HEIGHT", "%d", gtd->screen->pos_height);
+	msdp_update_varf(ses, buddy, "SCREEN_LOCATION_WIDTH",  "%d", gtd->screen->pos_width);
 
 	msdp_update_varf(ses, buddy, "SCREEN_FOCUS",     "%d", gtd->screen->focus);
 	msdp_update_varf(ses, buddy, "SCREEN_MINIMIZED", "%d", gtd->screen->minimized);

+ 3 - 0
src/terminal.c

@@ -218,6 +218,9 @@ char *get_charset(struct session *ses)
 		case CHARSET_FLAG_UTF8|CHARSET_FLAG_BIG5TOUTF8:
 			return "BIG5TOUTF8";
 
+	        case CHARSET_FLAG_UTF8|CHARSET_FLAG_CP1251TOUTF8:
+	        	return "CP1251TOUTF8";
+
 		case CHARSET_FLAG_UTF8|CHARSET_FLAG_FANSITOUTF8:
 			return "FANSI";
 		

+ 4 - 7
src/text.c

@@ -83,8 +83,6 @@ void print_line(struct session *ses, char **str, int prompt)
 
 	str_free(out);
 
-	SET_BIT(gtd->flags, TINTIN_FLAG_FLUSH);
-
 	pop_call();
 	return;
 }
@@ -108,12 +106,11 @@ void print_stdout(char *format, ...)
 	}
 	else
 	{
-		SET_BIT(gtd->flags, TINTIN_FLAG_FLUSH);
-
-		printf("%s", buffer);
+		SET_BIT(gtd->flags, TINTIN_FLAG_DISPLAYUPDATE);
 
-//		fwrite(buffer, len, 1, stdout);
-//		write(STDIN_FILENO, buffer, len); slooow
+		fputs(buffer, stdout);
+	
+//		printf("%s", buffer);
 	}
 	free(buffer);
 }

+ 144 - 56
src/tintin.h

@@ -161,10 +161,12 @@
 
 #define HISTORY_FILE         "history.txt"
 
-#define STRING_SIZE                  50000
-#define BUFFER_SIZE                  24000
+#define STRING_SIZE                  63000
+#define BUFFER_SIZE                  30000
 #define INPUT_SIZE                   10000
+#define PATH_SIZE                     4096
 #define STACK_SIZE                    1000
+#define NAME_SIZE                      256
 #define NUMBER_SIZE                    100
 #define LEGEND_SIZE                     50
 #define COLOR_SIZE                      50
@@ -172,7 +174,7 @@
 #define LIST_SIZE                        2
 
 #define CLIENT_NAME              "TinTin++"
-#define CLIENT_VERSION           "2.02.02 "
+#define CLIENT_VERSION           "2.02.03 "
 
 #define XT_E                            0x27
 #define XT_C                            0x5B
@@ -201,6 +203,7 @@
 
 #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_RESET         "\e[0m"        // "<088>" // reset
 #define COLOR_SEPARATOR     "\e[38;5;160m" // "<eaa>" // red
 #define COLOR_STATEMENT     "\e[38;5;040m" // "<aea>" // green
@@ -208,6 +211,7 @@
 #define COLOR_TEXT          "\e[0m"        // "<ddd>" // grey
 #define COLOR_TINTIN        "\e[38;5;184m" // "<eea>" // yellow
 
+
 #define TIMER_UPDATE_INPUT               0
 #define TIMER_UPDATE_SESSIONS            1
 #define TIMER_UPDATE_DELAYS              2
@@ -294,7 +298,9 @@ enum operators
 	TOKEN_TYPE_STRING,
 	TOKEN_TYPE_SWITCH,
 	TOKEN_TYPE_WHILE,
-	TOKEN_TYPE_BROKEN_WHILE
+	TOKEN_TYPE_BROKEN_WHILE,
+	TOKEN_TYPE_STATEMENT,
+	TOKEN_TYPE_CONFIG
 };
 
 /*
@@ -357,10 +363,12 @@ enum operators
 #define CHARSET_FLAG_ISO1TOUTF8           BV07
 #define CHARSET_FLAG_ISO2TOUTF8           BV08
 #define CHARSET_FLAG_KOI8TOUTF8           BV09
+#define CHARSET_FLAG_CP1251TOUTF8         BV10
+
 
 
 #define CHARSET_FLAG_EUC                  CHARSET_FLAG_BIG5|CHARSET_FLAG_GBK1
-#define CHARSET_FLAG_ALL_TOUTF8           CHARSET_FLAG_BIG5TOUTF8|CHARSET_FLAG_FANSITOUTF8|CHARSET_FLAG_GBK1TOUTF8|CHARSET_FLAG_ISO1TOUTF8|CHARSET_FLAG_ISO2TOUTF8|CHARSET_FLAG_KOI8TOUTF8
+#define CHARSET_FLAG_ALL_TOUTF8           CHARSET_FLAG_BIG5TOUTF8|CHARSET_FLAG_CP1251TOUTF8|CHARSET_FLAG_FANSITOUTF8|CHARSET_FLAG_GBK1TOUTF8|CHARSET_FLAG_ISO1TOUTF8|CHARSET_FLAG_ISO2TOUTF8|CHARSET_FLAG_KOI8TOUTF8
 #define CHARSET_FLAG_ALL                  CHARSET_FLAG_UTF8|CHARSET_FLAG_ALL_TOUTF8|CHARSET_FLAG_EUC
 
 
@@ -463,21 +471,23 @@ enum operators
 #define DRAW_FLAG_FAT                 BV31
 #define DRAW_FLAG_SANSSERIF           BV32
 
-#define EVENT_FLAG_CATCH              BV01
-#define EVENT_FLAG_CLASS              BV02
-#define EVENT_FLAG_GAG                BV03
-#define EVENT_FLAG_INPUT              BV04
-#define EVENT_FLAG_MAP                BV05
-#define EVENT_FLAG_MOUSE              BV06
-#define EVENT_FLAG_OUTPUT             BV07
-#define EVENT_FLAG_PORT               BV08
-#define EVENT_FLAG_SCAN               BV09
-#define EVENT_FLAG_SCREEN             BV10
-#define EVENT_FLAG_SESSION            BV11
-#define EVENT_FLAG_SYSTEM             BV12
-#define EVENT_FLAG_TELNET             BV13
-#define EVENT_FLAG_TIME               BV14
-#define EVENT_FLAG_VT100              BV15
+#define EVENT_FLAG_SILENT             BV01 // unused
+
+#define EVENT_FLAG_CATCH              BV03
+#define EVENT_FLAG_CLASS              BV04
+#define EVENT_FLAG_GAG                BV05
+#define EVENT_FLAG_INPUT              BV06
+#define EVENT_FLAG_MAP                BV07
+#define EVENT_FLAG_MOUSE              BV08
+#define EVENT_FLAG_OUTPUT             BV09
+#define EVENT_FLAG_PORT               BV10
+#define EVENT_FLAG_SCAN               BV11
+#define EVENT_FLAG_SCREEN             BV12
+#define EVENT_FLAG_SESSION            BV13
+#define EVENT_FLAG_SYSTEM             BV14
+#define EVENT_FLAG_TELNET             BV15
+#define EVENT_FLAG_TIME               BV16
+#define EVENT_FLAG_VT100              BV17
 
 
 #define PORT_FLAG_PRIVATE             BV01
@@ -538,12 +548,12 @@ enum operators
 #define SUB_COL                       (1 <<  3)
 #define SUB_ESC                       (1 <<  4)
 #define SUB_CMD                       (1 <<  5)
-#define SUB_SEC                       (1 <<  6)
+#define SUB_SEC                       (1 <<  6) // secure
 #define SUB_EOL                       (1 <<  7)
 #define SUB_LNF                       (1 <<  8)
-//#define SUB_FIX                       (1 <<  9)
-#define SUB_CMP                       (1 << 10)
-#define SUB_LIT                       (1 << 11)
+#define SUB_SIL                       (1 <<  9) // silent
+#define SUB_CMP                       (1 << 10) // basic color compression
+#define SUB_LIT                       (1 << 11) // no soft escaping
 
 #define TAB_FLAG_FORWARD              BV01
 #define TAB_FLAG_BACKWARD             BV02
@@ -569,10 +579,11 @@ enum operators
 #define TINTIN_FLAG_CHILDLOCK         (1 <<  8)
 #define TINTIN_FLAG_TERMINATE         (1 <<  9)
 #define TINTIN_FLAG_MOUSETRACKING     (1 << 10)
-#define TINTIN_FLAG_FLUSH             (1 << 11)
+#define TINTIN_FLAG_DISPLAYUPDATE     (1 << 11)
 #define TINTIN_FLAG_DAEMONIZE         (1 << 12)
 #define TINTIN_FLAG_HIDDENCURSOR      (1 << 13)
 #define TINTIN_FLAG_LOCAL             (1 << 14)
+#define TINTIN_FLAG_PRESERVEMACRO     (1 << 15)
 
 #define SES_FLAG_ECHOCOMMAND          BV01
 #define SES_FLAG_SNOOP                BV02
@@ -606,7 +617,7 @@ enum operators
 #define SES_FLAG_MOUSEDEBUG           BV30
 #define SES_FLAG_MOUSEINFO            BV31
 #define SES_FLAG_AUTOPROMPT           BV32
-
+#define SES_FLAG_BUFFERUPDATE         BV33 // needs to be finished
 
 #define TELOPT_FLAG_TELNET            BV01
 #define TELOPT_FLAG_SGA               BV02
@@ -954,18 +965,19 @@ enum operators
 
 #define IS_SPLIT(ses)             (gtd->screen->rows != (ses)->split->bot_row)
 #define SCROLL(ses)               ((ses)->cur_row == 0 || ((ses)->cur_row >= (ses)->split->top_row && (ses)->cur_row <= (ses)->split->bot_row) || (ses)->cur_row == gtd->screen->rows)
-#define VERBATIM(ses)             (gtd->level->verbatim || (gtd->level->input == 0 && HAS_BIT((ses)->flags, SES_FLAG_VERBATIM)))
+#define VERBATIM(ses)             (gtd->level->verbatim || (gtd->level->input == 0 && HAS_BIT((ses)->flags, SES_FLAG_VERBATIM)) || HAS_BIT(gtd->flags, TINTIN_FLAG_CHILDLOCK))
 
 #define DO_ARRAY(array) struct session *array (struct session *ses, struct listnode *list, char *arg, char *var)
 #define DO_BUFFER(buffer) void buffer (struct session *ses, char *arg)
 #define DO_CHAT(chat) void chat (char *arg1, char *arg2)
 #define DO_CLASS(class) struct session *class (struct session *ses, struct listnode *node, char *arg1, char *arg2)
-#define DO_COMMAND(command) struct session  *command (struct session *ses, char *arg)
+#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)
-#define DO_HISTORY(history) void history (struct session *ses, char *arg)
+#define DO_HISTORY(history) void history (struct session *ses, char *arg1, char *arg2, char *arg3)
 #define DO_LINE(line) struct session *line (struct session *ses, char *arg)
+#define DO_LOG(log) void log (struct session *ses, char *arg, char *arg1, char *arg2)
 #define DO_MAP(map) void map (struct session *ses, char *arg, char *arg1, char *arg2)
 #define DO_PATH(path) void path (struct session *ses, char *arg)
 #define DO_PORT(port) struct session *port (struct session *ses, char *arg1, char *arg2, char *arg)
@@ -1001,13 +1013,13 @@ struct listnode
 	char                  * arg3;
 	char                  * arg4;
 	char                  * group;
-	int                     flags;
+	unsigned int            shots;
 	union
 	{
 		pcre              * regex;      // act, alias, gag, highlight, substitute
 		char              * data;       // class
 		struct room_data  * room;       // terrain
-		long long           val64;      // delay, tick, path
+		long long           val64;      // delay, tick, path, event
 		short               val16[4];   // button
 		int                 val32[2];   // landmark, class
 	};
@@ -1040,7 +1052,8 @@ struct tintin_data
 	struct termios          old_terminal;
 	struct screen_data    * screen;
 	struct level_data     * level;
-	struct str_data       * memory;
+	struct memory_data    * memory;
+	struct str_data       * memory_debug;
 	char                  * detach_file;
 	int                     detach_port;
 	struct process_data     detach_info;
@@ -1049,7 +1062,6 @@ struct tintin_data
 	char                 *  attach_file;
 	int                     attach_pid;
 	int                     attach_sock;
-//	int                     fd_attach;
 	int                     daemon;
 	char                  * buf;
 	char                  * out;
@@ -1063,12 +1075,6 @@ struct tintin_data
 	char                    macro_buf[BUFFER_SIZE];
 	char                    paste_buf[BUFFER_SIZE];
 	char                    is_result[NUMBER_SIZE]; // not properly utilized?
-/*	int                     input_off;
-	int                     input_len;
-	int                     input_cur;
-	int                     input_pos;
-	int                     input_hid;
-	int                     input_tab;*/
 	char                  * home;
 	char                  * lang;
 	char                  * os;
@@ -1123,6 +1129,7 @@ struct session
 	time_t                  logline_time;
 	char                  * line_capturefile;
 	int                     line_captureindex;
+	int                     gagline;
 	struct listroot       * list[LIST_MAX];
 	int                     created;
 	int                     cur_row;
@@ -1169,9 +1176,11 @@ struct level_data
 	unsigned int            ignore;
 	unsigned int            info;
 	unsigned int            input;
-	unsigned int            oneshot;
+	unsigned int            local;
+	unsigned int            mshot;
 	unsigned int            quiet;
 	unsigned int            scroll;
+	unsigned int            shots;
 	unsigned int            verbatim;
 	unsigned int            verbose;
 };
@@ -1346,6 +1355,32 @@ struct msdp_data
 	int                    flags;
 };
 
+// gtd->memory->stack->name[]
+// gtd->memory->stack->index[]
+// gtd->memory->index;
+
+// gtd->memory->debug->next;
+// gtd->memory->alloc
+
+struct memory_data
+{
+	struct stack_data      ** debug;
+	int                       debug_len;
+	int                       debug_max;
+
+	struct str_data        ** stack;
+	int                       stack_len;
+	int                       stack_max;
+
+	struct str_data         * alloc;
+};
+
+struct stack_data
+{
+	char                    * name;
+	int                       index;
+};
+
 struct str_data
 {
 	struct str_data         * next;
@@ -1362,6 +1397,7 @@ struct row_data
 struct screen_data
 {
 	struct row_data      ** lines;
+	struct row_data      ** grid;
 	int                     rows;
 	int                     cols;
 	int                     height;
@@ -1505,14 +1541,15 @@ typedef struct session *ARRAY   (struct session *ses, struct listnode *list, cha
 typedef void            CHAT    (char *arg1, char *arg2);
 typedef struct session *CLASS   (struct session *ses, struct listnode *node, char *left, char *right);
 typedef struct session *CONFIG  (struct session *ses, char *arg1, char *arg2, int index);
-typedef struct session *COMMAND (struct session *ses, char *arg);
+typedef struct session *COMMAND (struct session *ses, char *arg, char *arg1, char *arg2, char *arg3, char *arg4);
 typedef void            DAEMON  (struct session *ses, char *arg);
 typedef void            MAP     (struct session *ses, char *arg, char *arg1, char *arg2);
 typedef void            CURSOR  (struct session *ses, char *arg);
 typedef void            PATH    (struct session *ses, char *arg);
 typedef struct session *PORT    (struct session *ses, char *arg1, char *arg2, char *arg);
 typedef struct session *LINE    (struct session *ses, char *arg);
-typedef void            HISTORY (struct session *ses, char *arg);
+typedef void            HISTORY (struct session *ses, char *arg1, char *arg2, char *arg3);
+typedef void            LOG     (struct session *ses, char *arg, char *arg1, char *arg2);
 typedef void            BUFFER  (struct session *ses, char *arg);
 typedef void            MSDP    (struct session *ses, struct port_data *buddy, int index);
 typedef void            SCREEN  (struct session *ses, int ind, char *arg, char *arg1, char *arg2);
@@ -1562,6 +1599,7 @@ struct command_type
 {
 	char                  * name;
 	COMMAND               * command;
+	int                     args;
 	int                     type;
 };
 
@@ -1617,7 +1655,7 @@ struct list_type
 	char                  * name_multi;
 	int                     mode;
 	int                     args;
-	int                     script_arg;
+	int                     script_arg;    
 	int                     priority_arg;
 	int                     flags;
 };
@@ -1630,6 +1668,12 @@ struct line_type
 	char                  * desc;
 };
 
+struct log_type
+{
+	char                  * name;
+	LOG                   * fun;
+	char                  * desc;
+};
 
 struct map_type
 {
@@ -1872,6 +1916,7 @@ extern DO_COMMAND(do_class);
 extern  int count_class(struct session *ses, struct listnode *group);
 extern void parse_class(struct session *ses, char *input, struct listnode *group);
 
+extern DO_CLASS(class_clear);
 extern DO_CLASS(class_close);
 extern DO_CLASS(class_kill);
 extern DO_CLASS(class_list);
@@ -1928,8 +1973,10 @@ extern DO_CURSOR(cursor_insert);
 extern DO_CURSOR(cursor_left);
 extern DO_CURSOR(cursor_left_word);
 extern DO_CURSOR(cursor_paste_buffer);
+extern DO_CURSOR(cursor_preserve_macro);
 extern DO_CURSOR(cursor_redraw_input);
 extern DO_CURSOR(cursor_redraw_line);
+extern DO_CURSOR(cursor_reset_macro);
 extern DO_CURSOR(cursor_right);
 extern DO_CURSOR(cursor_right_word);
 extern DO_CURSOR(cursor_set);
@@ -1968,9 +2015,10 @@ extern void  modified_input(void);
 
 extern DO_COMMAND(do_map);
 
+extern void delete_room_data(struct room_data *room);
 extern  int follow_map(struct session *ses, char *argument);
 extern void show_vtmap(struct session *ses);
-extern void map_mouse_handler(struct session *ses, char *left, char *right, int row, int col, int height, int width);
+extern void map_mouse_handler(struct session *ses, char *left, char *right, int row, int col, int rev_row, int rev_col, int height, int width);
 extern  int delete_map(struct session *ses);
 
 extern DO_MAP(map_at);
@@ -2092,10 +2140,12 @@ extern DO_CONFIG(config_wordwrap);
 #ifndef __SUBSTITUTE_H__
 #define __SUBSTITUTE_H__
 
+extern  int valid_escape(struct session *ses, char *arg);
 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 is_color_code(char *str);
+extern int is_color_name(char *str);
 extern int substitute_color(char *input, char *output, int colors);
 
 #endif
@@ -2132,6 +2182,8 @@ extern  int show_node_with_wild(struct session *ses, char *cptr, struct listroot
 extern void show_node(struct listroot *root, struct listnode *node, int level);
 extern void show_nest(struct listnode *node, char *result);
 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 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);
@@ -2142,9 +2194,10 @@ 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 *insert_node_list(struct listroot *root, char *arg1, char *arg2, char *arg3, char *arg4);
-extern struct listnode *update_node_list(struct listroot *root, 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);
+extern struct listnode *update_node_list(struct listroot *root, char *arg1, char *arg2, char *arg3, char *arg4);
 extern struct listnode *search_node_list(struct listroot *root, char *text);
 
 
@@ -2158,7 +2211,6 @@ extern int push_call(char *f, ...);
 extern void pop_call(void);
 extern void dump_stack(void);
 extern void dump_stack_fatal(void);
-extern void dump_full_stack(void);
 
 #endif
 
@@ -2179,6 +2231,7 @@ extern DO_COMMAND(do_draw);
 
 DO_DRAW(draw_blank);
 DO_DRAW(draw_bot_side);
+DO_DRAW(draw_arg);
 DO_DRAW(draw_box);
 DO_DRAW(draw_corner);
 DO_DRAW(draw_horizontal_line);
@@ -2243,6 +2296,7 @@ extern int read_history(struct session *ses, char *filename);
 
 DO_HISTORY(history_character);
 DO_HISTORY(history_delete);
+DO_HISTORY(history_get);
 DO_HISTORY(history_insert);
 DO_HISTORY(history_list);
 DO_HISTORY(history_size);
@@ -2263,9 +2317,11 @@ extern DO_LINE(line_convert);
 extern DO_LINE(line_debug);
 extern DO_LINE(line_gag);
 extern DO_LINE(line_ignore);
+extern DO_LINE(line_local);
 extern DO_LINE(line_log);
 extern DO_LINE(line_logmode);
 extern DO_LINE(line_logverbatim);
+extern DO_LINE(line_multishot);
 extern DO_LINE(line_oneshot);
 extern DO_LINE(line_quiet);
 extern DO_LINE(line_strip);
@@ -2281,6 +2337,11 @@ extern DO_LINE(line_verbose);
 
 extern DO_COMMAND(do_log);
 
+DO_LOG(log_append);
+DO_LOG(log_overwrite);
+DO_LOG(log_off);
+DO_LOG(log_remove);
+
 extern void loginit(struct session *ses, FILE *file, int newline);
 extern void logit(struct session *ses, char *txt, FILE *file, int newline);
 extern void write_html_header(struct session *ses, FILE *fp);
@@ -2320,23 +2381,32 @@ void  zlib_free(void *opaque, void *address);
 
 extern char *restring(char *point, char *string);
 extern char *restringf(char *point, char *fmt, ...);
+extern struct str_data *get_str_ptr(char *str);
+
 extern  int str_len(char *str);
-extern void str_fix(char *str);
+extern  int str_max(char *str);
+extern  int str_fix(char *str);
+
 extern char *str_alloc(int len);
-extern void str_clone(char **clone, char *original);
+extern void  str_free(char *ptr);
+
 extern char *str_mim(char *original);
 extern char *str_dup(char *original);
 extern char *str_dup_clone(char *original);
 extern char *str_dup_printf(char *fmt, ...);
+extern char *str_ndup(char *original, int len);
+
+extern char *str_resize(char **ptr, int add);
+extern void  str_clone(char **clone, char *original);
 extern char *str_cpy(char **ptr, char *str);
 extern char *str_cpy_printf(char **ptr, char *fmt, ...);
-extern char *str_ndup(char *original, int len);
 extern char *str_ncpy(char **ptr, char *str, int len);
-extern char *str_cat(char **ptr, char *str);
+extern char *str_cat(char **str, char *arg);
 extern char *str_cat_chr(char **ptr, char chr);
-extern char *str_cat_printf(char **ptr, char *fmt, ...);
+extern char *str_cat_printf(char **str, char *fmt, ...);
 extern char *str_ins(char **str, int index, char *buf);
-extern void str_free(char *ptr);
+
+extern char *str_alloc_stack();
 
 #endif
 
@@ -2432,8 +2502,10 @@ extern void process_mud_output(struct session *ses, char *linebuf, int prompt);
 #ifndef __PARSE_H__
 #define __PARSE_H__
 
-extern  int is_abbrev(char *s1, char *s2);
+extern  int is_abbrev(char *str1, char *str2);
+extern  int is_vowel(char *str);
 extern void filename_string(char *input, char *output);
+extern struct session *execute(struct session *ses, char *format, ...);
 extern struct session *parse_input(struct session *ses, char *input);
 extern struct session *parse_command(struct session *ses, char *input);
 extern  int is_speedwalk(struct session *ses, char *input);
@@ -2442,6 +2514,7 @@ extern void process_speedwalk(struct session *ses, char *input);
 extern struct session *parse_tintin_command(struct session *ses, char *input);
 extern int cnt_arg_all(struct session *ses, char *string, int flag);
 extern char *get_arg_all(struct session *ses, char *string, char *result, int verbatim);
+extern char *sub_arg_all(struct session *ses, char *string, char *result, int verbatim, int sub);
 extern char *get_arg_in_braces(struct session *ses, char *string, char *result, int flag);
 extern char *sub_arg_in_braces(struct session *ses, char *string, char *result, int flag, int sub);
 extern char *get_arg_with_spaces(struct session *ses, char *string, char *result, int flag);
@@ -2474,6 +2547,7 @@ extern DO_PATH(path_create);
 extern DO_PATH(path_describe);
 extern DO_PATH(path_delete);
 extern DO_PATH(path_destroy);
+extern DO_PATH(path_get);
 extern DO_PATH(path_goto);
 extern DO_PATH(path_insert);
 extern DO_PATH(path_load);
@@ -2546,6 +2620,7 @@ extern DO_COMMAND(do_screen);
 extern DO_SCREEN(screen_blur);
 extern DO_SCREEN(screen_clear);
 extern DO_SCREEN(screen_cursor);
+extern DO_SCREEN(screen_dump);
 extern DO_SCREEN(screen_fill);
 extern DO_SCREEN(screen_focus);
 extern DO_SCREEN(screen_fullscreen);
@@ -2587,13 +2662,14 @@ extern void fill_bot_region(struct session *ses, char *arg);
 extern void fill_left_region(struct session *ses, char *arg);
 extern void fill_right_region(struct session *ses, char *arg);
 extern void fill_split_region(struct session *ses, char *arg);
+extern int inside_scroll_region(struct session *ses, int row, int col);
 
 extern void print_screen();
 extern void init_screen(int rows, int cols, int pix_rows, int pix_cols);
 extern void destroy_screen();
 extern int inside_scroll_region(struct session *ses, int row, int col);
 extern void add_line_screen(char *str);
-extern void set_line_screen(char *str, int row, int col);
+extern void set_line_screen(struct session *ses, char *str, int row, int col);
 extern void get_line_screen(char *str, int row);
 extern  int get_link_screen(struct session *ses, char *result, int flags, int row, int col);
 extern void get_word_screen(char *str, int row, int col);
@@ -2676,6 +2752,12 @@ extern gnutls_session_t ssl_negotiate(struct session *ses);
 
 #endif
 
+#ifndef __STRING_H__
+#define __STRING_H__
+
+extern char *str_ins_str(struct session *ses, char **str, char *ins, int str_start, int str_end);
+
+#endif
 
 #ifndef __SYSTEM_H__
 #define __SYSTEM_H__
@@ -2708,6 +2790,7 @@ extern struct event_type event_table[];
 extern struct history_type history_table[];
 extern struct line_type line_table[];
 extern struct list_type list_table[LIST_MAX];
+extern struct log_type log_table[];
 extern struct map_type map_table[];
 extern struct path_type path_table[];
 extern struct port_type port_table[];
@@ -2914,6 +2997,9 @@ extern int is_gbk1(char *str);
 extern int gbk1_to_utf8(char *input, char *output);
 extern int utf8_to_gbk1(char *input, char *output);
 
+extern int cp1251_to_utf8(char *input, char *output);
+extern int utf8_to_cp1251(char *input, char *output);
+
 #endif
 
 #ifndef __VARIABLE_H__
@@ -2926,6 +3012,7 @@ extern DO_COMMAND(do_cat);
 extern DO_COMMAND(do_format);
 extern DO_COMMAND(do_replace);
 
+
 extern  int valid_variable(struct session *ses, char *arg);
 extern  int string_raw_str_len(struct session *ses, char *str, int start, int end);
 extern  int string_str_raw_len(struct session *ses, char *str, int start, int end);
@@ -2962,11 +3049,12 @@ extern void reset(struct session *ses);
 extern void scroll_region(struct session *ses, int top, int bottom);
 extern void reset_scroll_region(struct session *ses);
 extern int find_color_code(char *str);
+extern int find_escaped_color_code(char *str);
 extern int find_secure_color_code(char *str);
 extern int skip_one_char(struct session *ses, char *str, int *width);
 extern int skip_vt102_codes(char *str);
 extern int skip_vt102_codes_non_graph(char *str);
-extern void strip_vt102_codes(char *str, char *buf);
+extern int strip_vt102_codes(char *str, char *buf);
 extern void strip_vt102_codes_non_graph(char *str, char *buf);
 extern void strip_non_vt102_codes(char *str, char *buf);
 extern void get_color_codes(char *old, char *str, char *buf, int flags);

+ 21 - 4
src/tokenize.c

@@ -418,7 +418,7 @@ int find_command(char *command)
 		return -1;
 	}
 
-	if (isalpha((int) *command))
+	if (isalpha((int) *command) && command[1] != 0)
 	{
 		for (cmd = gtd->command_ref[tolower((int) *command) - 'a'] ; *command_table[cmd].name ; cmd++)
 		{
@@ -743,7 +743,24 @@ struct scriptnode *parse_script(struct scriptroot *root, int lvl, struct scriptn
 			case TOKEN_TYPE_COMMAND:
 				push_call("do_%s(%p,%p)", command_table[token->cmd].name, root->ses, token->str);
 
-				root->ses = (*command_table[token->cmd].command) (root->ses, token->str);
+				switch (command_table[token->cmd].args)
+				{
+					case 0:
+						root->ses = (*command_table[token->cmd].command) (root->ses, token->str, NULL, NULL, NULL, NULL);
+						break;
+					case 1:
+						root->ses = (*command_table[token->cmd].command) (root->ses, token->str, str_alloc_stack(), NULL, NULL, NULL);
+						break;
+					case 2:
+						root->ses = (*command_table[token->cmd].command) (root->ses, token->str, str_alloc_stack(), str_alloc_stack(), NULL, NULL);
+						break;
+					case 3:
+						root->ses = (*command_table[token->cmd].command) (root->ses, token->str, str_alloc_stack(), str_alloc_stack(), str_alloc_stack(), NULL);
+						break;
+					case 4:
+						root->ses = (*command_table[token->cmd].command) (root->ses, token->str, str_alloc_stack(), str_alloc_stack(), str_alloc_stack(), str_alloc_stack());
+						break;
+				}
 
 				pop_call();
 /*
@@ -1178,6 +1195,8 @@ struct session *script_driver(struct session *ses, int list, char *str)
 	if (--gtd->script_index == 0)
 	{
 		DEL_BIT(gtd->flags, TINTIN_FLAG_LOCAL);
+
+//		gtd->memory_index->len = 0;
 	}
 
 	gtd->level->input -= list != LIST_COMMAND;
@@ -1190,8 +1209,6 @@ struct session *script_driver(struct session *ses, int list, char *str)
 	free_list(root->local);
 	free(root);
 
-
-	
 	if (HAS_BIT(ses->flags, SES_FLAG_CLOSED))
 	{
 		pop_call();

+ 36 - 49
src/trigger.c

@@ -29,8 +29,6 @@
 
 DO_COMMAND(do_action)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE];
-
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
 	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
 	arg = get_arg_in_braces(ses, arg, arg3, GET_ALL);
@@ -80,7 +78,7 @@ void check_all_actions(struct session *ses, char *original, char *line)
 
 			substitute(ses, node->arg2, buf, SUB_ARG|SUB_SEC);
 
-			if (HAS_BIT(node->flags, NODE_FLAG_ONESHOT))
+			if (node->shots && --node->shots == 0)
 			{
 				delete_node_list(ses, LIST_ACTION, node);
 			}
@@ -101,8 +99,6 @@ void check_all_actions(struct session *ses, char *original, char *line)
 
 DO_COMMAND(do_alias)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE];
-
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
 	arg = get_arg_in_braces(ses, arg, arg3, GET_ALL);
@@ -144,7 +140,7 @@ int check_all_aliases(struct session *ses, char *input)
 
 	root = ses->list[LIST_ALIAS];
 
-	if (HAS_BIT(root->flags, LIST_FLAG_IGNORE))
+	if (gtd->level->ignore || HAS_BIT(root->flags, LIST_FLAG_IGNORE))
 	{
 		return FALSE;
 	}
@@ -210,7 +206,7 @@ int check_all_aliases(struct session *ses, char *input)
 
 			show_debug(ses, LIST_ALIAS, "#DEBUG ALIAS {%s} {%s}", node->arg1, gtd->vars[0]);
 
-			if (HAS_BIT(node->flags, NODE_FLAG_ONESHOT))
+			if (node->shots && --node->shots == 0)
 			{
 				delete_node_list(ses, LIST_ALIAS, node);
 			}
@@ -231,7 +227,6 @@ int check_all_aliases(struct session *ses, char *input)
 DO_COMMAND(do_button)
 {
 	struct listnode *node;
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE];
 	int index;
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
@@ -344,7 +339,7 @@ void check_all_buttons(struct session *ses, short row, short col, char *arg1, ch
 
 			substitute(ses, node->arg2, buf, SUB_ARG|SUB_SEC);
 
-			if (HAS_BIT(node->flags, NODE_FLAG_ONESHOT))
+			if (node->shots && --node->shots == 0)
 			{
 				delete_node_list(ses, LIST_BUTTON, node);
 			}
@@ -364,7 +359,7 @@ void check_all_buttons(struct session *ses, short row, short col, char *arg1, ch
 
 DO_COMMAND(do_delay)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE], time[BUFFER_SIZE];
+	char time[NUMBER_SIZE];
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
@@ -395,14 +390,14 @@ DO_COMMAND(do_delay)
 		}
 		else
 		{
+			struct listnode *node;
+
 			get_number_string(ses, arg3, time);
 
-			gtd->level->oneshot++;
+			node = update_node_list(ses->list[LIST_TICKER], arg1, arg2, time, "");
 
-			update_node_list(ses->list[LIST_TICKER], arg1, arg2, time, "");
+			node->shots = 1;
 
-			gtd->level->oneshot--;
-			
 			show_message(ses, LIST_TICKER, "#OK. #TICK {%s} WILL EXECUTE {%s} IN {%s} SECONDS.", arg1, arg2, time);
 		}
 	}
@@ -411,7 +406,9 @@ DO_COMMAND(do_delay)
 
 DO_COMMAND(do_undelay)
 {
-	if (isalpha(*arg))
+	sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+
+	if (isalpha((int) *arg1))
 	{
 		delete_node_with_wild(ses, LIST_TICKER, arg);
 	}
@@ -435,8 +432,6 @@ DO_COMMAND(do_undelay)
 
 DO_COMMAND(do_function)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
-
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
 
@@ -456,7 +451,7 @@ DO_COMMAND(do_function)
 	{
 		update_node_list(ses->list[LIST_FUNCTION], arg1, arg2, "", "");
 
-		show_message(ses, LIST_FUNCTION, "#OK. FUNCTION {%s} HAS BEEN SET TO {%s}.", arg1, arg2);
+		show_message(ses, LIST_FUNCTION, "#OK. FUNCTION {%s} NOW TRIGGERS {%s}.", arg1, arg2);
 	}
 	return ses;
 }
@@ -480,8 +475,6 @@ DO_COMMAND(do_unfunction)
 
 DO_COMMAND(do_gag)
 {
-	char arg1[BUFFER_SIZE];
-
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
 
 	if (*arg1 == 0)
@@ -518,11 +511,11 @@ void check_all_gags(struct session *ses, char *original, char *line)
 		{
 //			show_debug(ses, LIST_GAG, "#DEBUG GAG {%s}", node->arg1);
 
-			if (HAS_BIT(node->flags, NODE_FLAG_ONESHOT))
+			if (node->shots && --node->shots == 0)
 			{
 				delete_node_list(ses, LIST_GAG, node);
 			}
-			SET_BIT(ses->flags, SES_FLAG_GAG);
+			ses->gagline++;
 
 			return;
 		}
@@ -540,8 +533,6 @@ void check_all_gags(struct session *ses, char *original, char *line)
 
 DO_COMMAND(do_highlight)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE], temp[BUFFER_SIZE];
-
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
 	arg = get_arg_in_braces(ses, arg, arg3, GET_ALL);
@@ -559,7 +550,7 @@ DO_COMMAND(do_highlight)
 	}
 	else
 	{
-		if (get_color_names(ses, arg2, temp) == FALSE)
+		if (!is_color_name(arg2))
 		{
 			tintin_printf2(ses, "#HIGHLIGHT: VALID COLORS ARE:\n");
 			tintin_printf2(ses, "reset, bold, light, faint, dim, dark, underscore, blink, reverse, black, red, green, yellow, blue, magenta, cyan, white, b black, b red, b green, b yellow, b blue, b magenta, b cyan, b white, azure, ebony, jade, lime, orange, pink, silver, tan, violet.");
@@ -641,7 +632,7 @@ void check_all_highlights(struct session *ses, char *original, char *line)
 			}
 			while (check_one_regexp(ses, node, ptl, pto, 0));
 
-			if (HAS_BIT(node->flags, NODE_FLAG_ONESHOT))
+			if (node->shots && --node->shots == 0)
 			{
 				delete_node_list(ses, LIST_HIGHLIGHT, node);
 			}
@@ -664,10 +655,9 @@ void check_all_highlights(struct session *ses, char *original, char *line)
 
 DO_COMMAND(do_macro)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE];
-
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
+//	arg = get_arg_in_braces(ses, arg, arg3, GET_ALL);
 
 	if (*arg1 == 0)
 	{
@@ -682,11 +672,11 @@ DO_COMMAND(do_macro)
 	}
 	else
 	{
-		tintin_macro_compile(arg1, arg3);
+		tintin_macro_compile(arg1, arg4);
 
-		update_node_list(ses->list[LIST_MACRO], arg1, arg2, arg3, "");
+		update_node_list(ses->list[LIST_MACRO], arg1, arg2, "", arg4);
 
-		show_message(ses, LIST_MACRO, "#OK. MACRO {%s} HAS BEEN SET TO {%s}.", arg1, arg2);
+		show_message(ses, LIST_MACRO, "#OK. MACRO {%s} NOW TRIGGERS {%s}.", arg1, arg2);
 	}
 	return ses;
 }
@@ -711,8 +701,6 @@ DO_COMMAND(do_unmacro)
 
 DO_COMMAND(do_prompt)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE], arg4[BUFFER_SIZE];
-
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
 	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
 
@@ -773,18 +761,19 @@ int check_all_prompts(struct session *ses, char *original, char *line, int check
 			{
 				substitute(ses, node->arg2, original, SUB_ARG);
 				substitute(ses, original, original, SUB_VAR|SUB_FUN|SUB_COL|SUB_ESC);
+
+				strip_vt102_codes(original, line);
 			}
 
 			show_debug(ses, LIST_PROMPT, "#DEBUG PROMPT {%s}", node->arg1);
-//			show_debug(ses, LIST_GAG, "#DEBUG GAG {%s}", node->arg1);
 
 			split_show(ses, original, atoi(node->arg3), atoi(node->arg4));
 
-			if (HAS_BIT(node->flags, NODE_FLAG_ONESHOT))
+			if (node->shots && --node->shots == 0)
 			{
-				delete_node_list(ses, LIST_GAG, node);
+				delete_node_list(ses, LIST_PROMPT, node);
 			}
-			SET_BIT(ses->flags, SES_FLAG_GAG);
+			ses->gagline = 1;
 		}
 	}
 	return 0;
@@ -801,7 +790,7 @@ int check_all_prompts(struct session *ses, char *original, char *line, int check
 
 DO_COMMAND(do_substitute)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE], *str;
+	char *str;
 
 	str = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = get_arg_in_braces(ses, str, arg2, GET_ALL);
@@ -886,9 +875,9 @@ void check_all_substitutions(struct session *ses, char *original, char *line)
 
 				show_debug(ses, LIST_SUBSTITUTE, "#DEBUG SUBSTITUTE {%s} {%s}", node->arg1, match);
 			}
-			while (check_one_regexp(ses, node, ptl, pto, 0));
+			while (*pto && check_one_regexp(ses, node, ptl, pto, 0));
 
-			if (HAS_BIT(node->flags, NODE_FLAG_ONESHOT))
+			if (node->shots && --node->shots == 0)
 			{
 				delete_node_list(ses, LIST_SUBSTITUTE, node);
 			}
@@ -911,8 +900,6 @@ void check_all_substitutions(struct session *ses, char *original, char *line)
 
 DO_COMMAND(do_tab)
 {
-	char arg1[BUFFER_SIZE];
-
 	sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
 
 	if (*arg1 == 0)
@@ -949,19 +936,19 @@ DO_COMMAND(do_untab)
 
 DO_COMMAND(do_tick)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE], arg4[BUFFER_SIZE];
+	char time[NUMBER_SIZE];
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
-	arg = get_arg_in_braces(ses, arg, arg4, GET_ALL);
+	arg = get_arg_in_braces(ses, arg, arg3, GET_ALL);
 
-	if (*arg4 == 0)
+	if (*arg3 == 0)
 	{
-		strcpy(arg3, "60");
+		strcpy(time, "60");
 	}
 	else
 	{
-		get_number_string(ses, arg4, arg3);
+		get_number_string(ses, arg3, time);
 	}
 
 	if (*arg1 == 0)
@@ -977,9 +964,9 @@ DO_COMMAND(do_tick)
 	}
 	else
 	{
-		update_node_list(ses->list[LIST_TICKER], arg1, arg2, arg3, "");
+		update_node_list(ses->list[LIST_TICKER], arg1, arg2, time, "");
 
-		show_message(ses, LIST_TICKER, "#OK. #TICK {%s} NOW EXECUTES {%s} EVERY {%s} SECONDS.", arg1, arg2, arg3);
+		show_message(ses, LIST_TICKER, "#OK. #TICK {%s} NOW EXECUTES {%s} EVERY {%s} SECONDS.", arg1, arg2, time);
 	}
 	return ses;
 }

+ 24 - 12
src/update.c

@@ -76,6 +76,12 @@ void mainloop(void)
 		gtd->total_io_exec  += span_time_val;
 		gtd->total_io_delay += wait_time_val;
 
+		if (gtd->memory->stack_len > 1000)
+		{
+			tintin_printf2(NULL, "debug: memory_stack leak detected.\n");
+			gtd->memory->stack_len = 0;
+		}
+
 		if (--pulse.update_delays == 0)
 		{
 			pulse.update_delays = PULSE_UPDATE_DELAYS;
@@ -256,7 +262,7 @@ void update_input(void)
 
 		process_input();
 
-		SET_BIT(gtd->flags, TINTIN_FLAG_FLUSH);
+		SET_BIT(gtd->flags, TINTIN_FLAG_DISPLAYUPDATE);
 
 		if (gtd->detach_port)
 		{
@@ -373,12 +379,19 @@ void update_sessions(void)
 
 			DEL_BIT(ses->flags, SES_FLAG_PRINTBUFFER);
 		}
-	}
+		if (HAS_BIT(ses->flags, SES_FLAG_BUFFERUPDATE))
+		{
+			check_all_events(ses, SUB_ARG|SUB_SIL, 0, 0, "BUFFER UPDATE");
 
+			DEL_BIT(ses->flags, SES_FLAG_BUFFERUPDATE);
+		}
+	}
 
-	if (HAS_BIT(gtd->flags, TINTIN_FLAG_FLUSH))
+	if (HAS_BIT(gtd->flags, TINTIN_FLAG_DISPLAYUPDATE))
 	{
-		DEL_BIT(gtd->flags, TINTIN_FLAG_FLUSH);
+		check_all_events(gtd->ses, SUB_ARG|SUB_SIL, 0, 0, "DISPLAY UPDATE");
+
+		DEL_BIT(gtd->flags, TINTIN_FLAG_DISPLAYUPDATE);
 
 //		if (gtd->detach_port == 0)
 		{
@@ -735,7 +748,8 @@ void tick_update(void)
 
 	utime();
 
-	for (ses = gts->next ; ses ; ses = gtd->update)
+//	for (ses = gts->next ; ses ; ses = gtd->update)
+	for (ses = gts ; ses ; ses = gtd->update)
 	{
 		gtd->update = ses->next;
 
@@ -762,7 +776,7 @@ void tick_update(void)
 				{
 					show_debug(ses, LIST_TICKER, "#DEBUG TICKER {%s}", node->arg2);
 
-					if (HAS_BIT(node->flags, NODE_FLAG_ONESHOT))
+					if (node->shots && --node->shots == 0)
 					{
 						strcpy(buf, node->arg2);
 
@@ -922,8 +936,6 @@ void terminal_update(void)
 			show_vtmap(ses);
 
 			check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "MAP UPDATED VTMAP");
-
-			SET_BIT(gtd->flags, TINTIN_FLAG_FLUSH);
 		}
 	}
 
@@ -982,7 +994,7 @@ void time_update(void)
 		goto time_event_end;
 	}
 
-	strftime(str_min, 9, "%S", &gtd->calendar);
+	strftime(str_sec, 9, "%S", &gtd->calendar);
 	old_calendar.tm_sec = gtd->calendar.tm_sec;
 
 	if (gtd->calendar.tm_min == old_calendar.tm_min)
@@ -1069,10 +1081,10 @@ void time_update(void)
 
 	old_calendar.tm_sec = gtd->calendar.tm_sec;
 
-	check_all_events(NULL, SUB_ARG, 3, 7, "TIME %s:%s:%s", str_hour, str_min, str_sec, str_year, str_mon, str_wday, str_mday, str_hour, str_min, str_sec);
+	check_all_events(NULL, SUB_ARG|SUB_SIL, 3, 7, "TIME %s:%s:%s", str_hour, str_min, str_sec, str_year, str_mon, str_wday, str_mday, str_hour, str_min, str_sec);
 
-	check_all_events(NULL, SUB_ARG, 0, 7, "SECOND", str_year, str_mon, str_wday, str_mday, str_hour, str_min, str_sec);
-	check_all_events(NULL, SUB_ARG, 1, 7, "SECOND %s", str_sec, str_year, str_mon, str_wday, str_mday, str_hour, str_min, str_sec);
+	check_all_events(NULL, SUB_ARG|SUB_SIL, 0, 7, "SECOND", str_year, str_mon, str_wday, str_mday, str_hour, str_min, str_sec);
+	check_all_events(NULL, SUB_ARG|SUB_SIL, 1, 7, "SECOND %s", str_sec, str_year, str_mon, str_wday, str_mday, str_hour, str_min, str_sec);
 
 	time_event_end:
 

+ 145 - 7
src/utf8.c

@@ -457,6 +457,12 @@ int utf8_to_all(struct session *ses, char *in, char *out)
 		case CHARSET_FLAG_BIG5TOUTF8:
 			return utf8_to_big5(in, out);
 
+		case CHARSET_FLAG_CP1251TOUTF8:
+			return utf8_to_cp1251(in, out);
+
+		case CHARSET_FLAG_GBK1TOUTF8:
+			return utf8_to_gbk1(in, out);
+
 		case CHARSET_FLAG_FANSITOUTF8:
 			return sprintf(out, "%s", in);
 
@@ -466,9 +472,6 @@ int utf8_to_all(struct session *ses, char *in, char *out)
 		case CHARSET_FLAG_ISO2TOUTF8:
 			return utf8_to_iso2(in, out);
 
-		case CHARSET_FLAG_GBK1TOUTF8:
-			return utf8_to_gbk1(in, out);
-
 		case CHARSET_FLAG_KOI8TOUTF8:
 			return utf8_to_koi8(in, out);
 
@@ -484,21 +487,25 @@ int all_to_utf8(struct session *ses, char *in, char *out)
 		case CHARSET_FLAG_BIG5TOUTF8:
 			return big5_to_utf8(in, out);
 
+		case CHARSET_FLAG_CP1251TOUTF8:
+			return cp1251_to_utf8(in, out);
+
 		case CHARSET_FLAG_FANSITOUTF8:
 			return fansi_to_utf8(in, out);
 
+		case CHARSET_FLAG_GBK1TOUTF8:
+			return gbk1_to_utf8(in, out);
+
 		case CHARSET_FLAG_ISO1TOUTF8:
 			return iso1_to_utf8(in, out);
 
 		case CHARSET_FLAG_ISO2TOUTF8:
 			return iso2_to_utf8(in, out);
 
-
 		case CHARSET_FLAG_KOI8TOUTF8:
 			return koi8_to_utf8(in, out);
 
-		case CHARSET_FLAG_GBK1TOUTF8:
-			return gbk1_to_utf8(in, out);
+
 	}
 	tintin_printf2(ses, "debug: utf8_to_all: unknown error");
 	return 0;
@@ -699,6 +706,137 @@ int iso2_to_utf8(char *input, char *output)
 	return pto - (unsigned char *) output;
 }
 
+// CP1251 Special thanks to tpuctah for the data table
+
+struct interval_type unicode_to_cp1251_table[] =
+{
+	{0x00a0, 0x00a0}, {0x00a4, 0x00a4}, {0x00a6, 0x00a6}, {0x00a7, 0x00a7}, {0x00a9, 0x00a9}, {0x00ab, 0x00ab}, {0x00ac, 0x00ac}, {0x00ad, 0x00ad},
+	{0x00ae, 0x00ae}, {0x00b0, 0x00b0}, {0x00b1, 0x00b1}, {0x00b5, 0x00b5}, {0x00b6, 0x00b6}, {0x00b7, 0x00b7}, {0x00bb, 0x00bb}, {0x0401, 0x00a8},
+	{0x0402, 0x0080}, {0x0403, 0x0081}, {0x0404, 0x00aa}, {0x0405, 0x00bd}, {0x0406, 0x00b2}, {0x0407, 0x00af}, {0x0408, 0x00a3}, {0x0409, 0x008a},
+	{0x040a, 0x008c}, {0x040b, 0x008e}, {0x040c, 0x008d}, {0x040e, 0x00a1}, {0x040f, 0x008f}, {0x0410, 0x00c0}, {0x0411, 0x00c1}, {0x0412, 0x00c2},
+	{0x0413, 0x00c3}, {0x0414, 0x00c4}, {0x0415, 0x00c5}, {0x0416, 0x00c6}, {0x0417, 0x00c7}, {0x0418, 0x00c8}, {0x0419, 0x00c9}, {0x041a, 0x00ca},
+	{0x041b, 0x00cb}, {0x041c, 0x00cc}, {0x041d, 0x00cd}, {0x041e, 0x00ce}, {0x041f, 0x00cf}, {0x0420, 0x00d0}, {0x0421, 0x00d1}, {0x0422, 0x00d2},
+	{0x0423, 0x00d3}, {0x0424, 0x00d4}, {0x0425, 0x00d5}, {0x0426, 0x00d6}, {0x0427, 0x00d7}, {0x0428, 0x00d8}, {0x0429, 0x00d9}, {0x042a, 0x00da},
+	{0x042b, 0x00db}, {0x042c, 0x00dc}, {0x042d, 0x00dd}, {0x042e, 0x00de}, {0x042f, 0x00df}, {0x0430, 0x00e0}, {0x0431, 0x00e1}, {0x0432, 0x00e2},
+	{0x0433, 0x00e3}, {0x0434, 0x00e4}, {0x0435, 0x00e5}, {0x0436, 0x00e6}, {0x0437, 0x00e7}, {0x0438, 0x00e8}, {0x0439, 0x00e9}, {0x043a, 0x00ea},
+	{0x043b, 0x00eb}, {0x043c, 0x00ec}, {0x043d, 0x00ed}, {0x043e, 0x00ee}, {0x043f, 0x00ef}, {0x0440, 0x00f0}, {0x0441, 0x00f1}, {0x0442, 0x00f2},
+	{0x0443, 0x00f3}, {0x0444, 0x00f4}, {0x0445, 0x00f5}, {0x0446, 0x00f6}, {0x0447, 0x00f7}, {0x0448, 0x00f8}, {0x0449, 0x00f9}, {0x044a, 0x00fa},
+	{0x044b, 0x00fb}, {0x044c, 0x00fc}, {0x044d, 0x00fd}, {0x044e, 0x00fe}, {0x044f, 0x00ff}, {0x0451, 0x00b8}, {0x0452, 0x0090}, {0x0453, 0x0083},
+	{0x0454, 0x00ba}, {0x0455, 0x00be}, {0x0456, 0x00b3}, {0x0457, 0x00bf}, {0x0458, 0x00bc}, {0x0459, 0x009a}, {0x045a, 0x009c}, {0x045b, 0x009e},
+	{0x045c, 0x009d}, {0x045e, 0x00a2}, {0x045f, 0x009f}, {0x0490, 0x00a5}, {0x0491, 0x00b4}, {0x2013, 0x0096}, {0x2014, 0x0097}, {0x2018, 0x0091},
+	{0x2019, 0x0092}, {0x201a, 0x0082}, {0x201c, 0x0093}, {0x201d, 0x0094}, {0x201e, 0x0084}, {0x2020, 0x0086}, {0x2021, 0x0087}, {0x2022, 0x0095},
+	{0x2026, 0x0085}, {0x2030, 0x0089}, {0x2039, 0x008b}, {0x203a, 0x009b}, {0x20ac, 0x0088}, {0x2116, 0x00b9}, {0x2122, 0x0099}, {0xfffe, 0x0098}
+};
+
+int utf8_to_cp1251(char *input, char *output)
+{
+	char *pti, *pto;
+	int size, index, result;
+
+	pti = input;
+	pto = output;
+
+	while (*pti)
+	{
+		size = get_utf8_index(pti, &index);
+
+		if (size > 1)
+		{
+			result = boundless_binary_index_search(unicode_to_cp1251_table, sizeof(unicode_to_cp1251_table) / sizeof(struct interval_type), index);
+
+			if (result)
+			{
+				*pto++ = result;
+			}
+			else
+			{
+				tintin_printf(gtd->ses, "<118>utf8_to_cp1251: did not find unicode index '0x%04x'", index);
+
+				*pto++ = '?';
+			}
+			pti += size;
+		}
+		else
+		{
+			*pto++ = *pti++;
+		}
+	}
+	*pto = 0;
+
+	return pto - output;
+}
+
+int cp1251_to_utf8(char *input, char *output)
+{
+	unsigned char *pti, *pto;
+	int index;
+
+	static int cp1251[256] =
+	{
+		0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+		0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
+		0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+		0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
+		0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+		0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+		0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+		0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+		0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+		0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+		0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+		0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+		0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+		0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+		0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+		0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
+
+		0x0402, 0x0403, 0x201a, 0x0453, 0x201e, 0x2026, 0x2020, 0x2021,
+		0x20ac, 0x2030, 0x0409, 0x2039, 0x040a, 0x040c, 0x040b, 0x040f,
+		0x0452, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
+		0xfffe, 0x2122, 0x0459, 0x203a, 0x045a, 0x045c, 0x045b, 0x045f,
+		0x00a0, 0x040e, 0x045e, 0x0408, 0x00a4, 0x0490, 0x00a6, 0x00a7,
+		0x0401, 0x00a9, 0x0404, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x0407,
+		0x00b0, 0x00b1, 0x0406, 0x0456, 0x0491, 0x00b5, 0x00b6, 0x00b7,
+		0x0451, 0x2116, 0x0454, 0x00bb, 0x0458, 0x0405, 0x0455, 0x0457,
+		0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+		0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f,
+		0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+		0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f,
+		0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+		0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f,
+		0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+		0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f
+	};
+
+	pti = (unsigned char *) input;
+	pto = (unsigned char *) output;
+
+	while (*pti)
+	{
+		index = cp1251[*pti];
+
+		if (index < 128)
+		{
+			*pto++ = index;
+		}
+		else if (index < 4096)
+		{
+			*pto++ = 192 + index / 64;
+			*pto++ = 128 + index % 64;
+		}
+		else
+		{
+			*pto++ = 224 + index / 4096;
+			*pto++ = 128 + index / 64 % 64;
+			*pto++ = 128 + index % 64;
+		}
+		pti++;
+	}
+	*pto = 0;
+
+	return pto - (unsigned char *) output;
+}
+
 // KOI-8
 
 struct interval_type unicode_to_koi8_table[] =
@@ -1328,6 +1466,7 @@ int get_euc_width(struct session *ses, char *str, int *width)
 	return 1;
 }
 
+
 int is_gbk1(char *str)
 {
 	unsigned char *ptu = (unsigned char *) str;
@@ -1335,7 +1474,6 @@ int is_gbk1(char *str)
 	return ptu[0] > 128 && ptu[0] < 255 && ptu[1] > 64 && ptu[1] < 255;
 }
 
-
 int utf8_to_gbk1(char *input, char *output)
 {
 	char *pti, *pto;

+ 41 - 174
src/variable.c

@@ -29,7 +29,7 @@
 
 DO_COMMAND(do_variable)
 {
-	char arg1[BUFFER_SIZE], *str;
+	char *str;
 	struct listroot *root = ses->list[LIST_VARIABLE];
 	struct listnode *node;
 
@@ -101,7 +101,7 @@ DO_COMMAND(do_variable)
 
 DO_COMMAND(do_local)
 {
-	char arg1[BUFFER_SIZE], *str;
+	char *str;
 	struct listroot *root;
 	struct listnode *node;
 
@@ -169,8 +169,6 @@ DO_COMMAND(do_local)
 
 DO_COMMAND(do_unvariable)
 {
-	char arg1[BUFFER_SIZE];
-
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
 
 	do
@@ -192,7 +190,7 @@ DO_COMMAND(do_unvariable)
 
 DO_COMMAND(do_cat)
 {
-	char arg1[BUFFER_SIZE], *str;
+	char *str;
 	struct listnode *node;
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_NST, SUB_VAR|SUB_FUN);
@@ -235,7 +233,7 @@ DO_COMMAND(do_cat)
 
 DO_COMMAND(do_replace)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE], tmp[BUFFER_SIZE], *pti, *ptm, *str;
+	char tmp[BUFFER_SIZE], *pti, *ptm, *str;
 	struct listnode *node;
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_NST, SUB_VAR|SUB_FUN);
@@ -522,166 +520,14 @@ void colorstring(struct session *ses, char *str)
 	strcpy(str, result);
 }
 
-int translate_color_names(struct session *ses, char *string, char *result)
-{
-	int cnt;
-
-	*result = 0;
-
-	if (*string == '<')
-	{
-		strcpy(result, string);
-
-		return TRUE;
-	}
-
-	if (*string == '\\')
-	{
-		strcpy(result, string);
-
-		return TRUE;
-	}
-
-	while (*string)
-	{
-
-		if (isalpha(*string))
-		{
-			for (cnt = 0 ; *color_table[cnt].name ; cnt++)
-			{
-				if (!strncmp(color_table[cnt].name, string, color_table[cnt].len))
-				{
-					result += sprintf(result, "%s", color_table[cnt].code);
-
-					break;
-				}
-			}
-
-			if (*color_table[cnt].name == 0)
-			{
-				for (cnt = 0 ; *color_table[cnt].name ; cnt++)
-				{
-					if (!strncasecmp(color_table[cnt].name, string, color_table[cnt].len))
-					{
-						result += sprintf(result, "%s", color_table[cnt].code);
-
-						break;
-					}
-				}
-
-				if (*color_table[cnt].name == 0)
-				{
-					return FALSE;
-				}
-			}
-			string += strlen(color_table[cnt].name);
-		}
-
-		switch (*string)
-		{
-			case ' ':
-			case ';':
-			case ',':
-			case '{':
-			case '}':
-				string++;
-				break;
-
-			case 0:
-				return TRUE;
-
-			default:
-				return FALSE;
-		}
-	}
-	return TRUE;
-}
-
-int get_color_names(struct session *ses, char *string, char *result)
-{
-	int cnt;
-
-	*result = 0;
-
-	if (*string == '<')
-	{
-		substitute(ses, string, result, SUB_COL);
-
-		return TRUE;
-	}
-
-	if (*string == '\\')
-	{
-		substitute(ses, string, result, SUB_ESC);
-
-		return TRUE;
-	}
-
-	while (*string)
-	{
-		if (isalpha(*string))
-		{
-			for (cnt = 0 ; *color_table[cnt].name ; cnt++)
-			{
-				if (!strncmp(color_table[cnt].name, string, color_table[cnt].len))
-				{
-					substitute(ses, color_table[cnt].code, result, SUB_COL);
-
-					result += strlen(result);
-
-					break;
-				}
-			}
-
-			if (*color_table[cnt].name == 0)
-			{
-				for (cnt = 0 ; *color_table[cnt].name ; cnt++)
-				{
-					if (!strncasecmp(color_table[cnt].name, string, color_table[cnt].len))
-					{
-						substitute(ses, color_table[cnt].code, result, SUB_COL);
-
-						result += strlen(result);
-
-						break;
-					}
-				}
-
-				if (*color_table[cnt].name == 0)
-				{
-					return FALSE;
-				}
-			}
-			string += strlen(color_table[cnt].name);
-		}
-
-		switch (*string)
-		{
-			case ' ':
-			case ';':
-			case ',':
-			case '{':
-			case '}':
-				string++;
-				break;
-
-			case 0:
-				return TRUE;
-
-			default:
-				return FALSE;
-		}
-	}
-	return TRUE;
-}
-
-void headerstring(struct session *ses, char *str)
+void headerstring(struct session *ses, char *str, char *columns)
 {
 	char buf[BUFFER_SIZE], fill[BUFFER_SIZE];
 	int len, max;
 
 	len = string_raw_str_len(ses, str, 0, BUFFER_SIZE);
-	max =  get_scroll_cols(ses);
+
+	max = *columns ? atoi(columns) : get_scroll_cols(ses);
 
 	if (len > max - 2)
 	{
@@ -1135,11 +981,15 @@ int string_raw_str_len(struct session *ses, char *str, int raw_start, int raw_en
 		{
 			raw_cnt++;
 
-			if (str[raw_cnt] == '\\')
+			if (valid_escape(ses, &str[raw_cnt]))
 			{
 				raw_cnt++;
 				ret_cnt++;
 			}
+			else
+			{
+				ret_cnt++;
+			}
 			continue;
 		}
 
@@ -1211,14 +1061,26 @@ void justify_string(struct session *ses, char *in, char *out, int align, int cut
 
 void format_string(struct session *ses, char *format, char *arg, char *out)
 {
-	char argformat[BUFFER_SIZE], newformat[BUFFER_SIZE], arglist[30][20000], *ptf, *ptt, *pts, *ptn;
+	char *arglist[30];
+	char argformat[BUFFER_SIZE], newformat[BUFFER_SIZE], *ptf, *ptt, *pts, *ptn;
 	struct tm timeval_tm;
 	time_t    timeval_t;
-	int i;
+	int i, max;
+
+	push_call("format_string(%p,%p,%p,%p)",ses,format,arg,out);
 
-	for (i = 0 ; i < 30 ; i++)
+	for (max = 0 ; max < 4 ; max++)
 	{
-		arg = sub_arg_in_braces(ses, arg, arglist[i], GET_ONE, SUB_VAR|SUB_FUN);
+		arglist[max] = str_alloc_stack();
+
+		arg = sub_arg_in_braces(ses, arg, arglist[max], GET_ONE, SUB_VAR|SUB_FUN);
+	}
+
+	for (max = 4 ; *arg && max < 30 ; max++)
+	{
+		arglist[max] = str_alloc_stack();
+
+		arg = sub_arg_in_braces(ses, arg, arglist[max], GET_ONE, SUB_VAR|SUB_FUN);
 	}
 
 	i = 0;
@@ -1228,13 +1090,15 @@ void format_string(struct session *ses, char *format, char *arg, char *out)
 
 	while (*ptf)
 	{
-		if (i == 30)
-		{
-			break;
-		}
-
 		if (*ptf == '%')
 		{
+			if (i >= max)
+			{
+				*ptn++ = *ptf++;
+				*ptn++ = '%';
+				i++;
+				continue;
+			}
 			pts = ptn;
 
 			*ptn++ = *ptf++;
@@ -1280,9 +1144,10 @@ void format_string(struct session *ses, char *format, char *arg, char *out)
 						*ptn = 0;
 						break;
 
-					case 'w':
 					case 'b':
 					case 'B':
+					case 'h':
+					case 'w':
 					case 'z':
 					case 'Z':
 						strcpy(argformat, pts+1);
@@ -1327,7 +1192,7 @@ void format_string(struct session *ses, char *format, char *arg, char *out)
 								}
 		
 								*ptt = 0;
-		
+
 								if (atoi(arg1) < 0)
 								{
 									sprintf(argformat, "%%%d.%d",
@@ -1385,7 +1250,8 @@ void format_string(struct session *ses, char *format, char *arg, char *out)
 						break;
 
 					case 'h':
-						headerstring(ses, arglist[i]);
+						substitute(ses, arglist[i], arglist[i], SUB_VAR|SUB_FUN);
+						headerstring(ses, arglist[i], argformat);
 						break;
 
 					case 'l':
@@ -1520,6 +1386,7 @@ void format_string(struct session *ses, char *format, char *arg, char *out)
 
 	snprintf(out, BUFFER_SIZE - 1, newformat, arglist[0], arglist[1], arglist[2], arglist[3], arglist[4], arglist[5], arglist[6], arglist[7], arglist[8], arglist[9], arglist[10], arglist[11], arglist[12], arglist[13], arglist[14], arglist[15], arglist[16], arglist[17], arglist[18], arglist[19], arglist[20], arglist[21], arglist[22], arglist[23], arglist[24], arglist[25], arglist[26], arglist[27], arglist[28], arglist[29]);
 
+	pop_call();
 	return;
 }
 

+ 59 - 6
src/vt102.c

@@ -90,8 +90,6 @@ void restore_pos(struct session *ses)
 	{
 		print_stdout("\e[?25h");
 	}
-
-	SET_BIT(gtd->flags, TINTIN_FLAG_FLUSH);
 }
 
 void goto_pos(struct session *ses, int row, int col)
@@ -215,9 +213,11 @@ int skip_vt102_codes(char *str)
 			{
 				if (str[skip] == 30) // HTML_CLOSE
 				{
+					pop_call();
 					return skip + 1;
 				}
 			}
+			pop_call();
 			return 0;
 
 		case 127:   /* DEL */
@@ -269,6 +269,7 @@ int skip_vt102_codes(char *str)
 					{
 						if (str[skip] == '\a' || (str[skip] == '\e' && str[skip+1] == '\\'))
 						{
+							pop_call();
 							return skip + 1;
 						}
 					}
@@ -342,7 +343,7 @@ int find_color_code(char *str)
 
 	switch (str[0])
 	{
-		case  27:   /* ESC */
+		case  ASCII_ESC:
 			break;
 
 		default:
@@ -378,13 +379,63 @@ int find_color_code(char *str)
 	return 0;
 }
 
+int find_escaped_color_code(char *str)
+{
+	int skip;
+
+	switch (str[0])
+	{
+		case  '\\':
+			break;
+
+		default:
+			return 0;
+	}
+
+	switch (str[1])
+	{
+		case 'e':
+			break;
+		default:
+			return 0;
+	}
+
+	switch (str[2])
+	{
+		case '[':
+			break;
+
+		default:
+			return 0;
+	}
+
+	for (skip = 3 ; str[skip] != 0 ; skip++)
+	{
+		switch (str[skip])
+		{
+			case 'm':
+				return skip + 1;
+			case '@':
+			case '`':
+			case ']':
+				return 0;
+		}
+
+		if (isalpha((int) str[skip]))
+		{
+			return 0;
+		}
+	}
+	return 0;
+}
+
 int find_secure_color_code(char *str)
 {
 	int skip, valid = 1;
 
 	switch (str[0])
 	{
-		case  27:   /* ESC */
+		case  ASCII_ESC:   /* ESC */
 			break;
 
 		default:
@@ -532,7 +583,7 @@ int skip_vt102_codes_non_graph(char *str)
 	return 0;
 }
 
-void strip_vt102_codes(char *str, char *buf)
+int strip_vt102_codes(char *str, char *buf)
 {
 	char *pti, *pto;
 
@@ -552,6 +603,8 @@ void strip_vt102_codes(char *str, char *buf)
 		}
 	}
 	*pto = 0;
+
+	return pto - buf;
 }
 
 
@@ -718,7 +771,7 @@ void get_color_codes(char *old, char *str, char *buf, int flags)
 	{
 		switch (*pti)
 		{
-			case 27:
+			case ASCII_ESC:
 				pti += 2;
 
 				if (pti[-1] == 'm')

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff