Scandum 2 ani în urmă
părinte
comite
84ca426c77
14 a modificat fișierele cu 102 adăugiri și 74 ștergeri
  1. 4 2
      TODO
  2. 10 10
      docs/help.html
  3. 4 4
      docs/tutorial.html
  4. 5 1
      mods/igr.mods
  5. 2 1
      src/data.c
  6. 9 9
      src/help.c
  7. 1 1
      src/main.c
  8. 8 1
      src/parse.c
  9. 6 6
      src/show.c
  10. 1 1
      src/tables.c
  11. 1 1
      src/telopt_client.c
  12. 6 6
      src/telopt_server.c
  13. 2 1
      src/tintin.h
  14. 43 30
      src/tokenize.c

+ 4 - 2
TODO

@@ -3,14 +3,16 @@
 #high blo <118>
 #showme <158>test bli bla blo test
 
-- make #regex be able to use \n
-
 - split screen scrollback setting in #screen
 
 - Make #draw scroll grid table work properly.
 
 - Make sure #config compact also applies to the log file.
 
+- Add an #event that triggers when a function/variable is not found.
+
+- tab completion on input history
+
 - look into handling VARIABLE UPDATE event better
 
 - catch event to handle #map global exceptions

+ 10 - 10
docs/help.html

@@ -55,7 +55,7 @@ a:active {color:#b06}
 </span><span style='color:#FFF'>Command</span><span style='color:#AAA'>: #action </span><span style='color:#FFF'>{</span><span style='color:#AAA'>message</span><span style='color:#FFF'>} {</span><span style='color:#AAA'>commands</span><span style='color:#FFF'>} {</span><span style='color:#AAA'>priority</span><span style='color:#FFF'>}
 
 </span><span style='color:#AAA'>         The #action command can be used to respond with one or several
-         commands to a specific message send by the server. The %1-%99
+         commands to a specific message sent by the server. The %1-%99
          variables are substituted from the message and can be used in the
          command part of the action.
 
@@ -434,7 +434,7 @@ a:active {color:#b06}
            and names longer than 20 characters.
          </span><span style='color:#FFF'>#chat {message} {buddy|all} {text}
 </span><span style='color:#AAA'>           This is the main command used for communication. If you use
-           #chat message all, the message is marked as public and send to
+           #chat message all, the message is marked as public and sent to
            everyone you are connected to.
          </span><span style='color:#FFF'>#chat {accept} {buddy} {boost}
 </span><span style='color:#AAA'>           Accept a file transfer from a buddy. The boost is optional and
@@ -1463,7 +1463,7 @@ Command</span><span style='color:#AAA'>: #delay </span><span style='color:#FFF'>
 
 </span><span style='color:#0AA'>      ####################################################################
       #</span><span style='color:#AAA'>                                                                  </span><span style='color:#0AA'>#
-      #</span><span style='color:#AAA'>                    T I N T I N + +   2.02.40                     </span><span style='color:#0AA'>#
+      #</span><span style='color:#AAA'>                    T I N T I N + +   2.02.41b                    </span><span style='color:#0AA'>#
       #</span><span style='color:#AAA'>                                                                  </span><span style='color:#0AA'>#
       #</span><span style='color:#AAA'>      Code by Peter Unold, Bill Reis, and Igor van den Hoven      </span><span style='color:#0AA'>#
       #</span><span style='color:#AAA'>                                                                  </span><span style='color:#0AA'>#
@@ -1738,7 +1738,7 @@ Command</span><span style='color:#AAA'>: #delay </span><span style='color:#FFF'>
 
          All TinTin++ commands starts with a '#'.
 
-</span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #help -- #help is a client command, and isn't send to the server.
+</span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #help -- #help is a client command, and isn't sent to the server.
 
          All TinTin++ commands can be abbreviated when typed.
 
@@ -2593,7 +2593,7 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
 
 </span><span style='color:#AAA'>         Macros allow you to make tintin respond to function keys.
 
-         The key sequence send to the terminal when pressing a function key
+         The key sequence sent to the terminal when pressing a function key
          differs for every OS and terminal. To find out what sequence is sent
          you can enable the CONVERT META config option.
 
@@ -3315,7 +3315,7 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
          Keep in mind that the server is allowed to use &bsol;e]68;1;&bsol;a as well,
          subsequently various security measures are in place.
 
-         To create secure links, which are filtered out when send by a server,
+         To create secure links, which are filtered out when sent by a server,
          you need to use &bsol;e]68;2;&bsol;a, and they instead trigger the SECURE LINK
          event.
 
@@ -3911,7 +3911,7 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
          </span><span style='color:#FFF'>#scan {txt} &lt;filename&gt;
 
 </span><span style='color:#AAA'>           The scan txt &lt;filename&gt; command reads in a file and sends its content
-           to the screen as if it was send by a server. After using scan you can
+           to the screen as if it was sent by a server. After using scan you can
            use page-up and down to view the file.
 
            This command is useful to convert ansi color files to html or viewing
@@ -4390,7 +4390,7 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
 
 </span><span style='color:#FFF'>&bsol; </span><span style='color:#AAA'>        The back slash is used to escape a character. All available options
           are listed at #help escape. Escapes are typically escaped when text
-          leaves the client, by being send to a server, the shell, being
+          leaves the client, by being sent to a server, the shell, being
           displayed on the screen, or being processed as part of a regex.
           Escapes try to mimic escapes in PCRE when possible.
 
@@ -4672,9 +4672,9 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
 
 </span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #show {Targets starting with the letter A: &dollar;targets[A%*]
 
-              To disable using regular expressions start the match with '='.
+         To disable using regular expressions start the match with '='.
 
-</span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #show {A target literally defined as A%*: &dollar;targets[&bsol;A%*]
+</span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #show {A target literally defined as A%*: &dollar;targets[=A%*]
 
          To see the internal index of a variable use &amp;&lt;variable name&gt;. To see
          the size of a table you would use: &amp;targets[] or &amp;targets[%*]. A non

+ 4 - 4
docs/tutorial.html

@@ -95,7 +95,7 @@ a:active {color:#b06}
 
          All TinTin++ commands starts with a '#'.
 
-</span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #help -- #help is a client command, and isn't send to the server.
+</span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #help -- #help is a client command, and isn't sent to the server.
 
          All TinTin++ commands can be abbreviated when typed.
 
@@ -612,7 +612,7 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
 
 </span><span style='color:#0AA'>      ####################################################################
       #</span><span style='color:#AAA'>                                                                  </span><span style='color:#0AA'>#
-      #</span><span style='color:#AAA'>                    T I N T I N + +   2.02.40                     </span><span style='color:#0AA'>#
+      #</span><span style='color:#AAA'>                    T I N T I N + +   2.02.41b                    </span><span style='color:#0AA'>#
       #</span><span style='color:#AAA'>                                                                  </span><span style='color:#0AA'>#
       #</span><span style='color:#AAA'>      Code by Peter Unold, Bill Reis, and Igor van den Hoven      </span><span style='color:#0AA'>#
       #</span><span style='color:#AAA'>                                                                  </span><span style='color:#0AA'>#
@@ -1273,7 +1273,7 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
          Keep in mind that the server is allowed to use &bsol;e]68;1;&bsol;a as well,
          subsequently various security measures are in place.
 
-         To create secure links, which are filtered out when send by a server,
+         To create secure links, which are filtered out when sent by a server,
          you need to use &bsol;e]68;2;&bsol;a, and they instead trigger the SECURE LINK
          event.
 
@@ -1683,7 +1683,7 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
 
 </span><span style='color:#FFF'>&bsol; </span><span style='color:#AAA'>        The back slash is used to escape a character. All available options
           are listed at #help escape. Escapes are typically escaped when text
-          leaves the client, by being send to a server, the shell, being
+          leaves the client, by being sent to a server, the shell, being
           displayed on the screen, or being processed as part of a regex.
           Escapes try to mimic escapes in PCRE when possible.
 

+ 5 - 1
mods/igr.mods

@@ -1,4 +1,8 @@
-Mar 2023        2.02.32
+Jan 2024        2.02.41
+------------------------------------------------------------------------------
+tokenize.c      Fixed issues with tailing spaces for several statements.
+
+Mar 2023        2.02.40
 ------------------------------------------------------------------------------
 data.c          Changed the symbol for the strict equality assignment/lookup
                 from \ to = due to compatibility issues. You'll get a warning

+ 2 - 1
src/data.c

@@ -657,7 +657,8 @@ int bsearch_alnum_list(struct listroot *root, char *text, int seek)
 				}
 				break;
 
-			case '/':
+			case '=':
+			case '\\':
 				text++;
 				break;
 		}

+ 9 - 9
src/help.c

@@ -505,7 +505,7 @@ struct help_type help_table[] =
 		"<178>Command<278>: #action <178>{<278>message<178>} {<278>commands<178>} {<278>priority<178>}\n"
 		"\n"
 		"<278>         The #action command can be used to respond with one or several\n"
-		"<278>         commands to a specific message send by the server. The %1-%99\n"
+		"<278>         commands to a specific message sent by the server. The %1-%99\n"
 		"<278>         variables are substituted from the message and can be used in the\n"
 		"<278>         command part of the action.\n"
 		"\n"
@@ -886,7 +886,7 @@ struct help_type help_table[] =
 		"<278>           and names longer than 20 characters.\n"
 		"<278>         <178>#chat {message} {buddy|all} {text}\n"
 		"<278>           This is the main command used for communication. If you use\n"
-		"<278>           #chat message all, the message is marked as public and send to\n"
+		"<278>           #chat message all, the message is marked as public and sent to\n"
 		"<278>           everyone you are connected to.\n"
 		"<278>         <178>#chat {accept} {buddy} {boost}\n"
 		"<278>           Accept a file transfer from a buddy. The boost is optional and\n"
@@ -2209,7 +2209,7 @@ struct help_type help_table[] =
 		"\n"
 		"<278>         All TinTin++ commands starts with a '#'.\n"
 		"\n"
-		"<178>Example<278>: #help -- #help is a client command, and isn't send to the server.\n"
+		"<178>Example<278>: #help -- #help is a client command, and isn't sent to the server.\n"
 		"\n"
 		"<278>         All TinTin++ commands can be abbreviated when typed.\n"
 		"\n"
@@ -3068,7 +3068,7 @@ struct help_type help_table[] =
 		"\n"
 		"<278>         Macros allow you to make tintin respond to function keys.\n"
 		"\n"
-		"<278>         The key sequence send to the terminal when pressing a function key\n"
+		"<278>         The key sequence sent to the terminal when pressing a function key\n"
 		"<278>         differs for every OS and terminal. To find out what sequence is sent\n"
 		"<278>         you can enable the CONVERT META config option.\n"
 		"\n"
@@ -3810,7 +3810,7 @@ struct help_type help_table[] =
 		"<278>         Keep in mind that the server is allowed to use \\e]68;1;\\a as well,\n"
 		"<278>         subsequently various security measures are in place.\n"
 		"\n"
-		"<278>         To create secure links, which are filtered out when send by a server,\n"
+		"<278>         To create secure links, which are filtered out when sent by a server,\n"
 		"<278>         you need to use \\e]68;2;\\a, and they instead trigger the SECURE LINK\n"
 		"<278>         event.\n"
 		"\n"
@@ -4411,7 +4411,7 @@ struct help_type help_table[] =
 		"<278>         <178>#scan {txt} <filename>\n"
 		"\n"
 		"<278>           The scan txt <filename> command reads in a file and sends its content\n"
-		"<278>           to the screen as if it was send by a server. After using scan you can\n"
+		"<278>           to the screen as if it was sent by a server. After using scan you can\n"
 		"<278>           use page-up and down to view the file.\n"
 		"\n"
 		"<278>           This command is useful to convert ansi color files to html or viewing\n"
@@ -4896,7 +4896,7 @@ struct help_type help_table[] =
 		"\n"
 		"<178>\\ <278>        The back slash is used to escape a character. All available options\n"
 		"<278>          are listed at #help escape. Escapes are typically escaped when text\n"
-		"<278>          leaves the client, by being send to a server, the shell, being\n"
+		"<278>          leaves the client, by being sent to a server, the shell, being\n"
 		"<278>          displayed on the screen, or being processed as part of a regex.\n"
 		"<278>          Escapes try to mimic escapes in PCRE when possible.\n"
 		,
@@ -5179,9 +5179,9 @@ struct help_type help_table[] =
 		"\n"
 		"<178>Example<278>: #show {Targets starting with the letter A: $targets[A%*]\n"
 		"\n"
-		"              To disable using regular expressions start the match with '='.\n"
+		"<278>         To disable using regular expressions start the match with '='.\n"
 		"\n"
-		"<178>Example<278>: #show {A target literally defined as A%*: $targets[\\A%*]\n"
+		"<178>Example<278>: #show {A target literally defined as A%*: $targets[=A%*]\n"
 		"\n"
 		"<278>         To see the internal index of a variable use &<variable name>. To see\n"
 		"<278>         the size of a table you would use: &targets[] or &targets[%*]. A non\n"

+ 1 - 1
src/main.c

@@ -456,7 +456,7 @@ void init_tintin(int greeting)
 
 	gtd->flags          = TINTIN_FLAG_INHERITANCE;
 
-	gtd->mccp_len       = 10000;
+	gtd->mccp_len       = 16384;
 	gtd->mccp_buf       = (unsigned char *) calloc(1, gtd->mccp_len);
 
 	gtd->mud_output_max = 16384;

+ 8 - 1
src/parse.c

@@ -486,7 +486,14 @@ struct session *parse_tintin_command(struct session *ses, char *input)
 		return ses;
 	}
 
-	tintin_printf2(ses, "#ERROR: #UNKNOWN TINTIN-COMMAND '%s'.", line);
+	if (!strcasecmp(line, "exit") || !strcasecmp(line, "quit"))
+	{
+		tintin_printf2(ses, "#ERROR: UNKNOWN TINTIN COMMAND '%s'. SUGGESTION: 'end' OR 'zap'.", line);
+	}
+	else
+	{
+		tintin_printf2(ses, "#ERROR: UNKNOWN TINTIN COMMAND '%s'.", line);
+	}
 
 	check_all_events(ses, SUB_SEC|EVENT_FLAG_SYSTEM, 0, 1, "UNKNOWN COMMAND", line);
 

+ 6 - 6
src/show.c

@@ -157,7 +157,7 @@ void show_message(struct session *ses, int index, char *format, ...)
 
 	display:
 
-	if (check_all_events(ses, EVENT_FLAG_SYSTEM, 1, 0, "REFORMAT %s", format))
+	if (HAS_BIT(gtd->event_flags, EVENT_FLAG_REFORMAT) && check_all_events(ses, EVENT_FLAG_SYSTEM, 1, 0, "REFORMAT %s", format))
 	{
 		format = get_variable_def(ses, "result", format);
 	}
@@ -216,7 +216,7 @@ void show_error(struct session *ses, int index, char *format, ...)
 
 	push_call("show_error(%p,%p,%p)",ses,index,format);
 
-	if (check_all_events(ses, EVENT_FLAG_SYSTEM, 1, 0, "REFORMAT %s", format))
+	if (HAS_BIT(gtd->event_flags, EVENT_FLAG_REFORMAT) && check_all_events(ses, EVENT_FLAG_SYSTEM, 1, 0, "REFORMAT %s", format))
 	{
 		format = get_variable_def(ses, "result", format);
 	}
@@ -288,7 +288,7 @@ void show_debug(struct session *ses, int index, char *format, ...)
 		return;
 	}
 
-	if (check_all_events(ses, EVENT_FLAG_SYSTEM, 1, 0, "REFORMAT %s", format))
+	if (HAS_BIT(gtd->event_flags, EVENT_FLAG_REFORMAT) && check_all_events(ses, EVENT_FLAG_SYSTEM, 1, 0, "REFORMAT %s", format))
 	{
 		format = get_variable_def(ses, "result", format);
 	}
@@ -451,7 +451,7 @@ void tintin_header(struct session *ses, int width, char *format, ...)
 		return;
 	}
 
-	if (check_all_events(ses, EVENT_FLAG_SYSTEM, 1, 0, "REFORMAT %s", format))
+	if (HAS_BIT(gtd->event_flags, EVENT_FLAG_REFORMAT) && check_all_events(ses, EVENT_FLAG_SYSTEM, 1, 0, "REFORMAT %s", format))
 	{
 		format = get_variable_def(ses, "result", format);
 	}
@@ -500,7 +500,7 @@ void tintin_printf(struct session *ses, char *format, ...)
 
 	push_call("tintin_printf(%p,%p,...)",ses,format);
 
-	if (check_all_events(ses, EVENT_FLAG_SYSTEM, 1, 0, "REFORMAT %s", format))
+	if (HAS_BIT(gtd->event_flags, EVENT_FLAG_REFORMAT) && check_all_events(ses, EVENT_FLAG_SYSTEM, 1, 0, "REFORMAT %s", format))
 	{
 		format = get_variable_def(ses, "result", format);
 	}
@@ -524,7 +524,7 @@ void tintin_printf2(struct session *ses, char *format, ...)
 
 	push_call("tintin_printf2(%p,%p,...)",ses,format);
 
-	if (check_all_events(ses, EVENT_FLAG_SYSTEM, 1, 0, "REFORMAT %s", format))
+	if (HAS_BIT(gtd->event_flags, EVENT_FLAG_REFORMAT) && check_all_events(ses, EVENT_FLAG_SYSTEM, 1, 0, "REFORMAT %s", format))
 	{
 		format = get_variable_def(ses, "result", format);
 	}

+ 1 - 1
src/tables.c

@@ -840,7 +840,7 @@ struct event_type event_table[] =
 	{    "RECEIVED LINE",                          0, EVENT_FLAG_OUTPUT,   "OUTPUT",    "a new line is received"     },
 	{    "RECEIVED OUTPUT",                        0, EVENT_FLAG_OUTPUT,   "OUTPUT",    "bulk output is received"    },
 	{    "RECEIVED PROMPT",                        0, EVENT_FLAG_OUTPUT,   "OUTPUT",    "a prompt is received"       },
-	{    "REFORMAT ",                              0, EVENT_FLAG_SYSTEM,   "SYSTEM",    "system format message"      },
+	{    "REFORMAT ",                              0, EVENT_FLAG_REFORMAT, "REFORMAT",  "system format message"      },
 	{    "RELEASED ",                              0, EVENT_FLAG_MOUSE,    "MOUSE",     "mouse button is released"   },
 	{    "SCAN CSV HEADER",                        0, EVENT_FLAG_SCAN,     "SCAN",      "scanning a csv file"        },
 	{    "SCAN CSV LINE",                          0, EVENT_FLAG_SCAN,     "SCAN",      "scanning a csv file"        },

+ 1 - 1
src/telopt_client.c

@@ -2222,7 +2222,7 @@ int client_write_compressed(struct session *ses, char *txt, int length)
 
 	result = write(ses->socket, gtd->mccp_buf, gtd->mccp_len - ses->mccp3->avail_out);
 
-	if (result < 1)
+	if (result == -1)
 	{
 		syserr_printf(ses, "client_write_compressed: write");
 

+ 6 - 6
src/telopt_server.c

@@ -98,11 +98,11 @@ struct iac_type iac_server_table [] =
 
 void server_telopt_debug(struct session *ses, char *format, ...)
 {
-	char buf[BUFFER_SIZE];
-	va_list args;
-
 	if (HAS_BIT(ses->telopts, TELOPT_FLAG_DEBUG))
 	{
+		char buf[BUFFER_SIZE];
+		va_list args;
+
 		va_start(args, format);
 		vsprintf(buf, format, args);
 		va_end(args);
@@ -1078,7 +1078,7 @@ void end_mccp2(struct session *ses, struct port_data *buddy)
 
 	buddy->mccp2 = NULL;
 
-	tintin_printf2(ses, "MCCP2: COMPRESSION END");
+	server_telopt_debug(ses, "INFO MCCP2 COMPRESSION END");
 
 	return;
 }
@@ -1164,7 +1164,7 @@ int process_sb_mccp3(struct session *ses, struct port_data *buddy, unsigned char
 	}
 	else
 	{
-		tintin_printf2(ses, "INFO IAC SB MCCP3 INITIALIZED");
+		server_telopt_debug(ses, "INFO IAC SB MCCP3 INITIALIZED");
 	}
 	return 5;
 }
@@ -1173,7 +1173,7 @@ void end_mccp3(struct session *ses, struct port_data *buddy)
 {
 	if (buddy->mccp3)
 	{
-		tintin_printf2(ses, "MCCP3: COMPRESSION END");
+		server_telopt_debug(ses, "INFO MCCP3 COMPRESSION END");
 		inflateEnd(buddy->mccp3);
 		free(buddy->mccp3);
 		buddy->mccp3 = NULL;

+ 2 - 1
src/tintin.h

@@ -212,7 +212,7 @@
 
 
 #define CLIENT_NAME              "TinTin++"
-#define CLIENT_VERSION           "2.02.40 "
+#define CLIENT_VERSION           "2.02.41 "
 
 
 #define XT_E                            0x27
@@ -594,6 +594,7 @@ enum operators
 #define EVENT_FLAG_UPDATE             BV18
 #define EVENT_FLAG_VARIABLE           BV19
 #define EVENT_FLAG_VT100              BV20
+#define EVENT_FLAG_REFORMAT           BV21
 
 #define TAB_FLAG_FORWARD              BV01
 #define TAB_FLAG_BACKWARD             BV02

+ 43 - 30
src/tokenize.c

@@ -525,7 +525,6 @@ void pop_script_stack(void)
 	}
 }
 
-
 void tokenize_script(struct scriptroot *root, int lvl, char *str)
 {
 	char *arg, *line;
@@ -593,6 +592,10 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
 						tokenize_script(root, lvl--, line);
 
+						if (*line == 0)
+						{
+							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #CASE <CONDITIONAL> <COMMANDS>");
+						}
 						addtoken(root, lvl, TOKEN_TYPE_END, -1, "endcase");
 						break;
 
@@ -607,6 +610,10 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 						str = get_arg_in_braces(root->ses, arg, line, GET_ALL);
 						tokenize_script(root, lvl--, line);
 
+						if (*line == 0)
+						{
+							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #DEFAULT <COMMANDS>");
+						}
 						addtoken(root, lvl, TOKEN_TYPE_END, -1, "enddefault");
 						break;
 
@@ -616,6 +623,10 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 						str = get_arg_in_braces(root->ses, arg, line, GET_ALL);
 						tokenize_script(root, lvl--, line);
 
+						if (*line == 0)
+						{
+							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #ELSE <COMMANDS>");
+						}
 						addtoken(root, lvl, TOKEN_TYPE_END, -1, "endelse");
 						break;
 
@@ -626,20 +637,23 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
 						tokenize_script(root, lvl--, line);
 
+						if (*line == 0)
+						{
+							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #ELSEIF <CONDITIONAL> <COMMANDS>");
+						}
 						addtoken(root, lvl, TOKEN_TYPE_END, -1, "endelseif");
 						break;
 
 					case TOKEN_TYPE_FOREACH:
 						str = addforeachtoken(root, lvl++, TOKEN_TYPE_FOREACH, cmd, arg);
 
-						if (*str == 0 || *str == COMMAND_SEPARATOR)
-						{
-							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #FOREACH <LIST> <VARIABLE> <COMMANDS>");
-						}
-
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
 						tokenize_script(root, lvl--, line);
 
+						if (*line == 0)
+						{
+							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #FOREACH <LIST> <VARIABLE> <COMMANDS>");
+						}
 						addtoken(root, lvl, TOKEN_TYPE_END, -1, "endforeach");
 						break;
 
@@ -647,16 +661,17 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 						str = get_arg_in_braces(root->ses, arg, line, GET_ONE);
 						addtoken(root, lvl++, TOKEN_TYPE_IF, cmd, line);
 
-						if (*str == 0 || *str == COMMAND_SEPARATOR)
-						{
-							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #IF <CONDITIONAL> <TRUE> [FALSE]");
-						}
-
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
 						tokenize_script(root, lvl--, line);
 
+						if (*line == 0)
+						{
+							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #IF <CONDITIONAL> <TRUE> [FALSE]");
+						}
 						addtoken(root, lvl, TOKEN_TYPE_END, -1, "endif");
 
+						str = space_out(str);
+
 						if (*str && *str != COMMAND_SEPARATOR)
 						{
 							addtoken(root, lvl++, TOKEN_TYPE_ELSE, -1, "else");
@@ -671,35 +686,34 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 					case TOKEN_TYPE_LOOP:
 						str = addlooptoken(root, lvl++, TOKEN_TYPE_LOOP, cmd, arg);
 
-						if (*str == 0 || *str == COMMAND_SEPARATOR)
-						{
-							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #LOOP <START> <END> <COMMANDS>");
-						}
-
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
 						tokenize_script(root, lvl--, line);
 
+						if (*line == 0)
+						{
+							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #LOOP <START> <END> <COMMANDS>");
+						}
 						addtoken(root, lvl, TOKEN_TYPE_END, -1, "endloop");
 						break;
 
 					case TOKEN_TYPE_PARSE:
 						str = addparsetoken(root, lvl++, TOKEN_TYPE_PARSE, cmd, arg);
 
-						if (*str == 0 || *str == COMMAND_SEPARATOR)
-						{
-							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #PARSE <TEXT> <VARIABLE> <COMMANDS>");
-						}
-
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
-
 						tokenize_script(root, lvl--, line);
 
+						if (*line == 0)
+						{
+							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #PARSE <TEXT> <VARIABLE> <COMMANDS>");
+						}
 						addtoken(root, lvl, TOKEN_TYPE_END, -1, "endparse");
 						break;
 
 					case TOKEN_TYPE_REGEX:
 						str = addregextoken(root, lvl, TOKEN_TYPE_REGEX, cmd, arg);
 
+						str = space_out(str);
+
 						if (*str && *str != COMMAND_SEPARATOR)
 						{
 							addtoken(root, lvl++, TOKEN_TYPE_ELSE, -1, "else");
@@ -719,14 +733,13 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 					case TOKEN_TYPE_SWITCH:
 						str = addswitchtoken(root, lvl++, TOKEN_TYPE_SWITCH, cmd, arg);
 
-						if (*str == 0 || *str == COMMAND_SEPARATOR)
-						{
-							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #SWITCH <CONDITIONAL> <ARGUMENTS>");
-						}
-
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
 						tokenize_script(root, lvl--, line);
 
+						if (*line == 0)
+						{
+							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #SWITCH <CONDITIONAL> <ARGUMENTS>");
+						}
 						addtoken(root, lvl, TOKEN_TYPE_END, -1, "endswitch");
 						break;
 
@@ -734,14 +747,14 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 						str = get_arg_in_braces(root->ses, arg, line, GET_ONE);
 						addtoken(root, lvl++, TOKEN_TYPE_WHILE, cmd, line);
 
-						if (*str == 0 || *str == COMMAND_SEPARATOR)
+						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
+
+						if (*line == 0)
 						{
 							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #WHILE <CONDITIONAL> <COMMANDS>");
 							deltoken(root, root->prev);
 							break;
 						}
-
-						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
 						tokenize_script(root, lvl--, line);
 
 						addtoken(root, lvl, TOKEN_TYPE_END, -1, "endwhile");