Scandum 2 years ago
parent
commit
316d2700bb
50 changed files with 1389 additions and 858 deletions
  1. 3 3
      SCRIPTS
  2. 26 47
      TODO
  3. 52 26
      docs/help.html
  4. 20 12
      docs/tutorial.html
  5. 46 0
      mods/igr.mods
  6. 55 40
      src/banner.c
  7. 1 1
      src/base.c
  8. 14 14
      src/buffer.c
  9. 85 31
      src/class.c
  10. 1 1
      src/command.c
  11. 39 46
      src/config.c
  12. 57 8
      src/cursor.c
  13. 4 4
      src/daemon.c
  14. 15 10
      src/data.c
  15. 11 7
      src/draw.c
  16. 1 1
      src/edit.c
  17. 2 2
      src/event.c
  18. 14 12
      src/files.c
  19. 54 26
      src/help.c
  20. 2 26
      src/history.c
  21. 10 4
      src/input.c
  22. 23 23
      src/line.c
  23. 94 16
      src/list.c
  24. 30 9
      src/log.c
  25. 190 153
      src/mapper.c
  26. 19 19
      src/math.c
  27. 13 0
      src/misc.c
  28. 17 1
      src/net.c
  29. 5 0
      src/parse.c
  30. 31 27
      src/path.c
  31. 9 1
      src/port.c
  32. 15 15
      src/regex.c
  33. 15 19
      src/scan.c
  34. 25 33
      src/screen.c
  35. 21 19
      src/session.c
  36. 47 6
      src/show.c
  37. 3 3
      src/split.c
  38. 2 1
      src/ssl.c
  39. 7 8
      src/substitute.c
  40. 6 6
      src/system.c
  41. 4 2
      src/tables.c
  42. 20 20
      src/telnet.h
  43. 17 44
      src/telopt_client.c
  44. 51 27
      src/telopt_server.c
  45. 20 18
      src/tintin.h
  46. 7 7
      src/tokenize.c
  47. 142 33
      src/trigger.c
  48. 8 10
      src/update.c
  49. 5 4
      src/utf8.c
  50. 31 13
      src/variable.c

+ 3 - 3
SCRIPTS

@@ -52,9 +52,9 @@
 	{
 	{
 		#switch {1d4}
 		#switch {1d4}
 		{
 		{
-			#case {1} {cheer}
-			#case {2} {greet all}
-			#case {3} {smile}
+			#case {1} {cheer};
+			#case {2} {greet all};
+			#case {3} {smile};
 			#case {4} {laugh self}
 			#case {4} {laugh self}
 		}
 		}
 	}
 	}

+ 26 - 47
TODO

@@ -1,32 +1,33 @@
-#info mem
-#INFO MEMORY: STACK SIZE: 1800045
-#INFO MEMORY: STACK  MAX: 64
-#INFO MEMORY: STACK  CAP: 45
-#INFO MEMORY: STACK  LEN: 3
+- Problem with restoring true color subs.
+#sub bla {<F00AA00>bla}
+#high blo <118>
+#showme <158>test bli bla blo test
 
 
-#ERROR: index 386297 len = 1/0 max = 5706 flags = 6 (e)
-#INFO MEMORY: ALLOC SIZE: 17963354
-#INFO MEMORY: ALLOC USED: 13862779
-#INFO MEMORY: ALLOC  MAX: 1048576
-#INFO MEMORY: ALLOC  LEN: 547640
+- make #regex be able to use \n
 
 
-#INFO MEMORY: FREED SIZE: 1626853344
-#INFO MEMORY: FREED  MAX: 1048576
-#INFO MEMORY: FREED  LEN: 546481
+- split screen scrollback setting in #screen
 
 
-#INFO MEMORY: DEBUG SIZE: 1024
-#INFO MEMORY: DEBUG  MAX: 48
-#INFO MEMORY: DEBUG  LEN: 4
+- Make #draw scroll grid table work properly.
 
 
-- #var foo {x;{a;b;c};y;z}
-  #list foo create {$foo}
-  #list foo simplify
+- Make sure #config compact also applies to the log file.
 
 
-  #list explode has an issue with ';'
+- look into handling VARIABLE UPDATE event better
 
 
-- finish ? : support in #math
+- catch event to handle #map global exceptions
+
+- switch to pcre2
+
+- Add routine to escape 0x00 in port.c RECEIVED DATA event.
+
+- allow a full telnet disable in port.c
+
+- Add message when a substitution exceeds available memory.
 
 
-- multiline triggers
+- config loglevel medium option
+
+- look into GMCP larger than buffer size
+
+- finish ? : support in #math
 
 
 - finish create_node()
 - finish create_node()
 
 
@@ -50,8 +51,6 @@
 
 
 - look into a #debug flag for #class
 - look into a #debug flag for #class
 
 
-- switch to pcre2
-
 - Another nice thing would be if there was some flag to make a trigger match newlines as space.
 - Another nice thing would be if there was some flag to make a trigger match newlines as space.
 
 
 - fix up named delays and undelay
 - fix up named delays and undelay
@@ -72,17 +71,14 @@
   - add shadow session support with access to all events.
   - add shadow session support with access to all events.
 
 
   - set_line_screen debug: col = -5 (64) from draw_text(%p,%d,%p,%p,%p)
   - set_line_screen debug: col = -5 (64) from draw_text(%p,%d,%p,%p,%p)
+  - set_line_screen stack call triggered on android
 
 
   - regex101 like regex tester
   - regex101 like regex tester
 
 
   - check: #var bla { x};#draw scroll box 1 1 3 40 $bla
   - check: #var bla { x};#draw scroll box 1 1 3 40 $bla
 
 
-  - set_line_screen stack call triggered on android
-
   - input spell checking, #cursor display ?
   - input spell checking, #cursor display ?
 
 
-  - look into named actions as a 4th argument
-
   - Get discworld / aardwolf mxp to work for @sentix
   - Get discworld / aardwolf mxp to work for @sentix
 
 
   - look into default input color
   - look into default input color
@@ -137,18 +133,17 @@
   - multiple global exit rooms and noglobal flags.
   - multiple global exit rooms and noglobal flags.
   - auto align routine that inserts void rooms where needed
   - auto align routine that inserts void rooms where needed
   - look into writing script to drag rooms + void with mouse
   - look into writing script to drag rooms + void with mouse
-  - pancake mode to display rooms at all levels and annotations
   - Store the map filename to differentiate between maps.
   - Store the map filename to differentiate between maps.
   - #map list {<exits>} breaks on rooms that have e mapped to eu.
   - #map list {<exits>} breaks on rooms that have e mapped to eu.
   - finish landmarks
   - finish landmarks
   - map sandbox mode support (flags to disable saving?)
   - map sandbox mode support (flags to disable saving?)
   - add ghosting to fix #map flag nofollow exit cmd issues?
   - add ghosting to fix #map flag nofollow exit cmd issues?
   - Request: 'stop' #map center command, so i could see how the 'user' moves, rather map moves around him? 
   - Request: 'stop' #map center command, so i could see how the 'user' moves, rather map moves around him? 
-  - #map uninsert <vnum>
   - make map spacing easier
   - make map spacing easier
   - event for failed #map move.
   - event for failed #map move.
   - look into #send triggering follow map.
   - look into #send triggering follow map.
   - add {roomdata} search to #map list
   - add {roomdata} search to #map list
+  - change 'C' to 'S' in map file
 
 
   - Make actions with a priority of 0. trigger always
   - Make actions with a priority of 0. trigger always
 
 
@@ -171,14 +166,10 @@
 
 
   - look into discord api / arachnos
   - look into discord api / arachnos
 
 
-  - better color syntax highlighting configuration.
-
-  - See about adding SESSIONS to the list table.
+  - Add SESSIONS to the list table.
 
 
   - Add debugger to syntax highlighter, substitution highlighing, 256 color support, and variable expansion.
   - Add debugger to syntax highlighter, substitution highlighing, 256 color support, and variable expansion.
 
 
-  - fix readmud in net.c to not move the cursor on inactive sessions.
-
   - add packets patched counter
   - add packets patched counter
 
 
   - reportable_sounds
   - reportable_sounds
@@ -189,18 +180,10 @@
 
 
   - see if #break 2 is possible, maybe #continue 2 as well.
   - see if #break 2 is possible, maybe #continue 2 as well.
 
 
-  - http://tintin.sourceforge.net/board/viewtopic.php?t=2339 (map area data)
-
   - IPv6 for chat
   - IPv6 for chat
 
 
-  - http://tintin.sourceforge.net/board/viewtopic.php?p=9109 (vt102 strip \e[2J\e[H )
-
-  - http://tintin.sourceforge.net/board/viewtopic.php?p=8766#8766 (global verbose toggle?)
-
   - See about adding ~/ handling for file names.
   - See about adding ~/ handling for file names.
 
 
-  - Look into adding basic EUC-KR support.
-
 --------------------------------------------------------------------------------
 --------------------------------------------------------------------------------
 
 
 * LOW PRIORITY
 * LOW PRIORITY
@@ -211,12 +194,8 @@
 
 
   - multi-line buffer searches / captures / deletes
   - multi-line buffer searches / captures / deletes
 
 
-  - multi-line triggers (use nested actions?)
-
   - add color based auto unwrap routine.
   - add color based auto unwrap routine.
 
 
-  - Start of line anchors aren't working in #replace.
-
   - add #history filter option to filter out 1 letter commands.
   - add #history filter option to filter out 1 letter commands.
 
 
   - Look into config option to change the working directory
   - Look into config option to change the working directory

+ 52 - 26
docs/help.html

@@ -832,7 +832,7 @@ Command</span><span style='color:#AAA'>: #delay </span><span style='color:#FFF'>
          BOTTOM      draw on the bottom side if possible.
          BOTTOM      draw on the bottom side if possible.
          BOXED       draw a box along the square.
          BOXED       draw a box along the square.
          BUMPED      precede the draw with an enter.
          BUMPED      precede the draw with an enter.
-         CALIGN      center text.
+         CALIGN      both LALIGN and RALIGN to center text.
          CIRCLED     circle the corners.
          CIRCLED     circle the corners.
          CONVERT     draw text with meta conversion.
          CONVERT     draw text with meta conversion.
          CROSSED     cross the corners.
          CROSSED     cross the corners.
@@ -891,7 +891,7 @@ Command</span><span style='color:#AAA'>: #delay </span><span style='color:#FFF'>
          All draw types take an optional text argument as long as a valid
          All draw types take an optional text argument as long as a valid
          square with enough space has been defined. Text is automatically
          square with enough space has been defined. Text is automatically
          word wrapped and text formatting can be customized with the
          word wrapped and text formatting can be customized with the
-         CALIGN, LALIGN, RALIGN, and UALIGN options.
+         BALIGN, TALIGN, LALIGN, RALIGN, and UALIGN options.
 
 
 </span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #draw Blue box 1 1 3 20 {Hello world!}
 </span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #draw Blue box 1 1 3 20 {Hello world!}
 
 
@@ -1183,9 +1183,9 @@ Command</span><span style='color:#AAA'>: #delay </span><span style='color:#FFF'>
          </span><span style='color:#FFF'>RECEIVED INPUT CHARACTER
          </span><span style='color:#FFF'>RECEIVED INPUT CHARACTER
 </span><span style='color:#AAA'>           %0 character  %1 unicode index  %2 size  %3 width
 </span><span style='color:#AAA'>           %0 character  %1 unicode index  %2 size  %3 width
 
 
-         NO SESSION ACTIVE      %0 raw text %1 size
-         SEND OUTPUT            %0 raw text %1 size
-         SENT OUTPUT            %0 raw text %1 size
+         </span><span style='color:#FFF'>NO SESSION ACTIVE</span><span style='color:#AAA'>      %0 raw text %1 size
+         </span><span style='color:#FFF'>SEND OUTPUT</span><span style='color:#AAA'>            %0 raw text %1 size
+         </span><span style='color:#FFF'>SENT OUTPUT</span><span style='color:#AAA'>            %0 raw text %1 size
 
 
          </span><span style='color:#5F5'>MAP EVENTS
          </span><span style='color:#5F5'>MAP EVENTS
 
 
@@ -1237,6 +1237,8 @@ Command</span><span style='color:#AAA'>: #delay </span><span style='color:#FFF'>
 </span><span style='color:#AAA'>         </span><span style='color:#FFF'>BUFFER UPDATE</span><span style='color:#AAA'>, </span><span style='color:#FFF'>DISPLAY UPDATE
 </span><span style='color:#AAA'>         </span><span style='color:#FFF'>BUFFER UPDATE</span><span style='color:#AAA'>, </span><span style='color:#FFF'>DISPLAY UPDATE
 </span><span style='color:#AAA'>           These events have no additional arguments.
 </span><span style='color:#AAA'>           These events have no additional arguments.
 
 
+         </span><span style='color:#FFF'>PROCESSED LINE         </span><span style='color:#AAA'>%0 raw text %1 plain text %2 prompt (0 or 1)
+
          </span><span style='color:#FFF'>RECEIVED LINE          </span><span style='color:#AAA'>%0 raw text %1 plain text
          </span><span style='color:#FFF'>RECEIVED LINE          </span><span style='color:#AAA'>%0 raw text %1 plain text
          </span><span style='color:#FFF'>RECEIVED OUTPUT        </span><span style='color:#AAA'>%0 raw text %1 plain text
          </span><span style='color:#FFF'>RECEIVED OUTPUT        </span><span style='color:#AAA'>%0 raw text %1 plain text
          </span><span style='color:#FFF'>RECEIVED PROMPT        </span><span style='color:#AAA'>%0 raw text %1 plain text
          </span><span style='color:#FFF'>RECEIVED PROMPT        </span><span style='color:#AAA'>%0 raw text %1 plain text
@@ -1250,6 +1252,7 @@ Command</span><span style='color:#AAA'>: #delay </span><span style='color:#FFF'>
          </span><span style='color:#FFF'>PORT DISCONNECTION     </span><span style='color:#AAA'>%0 name %1 ip %2 port
          </span><span style='color:#FFF'>PORT DISCONNECTION     </span><span style='color:#AAA'>%0 name %1 ip %2 port
          </span><span style='color:#FFF'>PORT LOG MESSAGE       </span><span style='color:#AAA'>%0 name %1 ip %2 port %3 data %4 plain data
          </span><span style='color:#FFF'>PORT LOG MESSAGE       </span><span style='color:#AAA'>%0 name %1 ip %2 port %3 data %4 plain data
          </span><span style='color:#FFF'>PORT RECEIVED MESSAGE  </span><span style='color:#AAA'>%0 name %1 ip %2 port %3 data %4 plain data
          </span><span style='color:#FFF'>PORT RECEIVED MESSAGE  </span><span style='color:#AAA'>%0 name %1 ip %2 port %3 data %4 plain data
+         </span><span style='color:#FFF'>PORT RECEIVED DATA     </span><span style='color:#AAA'>%0 name %1 ip %2 port %3 data %4 size
 
 
          </span><span style='color:#5F5'>SCAN EVENTS
          </span><span style='color:#5F5'>SCAN EVENTS
 
 
@@ -1302,6 +1305,8 @@ Command</span><span style='color:#AAA'>: #delay </span><span style='color:#FFF'>
          </span><span style='color:#FFF'>UNKNOWN COMMAND        </span><span style='color:#AAA'>%0 raw text
          </span><span style='color:#FFF'>UNKNOWN COMMAND        </span><span style='color:#AAA'>%0 raw text
          </span><span style='color:#FFF'>SIGUSR                 </span><span style='color:#AAA'>%0 signal
          </span><span style='color:#FFF'>SIGUSR                 </span><span style='color:#AAA'>%0 signal
 
 
+         </span><span style='color:#FFF'>REFORMAT &lt;MESSAGE&gt;     </span><span style='color:#AAA'>Use #return to change MESSAGE
+
          </span><span style='color:#5F5'>TELNET EVENTS
          </span><span style='color:#5F5'>TELNET EVENTS
 
 
 </span><span style='color:#AAA'>         </span><span style='color:#FFF'>IAC &lt;EVENT&gt;
 </span><span style='color:#AAA'>         </span><span style='color:#FFF'>IAC &lt;EVENT&gt;
@@ -1458,7 +1463,7 @@ Command</span><span style='color:#AAA'>: #delay </span><span style='color:#FFF'>
 
 
 </span><span style='color:#0AA'>      ####################################################################
 </span><span style='color:#0AA'>      ####################################################################
       #</span><span style='color:#AAA'>                                                                  </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.31                     </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'>                                                                  </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'>      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'>#
       #</span><span style='color:#AAA'>                                                                  </span><span style='color:#0AA'>#
@@ -1567,11 +1572,12 @@ Command</span><span style='color:#AAA'>: #delay </span><span style='color:#FFF'>
 
 
 </span><span style='color:#FF5'>         HISTORY
 </span><span style='color:#FF5'>         HISTORY
 
 
-</span><span style='color:#FFF'>Command</span><span style='color:#AAA'>: #history </span><span style='color:#FFF'>{</span><span style='color:#AAA'>delete</span><span style='color:#FFF'>}</span><span style='color:#AAA'>                 Delete the last command.
-         #history </span><span style='color:#FFF'>{</span><span style='color:#AAA'>insert</span><span style='color:#FFF'>}    {</span><span style='color:#AAA'>command</span><span style='color:#FFF'>}</span><span style='color:#AAA'>    Insert a command.
-         #history </span><span style='color:#FFF'>{</span><span style='color:#AAA'>list</span><span style='color:#FFF'>}</span><span style='color:#AAA'>                   Display the entire command history.
-         #history </span><span style='color:#FFF'>{</span><span style='color:#AAA'>read</span><span style='color:#FFF'>}      {</span><span style='color:#AAA'>filename</span><span style='color:#FFF'>}</span><span style='color:#AAA'>   Read a command history from file.
-         #history </span><span style='color:#FFF'>{</span><span style='color:#AAA'>write</span><span style='color:#FFF'>}     {</span><span style='color:#AAA'>filename</span><span style='color:#FFF'>}</span><span style='color:#AAA'>   Write a command history to file.
+</span><span style='color:#FFF'>Command</span><span style='color:#AAA'>: #history </span><span style='color:#FFF'>{</span><span style='color:#AAA'>delete</span><span style='color:#FFF'>}</span><span style='color:#AAA'>                    Delete the last command.
+         #history </span><span style='color:#FFF'>{</span><span style='color:#AAA'>get</span><span style='color:#FFF'>}    {</span><span style='color:#AAA'>variable</span><span style='color:#FFF'>} {</span><span style='color:#AAA'>range</span><span style='color:#FFF'>}</span><span style='color:#AAA'> Store list in variable.
+         #history </span><span style='color:#FFF'>{</span><span style='color:#AAA'>insert</span><span style='color:#FFF'>} {</span><span style='color:#AAA'>command</span><span style='color:#FFF'>}</span><span style='color:#AAA'>          Insert a command.
+         #history </span><span style='color:#FFF'>{</span><span style='color:#AAA'>list</span><span style='color:#FFF'>}     </span><span style='color:#AAA'>                 Display the command history.
+         #history </span><span style='color:#FFF'>{</span><span style='color:#AAA'>read</span><span style='color:#FFF'>}   {</span><span style='color:#AAA'>filename</span><span style='color:#FFF'>}</span><span style='color:#AAA'>         Read a command history from file.
+         #history </span><span style='color:#FFF'>{</span><span style='color:#AAA'>write</span><span style='color:#FFF'>}  {</span><span style='color:#AAA'>filename</span><span style='color:#FFF'>}</span><span style='color:#AAA'>         Write a command history to file.
 
 
          Without an argument all available options are shown.
          Without an argument all available options are shown.
 
 
@@ -1601,7 +1607,7 @@ Command</span><span style='color:#AAA'>: #delay </span><span style='color:#FFF'>
 
 
 </span><span style='color:#FF5'>         IF
 </span><span style='color:#FF5'>         IF
 
 
-</span><span style='color:#FFF'>Command</span><span style='color:#AAA'>: #if </span><span style='color:#FFF'>{</span><span style='color:#AAA'>conditional</span><span style='color:#FFF'>} {</span><span style='color:#AAA'>commands if true</span><span style='color:#FFF'>}
+</span><span style='color:#FFF'>Command</span><span style='color:#AAA'>: #if </span><span style='color:#FFF'>{</span><span style='color:#AAA'>conditional</span><span style='color:#FFF'>} {</span><span style='color:#AAA'>commands if true</span><span style='color:#FFF'>} {</span><span style='color:#AAA'>commands if false</span><span style='color:#FFF'>}
 
 
 </span><span style='color:#AAA'>         The #if command works similar to an if statement in other languages,
 </span><span style='color:#AAA'>         The #if command works similar to an if statement in other languages,
          and is based on the way C handles its conditional statements.
          and is based on the way C handles its conditional statements.
@@ -1613,13 +1619,16 @@ Command</span><span style='color:#AAA'>: #delay </span><span style='color:#FFF'>
          executed. See the 'math' helpfile for more information.
          executed. See the 'math' helpfile for more information.
 
 
          To handle the case where an if statement is false it can be followed
          To handle the case where an if statement is false it can be followed
-         by the #else command.
+         by the #else command. Alternatively, the else can be provided as the
+         third argument.
 
 
 </span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #action {%0 gives you %1 gold coins.} {#if {%1 &gt; 5000} {thank %0}}
 </span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #action {%0 gives you %1 gold coins.} {#if {%1 &gt; 5000} {thank %0}}
          If someone gives you more than 5000 coins, thank them.
          If someone gives you more than 5000 coins, thank them.
 
 
 </span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #alias {k} {#if {&quot;%0&quot; == &quot;&quot;} {kill &dollar;target};#else {kill %0}}
 </span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #alias {k} {#if {&quot;%0&quot; == &quot;&quot;} {kill &dollar;target};#else {kill %0}}
 
 
+</span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #if {&quot;%0&quot; == &quot;{bli|bla}&quot;} {#showme %0 is either bli or bla.}
+
 </span><span style='color:#FFF'>Related</span><span style='color:#AAA'>: <a href='#CASE'>case</a>, <a href='#DEFAULT'>default</a>, <a href='#ELSE'>else</a>, <a href='#ELSEIF'>elseif</a>, <a href='#MATH'>math</a>, <a href='#SWITCH'>switch</a> and <a href='#REGEXP'>regexp</a>.
 </span><span style='color:#FFF'>Related</span><span style='color:#AAA'>: <a href='#CASE'>case</a>, <a href='#DEFAULT'>default</a>, <a href='#ELSE'>else</a>, <a href='#ELSEIF'>elseif</a>, <a href='#MATH'>math</a>, <a href='#SWITCH'>switch</a> and <a href='#REGEXP'>regexp</a>.
 <a name='IGNORE'></a>
 <a name='IGNORE'></a>
 
 
@@ -2056,7 +2065,7 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
 </span><span style='color:#AAA'>         </span><span style='color:#FFF'>#line background &lt;argument&gt;
 </span><span style='color:#AAA'>         </span><span style='color:#FFF'>#line background &lt;argument&gt;
 </span><span style='color:#AAA'>           Prevent new session activation.
 </span><span style='color:#AAA'>           Prevent new session activation.
 
 
-         </span><span style='color:#FFF'>#line capture &lt;variable&gt; &lt;argument&gt;.
+         </span><span style='color:#FFF'>#line capture &lt;variable&gt; &lt;argument&gt;
 </span><span style='color:#AAA'>           Argument is executed and output stored in &lt;variable&gt;.
 </span><span style='color:#AAA'>           Argument is executed and output stored in &lt;variable&gt;.
 
 
          </span><span style='color:#FFF'>#line convert &lt;argument&gt;
          </span><span style='color:#FFF'>#line convert &lt;argument&gt;
@@ -2120,6 +2129,7 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
 </span><span style='color:#AAA'>         #list {var} {add} &lt;items&gt;              Add &lt;items&gt; to the list
 </span><span style='color:#AAA'>         #list {var} {add} &lt;items&gt;              Add &lt;items&gt; to the list
          #list {var} {clear}                    Empty the given list
          #list {var} {clear}                    Empty the given list
          #list {var} {collapse} &lt;separator&gt;     Turn list into a variable
          #list {var} {collapse} &lt;separator&gt;     Turn list into a variable
+         #list {var} {copy} &lt;variable&gt;          Copy variable to the list
          #list {var} {create} &lt;items&gt;           Create a list using &lt;items&gt;
          #list {var} {create} &lt;items&gt;           Create a list using &lt;items&gt;
          #list {var} {delete} &lt;index&gt; [amount]  Delete the item at &lt;index&gt;,
          #list {var} {delete} &lt;index&gt; [amount]  Delete the item at &lt;index&gt;,
                                                 the [amount] is optional.
                                                 the [amount] is optional.
@@ -2140,6 +2150,7 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
          #list {var} {size} &lt;variable&gt;          Copy list size to {variable}
          #list {var} {size} &lt;variable&gt;          Copy list size to {variable}
          #list {var} {sort} [items]             Sort list alphabetically, if
          #list {var} {sort} [items]             Sort list alphabetically, if
                                                 an item is given it's added.
                                                 an item is given it's added.
+         #list {var} {swap} &lt;index&gt; &lt;index&gt;     Swap two items
          #list {var} {tokenize} &lt;string&gt;        Create a character list
          #list {var} {tokenize} &lt;string&gt;        Create a character list
 
 
          The index should be between +1 and the list's size. You can also give
          The index should be between +1 and the list's size. You can also give
@@ -2533,6 +2544,9 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
 </span><span style='color:#AAA'>           Start logging to the given file, if the file already exists it won't
 </span><span style='color:#AAA'>           Start logging to the given file, if the file already exists it won't
            be overwritten and data will be appended to the end.
            be overwritten and data will be appended to the end.
 
 
+         </span><span style='color:#FFF'>#log make &lt;directory&gt;
+</span><span style='color:#AAA'>           Create the given directory.
+
          </span><span style='color:#FFF'>#log move &lt;filename_1&gt; &lt;filename_2&gt;
          </span><span style='color:#FFF'>#log move &lt;filename_1&gt; &lt;filename_2&gt;
 </span><span style='color:#AAA'>           Move filename_1 to filename_2. This can be any file and doesn't need
 </span><span style='color:#AAA'>           Move filename_1 to filename_2. This can be any file and doesn't need
            to be a log file.
            to be a log file.
@@ -3237,6 +3251,9 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
          Links can be created using the MSLP protocol which will generate link
          Links can be created using the MSLP protocol which will generate link
          specific events when clicked.
          specific events when clicked.
 
 
+         In order to copy/paste, most terminals require that you press the shift
+         key during selection.
+
 
 
 </span><span style='color:#FFF'>Related</span><span style='color:#AAA'>: <a href='#BUTTON'>button</a>, <a href='#DRAW'>draw</a>, <a href='#EVENT'>event</a> and <a href='#MSLP'>MSLP</a>.
 </span><span style='color:#FFF'>Related</span><span style='color:#AAA'>: <a href='#BUTTON'>button</a>, <a href='#DRAW'>draw</a>, <a href='#EVENT'>event</a> and <a href='#MSLP'>MSLP</a>.
 <a name='MSDP'></a>
 <a name='MSDP'></a>
@@ -3302,7 +3319,9 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
          you need to use &bsol;e]68;2;&bsol;a, and they instead trigger the SECURE LINK
          you need to use &bsol;e]68;2;&bsol;a, and they instead trigger the SECURE LINK
          event.
          event.
 
 
-</span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #sub {%* tells %*} {&bsol;e]68;2;EXEC;#cursor set tell %1 &bsol;a&bsol;e[4m%0&bsol;e[24m}
+         To creae a link that is not undelined, use &bsol;e]4;24m text &bsol;e]24m.
+
+</span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #sub {%* tells %*} {&bsol;e]68;2;EXEC;#cursor set tell %1 &bsol;a&bsol;e[4;24m%0&bsol;e[24m}
 </span><span style='color:#FFF'>       </span><span style='color:#AAA'>  #event {PRESSED SECURE LINK EXEC MOUSE BUTTON ONE} {%4}
 </span><span style='color:#FFF'>       </span><span style='color:#AAA'>  #event {PRESSED SECURE LINK EXEC MOUSE BUTTON ONE} {%4}
 
 
          This would make you start a reply when clicking on a tell.
          This would make you start a reply when clicking on a tell.
@@ -3444,7 +3463,7 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
          is used.
          is used.
 
 
 </span><span style='color:#FFF'>TinTin++ Description                                      POSIX
 </span><span style='color:#FFF'>TinTin++ Description                                      POSIX
-      %a </span><span style='color:#AAA'>Match zero or more characters including newlines ([^&bsol;n]*?)
+      %a </span><span style='color:#AAA'>Match zero or more characters including newlines ([^&bsol;0]*?)
 </span><span style='color:#FFF'>      %A </span><span style='color:#AAA'>Match zero or more newlines                      ([&bsol;n]*?)
 </span><span style='color:#FFF'>      %A </span><span style='color:#AAA'>Match zero or more newlines                      ([&bsol;n]*?)
 </span><span style='color:#FFF'>      %c </span><span style='color:#AAA'>Match zero or more ansi color codes              ((?:&bsol;e&bsol;[[0-9;]*m)*?)
 </span><span style='color:#FFF'>      %c </span><span style='color:#AAA'>Match zero or more ansi color codes              ((?:&bsol;e&bsol;[[0-9;]*m)*?)
 </span><span style='color:#FFF'>      %d </span><span style='color:#AAA'>Match zero or more digits                        ([0-9]*?)
 </span><span style='color:#FFF'>      %d </span><span style='color:#AAA'>Match zero or more digits                        ([0-9]*?)
@@ -3452,6 +3471,7 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
 </span><span style='color:#FFF'>      %i </span><span style='color:#AAA'>Matches become case insensitive                  (?i)
 </span><span style='color:#FFF'>      %i </span><span style='color:#AAA'>Matches become case insensitive                  (?i)
 </span><span style='color:#FFF'>      %I </span><span style='color:#AAA'>Matches become case sensitive (default)          (?-i)
 </span><span style='color:#FFF'>      %I </span><span style='color:#AAA'>Matches become case sensitive (default)          (?-i)
 </span><span style='color:#FFF'>      %s </span><span style='color:#AAA'>Match zero or more spaces                        ([&bsol;r&bsol;n&bsol;t ]*?)
 </span><span style='color:#FFF'>      %s </span><span style='color:#AAA'>Match zero or more spaces                        ([&bsol;r&bsol;n&bsol;t ]*?)
+</span><span style='color:#FFF'>      %S </span><span style='color:#AAA'>Match zero or more non-spaces                    ([^&bsol;r&bsol;n&bsol;t ]*?)
 </span><span style='color:#FFF'>      %w </span><span style='color:#AAA'>Match zero or more word characters               ([A-Za-z0-9_]*?)
 </span><span style='color:#FFF'>      %w </span><span style='color:#AAA'>Match zero or more word characters               ([A-Za-z0-9_]*?)
 </span><span style='color:#FFF'>      %W </span><span style='color:#AAA'>Match zero or more non-word characters           ([^A-Za-z0-9_]*?)
 </span><span style='color:#FFF'>      %W </span><span style='color:#AAA'>Match zero or more non-word characters           ([^A-Za-z0-9_]*?)
 </span><span style='color:#FFF'>      %? </span><span style='color:#AAA'>Match zero or one character                      (.??)
 </span><span style='color:#FFF'>      %? </span><span style='color:#AAA'>Match zero or one character                      (.??)
@@ -3791,10 +3811,10 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
 
 
 </span><span style='color:#FFF'>Command</span><span style='color:#AAA'>: #</span><span style='color:#FFF'>[</span><span style='color:#AAA'>number</span><span style='color:#FFF'>] {</span><span style='color:#AAA'>commands</span><span style='color:#FFF'>}
 </span><span style='color:#FFF'>Command</span><span style='color:#AAA'>: #</span><span style='color:#FFF'>[</span><span style='color:#AAA'>number</span><span style='color:#FFF'>] {</span><span style='color:#AAA'>commands</span><span style='color:#FFF'>}
 
 
-        Sometimes you want to repeat the same command multiple times. This is
+</span><span style='color:#AAA'>        Sometimes you want to repeat the same command multiple times. This is
         the easiest way to accomplish that.
         the easiest way to accomplish that.
 
 
-Example</span><span style='color:#AAA'>: #10 {buy bread}
+</span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #10 {buy bread}
 
 
 </span><span style='color:#FFF'>Related</span><span style='color:#AAA'>: <a href='#MATHEMATICS'>mathematics</a> and <a href='#STATEMENTS'>statements</a>.
 </span><span style='color:#FFF'>Related</span><span style='color:#AAA'>: <a href='#MATHEMATICS'>mathematics</a> and <a href='#STATEMENTS'>statements</a>.
 <a name='REPLACE'></a>
 <a name='REPLACE'></a>
@@ -4294,7 +4314,7 @@ Example</span><span style='color:#AAA'>: #10 {buy bread}
          Replace generic dark blue color codes with bright blue ones.
          Replace generic dark blue color codes with bright blue ones.
 
 
 </span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #sub {%1massacres%2} {&lt;018&gt;%1&lt;118&gt;MASSACRES&lt;018&gt;%2}
 </span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #sub {%1massacres%2} {&lt;018&gt;%1&lt;118&gt;MASSACRES&lt;018&gt;%2}
-         Replaces all occurrences of 'massacres' with 'MASSACRES' in red.
+         Replace a line containing 'massacres' with 'MASSACRES' in red.
 
 
 </span><span style='color:#FFF'>Comment</span><span style='color:#AAA'>: See '#help action', for more information about triggers.
 </span><span style='color:#FFF'>Comment</span><span style='color:#AAA'>: See '#help action', for more information about triggers.
 
 
@@ -4562,23 +4582,25 @@ Example</span><span style='color:#AAA'>: #10 {buy bread}
 
 
 </span><span style='color:#5F5'>         Multi-line triggers
 </span><span style='color:#5F5'>         Multi-line triggers
 
 
-</span><span style='color:#AAA'>         If an action contains the &bsol;n sequence it will be turned into a
-         multi-line trigger. A multi-line action is executed on incoming blocks
-         of text from the MUD, and they will not trigger if the regular
-         expression spans more than one block. You can visualize incoming
-         blocks by using #event {RECEIVED OUTPUT} {#echo &lt;058&gt;%+80h BLOCK}
+</span><span style='color:#AAA'>         If an action or substitution contains the &bsol;n sequence it will be
+         turned into a multi-line trigger. A multi-line trigger is executed on
+         incoming blocks of text from the MUD, and they will not trigger if the
+         regular expression spans more than one block. You can visualize
+         incoming blocks by using the following event:
+
+         #event {RECEIVED OUTPUT} {#echo &lt;058&gt;%+80h BLOCK}
 
 
          Since the %* expression does not capture the &bsol;n sequence it is required
          Since the %* expression does not capture the &bsol;n sequence it is required
          to use %a to capture multiple lines. To capture the start of the block
          to use %a to capture multiple lines. To capture the start of the block
          use &bsol;A and for the end use &bsol;Z. You can use ^ and &dollar; to capture the
          use &bsol;A and for the end use &bsol;Z. You can use ^ and &dollar; to capture the
          start and end of a line.
          start and end of a line.
 
 
-         Multi-line actions trigger before regular actions. Multiple
+         Multi-line triggers trigger before regular triggers. Multiple
          multi-line actions can trigger per block, and each multi-line action
          multi-line actions can trigger per block, and each multi-line action
          can trigger multiple times per block. Packet fragmentation is not
          can trigger multiple times per block. Packet fragmentation is not
          currently handled.
          currently handled.
 
 
-         Multi-line actions are experimental and subject to change.
+         Multi-line triggers are experimental and subject to change.
 
 
 </span><span style='color:#5F5'>         Input triggers
 </span><span style='color:#5F5'>         Input triggers
 
 
@@ -4650,6 +4672,10 @@ Example</span><span style='color:#AAA'>: #10 {buy bread}
 
 
 </span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #show {Targets starting with the letter A: &dollar;targets[A%*]
 </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 '='.
+
+</span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #show {A target literally defined as A%*: &dollar;targets[&bsol;A%*]
+
          To see the internal index of a variable use &amp;&lt;variable name&gt;. To see
          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
          the size of a table you would use: &amp;targets[] or &amp;targets[%*]. A non
          existent nested variable will report itself as 0.
          existent nested variable will report itself as 0.

+ 20 - 12
docs/tutorial.html

@@ -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:#0AA'>      ####################################################################
       #</span><span style='color:#AAA'>                                                                  </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.31                     </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'>                                                                  </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'>      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'>#
       #</span><span style='color:#AAA'>                                                                  </span><span style='color:#0AA'>#
@@ -1209,6 +1209,9 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
          Links can be created using the MSLP protocol which will generate link
          Links can be created using the MSLP protocol which will generate link
          specific events when clicked.
          specific events when clicked.
 
 
+         In order to copy/paste, most terminals require that you press the shift
+         key during selection.
+
 
 
 </span><span style='color:#FFF'>Related</span><span style='color:#AAA'>: <a href='help.html#BUTTON'>button</a>, <a href='help.html#DRAW'>draw</a>, <a href='help.html#EVENT'>event</a> and <a href='#MSLP'>MSLP</a>.
 </span><span style='color:#FFF'>Related</span><span style='color:#AAA'>: <a href='help.html#BUTTON'>button</a>, <a href='help.html#DRAW'>draw</a>, <a href='help.html#EVENT'>event</a> and <a href='#MSLP'>MSLP</a>.
 <a name='MSDP'></a>
 <a name='MSDP'></a>
@@ -1274,7 +1277,9 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
          you need to use &bsol;e]68;2;&bsol;a, and they instead trigger the SECURE LINK
          you need to use &bsol;e]68;2;&bsol;a, and they instead trigger the SECURE LINK
          event.
          event.
 
 
-</span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #sub {%* tells %*} {&bsol;e]68;2;EXEC;#cursor set tell %1 &bsol;a&bsol;e[4m%0&bsol;e[24m}
+         To creae a link that is not undelined, use &bsol;e]4;24m text &bsol;e]24m.
+
+</span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #sub {%* tells %*} {&bsol;e]68;2;EXEC;#cursor set tell %1 &bsol;a&bsol;e[4;24m%0&bsol;e[24m}
 </span><span style='color:#FFF'>       </span><span style='color:#AAA'>  #event {PRESSED SECURE LINK EXEC MOUSE BUTTON ONE} {%4}
 </span><span style='color:#FFF'>       </span><span style='color:#AAA'>  #event {PRESSED SECURE LINK EXEC MOUSE BUTTON ONE} {%4}
 
 
          This would make you start a reply when clicking on a tell.
          This would make you start a reply when clicking on a tell.
@@ -1323,7 +1328,7 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
          is used.
          is used.
 
 
 </span><span style='color:#FFF'>TinTin++ Description                                      POSIX
 </span><span style='color:#FFF'>TinTin++ Description                                      POSIX
-      %a </span><span style='color:#AAA'>Match zero or more characters including newlines ([^&bsol;n]*?)
+      %a </span><span style='color:#AAA'>Match zero or more characters including newlines ([^&bsol;0]*?)
 </span><span style='color:#FFF'>      %A </span><span style='color:#AAA'>Match zero or more newlines                      ([&bsol;n]*?)
 </span><span style='color:#FFF'>      %A </span><span style='color:#AAA'>Match zero or more newlines                      ([&bsol;n]*?)
 </span><span style='color:#FFF'>      %c </span><span style='color:#AAA'>Match zero or more ansi color codes              ((?:&bsol;e&bsol;[[0-9;]*m)*?)
 </span><span style='color:#FFF'>      %c </span><span style='color:#AAA'>Match zero or more ansi color codes              ((?:&bsol;e&bsol;[[0-9;]*m)*?)
 </span><span style='color:#FFF'>      %d </span><span style='color:#AAA'>Match zero or more digits                        ([0-9]*?)
 </span><span style='color:#FFF'>      %d </span><span style='color:#AAA'>Match zero or more digits                        ([0-9]*?)
@@ -1331,6 +1336,7 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
 </span><span style='color:#FFF'>      %i </span><span style='color:#AAA'>Matches become case insensitive                  (?i)
 </span><span style='color:#FFF'>      %i </span><span style='color:#AAA'>Matches become case insensitive                  (?i)
 </span><span style='color:#FFF'>      %I </span><span style='color:#AAA'>Matches become case sensitive (default)          (?-i)
 </span><span style='color:#FFF'>      %I </span><span style='color:#AAA'>Matches become case sensitive (default)          (?-i)
 </span><span style='color:#FFF'>      %s </span><span style='color:#AAA'>Match zero or more spaces                        ([&bsol;r&bsol;n&bsol;t ]*?)
 </span><span style='color:#FFF'>      %s </span><span style='color:#AAA'>Match zero or more spaces                        ([&bsol;r&bsol;n&bsol;t ]*?)
+</span><span style='color:#FFF'>      %S </span><span style='color:#AAA'>Match zero or more non-spaces                    ([^&bsol;r&bsol;n&bsol;t ]*?)
 </span><span style='color:#FFF'>      %w </span><span style='color:#AAA'>Match zero or more word characters               ([A-Za-z0-9_]*?)
 </span><span style='color:#FFF'>      %w </span><span style='color:#AAA'>Match zero or more word characters               ([A-Za-z0-9_]*?)
 </span><span style='color:#FFF'>      %W </span><span style='color:#AAA'>Match zero or more non-word characters           ([^A-Za-z0-9_]*?)
 </span><span style='color:#FFF'>      %W </span><span style='color:#AAA'>Match zero or more non-word characters           ([^A-Za-z0-9_]*?)
 </span><span style='color:#FFF'>      %? </span><span style='color:#AAA'>Match zero or one character                      (.??)
 </span><span style='color:#FFF'>      %? </span><span style='color:#AAA'>Match zero or one character                      (.??)
@@ -1494,10 +1500,10 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
 
 
 </span><span style='color:#FFF'>Command</span><span style='color:#AAA'>: #</span><span style='color:#FFF'>[</span><span style='color:#AAA'>number</span><span style='color:#FFF'>] {</span><span style='color:#AAA'>commands</span><span style='color:#FFF'>}
 </span><span style='color:#FFF'>Command</span><span style='color:#AAA'>: #</span><span style='color:#FFF'>[</span><span style='color:#AAA'>number</span><span style='color:#FFF'>] {</span><span style='color:#AAA'>commands</span><span style='color:#FFF'>}
 
 
-        Sometimes you want to repeat the same command multiple times. This is
+</span><span style='color:#AAA'>        Sometimes you want to repeat the same command multiple times. This is
         the easiest way to accomplish that.
         the easiest way to accomplish that.
 
 
-Example</span><span style='color:#AAA'>: #10 {buy bread}
+</span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #10 {buy bread}
 
 
 </span><span style='color:#FFF'>Related</span><span style='color:#AAA'>: <a href='#MATHEMATICS'>mathematics</a> and <a href='#STATEMENTS'>statements</a>.
 </span><span style='color:#FFF'>Related</span><span style='color:#AAA'>: <a href='#MATHEMATICS'>mathematics</a> and <a href='#STATEMENTS'>statements</a>.
 <a name='SCREEN_READER'></a>
 <a name='SCREEN_READER'></a>
@@ -1792,23 +1798,25 @@ Example</span><span style='color:#AAA'>: #10 {buy bread}
 
 
 </span><span style='color:#5F5'>         Multi-line triggers
 </span><span style='color:#5F5'>         Multi-line triggers
 
 
-</span><span style='color:#AAA'>         If an action contains the &bsol;n sequence it will be turned into a
-         multi-line trigger. A multi-line action is executed on incoming blocks
-         of text from the MUD, and they will not trigger if the regular
-         expression spans more than one block. You can visualize incoming
-         blocks by using #event {RECEIVED OUTPUT} {#echo &lt;058&gt;%+80h BLOCK}
+</span><span style='color:#AAA'>         If an action or substitution contains the &bsol;n sequence it will be
+         turned into a multi-line trigger. A multi-line trigger is executed on
+         incoming blocks of text from the MUD, and they will not trigger if the
+         regular expression spans more than one block. You can visualize
+         incoming blocks by using the following event:
+
+         #event {RECEIVED OUTPUT} {#echo &lt;058&gt;%+80h BLOCK}
 
 
          Since the %* expression does not capture the &bsol;n sequence it is required
          Since the %* expression does not capture the &bsol;n sequence it is required
          to use %a to capture multiple lines. To capture the start of the block
          to use %a to capture multiple lines. To capture the start of the block
          use &bsol;A and for the end use &bsol;Z. You can use ^ and &dollar; to capture the
          use &bsol;A and for the end use &bsol;Z. You can use ^ and &dollar; to capture the
          start and end of a line.
          start and end of a line.
 
 
-         Multi-line actions trigger before regular actions. Multiple
+         Multi-line triggers trigger before regular triggers. Multiple
          multi-line actions can trigger per block, and each multi-line action
          multi-line actions can trigger per block, and each multi-line action
          can trigger multiple times per block. Packet fragmentation is not
          can trigger multiple times per block. Packet fragmentation is not
          currently handled.
          currently handled.
 
 
-         Multi-line actions are experimental and subject to change.
+         Multi-line triggers are experimental and subject to change.
 
 
 </span><span style='color:#5F5'>         Input triggers
 </span><span style='color:#5F5'>         Input triggers
 
 

+ 46 - 0
mods/igr.mods

@@ -1,3 +1,49 @@
+Mar 2023        2.02.32
+------------------------------------------------------------------------------
+data.c          Changed the symbol for the strict equality assignment/lookup
+                from \ to = due to compatibility issues. You'll get a warning
+                if a variable or table key begins with a \.
+
+net.c           Added the PROCESSED LINE event. Like RECEIVED LINE, but it
+                triggers after line triggers have been processed.
+
+variable.c      Added support to use \A in #replace and #substitute to only
+                match the start of a line. When using ^ the behavior is more
+                ambiguous, matching at the start of each line and at the end
+                of each preceding match.
+
+net.c           Added the PACKET PATCH event which triggers when a broken
+                packet is detected. Has some utility for trouble shooting.
+
+list.c          Added #list <list> copy <variable> to copy a variable to the
+                given list. Will copy tables as well.
+
+log.c           Added #log make <directory> to create directories. #log remove
+                <directory> can be used to remove one.
+
+trigger.c       Added support for multi-line substitutions.
+
+show.c          Added a REFORMAT event which can be used to alter system
+                messages. Must use #return to set the new message format.
+
+help.c          Added a CATCH HELP event.
+
+                #event {CATCH HELP NOP} {#line ignore #showme bla}
+
+class.c         #class clear/close/kill/list/load/save/size/write no longer
+                create a class if none exists.
+
+split.c         When using #split 0 1 0 -80 it will correctly use the negative
+                argument on subsequent screen resizes.
+
+list.c          Added #list swap <index1> <index2> to swap two list items.
+
+cursor.c        You can paste multi-line triggers by first pressing ctrl-v,
+                next paste the data, followed by pressing ctrl-enter.
+
+mapper.c        Added #map flag autolink <on|off>. Default is on. Set to off
+                to disable automatically linking overlapping rooms.
+
 Jan 2023        2.02.31
 Jan 2023        2.02.31
 ------------------------------------------------------------------------------
 ------------------------------------------------------------------------------
 cursor.c        #cursor {get} will escape braces and other special characters.
 cursor.c        #cursor {get} will escape braces and other special characters.

+ 55 - 40
src/banner.c

@@ -103,6 +103,23 @@ void banner_expires(struct session *ses, char *name, char *arg, char *arg1)
 
 
 void banner_init(struct session *ses, char *arg1)
 void banner_init(struct session *ses, char *arg1)
 {
 {
+	banner_create(ses, "Armageddon", arg1);
+
+	banner_desc(ses, "Armageddon",
+		"Armageddon MUD is set in the brutal post-apocalyptic world of Zalanthas.\n"
+		"Emphasizing roleplay over combat, the game offers a rich, immersive experience.\n"
+		"Zalanthas is ruled by sorcerer-kings and their powerful Templarate, dominating\n"
+		"the twin cities of Allanak and Tuluk. Magic not sanctioned by these rulers is\n"
+		"feared and often met with fatal consequences. Survival is a constant struggle\n"
+		"in this harsh environment, and death is permanent. Armageddon MUD delivers a\n"
+		"distinctive roleplaying adventure, with a dedicated community of players and\n"
+		"staff actively shaping the ongoing Zalanthan narrative for over three decades.", arg1);
+
+	banner_website(ses, "Armageddon", "https://armageddon.org", arg1);
+	banner_address(ses, "Armageddon", "arm armageddon.org 4050", arg1);
+	banner_expires(ses, "Armageddon", "2030", arg1);
+
+
 	banner_create(ses, "Lost Souls", arg1);
 	banner_create(ses, "Lost Souls", arg1);
 
 
 	banner_desc(ses, "Lost Souls",
 	banner_desc(ses, "Lost Souls",
@@ -118,7 +135,7 @@ void banner_init(struct session *ses, char *arg1)
 
 
 	banner_website(ses, "Lost Souls", "https://lostsouls.org", arg1);
 	banner_website(ses, "Lost Souls", "https://lostsouls.org", arg1);
 	banner_address(ses, "Lost Souls", "ls lostsouls.org 23", arg1);
 	banner_address(ses, "Lost Souls", "ls lostsouls.org 23", arg1);
-	banner_expires(ses, "Lost Souls", "2028", arg1);
+	banner_expires(ses, "Lost Souls", "2029", arg1);
 
 
 
 
 	banner_create(ses, "Kallisti MUD", arg1);
 	banner_create(ses, "Kallisti MUD", arg1);
@@ -136,9 +153,10 @@ void banner_init(struct session *ses, char *arg1)
 
 
 	banner_website(ses, "Kallisti MUD", "https://www.KallistiMUD.com", arg1);
 	banner_website(ses, "Kallisti MUD", "https://www.KallistiMUD.com", arg1);
 	banner_address(ses, "Kallisti MUD", "LoK kallistimud.com 4000", arg1);
 	banner_address(ses, "Kallisti MUD", "LoK kallistimud.com 4000", arg1);
-	banner_expires(ses, "Kallisti MUD", "2028", arg1);
+	banner_expires(ses, "Kallisti MUD", "2029", arg1);
 	banner_flag(ses, "Kallisti MUD", BANNER_FLAG_DUPLICATE);
 	banner_flag(ses, "Kallisti MUD", BANNER_FLAG_DUPLICATE);
 
 
+
 	banner_create(ses, "Legends of Kallisti", arg1);
 	banner_create(ses, "Legends of Kallisti", arg1);
 
 
 	banner_desc(ses, "Legends of Kallisti",
 	banner_desc(ses, "Legends of Kallisti",
@@ -154,7 +172,7 @@ void banner_init(struct session *ses, char *arg1)
 
 
 	banner_website(ses, "Legends of Kallisti", "https://legendsofkallisti.com", arg1);
 	banner_website(ses, "Legends of Kallisti", "https://legendsofkallisti.com", arg1);
 	banner_address(ses, "Legends of Kallisti", "LoK legendsofkallisti.com 4000", arg1);
 	banner_address(ses, "Legends of Kallisti", "LoK legendsofkallisti.com 4000", arg1);
-	banner_expires(ses, "Legends of Kallisti", "2028", arg1);
+	banner_expires(ses, "Legends of Kallisti", "2029", arg1);
 
 
 
 
 	banner_create(ses, "3Kingdoms", arg1);
 	banner_create(ses, "3Kingdoms", arg1);
@@ -172,7 +190,7 @@ void banner_init(struct session *ses, char *arg1)
 
 
 	banner_website(ses, "3Kingdoms", "http://3k.org", arg1);
 	banner_website(ses, "3Kingdoms", "http://3k.org", arg1);
 	banner_address(ses, "3Kingdoms", "3K 3k.org 3000", arg1);
 	banner_address(ses, "3Kingdoms", "3K 3k.org 3000", arg1);
-	banner_expires(ses, "3Kingdoms", "2028", arg1);
+	banner_expires(ses, "3Kingdoms", "2029", arg1);
 
 
 
 
 	banner_create(ses, "RetroMUD", arg1);
 	banner_create(ses, "RetroMUD", arg1);
@@ -187,23 +205,6 @@ void banner_init(struct session *ses, char *arg1)
 	banner_expires(ses, "RetroMUD", "2032", arg1);
 	banner_expires(ses, "RetroMUD", "2032", arg1);
 
 
 
 
-	banner_create(ses, "Realm of Utopian Dreams (RUD)", arg1);
-
-	banner_desc(ses, "Realm of Utopian Dreams (RUD)",
-		"RUD is a unique ROM-based high-fantasy MUD with character choices for many play\n"
-		"styles from hack-n-slash to roleplay. Each of the races and classes offer\n"
-		"unique spells and skills, unlocked through a tiered remort system with\n"
-		"customization through religion memberships and epic advancements. RUD started\n"
-		"in 1996, always seeking new adventurers to become the next hero, build a home,\n"
-		"start a shop, and eventually become Nobles of the Realm! New players to RUD can\n"
-		"be just as successful as 20+ year veterans. We run quests, plots, and annual\n"
-		"festivals in an ever evolving world. Come build Lantarea with us!", arg1);
-
-	banner_website(ses, "Realm of Utopian Dreams (RUD)", "http://rudmud.com", arg1);
-	banner_address(ses, "Realm of Utopian Dreams (RUD)", "rud rudmud.com 1701", arg1);
-	banner_expires(ses, "Realm of Utopian Dreams (RUD)", "2028", arg1);
-
-
 	banner_create(ses, "Alter Aeon", arg1);
 	banner_create(ses, "Alter Aeon", arg1);
 
 
 	banner_desc(ses, "Alter Aeon",
 	banner_desc(ses, "Alter Aeon",
@@ -217,9 +218,26 @@ void banner_init(struct session *ses, char *arg1)
 
 
 	banner_website(ses, "Alter Aeon", "https://www.alteraeon.com", arg1);
 	banner_website(ses, "Alter Aeon", "https://www.alteraeon.com", arg1);
 	banner_address(ses, "Alter Aeon", "aa alteraeon.com 3000", arg1);
 	banner_address(ses, "Alter Aeon", "aa alteraeon.com 3000", arg1);
-	banner_expires(ses, "Alter Aeon", "2028", arg1);
+	banner_expires(ses, "Alter Aeon", "2029", arg1);
+
+
+	banner_create(ses, "New Worlds Ateraan", arg1);
+
+	banner_desc(ses, "New Worlds Ateraan",
+		"Ateraan is a world of Intensive Roleplaying offering many unique and powerful\n"
+		"guilds, races, politics, religion, justice, economy, and a storyline that is\n"
+		"dominantly player controlled and based on a novel. The game is based on a\n"
+		"Kingdom with knights, merchants, mages, and thieves, and a fierce southern\n"
+		"state that has warriors, shaman, slaves, and servants. Ships rule the seas and\n"
+		"caravans travel the lands. With 100's of players and features like invasions,\n"
+		"ship creation, house building, clans, theaters, leatherball fields, and massive\n"
+		"events, the game is incredibly robust and diverse.", arg1);
 
 
+	banner_website(ses, "New Worlds Ateraan", "http://www.ateraan.com", arg1);
+	banner_address(ses, "New Worlds Ateraan", "nwa ateraan.com 4002", arg1);
+	banner_expires(ses, "New Worlds Ateraan", "2029", arg1);
 
 
+/*
 	banner_create(ses, "Threshold RPG", arg1);
 	banner_create(ses, "Threshold RPG", arg1);
 
 
 	banner_desc(ses, "Threshold RPG",
 	banner_desc(ses, "Threshold RPG",
@@ -234,6 +252,21 @@ void banner_init(struct session *ses, char *arg1)
 	banner_address(ses, "Threshold RPG", "thresh thresholdrpg.com 3333", arg1);
 	banner_address(ses, "Threshold RPG", "thresh thresholdrpg.com 3333", arg1);
 	banner_expires(ses, "Threshold RPG", "2028", arg1);
 	banner_expires(ses, "Threshold RPG", "2028", arg1);
 
 
+	banner_create(ses, "Realm of Utopian Dreams (RUD)", arg1);
+
+	banner_desc(ses, "Realm of Utopian Dreams (RUD)",
+		"RUD is a unique ROM-based high-fantasy MUD with character choices for many play\n"
+		"styles from hack-n-slash to roleplay. Each of the races and classes offer\n"
+		"unique spells and skills, unlocked through a tiered remort system with\n"
+		"customization through religion memberships and epic advancements. RUD started\n"
+		"in 1996, always seeking new adventurers to become the next hero, build a home,\n"
+		"start a shop, and eventually become Nobles of the Realm! New players to RUD can\n"
+		"be just as successful as 20+ year veterans. We run quests, plots, and annual\n"
+		"festivals in an ever evolving world. Come build Lantarea with us!", arg1);
+
+	banner_website(ses, "Realm of Utopian Dreams (RUD)", "http://rudmud.com", arg1);
+	banner_address(ses, "Realm of Utopian Dreams (RUD)", "rud rudmud.com 1701", arg1);
+	banner_expires(ses, "Realm of Utopian Dreams (RUD)", "2028", arg1);
 
 
 	banner_create(ses, "Primal Darkness", arg1);
 	banner_create(ses, "Primal Darkness", arg1);
 	
 	
@@ -251,24 +284,6 @@ void banner_init(struct session *ses, char *arg1)
 	banner_address(ses, "Primal Darkness", "pd mud.primaldarkness.com 5000", arg1);
 	banner_address(ses, "Primal Darkness", "pd mud.primaldarkness.com 5000", arg1);
 	banner_expires(ses, "Primal Darkness", "2028", arg1);
 	banner_expires(ses, "Primal Darkness", "2028", arg1);
 
 
-
-	banner_create(ses, "New Worlds Ateraan", arg1);
-
-	banner_desc(ses, "New Worlds Ateraan",
-		"Ateraan is a world of Intensive Roleplaying offering many unique and powerful\n"
-		"guilds, races, politics, religion, justice, economy, and a storyline that is\n"
-		"dominantly player controlled and based on a novel. The game is based on a\n"
-		"Kingdom with knights, merchants, mages, and thieves, and a fierce southern\n"
-		"state that has warriors, shaman, slaves, and servants. Ships rule the seas and\n"
-		"caravans travel the lands. With 100's of players and features like invasions,\n"
-		"ship creation, house building, clans, theaters, leatherball fields, and massive\n"
-		"events, the game is incredibly robust and diverse.", arg1);
-
-	banner_website(ses, "New Worlds Ateraan", "http://www.ateraan.com", arg1);
-	banner_address(ses, "New Worlds Ateraan", "nwa ateraan.com 4002", arg1);
-	banner_expires(ses, "New Worlds Ateraan", "2028", arg1);
-
-/*
 	banner_create(ses, "Carrion Fields", arg1);
 	banner_create(ses, "Carrion Fields", arg1);
 
 
 	banner_desc(ses, "Carrion Fields",
 	banner_desc(ses, "Carrion Fields",

+ 1 - 1
src/base.c

@@ -148,7 +148,7 @@ int str_to_base64(char *in, char *out, size_t size)
 
 
 	pto = out;
 	pto = out;
 
 
-	for (cnt = 0 ; cnt + 3 < size ; cnt += 3)
+	for (cnt = 0 ; cnt + 3 <= size ; cnt += 3)
 	{
 	{
 		*pto++ = base64_table[(unsigned char) in[cnt + 0] % 64];
 		*pto++ = base64_table[(unsigned char) in[cnt + 0] % 64];
 		*pto++ = base64_table[(unsigned char) in[cnt + 0] / 64 + (unsigned char) in[cnt + 1] % 16 * 4];
 		*pto++ = base64_table[(unsigned char) in[cnt + 0] / 64 + (unsigned char) in[cnt + 1] % 16 * 4];

+ 14 - 14
src/buffer.c

@@ -712,7 +712,7 @@ DO_BUFFER(buffer_clear)
 
 
 	if (min > max)
 	if (min > max)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#ERROR: #BUFFER CLEAR {%d} {%d} LOWER BOUND EXCEEDS UPPER BOUND.", min, max);
+		show_error(ses, LIST_COMMAND, "#ERROR: #BUFFER CLEAR {%d} {%d}: LOWER BOUND EXCEEDS UPPER BOUND.", min, max);
 
 
 		return;
 		return;
 	}
 	}
@@ -931,7 +931,7 @@ DO_BUFFER(buffer_find)
 
 
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
-		show_error(gtd->ses, LIST_COMMAND, "#BUFFER, FIND WHAT?");
+		show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #BUFFER FIND [PAGE] <SEARCH TEXT>");
 
 
 		return;
 		return;
 	}
 	}
@@ -944,7 +944,7 @@ DO_BUFFER(buffer_find)
 
 
 		if (*arg2 == 0)
 		if (*arg2 == 0)
 		{
 		{
-			show_error(gtd->ses, LIST_COMMAND, "#BUFFER, FIND OCCURANCE %d OF WHAT?", page);
+			show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #BUFFER FIND {%d} <SEARCH TEXT>", page);
 
 
 			return;
 			return;
 		}
 		}
@@ -1001,7 +1001,7 @@ DO_BUFFER(buffer_find)
 
 
 	if (scroll_cnt < 0 || scroll_cnt >= ses->scroll->used)
 	if (scroll_cnt < 0 || scroll_cnt >= ses->scroll->used)
 	{
 	{
-		show_error(gtd->ses, LIST_COMMAND, "#BUFFER FIND, NO MATCHES FOUND.");
+		show_error(gtd->ses, LIST_COMMAND, "#BUFFER FIND: NO MATCHES FOUND.");
 
 
 		return;
 		return;
 	}
 	}
@@ -1063,7 +1063,7 @@ DO_BUFFER(buffer_get)
 
 
 	if (min > max)
 	if (min > max)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#ERROR: #BUFFER GET {%s} {%d} {%d} LOWER BOUND EXCEEDS UPPER BOUND.", arg1, min, max);
+		show_error(ses, LIST_COMMAND, "#ERROR: #BUFFER GET {%s} {%d} {%d}: LOWER BOUND EXCEEDS UPPER BOUND.", arg1, min, max);
 
 
 		return;
 		return;
 	}
 	}
@@ -1079,7 +1079,7 @@ DO_BUFFER(buffer_get)
 		add_nest_node_ses(ses, arg1, "{%d}{%s}", ++cnt, arg2);
 		add_nest_node_ses(ses, arg1, "{%d}{%s}", ++cnt, arg2);
 	}
 	}
 
 
-	show_message(ses, LIST_COMMAND, "#BUFFER GET: %d LINE%s SAVED TO {%s}.", cnt, cnt > 1 ? "S" : "", arg1);
+	show_message(ses, LIST_COMMAND, "#BUFFER GET: %d LINES SAVED TO {%s}.", cnt, arg1);
 
 
 	return;
 	return;
 }
 }
@@ -1127,13 +1127,13 @@ DO_BUFFER(buffer_write)
 
 
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #BUFFER WRITE <FILENAME>]");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #BUFFER WRITE <FILENAME>");
 	}
 	}
 	else
 	else
 	{
 	{
 		if ((fp = fopen(arg1, "w")))
 		if ((fp = fopen(arg1, "w")))
 		{
 		{
-			show_message(ses, LIST_COMMAND, "#OK: WRITING BUFFER TO '%s'.", arg1);
+			show_message(ses, LIST_COMMAND, "#BUFFER WRITE: %d LINES WRITTEN TO {%s}.", ses->scroll->used - 1, arg1);
 
 
 			logheader(ses, fp, ses->log->mode | LOG_FLAG_OVERWRITE);
 			logheader(ses, fp, ses->log->mode | LOG_FLAG_OVERWRITE);
 
 
@@ -1158,7 +1158,7 @@ DO_BUFFER(buffer_write)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#ERROR: #BUFFER WRITE {%s} - FAILED TO OPEN FILE.", arg1);
+			show_error(ses, LIST_COMMAND, "#ERROR: #BUFFER WRITE {%s}: COULDN'T OPEN FILE.", arg1);
 		}
 		}
 	}
 	}
 	return;
 	return;
@@ -1200,7 +1200,7 @@ DO_BUFFER(buffer_info)
 		add_nest_node_ses(ses, arg2, "{USED}{%d}", ses->scroll->used);
 		add_nest_node_ses(ses, arg2, "{USED}{%d}", ses->scroll->used);
 		add_nest_node_ses(ses, arg2, "{WRAP}{%d}", ses->scroll->wrap);
 		add_nest_node_ses(ses, arg2, "{WRAP}{%d}", ses->scroll->wrap);
 
 
-		show_message(ses, LIST_COMMAND, "#BUFFER INFO: SAVED TO {%s}", arg2);
+		show_message(ses, LIST_COMMAND, "#BUFFER INFO: DATA SAVED TO {%s}", arg2);
 	}
 	}
 	else
 	else
 	{
 	{
@@ -1222,7 +1222,7 @@ DO_COMMAND(do_grep)
 
 
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: GREP [#] <SEARCH TEXT>");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #GREP [PAGE] <SEARCH TEXT>");
 
 
 		return ses;
 		return ses;
 	}
 	}
@@ -1235,7 +1235,7 @@ DO_COMMAND(do_grep)
 
 
 		if (*arg2 == 0)
 		if (*arg2 == 0)
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: #grep {%s} <SEARCH TEXT>", arg1);
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #GREP {%s} <SEARCH TEXT>", arg1);
 
 
 			return ses;
 			return ses;
 		}
 		}
@@ -1286,7 +1286,7 @@ DO_COMMAND(do_grep)
 
 
 		if (grep_cnt <= grep_min)
 		if (grep_cnt <= grep_min)
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#NO MATCHES FOUND.");
+			show_error(ses, LIST_COMMAND, "#GREP: #NO MATCHES FOUND.");
 
 
 			gtd->level->grep--;
 			gtd->level->grep--;
 
 
@@ -1344,7 +1344,7 @@ DO_COMMAND(do_grep)
 
 
 		if (grep_cnt == 0)
 		if (grep_cnt == 0)
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#NO MATCHES FOUND.");
+			show_error(ses, LIST_COMMAND, "#GREP: #NO MATCHES FOUND.");
 
 
 			gtd->level->grep--;
 			gtd->level->grep--;
 
 

+ 85 - 31
src/class.c

@@ -46,29 +46,30 @@ struct class_type
 {
 {
 	char                  * name;
 	char                  * name;
 	CLASS                 * fun;
 	CLASS                 * fun;
+	char                  * desc;
 };
 };
 
 
 struct class_type class_table[] =
 struct class_type class_table[] =
 {
 {
-	{    "ASSIGN",            class_assign           },
-	{    "CLEAR",             class_clear            },
-	{    "CLOSE",             class_close            },
-	{    "KILL",              class_kill             },
-	{    "LIST",              class_list             },
-	{    "LOAD",              class_load             },
-	{    "OPEN",              class_open             },
-	{    "READ",              class_read             },
-	{    "SAVE",              class_save             },
-	{    "SIZE",              class_size             },
-	{    "WRITE",             class_write            },
-	{    "",                  NULL                   },
+	{    "ASSIGN",            class_assign,   "Execute command with given class opened."        },
+	{    "CLEAR",             class_clear,    "Delete triggers associated with given class."    },
+	{    "CLOSE",             class_close,    "Close given class."                              },
+	{    "KILL",              class_kill,     "Clear, close, and remove given class."           },
+	{    "LIST",              class_list,     "List triggers associated with given class."      },
+	{    "LOAD",              class_load,     "Load saved data of given class."                 },
+	{    "OPEN",              class_open,     "Open given class."                               },
+	{    "READ",              class_read,     "Read file with given class opened."              },
+	{    "SAVE",              class_save,     "Save given class to memory."                     },
+	{    "SIZE",              class_size,     "Store size of given class to a variable."        },
+	{    "WRITE",             class_write,    "Write given class to file."                      },
+	{    "",                  NULL,           NULL                                              }
 };
 };
 
 
 int count_class(struct session *ses, struct listnode *group);
 int count_class(struct session *ses, struct listnode *group);
 
 
 DO_COMMAND(do_class)
 DO_COMMAND(do_class)
 {
 {
-	int i;
+	int i, cnt;
 	struct listroot *root;
 	struct listroot *root;
 	struct listnode *node;
 	struct listnode *node;
 
 
@@ -91,7 +92,9 @@ DO_COMMAND(do_class)
 	}
 	}
 	else if (*arg2 == 0)
 	else if (*arg2 == 0)
 	{
 	{
-		class_list(ses, NULL, arg1, arg2);
+		node = search_node_list(ses->list[LIST_CLASS], arg1);
+
+		class_list(ses, node, arg1, arg2);
 	}
 	}
 	else
 	else
 	{
 	{
@@ -105,27 +108,36 @@ DO_COMMAND(do_class)
 
 
 		if (*class_table[i].name == 0)
 		if (*class_table[i].name == 0)
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: CLASS {name} {OPEN|CLEAR|CLOSE|READ|SIZE|WRITE|KILL}.", arg1, capitalize(arg2));
+			tintin_header(ses, 80, " CLASS OPTIONS ");
+
+			for (cnt = 0 ; *class_table[cnt].fun != NULL ; cnt++)
+			{
+				if (*class_table[cnt].desc)
+				{
+					tintin_printf2(ses, "  [%-13s] %s", class_table[cnt].name, class_table[cnt].desc);
+				}
+			}
+			tintin_header(ses, 80, "");
 		}
 		}
 		else
 		else
 		{
 		{
 			node = search_node_list(ses->list[LIST_CLASS], arg1);
 			node = search_node_list(ses->list[LIST_CLASS], arg1);
 
 
-			if (node == NULL)
-			{
-				show_info(ses, LIST_CLASS, "#INFO: CLASS {%s} CREATED", arg1);
-
-				check_all_events(ses, EVENT_FLAG_CLASS, 0, 1, "CLASS CREATED", arg1);
-				check_all_events(ses, EVENT_FLAG_CLASS, 1, 1, "CLASS CREATED %s", arg1, arg1);
-
-				node = update_node_list(ses->list[LIST_CLASS], arg1, "", arg3, "");
-			}
 			class_table[i].fun(ses, node, arg1, arg3);
 			class_table[i].fun(ses, node, arg1, arg3);
 		}
 		}
 	}
 	}
 	return ses;
 	return ses;
 }
 }
 
 
+struct listnode *create_class(struct session *ses, char *arg1, char *arg3)
+{
+	show_info(ses, LIST_CLASS, "#INFO: CLASS {%s} CREATED", arg1);
+
+	check_all_events(ses, EVENT_FLAG_CLASS, 0, 1, "CLASS CREATED", arg1);
+	check_all_events(ses, EVENT_FLAG_CLASS, 1, 1, "CLASS CREATED %s", arg1, arg1);
+
+	return update_node_list(ses->list[LIST_CLASS], arg1, "", arg3, "");
+}
 
 
 int count_class(struct session *ses, struct listnode *group)
 int count_class(struct session *ses, struct listnode *group)
 {
 {
@@ -151,6 +163,10 @@ int count_class(struct session *ses, struct listnode *group)
 
 
 DO_CLASS(class_assign)
 DO_CLASS(class_assign)
 {
 {
+	if (node == NULL)
+	{
+		node = create_class(ses, arg1, arg2);
+	}
 	char *tmp = ses->group;
 	char *tmp = ses->group;
 
 
 	ses->group = strdup(arg1);
 	ses->group = strdup(arg1);
@@ -168,6 +184,13 @@ DO_CLASS(class_clear)
 {
 {
 	int type, index;
 	int type, index;
 
 
+	if (node == NULL)
+	{
+		show_message(ses, LIST_CLASS, "#CLASS {%s} DOES NOT EXIST.", arg1);
+
+		return ses;
+	}
+
 	check_all_events(ses, EVENT_FLAG_CLASS, 0, 1, "CLASS CLEAR", ses->group);
 	check_all_events(ses, EVENT_FLAG_CLASS, 0, 1, "CLASS CLEAR", ses->group);
 	check_all_events(ses, EVENT_FLAG_CLASS, 1, 1, "CLASS CLEAR %s", ses->group, ses->group);
 	check_all_events(ses, EVENT_FLAG_CLASS, 1, 1, "CLASS CLEAR %s", ses->group, ses->group);
 
 
@@ -199,11 +222,9 @@ DO_CLASS(class_clear)
 
 
 DO_CLASS(class_close)
 DO_CLASS(class_close)
 {
 {
-	node = search_node_list(ses->list[LIST_CLASS], arg1);
-
 	if (node == NULL)
 	if (node == NULL)
 	{
 	{
-		show_message(ses, LIST_CLASS, "#CLASS {%s} NO LONGER EXIST.", arg1);
+		show_message(ses, LIST_CLASS, "#CLASS {%s} DOES NOT EXIST.", arg1);
 	}
 	}
 	else
 	else
 	{
 	{
@@ -248,7 +269,7 @@ DO_CLASS(class_list)
 {
 {
 	int i, j;
 	int i, j;
 
 
-	if (search_node_list(ses->list[LIST_CLASS], arg1))
+	if (node)
 	{
 	{
 		tintin_header(ses, 80, " %s ", arg1);
 		tintin_header(ses, 80, " %s ", arg1);
 
 
@@ -285,6 +306,13 @@ DO_CLASS(class_kill)
 {
 {
 	int group;
 	int group;
 
 
+	if (node == NULL)
+	{
+		show_message(ses, LIST_CLASS, "#CLASS {%s} DOES NOT EXIST.", arg1);
+
+		return ses;
+	}
+
 	class_clear(ses, node, arg1, arg2);
 	class_clear(ses, node, arg1, arg2);
 
 
 	group = search_index_list(ses->list[LIST_CLASS], arg1, NULL);
 	group = search_index_list(ses->list[LIST_CLASS], arg1, NULL);
@@ -303,6 +331,13 @@ DO_CLASS(class_load)
 {
 {
 	FILE *file;
 	FILE *file;
 
 
+	if (node == NULL)
+	{
+		show_error(ses, LIST_CLASS, "#CLASS {%s} DOES NOT EXIST.", arg1);
+
+		return ses;
+	}
+
 	if (node->data == NULL)
 	if (node->data == NULL)
 	{
 	{
 		show_error(ses, LIST_CLASS, "#CLASS {%s} DOES NOT HAVE ANY DATA SAVED.", arg1);
 		show_error(ses, LIST_CLASS, "#CLASS {%s} DOES NOT HAVE ANY DATA SAVED.", arg1);
@@ -328,6 +363,11 @@ DO_CLASS(class_open)
 {
 {
 	int count;
 	int count;
 
 
+	if (node == NULL)
+	{
+		node = create_class(ses, arg1, arg2);
+	}
+
 	if (!strcmp(ses->group, arg1))
 	if (!strcmp(ses->group, arg1))
 	{
 	{
 		show_message(ses, LIST_CLASS, "#CLASS {%s} IS ALREADY OPENED AND ACTIVATED.", arg1);
 		show_message(ses, LIST_CLASS, "#CLASS {%s} IS ALREADY OPENED AND ACTIVATED.", arg1);
@@ -372,6 +412,13 @@ DO_CLASS(class_save)
 	size_t len;
 	size_t len;
 	int list, index;
 	int list, index;
 
 
+	if (node == NULL)
+	{
+		show_error(ses, LIST_CLASS, "#ERROR: #CLASS {%s} DOES NOT EXIST.", arg1);
+
+		return ses;
+	}
+
 	file = open_memstream(&node->data, (size_t *) &len);
 	file = open_memstream(&node->data, (size_t *) &len);
 
 
 	fprintf(file, "%cCLASS {%s} OPEN\n\n", gtd->tintin_char, arg1);
 	fprintf(file, "%cCLASS {%s} OPEN\n\n", gtd->tintin_char, arg1);
@@ -407,12 +454,12 @@ DO_CLASS(class_size)
 {
 {
 	if (*arg1 == 0 || *arg2 == 0)
 	if (*arg1 == 0 || *arg2 == 0)
 	{
 	{
-		show_error(ses, LIST_CLASS, "#SYNTAX: #CLASS {<class name>} SIZE {<variable>}.");
+		show_error(ses, LIST_CLASS, "#SYNTAX: #CLASS <NAME> SIZE <VARIABLE>");
 		
 		
 		return ses;
 		return ses;
 	}
 	}
 
 
-	set_nest_node_ses(ses, arg2, "%d", count_class(ses, node));
+	set_nest_node_ses(ses, arg2, "%d", node ? count_class(ses, node) : 0);
 
 
 	return ses;
 	return ses;
 }
 }
@@ -423,9 +470,16 @@ DO_CLASS(class_write)
 	FILE *file;
 	FILE *file;
 	int list, index;
 	int list, index;
 
 
+	if (node == NULL)
+	{
+		show_error(ses, LIST_CLASS, "#ERROR: #CLASS {%s} DOES NOT EXIST.", arg1);
+
+		return ses;
+	}
+
 	if (*arg2 == 0 || (file = fopen(arg2, "w")) == NULL)
 	if (*arg2 == 0 || (file = fopen(arg2, "w")) == NULL)
 	{
 	{
-		show_error(ses, LIST_CLASS, "#ERROR: #CLASS WRITE {%s} - COULDN'T OPEN FILE TO WRITE.", arg2);
+		show_error(ses, LIST_CLASS, "#ERROR: #CLASS WRITE {%s}: COULDN'T OPEN FILE.", arg2);
 		
 		
 		return ses;
 		return ses;
 	}
 	}

+ 1 - 1
src/command.c

@@ -322,7 +322,7 @@ struct command_type command_table[] =
 	{    "pathdir",           do_pathdir,           3, TOKEN_TYPE_COMMAND },
 	{    "pathdir",           do_pathdir,           3, TOKEN_TYPE_COMMAND },
 	{    "port",              do_port,              2, TOKEN_TYPE_COMMAND },
 	{    "port",              do_port,              2, TOKEN_TYPE_COMMAND },
 	{    "prompt",            do_prompt,            2, TOKEN_TYPE_COMMAND },
 	{    "prompt",            do_prompt,            2, TOKEN_TYPE_COMMAND },
-	{    "read",              do_read,              1, TOKEN_TYPE_COMMAND },
+	{    "read",              do_read,              2, TOKEN_TYPE_COMMAND },
 	{    "regexp",            do_regexp,            3, TOKEN_TYPE_REGEX   },
 	{    "regexp",            do_regexp,            3, TOKEN_TYPE_REGEX   },
 	{    "replace",           do_replace,           3, TOKEN_TYPE_COMMAND },
 	{    "replace",           do_replace,           3, TOKEN_TYPE_COMMAND },
 	{    "return",            do_nop,               0, TOKEN_TYPE_RETURN  },
 	{    "return",            do_nop,               0, TOKEN_TYPE_RETURN  },

+ 39 - 46
src/config.c

@@ -391,16 +391,9 @@ DO_CONFIG(config_autotab)
 {
 {
 	if (*arg2)
 	if (*arg2)
 	{
 	{
-		if (!is_number(arg2))
-		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {AUTO TAB} <NUMBER>");
-
-			return NULL;
-		}
-
-		if (atoi(arg2) < 1 || atoi(arg2) > 999999)
+		if (!is_number(arg2) || atoi(arg2) < 1 || atoi(arg2) > 999999)
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#ERROR: #CONFIG BUFFER: PROVIDE A NUMBER BETWEEN 1 and 999999");
+			show_error(ses, LIST_CONFIG, "#ERROR: #CONFIG {%s} {%s}: PROVIDE A NUMBER BETWEEN 1 and 999999.", config_table[index].name, arg2);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -419,7 +412,7 @@ DO_CONFIG(config_buffersize)
 	{
 	{
 		if (!is_number(arg2))
 		if (!is_number(arg2))
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {BUFFER SIZE} <NUMBER>");
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <NUMBER>", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -434,7 +427,7 @@ DO_CONFIG(config_buffersize)
 				break;
 				break;
 
 
 			default:
 			default:
-				show_error(ses, LIST_CONFIG, "#ERROR: #CONFIG BUFFER: SIZE MUST BE 100, 1000, 10000, 100000, or 1000000.");
+				show_error(ses, LIST_CONFIG, "#ERROR: #CONFIG {BUFFER SIZE}: SIZE MUST BE 100, 1000, 10000, 100000, or 1000000.");
 				return NULL;
 				return NULL;
 		}
 		}
 		init_buffer(ses, atoi(arg2));
 		init_buffer(ses, atoi(arg2));
@@ -482,7 +475,7 @@ DO_CONFIG(config_charset)
 
 
 			if (*charset_table[index].name == 0)
 			if (*charset_table[index].name == 0)
 			{
 			{
-				show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {CHARSET} <AUTO|ASCII|BIG-5|BIG5TOUTF8|CP437TOUTF8|CP949|CP949TOUTF8|CP1251TOUTF8|GBK-1|GBK1TOUTF8|ISO1TOUTF8|ISO2TOUTF8|KOI8TOUTF8|UTF-8>");
+				show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {CHARSET} {AUTO|ASCII|BIG-5|BIG5TOUTF8|CP437TOUTF8|CP949|CP949TOUTF8|CP1251TOUTF8|GBK-1|GBK1TOUTF8|ISO1TOUTF8|ISO2TOUTF8|KOI8TOUTF8|UTF-8}");
 
 
 				return NULL;
 				return NULL;
 			}
 			}
@@ -503,7 +496,7 @@ DO_CONFIG(config_charset)
 
 
 	if (*charset_table[index].name == 0)
 	if (*charset_table[index].name == 0)
 	{
 	{
-		show_error(ses, LIST_CONFIG, "#CONFIG CHARSET: INVALID FLAG: %d", ses->charset);
+		show_error(ses, LIST_CONFIG, "#ERROR: #CONFIG {CHARSET}: INVALID FLAG: %d.", ses->charset);
 
 
 		return NULL;
 		return NULL;
 	}
 	}
@@ -527,7 +520,7 @@ DO_CONFIG(config_childlock)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF>", config_table[index].name);
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} {ON|OFF}", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -564,7 +557,7 @@ DO_CONFIG(config_colormode)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF|ANSI|256|TRUE>", config_table[index].name);
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} {ON|OFF|ANSI|256|TRUE}", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -588,7 +581,7 @@ DO_CONFIG(config_colorpatch)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF>", config_table[index].name);
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} {ON|OFF}", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -625,7 +618,7 @@ DO_CONFIG(config_commandecho)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF>", config_table[index].name);
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} {ON|OFF}", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -649,7 +642,7 @@ DO_CONFIG(config_compact)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF>", config_table[index].name);
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} {ON|OFF}", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -665,13 +658,13 @@ DO_CONFIG(config_connectretry)
 	{
 	{
 		if (!is_number(arg2))
 		if (!is_number(arg2))
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {CONNECT RETRY} <NUMBER>");
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <NUMBER>", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
 		else if (atof(arg2) < 0 || atof(arg2) > 10000)
 		else if (atof(arg2) < 0 || atof(arg2) > 10000)
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#ERROR: #CONFIG CONNECT RETRY: PROVIDE A NUMBER BETWEEN 0.0 and 10000.0");
+			show_error(ses, LIST_CONFIG, "#ERROR: #CONFIG {CONNECT RETRY}: PROVIDE A NUMBER BETWEEN 0.0 and 10000.");
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -697,7 +690,7 @@ DO_CONFIG(config_convertmeta)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF>", config_table[index].name);
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} {ON|OFF}", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -721,7 +714,7 @@ DO_CONFIG(config_debugtelnet)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF>", config_table[index].name);
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} {ON|OFF}", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -737,14 +730,14 @@ DO_CONFIG(config_historysize)
 	{
 	{
 		if (!is_number(arg2))
 		if (!is_number(arg2))
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {HISTORY SIZE} <NUMBER>");
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <NUMBER>", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
 
 
 		if (atoi(arg2) < 0 || atoi(arg2) > 9999)
 		if (atoi(arg2) < 0 || atoi(arg2) > 9999)
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#ERROR: #CONFIG HISTORY: PROVIDE A NUMBER BETWEEN 0 and 9999");
+			show_error(ses, LIST_CONFIG, "#ERROR: #CONFIG {%s}: PROVIDE A NUMBER BETWEEN 0 and 9999.", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -770,7 +763,7 @@ DO_CONFIG(config_hibernate)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF>", config_table[index].name);
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} {ON|OFF}", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -794,7 +787,7 @@ DO_CONFIG(config_inheritance)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF>", config_table[index].name);
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} {ON|OFF}", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -819,7 +812,7 @@ DO_CONFIG(config_loglevel)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <LOW|HIGH>", config_table[index].name);
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} {LOW|HIGH}", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -854,7 +847,7 @@ DO_CONFIG(config_logmode)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG LOG <HTML|PLAIN|RAW>");
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} {HTML|PLAIN|RAW}", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -879,7 +872,7 @@ DO_CONFIG(config_mccp)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF>", config_table[index].name);
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} {ON|OFF}", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -938,7 +931,7 @@ DO_CONFIG(config_mousetracking)
 			}
 			}
 			else
 			else
 			{
 			{
-				show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF|DEBUG|INFO|PIXELS>", config_table[index].name);
+				show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} {ON|OFF|DEBUG|INFO|PIXELS}", config_table[index].name);
 
 
 				return NULL;
 				return NULL;
 			}
 			}
@@ -991,13 +984,13 @@ DO_CONFIG(config_packetpatch)
 		}
 		}
 		else if (!is_number(arg2))
 		else if (!is_number(arg2))
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {PACKET PATCH} <NUMBER>");
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <NUMBER>", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
 		else if (atof(arg2) < 0 || atof(arg2) > 10)
 		else if (atof(arg2) < 0 || atof(arg2) > 10)
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#ERROR: #CONFIG PACKET PATCH: PROVIDE A NUMBER BETWEEN 0.00 and 10.00");
+			show_error(ses, LIST_CONFIG, "#ERROR: #CONFIG {PACKET PATCH}: PROVIDE A NUMBER BETWEEN 0.00 and 10.");
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -1045,7 +1038,7 @@ DO_CONFIG(config_randomseed)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <AUTO|NUMBER>", config_table[index].name);
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} {AUTO|<NUMBER>}", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -1061,7 +1054,7 @@ DO_CONFIG(config_repeatchar)
 	{
 	{
 		if (!ispunct((int) arg2[0]))
 		if (!ispunct((int) arg2[0]))
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#ERROR: #CONFIG REPEAT CHAR: INVALID CHARACTER {%c}", arg2[0]);
+			show_error(ses, LIST_CONFIG, "#ERROR: #CONFIG {%s}: INVALID CHARACTER {%c}.", config_table[index].name, arg2[0]);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -1090,7 +1083,7 @@ DO_CONFIG(config_repeatenter)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF>", config_table[index].name);
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} {ON|OFF}", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -1115,7 +1108,7 @@ DO_CONFIG(config_screenreader)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF>", config_table[index].name);
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} {ON|OFF}", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -1142,7 +1135,7 @@ DO_CONFIG(config_scrolllock)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF>", config_table[index].name);
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} {ON|OFF}", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -1166,7 +1159,7 @@ DO_CONFIG(config_speedwalk)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF>", config_table[index].name);
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} {ON|OFF}", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -1186,13 +1179,13 @@ DO_CONFIG(config_tabwidth)
 		}
 		}
 		else if (!is_number(arg2))
 		else if (!is_number(arg2))
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {TAB WIDTH} <NUMBER>");
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <NUMBER>", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
 		else if (atof(arg2) < 1 || atof(arg2) > 16)
 		else if (atof(arg2) < 1 || atof(arg2) > 16)
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#ERROR: #CONFIG TAB WIDTH: PROVIDE A NUMBER BETWEEN 1 and 16");
+			show_error(ses, LIST_CONFIG, "#ERROR: #CONFIG {TAB WIDTH}: PROVIDE A NUMBER BETWEEN 1 and 16.");
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -1234,7 +1227,7 @@ DO_CONFIG(config_telnet)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF|DEBUG|INFO>", config_table[index].name);
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} {ON|OFF|DEBUG|INFO}", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -1251,7 +1244,7 @@ DO_CONFIG(config_tintinchar)
 	{
 	{
 		if (!ispunct((int) arg2[0]))
 		if (!ispunct((int) arg2[0]))
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#ERROR: #CONFIG TINTIN CHAR: INVALID CHARACTER {%c}", arg2[0]);
+			show_error(ses, LIST_CONFIG, "#ERROR: #CONFIG {%s}: INVALID CHARACTER {%c}.", config_table[index].name, arg2[0]);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -1277,7 +1270,7 @@ DO_CONFIG(config_verbatim)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF>", config_table[index].name);
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} {ON|OFF}", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -1293,7 +1286,7 @@ DO_CONFIG(config_verbatimchar)
 	{
 	{
 		if (!ispunct((int) arg2[0]))
 		if (!ispunct((int) arg2[0]))
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#ERROR: #CONFIG VERBATIM CHAR: INVALID CHARACTER {%c}", arg2[0]);
+			show_error(ses, LIST_CONFIG, "#ERROR: #CONFIG {%s}: INVALID CHARACTER {%c}.", config_table[index].name, arg2[0]);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -1319,7 +1312,7 @@ DO_CONFIG(config_verbose)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF>", config_table[index].name);
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} {ON|OFF}", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}
@@ -1343,7 +1336,7 @@ DO_CONFIG(config_wordwrap)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF>", config_table[index].name);
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} {ON|OFF}", config_table[index].name);
 
 
 			return NULL;
 			return NULL;
 		}
 		}

+ 57 - 8
src/cursor.c

@@ -1033,7 +1033,7 @@ DO_CURSOR(cursor_echo)
 	}
 	}
 	else
 	else
 	{
 	{
-		show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {ECHO} {ON|OFF}.");
+		show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {ECHO} {ON|OFF}");
 	}
 	}
 }
 }
 
 
@@ -1137,6 +1137,55 @@ DO_CURSOR(cursor_enter)
 	return;
 	return;
 }
 }
 
 
+DO_CURSOR(cursor_escape_enter)
+{
+	if (*gtd->ses->input->buf != 0)
+	{
+		int nest = 0;
+		char *pti = gtd->ses->input->buf;
+		char *pto = gtd->ses->input->buf;
+
+		while (*pti)
+		{
+			switch (*pti)
+			{
+				case '{':
+					nest++;
+					*pto++ = *pti++;
+					break;
+				case '}':
+					nest--;
+					*pto++ = *pti++;
+					break;
+				case '\\':
+					if (pti[1] == 'n')
+					{
+						if (pti[2] == '#' && nest == 0)
+						{
+							*pto++ = ';';
+						}
+						pti += 2;
+					}
+					else if (pti[1])
+					{
+						*pto++ = *pti++;
+						*pto++ = *pti++;
+					}
+					else
+					{
+						*pto++ = *pti++;
+					}
+					break;
+				default:
+					*pto++ = *pti++;
+					break;
+			}
+		}
+		*pto = 0;
+	}
+	cursor_enter(ses, "");
+}
+	
 DO_CURSOR(cursor_soft_enter)
 DO_CURSOR(cursor_soft_enter)
 {
 {
 	if (!inputline_editor())
 	if (!inputline_editor())
@@ -1236,11 +1285,11 @@ DO_CURSOR(cursor_flag)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {FLAG} {EOL} {CR|LF|CRLF|CRNUL|OFF}.");
+			show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {FLAG} {EOL} {CR|LF|CRLF|CRNUL|OFF}");
 			return;
 			return;
 		}
 		}
 
 
-		show_message(gtd->ses, LIST_COMMAND, "#CURSOR FLAG EOL HAS BEEN SET TO: %s",
+		show_message(gtd->ses, LIST_COMMAND, "#CURSOR FLAG EOL HAS BEEN SET TO: %s.",
 			HAS_BIT(ses->telopts, TELOPT_FLAG_CR|TELOPT_FLAG_LF) == 0 ? "OFF" :
 			HAS_BIT(ses->telopts, TELOPT_FLAG_CR|TELOPT_FLAG_LF) == 0 ? "OFF" :
 			HAS_BIT(ses->telopts, TELOPT_FLAG_CR|TELOPT_FLAG_NUL) == (TELOPT_FLAG_CR|TELOPT_FLAG_NUL) ? "CRNUL" :
 			HAS_BIT(ses->telopts, TELOPT_FLAG_CR|TELOPT_FLAG_NUL) == (TELOPT_FLAG_CR|TELOPT_FLAG_NUL) ? "CRNUL" :
 			HAS_BIT(ses->telopts, TELOPT_FLAG_CR|TELOPT_FLAG_LF) == TELOPT_FLAG_CR ? "CR" :
 			HAS_BIT(ses->telopts, TELOPT_FLAG_CR|TELOPT_FLAG_LF) == TELOPT_FLAG_CR ? "CR" :
@@ -1265,7 +1314,7 @@ DO_CURSOR(cursor_flag)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {FLAG} {ECHO} {ON|OFF}.");
+			show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {FLAG} {ECHO} {ON|OFF}");
 		}
 		}
 		return;
 		return;
 	}
 	}
@@ -1286,12 +1335,12 @@ DO_CURSOR(cursor_flag)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {FLAG} {INSERT} {ON|OFF}.");
+			show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {FLAG} {INSERT} {ON|OFF}");
 		}
 		}
 		return;
 		return;
 	}
 	}
 
 
-	show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {FLAG} {ECHO|EOL|INSERT} {ON|OFF}.");
+	show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {FLAG} {ECHO|EOL|INSERT} {ON|OFF}");
 }
 }
 
 
 DO_CURSOR(cursor_get)
 DO_CURSOR(cursor_get)
@@ -1302,7 +1351,7 @@ DO_CURSOR(cursor_get)
 
 
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR GET {variable}");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR GET <VARIABLE>");
 	}
 	}
 	else
 	else
 	{
 	{
@@ -1593,7 +1642,7 @@ DO_CURSOR(cursor_insert)
 	}
 	}
 	else
 	else
 	{
 	{
-		show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {INSERT} {ON|OFF}.");
+		show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {INSERT} {ON|OFF}");
 	}
 	}
 }
 }
 
 

+ 4 - 4
src/daemon.c

@@ -180,11 +180,11 @@ DO_DAEMON(daemon_attach)
 
 
 		if (*arg1)
 		if (*arg1)
 		{
 		{
-			show_message(ses, LIST_COMMAND, "#DAEMON ATTACH: UNABLE TO FIND DAEMON FILE {%s} IN {%s}.", arg1, filename);
+			show_message(ses, LIST_COMMAND, "#ERROR: #DAEMON ATTACH: UNABLE TO FIND DAEMON FILE {%s} IN {%s}.", arg1, filename);
 		}
 		}
 		else
 		else
 		{
 		{
-			show_message(ses, LIST_COMMAND, "#DAEMON ATTACH: NO AVAILABLE DAEMON FILES FOUND IN {%s}.", filename);
+			show_message(ses, LIST_COMMAND, "#ERROR: #DAEMON ATTACH: NO AVAILABLE DAEMON FILES FOUND IN {%s}.", filename);
 		}
 		}
 
 
 		return;
 		return;
@@ -351,7 +351,7 @@ DO_DAEMON(daemon_detach)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(gtd->ses, LIST_COMMAND, "#DAEMON DETACH: ALREADY FULLY DETACHED.");
+			show_error(gtd->ses, LIST_COMMAND, "#ERROR: #DAEMON DETACH: ALREADY FULLY DETACHED.");
 		}
 		}
 		return;
 		return;
 	}
 	}
@@ -410,7 +410,7 @@ DO_DAEMON(daemon_detach)
 
 
 	if (strlen(filename) >= sizeof(addr_un.sun_path))
 	if (strlen(filename) >= sizeof(addr_un.sun_path))
 	{
 	{
-		tintin_printf(ses, "#DAEMON DETACH: FILE NAME LENGTH OF {%s} EXCEEDS MAXIMUM OF %d.", filename, sizeof(addr_un.sun_path));
+		show_error(ses, LIST_COMMAND, "#ERROR: #DAEMON DETACH: FILE NAME LENGTH OF {%s} EXCEEDS MAXIMUM OF %d.", filename, sizeof(addr_un.sun_path));
 
 
 		return;
 		return;
 	}
 	}

+ 15 - 10
src/data.c

@@ -164,6 +164,11 @@ struct listnode *create_node_list(struct listroot *root, char *arg1, char *arg2,
 	}
 	}
 
 
 	if (HAS_BIT(root->flags, LIST_FLAG_NEST) && *arg1 == '\\')
 	if (HAS_BIT(root->flags, LIST_FLAG_NEST) && *arg1 == '\\')
+	{
+		show_error(root->ses, LIST_COMMAND, "#WARNING: VARIABLE {%s}. THE \\ CHARACTER NEEDS TO BE REPLACED WITH = FOR A STRICT EQUALITY MATCH.", arg1);
+		arg1++;
+	}
+	else if (HAS_BIT(root->flags, LIST_FLAG_NEST) && *arg1 == '=')
 	{
 	{
 		arg1++;
 		arg1++;
 	}
 	}
@@ -652,7 +657,7 @@ int bsearch_alnum_list(struct listroot *root, char *text, int seek)
 				}
 				}
 				break;
 				break;
 
 
-			case '\\':
+			case '/':
 				text++;
 				text++;
 				break;
 				break;
 		}
 		}
@@ -982,7 +987,7 @@ int delete_node_with_wild(struct session *ses, int type, char *text)
 	{
 	{
 		node = root->list[index];
 		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);
+		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_index_list(root, index);
 		delete_index_list(root, index);
 
 
@@ -993,7 +998,7 @@ int delete_node_with_wild(struct session *ses, int type, char *text)
 	{
 	{
 		if (match(ses, root->list[index]->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[index]->arg1, is_vowel(list_table[type].name) ? "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, index);
 			delete_index_list(root, index);
 
 
@@ -1068,7 +1073,7 @@ DO_COMMAND(do_kill)
 
 
 	if (index == LIST_MAX)
 	if (index == LIST_MAX)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#ERROR: #KILL {%s} {%s} - NO MATCH FOUND.", arg1, arg2);
+		show_error(ses, LIST_COMMAND, "#ERROR: #KILL {%s} {%s}: NO MATCH FOUND.", arg1, arg2);
 	}
 	}
 	return ses;
 	return ses;
 }
 }
@@ -1134,7 +1139,7 @@ DO_COMMAND(do_message)
 
 
 		if (found == FALSE)
 		if (found == FALSE)
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#ERROR: #MESSAGE {%s} - NO MATCH FOUND.", arg1);
+			show_error(ses, LIST_COMMAND, "#ERROR: #MESSAGE {%s}: NO MATCH FOUND.", arg1);
 		}
 		}
 	}
 	}
 	return ses;
 	return ses;
@@ -1213,7 +1218,7 @@ DO_COMMAND(do_ignore)
 
 
 		if (found == FALSE)
 		if (found == FALSE)
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#ERROR: #IGNORE {%s} - NO MATCH FOUND.", arg1);
+			show_error(ses, LIST_COMMAND, "#ERROR: #IGNORE {%s}: NO MATCH FOUND.", arg1);
 		}
 		}
 	}
 	}
 	return ses;
 	return ses;
@@ -1285,7 +1290,7 @@ DO_COMMAND(do_debug)
 
 
 		if (found == FALSE)
 		if (found == FALSE)
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#DEBUG {%s} - NO MATCH FOUND.", arg1);
+			show_error(ses, LIST_COMMAND, "#DEBUG {%s}: NO MATCH FOUND.", arg1);
 		}
 		}
 	}
 	}
 	return ses;
 	return ses;
@@ -1373,7 +1378,7 @@ DO_COMMAND(do_info)
 				}
 				}
 				else
 				else
 				{
 				{
-					show_error(ses, LIST_COMMAND, "#SYNTAX: #INFO {%s} [ON|OFF|LIST|SAVE|SYSTEM]", arg1);
+					show_error(ses, LIST_COMMAND, "#SYNTAX: #INFO {%s} [ON|OFF|LIST|SAVE]", arg1);
 				}
 				}
 				return ses;
 				return ses;
 			}
 			}
@@ -1580,7 +1585,7 @@ DO_COMMAND(do_info)
 					{
 					{
 						str_ptr = gtd->memory->list[index];
 						str_ptr = gtd->memory->list[index];
 
 
-						if (str_ptr->max != NAME_SIZE + 1 && strlen(get_str_str(str_ptr)) != str_ptr->len)
+						if (!HAS_BIT(str_ptr->flags, STR_FLAG_FREE) && str_ptr->max != NAME_SIZE + 1 && strlen(get_str_str(str_ptr)) != str_ptr->len)
 						{
 						{
 							tintin_printf2(ses, "#ERROR: index %d len = %d/%d max = %d flags = %d (%s)", index, strlen(get_str_str(str_ptr)), str_ptr->len, str_ptr->max, str_ptr->flags, get_str_str(str_ptr));
 							tintin_printf2(ses, "#ERROR: index %d len = %d/%d max = %d flags = %d (%s)", index, strlen(get_str_str(str_ptr)), str_ptr->len, str_ptr->max, str_ptr->flags, get_str_str(str_ptr));
 						}
 						}
@@ -1647,7 +1652,7 @@ DO_COMMAND(do_info)
 					if (is_abbrev(arg2, "SAVE"))
 					if (is_abbrev(arg2, "SAVE"))
 					{
 					{
 						set_nest_node_ses(ses, "info[OUTPUT]", "{RAWBUF}{%s}", gtd->mud_output_buf);
 						set_nest_node_ses(ses, "info[OUTPUT]", "{RAWBUF}{%s}", gtd->mud_output_buf);
-						add_nest_node_ses(ses, "info[OUTPUT]", "{RAWLEN}{%s}", gtd->mud_output_len);
+						add_nest_node_ses(ses, "info[OUTPUT]", "{RAWLEN}{%d}", gtd->mud_output_len);
 						add_nest_node_ses(ses, "info[OUTPUT]", "{STRBUF}{%s}", gtd->mud_output_strip_buf);
 						add_nest_node_ses(ses, "info[OUTPUT]", "{STRBUF}{%s}", gtd->mud_output_strip_buf);
 						add_nest_node_ses(ses, "info[OUTPUT]", "{STRLEN}{%d}", gtd->mud_output_strip_len);
 						add_nest_node_ses(ses, "info[OUTPUT]", "{STRLEN}{%d}", gtd->mud_output_strip_len);
 						add_nest_node_ses(ses, "info[OUTPUT]", "{LINE}{%s}",   gtd->mud_output_line);
 						add_nest_node_ses(ses, "info[OUTPUT]", "{LINE}{%s}",   gtd->mud_output_line);

+ 11 - 7
src/draw.c

@@ -457,7 +457,7 @@ DO_COMMAND(do_draw)
 
 
 			if (!is_math(ses, arg1) || !is_math(ses, arg2) || !is_math(ses, arg3) || !is_math(ses, arg4))
 			if (!is_math(ses, arg1) || !is_math(ses, arg2) || !is_math(ses, arg3) || !is_math(ses, arg4))
 			{
 			{
-				show_error(ses, LIST_COMMAND, "#ERROR: #DRAW NON-NUMERIC SQUARE: %s {%s %s %s %s}",
+				show_error(ses, LIST_COMMAND, "#ERROR: #DRAW: NON-NUMERIC SQUARE: %s {%s %s %s %s}",
 					draw_table[index].name,
 					draw_table[index].name,
 					is_math(ses, arg1) ? ntos(top_row) : arg1,
 					is_math(ses, arg1) ? ntos(top_row) : arg1,
 					is_math(ses, arg2) ? ntos(top_col) : arg2,
 					is_math(ses, arg2) ? ntos(top_col) : arg2,
@@ -508,7 +508,7 @@ DO_COMMAND(do_draw)
 
 
 			if (top_row > bot_row || top_col > bot_col)
 			if (top_row > bot_row || top_col > bot_col)
 			{
 			{
-				show_error(ses, LIST_COMMAND, "#ERROR: #DRAW INVALID SQUARE: %s {%d %d %d %d} ROWS: %d COLS: %d", draw_table[index].name, top_row, top_col, bot_row, bot_col, 1 + bot_row - top_row, 1 + bot_col - top_col);
+				show_error(ses, LIST_COMMAND, "#ERROR: #DRAW: INVALID SQUARE: %s {%d %d %d %d} ROWS: %d COLS: %d", draw_table[index].name, top_row, top_col, bot_row, bot_col, 1 + bot_row - top_row, 1 + bot_col - top_col);
 
 
 				return ses;
 				return ses;
 			}
 			}
@@ -1510,10 +1510,14 @@ DO_DRAW(draw_buffer)
 		line = ses->scroll->line;
 		line = ses->scroll->line;
 	}
 	}
 
 
-	for (cnt = rows ; cnt >= 0 && line - cnt >= 0 ; cnt--)
+	for (cnt = rows ; cnt >= 0 ; cnt--)
 	{
 	{
-		str_cat_printf(&buf, "{%s}", ses->scroll->buffer[line - cnt]->str);
+		if (line - cnt >= 0)
+		{
+			str_cat_printf(&buf, "{%s}", ses->scroll->buffer[line - cnt]->str);
+		}
 	}
 	}
+	tintin_printf2(gtd->ses, "[%d] (%d) (%s)", line, rows, buf);
 
 
 	draw_box(ses, top_row, top_col, bot_row, bot_col, rows, cols, flags, box_color, txt_color, buf, arg1, arg2, arg3);
 	draw_box(ses, top_row, top_col, bot_row, bot_col, rows, cols, flags, box_color, txt_color, buf, arg1, arg2, arg3);
 
 
@@ -1806,7 +1810,7 @@ DO_DRAW(draw_hbar)
 
 
 	if (bar <= 0)
 	if (bar <= 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#DRAW BAR %d %d %d %d: DRAWING WIDTH (%d) MUST BE GREATER THAN 0.", top_row, top_col, bot_row, bot_col, bar);
+		show_error(ses, LIST_COMMAND, "#ERROR: #DRAW BAR %d %d %d %d: DRAWING WIDTH (%d) MUST BE GREATER THAN 0.", top_row, top_col, bot_row, bot_col, bar);
 
 
 		return;
 		return;
 	}
 	}
@@ -1836,7 +1840,7 @@ DO_DRAW(draw_hbar)
 
 
 	if (max <= 0)
 	if (max <= 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#DRAW BAR {%s;%s;%s}: MAX (%Lg) MUST BE GREATER THAN 0.", arg1, arg2, arg3, max);
+		show_error(ses, LIST_COMMAND, "#ERROR: #DRAW BAR {%s;%s;%s}: MAX (%Lg) MUST BE GREATER THAN 0.", arg1, arg2, arg3, max);
 
 
 		return;
 		return;
 	}
 	}
@@ -1932,7 +1936,7 @@ DO_DRAW(draw_rain)
 
 
 	if (!valid_variable(ses, arg1))
 	if (!valid_variable(ses, arg1))
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #DRAW {<COLOR>} RAIN %d %d %d %d {<VARIABLE>} {[SPAWN]} {[FADE]} {[LEGEND]}.", top_row, top_col, bot_row, bot_col);
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #DRAW <COLOR> RAIN %d %d %d %d <VARIABLE> [SPAWN] [FADE] [LEGEND]", top_row, top_col, bot_row, bot_col);
 
 
 		return;
 		return;
 	}
 	}

+ 1 - 1
src/edit.c

@@ -180,7 +180,7 @@ DO_EDIT(edit_read)
 
 
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #EDIT READ {<FILENAME>}");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #EDIT READ <FILENAME>");
 
 
 		return ses;
 		return ses;
 	}
 	}

+ 2 - 2
src/event.c

@@ -128,7 +128,7 @@ DO_COMMAND(do_event)
 
 
 			if (symbol == 0)
 			if (symbol == 0)
 			{
 			{
-				show_message(ses, LIST_ALIAS, "#EVENT: NO MATCH(ES) FOUND FOR {%s}.", arg1);
+				show_message(ses, LIST_EVENT, "#EVENT: NO MATCHES FOUND FOR {%s}.", arg1);
 			}
 			}
 		}
 		}
 	}
 	}
@@ -157,7 +157,7 @@ DO_COMMAND(do_event)
 				return ses;
 				return ses;
 			}
 			}
 		}
 		}
-		show_error(ses, LIST_EVENT, "#EVENT {%s} IS NOT AN EXISTING EVENT.", arg1);
+		show_error(ses, LIST_EVENT, "#ERROR: #EVENT {%s} IS NOT AN EXISTING EVENT.", arg1);
 	}
 	}
 	return ses;
 	return ses;
 }
 }

+ 14 - 12
src/files.c

@@ -33,13 +33,14 @@ DO_COMMAND(do_read)
 {
 {
 	FILE *file;
 	FILE *file;
 
 
-	sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+	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 ((file = fopen(arg1, "r")) == NULL)
 	if ((file = fopen(arg1, "r")) == NULL)
 	{
 	{
 		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "READ ERROR", arg1, "FILE NOT FOUND.");
 		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "READ ERROR", arg1, "FILE NOT FOUND.");
 
 
-		tintin_printf(ses, "#READ {%s} - FILE NOT FOUND.", arg1);
+		tintin_printf(ses, "#READ {%s}: FILE NOT FOUND.", arg1);
 
 
 		return ses;
 		return ses;
 	}
 	}
@@ -63,7 +64,7 @@ struct session *read_file(struct session *ses, FILE *file, char *filename)
 	{
 	{
 		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "READ ERROR", filename, "INVALID START OF FILE");
 		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "READ ERROR", filename, "INVALID START OF FILE");
 
 
-		tintin_printf(ses, "#ERROR: #READ {%s} - INVALID START OF FILE '%c'.", filename, temp[0]);
+		tintin_printf(ses, "#ERROR: #READ {%s}: INVALID START OF FILE '%c'.", filename, temp[0]);
 
 
 		return ses;
 		return ses;
 	}
 	}
@@ -88,7 +89,7 @@ struct session *read_file(struct session *ses, FILE *file, char *filename)
 	{
 	{
 		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "READ ERROR", filename, "FAILED TO ALLOCATE MEMORY");
 		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "READ ERROR", filename, "FAILED TO ALLOCATE MEMORY");
 
 
-		tintin_printf(ses, "#ERROR: #READ {%s} - FAILED TO ALLOCATE %d BYTES OF MEMORY.", filename, size + 2);
+		tintin_printf(ses, "#ERROR: #READ {%s}: FAILED TO ALLOCATE %d BYTES OF MEMORY.", filename, size + 2);
 
 
 		return ses;
 		return ses;
 	}
 	}
@@ -98,7 +99,7 @@ struct session *read_file(struct session *ses, FILE *file, char *filename)
 	{
 	{
 		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "READ ERROR", filename, "FREAD FAILURE");
 		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "READ ERROR", filename, "FREAD FAILURE");
 		
 		
-		tintin_printf(ses, "#ERROR: #READ {%s} - FREAD FAILURE.", filename);
+		tintin_printf(ses, "#ERROR: #READ {%s}: FREAD FAILURE.", filename);
 
 
 		return ses;
 		return ses;
 	}
 	}
@@ -209,7 +210,7 @@ struct session *read_file(struct session *ses, FILE *file, char *filename)
 						{
 						{
 							if (*pti == gtd->tintin_char)
 							if (*pti == gtd->tintin_char)
 							{
 							{
-								show_error(ses, LIST_COMMAND, "#WARNING: #READ {%s} MISSING SEMICOLON ON LINE %d.", filename, lnc);
+								show_error(ses, LIST_COMMAND, "#WARNING: #READ {%s}: MISSING SEMICOLON ON LINE %d.", filename, lnc);
 							}
 							}
 						}
 						}
 
 
@@ -297,7 +298,7 @@ struct session *read_file(struct session *ses, FILE *file, char *filename)
 	{
 	{
 		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "READ ERROR", filename, "MISSING BRACE OPEN OR CLOSE");
 		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "READ ERROR", filename, "MISSING BRACE OPEN OR CLOSE");
 
 
-		tintin_printf(ses, "#ERROR: #READ {%s} - MISSING %d '%c' BETWEEN LINE %d AND %d.", filename, abs(lvl), lvl < 0 ? DEFAULT_OPEN : DEFAULT_CLOSE, fix == 0 ? 1 : ok, fix == 0 ? lnc + 1 : fix);
+		tintin_printf(ses, "#ERROR: #READ {%s}: MISSING %d '%c' BETWEEN LINE %d AND %d.", filename, abs(lvl), lvl < 0 ? DEFAULT_OPEN : DEFAULT_CLOSE, fix == 0 ? 1 : ok, fix == 0 ? lnc + 1 : fix);
 
 
 		free(bufi);
 		free(bufi);
 		free(bufo);
 		free(bufo);
@@ -309,7 +310,7 @@ struct session *read_file(struct session *ses, FILE *file, char *filename)
 	{
 	{
 		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "READ ERROR", filename, "MISSING COMMENT OPEN OR CLOSE");
 		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "READ ERROR", filename, "MISSING COMMENT OPEN OR CLOSE");
 
 
-		tintin_printf(ses, "#ERROR: #READ {%s} - MISSING %d '%s'", filename, abs(com), com < 0 ? "/*" : "*/");
+		tintin_printf(ses, "#ERROR: #READ {%s}: MISSING %d '%s'", filename, abs(com), com < 0 ? "/*" : "*/");
 
 
 		free(bufi);
 		free(bufi);
 		free(bufo);
 		free(bufo);
@@ -324,7 +325,7 @@ struct session *read_file(struct session *ses, FILE *file, char *filename)
 		gtd->level->verbose++;
 		gtd->level->verbose++;
 		gtd->level->debug++;
 		gtd->level->debug++;
 
 
-		show_error(ses, LIST_COMMAND, "\e[1;5;31mWARNING: SETTING THE COMMAND CHARACTER TO '%c' BECAUSE IT'S THE FIRST CHARACTER IN THE FILE.", bufo[0]);
+		show_error(ses, LIST_COMMAND, "#WARNING: #READ {%s}: SETTING THE COMMAND CHARACTER TO '%c' BECAUSE IT'S THE FIRST CHARACTER IN THE FILE.", filename, bufo[0]);
 
 
 		gtd->level->debug--;
 		gtd->level->debug--;
 		gtd->level->verbose--;
 		gtd->level->verbose--;
@@ -359,7 +360,7 @@ struct session *read_file(struct session *ses, FILE *file, char *filename)
 
 
 		if (pto - bufi >= BUFFER_SIZE)
 		if (pto - bufi >= BUFFER_SIZE)
 		{
 		{
-			show_debug(ses, LIST_COMMAND, "#WARNING: #READ {%s} - POSSIBLE 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])
 		if (bufi[0])
@@ -421,7 +422,7 @@ DO_COMMAND(do_write)
 	{
 	{
 		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "WRITE ERROR", arg1, "INVALID FILE NAME");
 		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "WRITE ERROR", arg1, "INVALID FILE NAME");
 
 
-		tintin_printf2(ses, "#SYNTAX: #WRITE {<filename>} {[FORCE]}");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #WRITE <FILENAME> [FORCE]");
 
 
 		return ses;
 		return ses;
 	}
 	}
@@ -429,6 +430,7 @@ DO_COMMAND(do_write)
 	if (is_suffix(arg1, ".map") && !is_abbrev(arg2, "FORCE"))
 	if (is_suffix(arg1, ".map") && !is_abbrev(arg2, "FORCE"))
 	{
 	{
 		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "WRITE ERROR", arg1, "INVALID FILE EXTENSION");
 		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "WRITE ERROR", arg1, "INVALID FILE EXTENSION");
+
 		tintin_printf2(ses, "#WRITE {%s}: USE {FORCE} TO OVERWRITE .map FILES.", arg1);
 		tintin_printf2(ses, "#WRITE {%s}: USE {FORCE} TO OVERWRITE .map FILES.", arg1);
 
 
 		return ses;
 		return ses;
@@ -438,7 +440,7 @@ DO_COMMAND(do_write)
 	{
 	{
 		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "WRITE ERROR", arg1, "FAILED TO OPEN");
 		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "WRITE ERROR", arg1, "FAILED TO OPEN");
 
 
-		tintin_printf(ses, "#ERROR: #WRITE: COULDN'T OPEN {%s} TO WRITE.", arg1);
+		show_error(ses, LIST_COMMAND, "#ERROR: #WRITE: COULDN'T OPEN {%s} TO WRITE.", arg1);
 
 
 		return ses;
 		return ses;
 	}
 	}

+ 54 - 26
src/help.c

@@ -462,8 +462,10 @@ DO_COMMAND(do_help)
 		{
 		{
 			if (is_abbrev(arg1, help_table[cnt].name))
 			if (is_abbrev(arg1, help_table[cnt].name))
 			{
 			{
-				print_lines(ses, SUB_COL, "", /*COLOR_HELP_DIM,*/ "%s<088>\n", help_table[cnt].text);
-
+				if (!check_all_events(ses, EVENT_FLAG_CATCH, 1, 0, "CATCH HELP %s", help_table[cnt].name))
+				{
+					print_lines(ses, SUB_COL, "", /*COLOR_HELP_DIM,*/ "%s<088>\n", help_table[cnt].text);
+				}
 				if (*help_table[cnt].also)
 				if (*help_table[cnt].also)
 				{
 				{
 					print_lines(ses, SUB_COL, "", "%s<088>\n\n", help_related(ses, cnt, 0));
 					print_lines(ses, SUB_COL, "", "%s<088>\n\n", help_related(ses, cnt, 0));
@@ -489,7 +491,7 @@ DO_COMMAND(do_help)
 
 
 		if (found == FALSE)
 		if (found == FALSE)
 		{
 		{
-			tintin_printf2(ses, "No help found for '%s'", arg1);
+			show_message(ses, LIST_COMMAND, "#HELP: NO MATCHES FOUND FOR {%s}.", arg1);
 		}
 		}
 	}
 	}
 	return ses;
 	return ses;
@@ -1283,7 +1285,7 @@ struct help_type help_table[] =
 		"<278>         BOTTOM      draw on the bottom side if possible.\n"
 		"<278>         BOTTOM      draw on the bottom side if possible.\n"
 		"<278>         BOXED       draw a box along the square.\n"
 		"<278>         BOXED       draw a box along the square.\n"
 		"<278>         BUMPED      precede the draw with an enter.\n"
 		"<278>         BUMPED      precede the draw with an enter.\n"
-		"<278>         CALIGN      center text.\n"
+		"<278>         CALIGN      both LALIGN and RALIGN to center text.\n"
 		"<278>         CIRCLED     circle the corners.\n"
 		"<278>         CIRCLED     circle the corners.\n"
 		"<278>         CONVERT     draw text with meta conversion.\n"
 		"<278>         CONVERT     draw text with meta conversion.\n"
 		"<278>         CROSSED     cross the corners.\n"
 		"<278>         CROSSED     cross the corners.\n"
@@ -1342,7 +1344,7 @@ struct help_type help_table[] =
 		"<278>         All draw types take an optional text argument as long as a valid\n"
 		"<278>         All draw types take an optional text argument as long as a valid\n"
 		"<278>         square with enough space has been defined. Text is automatically\n"
 		"<278>         square with enough space has been defined. Text is automatically\n"
 		"<278>         word wrapped and text formatting can be customized with the\n"
 		"<278>         word wrapped and text formatting can be customized with the\n"
-		"<278>         CALIGN, LALIGN, RALIGN, and UALIGN options.\n"
+		"<278>         BALIGN, TALIGN, LALIGN, RALIGN, and UALIGN options.\n"
 		"\n"
 		"\n"
 		"<178>Example<278>: #draw Blue box 1 1 3 20 {Hello world!}\n"
 		"<178>Example<278>: #draw Blue box 1 1 3 20 {Hello world!}\n"
 		,
 		,
@@ -1701,6 +1703,8 @@ struct help_type help_table[] =
 		"<278>         <178>BUFFER UPDATE<278>, <178>DISPLAY UPDATE\n"
 		"<278>         <178>BUFFER UPDATE<278>, <178>DISPLAY UPDATE\n"
 		"<278>           These events have no additional arguments.\n"
 		"<278>           These events have no additional arguments.\n"
 		"\n"
 		"\n"
+		"<278>         <178>PROCESSED LINE         <278>%0 raw text %1 plain text %2 prompt (0 or 1)\n"
+		"\n"
 		"<278>         <178>RECEIVED LINE          <278>%0 raw text %1 plain text\n"
 		"<278>         <178>RECEIVED LINE          <278>%0 raw text %1 plain text\n"
 		"<278>         <178>RECEIVED OUTPUT        <278>%0 raw text %1 plain text\n"
 		"<278>         <178>RECEIVED OUTPUT        <278>%0 raw text %1 plain text\n"
 		"<278>         <178>RECEIVED PROMPT        <278>%0 raw text %1 plain text\n"
 		"<278>         <178>RECEIVED PROMPT        <278>%0 raw text %1 plain text\n"
@@ -1714,6 +1718,7 @@ struct help_type help_table[] =
 		"<278>         <178>PORT DISCONNECTION     <278>%0 name %1 ip %2 port\n"
 		"<278>         <178>PORT DISCONNECTION     <278>%0 name %1 ip %2 port\n"
 		"<278>         <178>PORT LOG MESSAGE       <278>%0 name %1 ip %2 port %3 data %4 plain data\n"
 		"<278>         <178>PORT LOG MESSAGE       <278>%0 name %1 ip %2 port %3 data %4 plain data\n"
 		"<278>         <178>PORT RECEIVED MESSAGE  <278>%0 name %1 ip %2 port %3 data %4 plain data\n"
 		"<278>         <178>PORT RECEIVED MESSAGE  <278>%0 name %1 ip %2 port %3 data %4 plain data\n"
+		"<278>         <178>PORT RECEIVED DATA     <278>%0 name %1 ip %2 port %3 data %4 size\n"
 		"\n"
 		"\n"
 		"<278>         <128>SCAN EVENTS\n"
 		"<278>         <128>SCAN EVENTS\n"
 		"\n"
 		"\n"
@@ -1766,6 +1771,8 @@ struct help_type help_table[] =
 		"<278>         <178>UNKNOWN COMMAND        <278>%0 raw text\n"
 		"<278>         <178>UNKNOWN COMMAND        <278>%0 raw text\n"
 		"<278>         <178>SIGUSR                 <278>%0 signal\n"
 		"<278>         <178>SIGUSR                 <278>%0 signal\n"
 		"\n"
 		"\n"
+		"<278>         <178>REFORMAT <MESSAGE>     <278>Use #return to change MESSAGE\n"
+		"\n"
 		"<278>         <128>TELNET EVENTS\n"
 		"<278>         <128>TELNET EVENTS\n"
 		"\n"
 		"\n"
 		"<278>         <178>IAC <EVENT>\n"
 		"<278>         <178>IAC <EVENT>\n"
@@ -2035,11 +2042,12 @@ struct help_type help_table[] =
 	{
 	{
 		"HISTORY",
 		"HISTORY",
 		TOKEN_TYPE_COMMAND,
 		TOKEN_TYPE_COMMAND,
-		"<178>Command<278>: #history <178>{<278>delete<178>}<278>                 Delete the last command.\n"
-		"<278>         #history <178>{<278>insert<178>}    {<278>command<178>}<278>    Insert a command.\n"
-		"<278>         #history <178>{<278>list<178>}<278>                   Display the entire command history.\n"
-		"<278>         #history <178>{<278>read<178>}      {<278>filename<178>}<278>   Read a command history from file.\n"
-		"<278>         #history <178>{<278>write<178>}     {<278>filename<178>}<278>   Write a command history to file.\n"
+		"<178>Command<278>: #history <178>{<278>delete<178>}<278>                    Delete the last command.\n"
+		"<278>         #history <178>{<278>get<178>}    {<278>variable<178>} {<278>range<178>}<278> Store list in variable.\n"
+		"<278>         #history <178>{<278>insert<178>} {<278>command<178>}<278>          Insert a command.\n"
+		"<278>         #history <178>{<278>list<178>}     <278>                 Display the command history.\n"
+		"<278>         #history <178>{<278>read<178>}   {<278>filename<178>}<278>         Read a command history from file.\n"
+		"<278>         #history <178>{<278>write<178>}  {<278>filename<178>}<278>         Write a command history to file.\n"
 		"\n"
 		"\n"
 		"<278>         Without an argument all available options are shown.\n"
 		"<278>         Without an argument all available options are shown.\n"
 		"\n"
 		"\n"
@@ -2069,7 +2077,7 @@ struct help_type help_table[] =
 	{
 	{
 		"IF",
 		"IF",
 		TOKEN_TYPE_COMMAND,
 		TOKEN_TYPE_COMMAND,
-		"<178>Command<278>: #if <178>{<278>conditional<178>} {<278>commands if true<178>}\n"
+		"<178>Command<278>: #if <178>{<278>conditional<178>} {<278>commands if true<178>} {<278>commands if false<178>}\n"
 		"\n"
 		"\n"
 		"<278>         The #if command works similar to an if statement in other languages,\n"
 		"<278>         The #if command works similar to an if statement in other languages,\n"
 		"<278>         and is based on the way C handles its conditional statements.\n"
 		"<278>         and is based on the way C handles its conditional statements.\n"
@@ -2081,12 +2089,15 @@ struct help_type help_table[] =
 		"<278>         executed. See the 'math' helpfile for more information.\n"
 		"<278>         executed. See the 'math' helpfile for more information.\n"
 		"\n"
 		"\n"
 		"<278>         To handle the case where an if statement is false it can be followed\n"
 		"<278>         To handle the case where an if statement is false it can be followed\n"
-		"<278>         by the #else command.\n"
+		"<278>         by the #else command. Alternatively, the else can be provided as the\n"
+		"<278>         third argument.\n"
 		"\n"
 		"\n"
 		"<178>Example<278>: #action {%0 gives you %1 gold coins.} {#if {%1 > 5000} {thank %0}}\n"
 		"<178>Example<278>: #action {%0 gives you %1 gold coins.} {#if {%1 > 5000} {thank %0}}\n"
 		"<278>         If someone gives you more than 5000 coins, thank them.\n"
 		"<278>         If someone gives you more than 5000 coins, thank them.\n"
 		"\n"
 		"\n"
-		"<178>Example<278>: #alias {k} {#if {\"%0\" == \"\"} {kill $target};#else {kill %0}}\n",
+		"<178>Example<278>: #alias {k} {#if {\"%0\" == \"\"} {kill $target};#else {kill %0}}\n"
+		"\n"
+		"<178>Example<278>: #if {\"%0\" == \"{bli|bla}\"} {#showme %0 is either bli or bla.}\n",
 		
 		
 		"case default else elseif math switch regexp"
 		"case default else elseif math switch regexp"
 	},
 	},
@@ -2525,7 +2536,7 @@ struct help_type help_table[] =
 		"<278>         <178>#line background <argument>\n"
 		"<278>         <178>#line background <argument>\n"
 		"<278>           Prevent new session activation.\n"
 		"<278>           Prevent new session activation.\n"
 		"\n"
 		"\n"
-		"<278>         <178>#line capture <variable> <argument.\n"
+		"<278>         <178>#line capture <variable> <argument>\n"
 		"<278>           Argument is executed and output stored in <variable>.\n"
 		"<278>           Argument is executed and output stored in <variable>.\n"
 		"\n"
 		"\n"
 		"<278>         <178>#line convert <argument>\n"
 		"<278>         <178>#line convert <argument>\n"
@@ -2589,6 +2600,7 @@ struct help_type help_table[] =
 		"<278>         #list {var} {add} <items>              Add <items> to the list\n"
 		"<278>         #list {var} {add} <items>              Add <items> to the list\n"
 		"<278>         #list {var} {clear}                    Empty the given list\n"
 		"<278>         #list {var} {clear}                    Empty the given list\n"
 		"<278>         #list {var} {collapse} <separator>     Turn list into a variable\n"
 		"<278>         #list {var} {collapse} <separator>     Turn list into a variable\n"
+		"<278>         #list {var} {copy} <variable>          Copy variable to the list\n"
 		"<278>         #list {var} {create} <items>           Create a list using <items>\n"
 		"<278>         #list {var} {create} <items>           Create a list using <items>\n"
 		"<278>         #list {var} {delete} <index> [amount]  Delete the item at <index>,\n"
 		"<278>         #list {var} {delete} <index> [amount]  Delete the item at <index>,\n"
 		"<278>                                                the [amount] is optional.\n"
 		"<278>                                                the [amount] is optional.\n"
@@ -2609,6 +2621,7 @@ struct help_type help_table[] =
 		"<278>         #list {var} {size} <variable>          Copy list size to {variable}\n"
 		"<278>         #list {var} {size} <variable>          Copy list size to {variable}\n"
 		"<278>         #list {var} {sort} [items]             Sort list alphabetically, if\n"
 		"<278>         #list {var} {sort} [items]             Sort list alphabetically, if\n"
 		"<278>                                                an item is given it's added.\n"
 		"<278>                                                an item is given it's added.\n"
+		"<278>         #list {var} {swap} <index> <index>     Swap two items\n"
 		"<278>         #list {var} {tokenize} <string>        Create a character list\n"
 		"<278>         #list {var} {tokenize} <string>        Create a character list\n"
 		"\n"
 		"\n"
 		"<278>         The index should be between +1 and the list's size. You can also give\n"
 		"<278>         The index should be between +1 and the list's size. You can also give\n"
@@ -3005,6 +3018,9 @@ struct help_type help_table[] =
 		"<278>           Start logging to the given file, if the file already exists it won't\n"
 		"<278>           Start logging to the given file, if the file already exists it won't\n"
 		"<278>           be overwritten and data will be appended to the end.\n"
 		"<278>           be overwritten and data will be appended to the end.\n"
 		"\n"
 		"\n"
+		"<278>         <178>#log make <directory>\n"
+		"<278>           Create the given directory.\n"
+		"\n"
 		"<278>         <178>#log move <filename_1> <filename_2>\n"
 		"<278>         <178>#log move <filename_1> <filename_2>\n"
 		"<278>           Move filename_1 to filename_2. This can be any file and doesn't need\n"
 		"<278>           Move filename_1 to filename_2. This can be any file and doesn't need\n"
 		"<278>           to be a log file.\n"
 		"<278>           to be a log file.\n"
@@ -3727,6 +3743,9 @@ struct help_type help_table[] =
 		"\n"
 		"\n"
 		"<278>         Links can be created using the MSLP protocol which will generate link\n"
 		"<278>         Links can be created using the MSLP protocol which will generate link\n"
 		"<278>         specific events when clicked.\n"
 		"<278>         specific events when clicked.\n"
+		"\n"
+		"<278>         In order to copy/paste, most terminals require that you press the shift\n"
+		"<278>         key during selection.\n"
 		"\n",
 		"\n",
 		
 		
 		"button draw event MSLP"
 		"button draw event MSLP"
@@ -3795,7 +3814,9 @@ struct help_type help_table[] =
 		"<278>         you need to use \\e]68;2;\\a, and they instead trigger the SECURE LINK\n"
 		"<278>         you need to use \\e]68;2;\\a, and they instead trigger the SECURE LINK\n"
 		"<278>         event.\n"
 		"<278>         event.\n"
 		"\n"
 		"\n"
-		"<178>Example<278>: #sub {%* tells %*} {\\e]68;2;EXEC;#cursor set tell %1 \\a\\e[4m%0\\e[24m}\n"
+		"<278>         To creae a link that is not undelined, use \\e]4;24m text \\e]24m.\n"
+		"\n"
+		"<178>Example<278>: #sub {%* tells %*} {\\e]68;2;EXEC;#cursor set tell %1 \\a\\e[4;24m%0\\e[24m}\n"
 		"<178>       <278>  #event {PRESSED SECURE LINK EXEC MOUSE BUTTON ONE} {%4}\n"
 		"<178>       <278>  #event {PRESSED SECURE LINK EXEC MOUSE BUTTON ONE} {%4}\n"
 		"\n"
 		"\n"
 		"<278>         This would make you start a reply when clicking on a tell.\n"
 		"<278>         This would make you start a reply when clicking on a tell.\n"
@@ -3938,7 +3959,7 @@ struct help_type help_table[] =
 		"<278>         is used.\n"
 		"<278>         is used.\n"
 		"\n"
 		"\n"
 		"<178>TinTin++ <178>Description                                      POSIX\n"
 		"<178>TinTin++ <178>Description                                      POSIX\n"
-		"<178>      %a <278>Match zero or more characters including newlines ([^\\n]*?)\n"       
+		"<178>      %a <278>Match zero or more characters including newlines ([^\\0]*?)\n"       
 		"<178>      %A <278>Match zero or more newlines                      ([\\n]*?)\n"
 		"<178>      %A <278>Match zero or more newlines                      ([\\n]*?)\n"
 		"<178>      %c <278>Match zero or more ansi color codes              ((?:\\e\\[[0-9;]*m)*?)\n"
 		"<178>      %c <278>Match zero or more ansi color codes              ((?:\\e\\[[0-9;]*m)*?)\n"
 		"<178>      %d <278>Match zero or more digits                        ([0-9]*?)\n"
 		"<178>      %d <278>Match zero or more digits                        ([0-9]*?)\n"
@@ -3946,6 +3967,7 @@ struct help_type help_table[] =
 		"<178>      %i <278>Matches become case insensitive                  (?i)\n"
 		"<178>      %i <278>Matches become case insensitive                  (?i)\n"
 		"<178>      %I <278>Matches become case sensitive (default)          (?-i)\n"
 		"<178>      %I <278>Matches become case sensitive (default)          (?-i)\n"
 		"<178>      %s <278>Match zero or more spaces                        ([\\r\\n\\t ]*?)\n"
 		"<178>      %s <278>Match zero or more spaces                        ([\\r\\n\\t ]*?)\n"
+		"<178>      %S <278>Match zero or more non-spaces                    ([^\\r\\n\\t ]*?)\n"
 		"<178>      %w <278>Match zero or more word characters               ([A-Za-z0-9_]*?)\n"
 		"<178>      %w <278>Match zero or more word characters               ([A-Za-z0-9_]*?)\n"
 		"<178>      %W <278>Match zero or more non-word characters           ([^A-Za-z0-9_]*?)\n"
 		"<178>      %W <278>Match zero or more non-word characters           ([^A-Za-z0-9_]*?)\n"
 		"<178>      %? <278>Match zero or one character                      (.\?\?)\n"
 		"<178>      %? <278>Match zero or one character                      (.\?\?)\n"
@@ -4289,8 +4311,8 @@ struct help_type help_table[] =
 		TOKEN_TYPE_STRING,
 		TOKEN_TYPE_STRING,
 		"<178>Command<278>: #<178>[<078>number<178>] {<278>commands<178>}\n"
 		"<178>Command<278>: #<178>[<078>number<178>] {<278>commands<178>}\n"
 		"\n"
 		"\n"
-		"        Sometimes you want to repeat the same command multiple times. This is\n"
-		"        the easiest way to accomplish that.\n"
+		"<278>        Sometimes you want to repeat the same command multiple times. This is\n"
+		"<278>        the easiest way to accomplish that.\n"
 		"\n"
 		"\n"
 		"<178>Example<278>: #10 {buy bread}\n",
 		"<178>Example<278>: #10 {buy bread}\n",
 		
 		
@@ -4798,7 +4820,7 @@ struct help_type help_table[] =
 		"<278>         Replace generic dark blue color codes with bright blue ones.\n"
 		"<278>         Replace generic dark blue color codes with bright blue ones.\n"
 		"\n"
 		"\n"
 		"<178>Example<278>: #sub {%1massacres%2} {<<888>018>%1<<888>118>MASSACRES<<888>018>%2}\n"
 		"<178>Example<278>: #sub {%1massacres%2} {<<888>018>%1<<888>118>MASSACRES<<888>018>%2}\n"
-		"<278>         Replaces all occurrences of 'massacres' with 'MASSACRES' in red.\n"
+		"<278>         Replace a line containing 'massacres' with 'MASSACRES' in red.\n"
 		"\n"
 		"\n"
 		"<178>Comment<278>: See '#help action', for more information about triggers.\n"
 		"<178>Comment<278>: See '#help action', for more information about triggers.\n"
 		"\n"
 		"\n"
@@ -5066,23 +5088,25 @@ struct help_type help_table[] =
 		"\n"
 		"\n"
 		"<128>         Multi-line triggers\n"
 		"<128>         Multi-line triggers\n"
 		"\n"
 		"\n"
-		"<278>         If an action contains the \\n sequence it will be turned into a\n"
-		"<278>         multi-line trigger. A multi-line action is executed on incoming blocks\n"
-		"<278>         of text from the MUD, and they will not trigger if the regular\n"
-		"<278>         expression spans more than one block. You can visualize incoming\n"
-		"<278>         blocks by using #event {RECEIVED OUTPUT} {#echo <<888>058>%+80h BLOCK}\n"
+		"<278>         If an action or substitution contains the \\n sequence it will be\n"
+		"<278>         turned into a multi-line trigger. A multi-line trigger is executed on\n"
+		"<278>         incoming blocks of text from the MUD, and they will not trigger if the\n"
+		"<278>         regular expression spans more than one block. You can visualize\n"
+		"<278>         incoming blocks by using the following event:\n"
+		"\n"
+		"<278>         #event {RECEIVED OUTPUT} {#echo <<888>058>%+80h BLOCK}\n"
 		"\n"
 		"\n"
 		"<278>         Since the %* expression does not capture the \\n sequence it is required\n"
 		"<278>         Since the %* expression does not capture the \\n sequence it is required\n"
 		"<278>         to use %a to capture multiple lines. To capture the start of the block\n"
 		"<278>         to use %a to capture multiple lines. To capture the start of the block\n"
 		"<278>         use \\A and for the end use \\Z. You can use ^ and $ to capture the\n"
 		"<278>         use \\A and for the end use \\Z. You can use ^ and $ to capture the\n"
 		"<278>         start and end of a line.\n"
 		"<278>         start and end of a line.\n"
 		"\n"
 		"\n"
-		"<278>         Multi-line actions trigger before regular actions. Multiple\n"
+		"<278>         Multi-line triggers trigger before regular triggers. Multiple\n"
 		"<278>         multi-line actions can trigger per block, and each multi-line action\n"
 		"<278>         multi-line actions can trigger per block, and each multi-line action\n"
 		"<278>         can trigger multiple times per block. Packet fragmentation is not\n"
 		"<278>         can trigger multiple times per block. Packet fragmentation is not\n"
 		"<278>         currently handled.\n"
 		"<278>         currently handled.\n"
 		"\n"
 		"\n"
-		"<278>         Multi-line actions are experimental and subject to change.\n"
+		"<278>         Multi-line triggers are experimental and subject to change.\n"
 		"\n"
 		"\n"
 		"<128>         Input triggers\n"
 		"<128>         Input triggers\n"
 		"\n"
 		"\n"
@@ -5155,6 +5179,10 @@ struct help_type help_table[] =
 		"\n"
 		"\n"
 		"<178>Example<278>: #show {Targets starting with the letter A: $targets[A%*]\n"
 		"<178>Example<278>: #show {Targets starting with the letter A: $targets[A%*]\n"
 		"\n"
 		"\n"
+		"              To disable using regular expressions start the match with '='.\n"
+		"\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>         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"
 		"<278>         the size of a table you would use: &targets[] or &targets[%*]. A non\n"
 		"<278>         existent nested variable will report itself as 0.\n"
 		"<278>         existent nested variable will report itself as 0.\n"

+ 2 - 26
src/history.c

@@ -127,15 +127,6 @@ struct session *repeat_history(struct session *ses, char *line)
 	return ses;
 	return ses;
 }
 }
 
 
-DO_HISTORY(history_character)
-{
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
-
-	gtd->repeat_char = *arg1;
-
-	show_message(ses, LIST_HISTORY, "#HISTORY CHARACTER SET TO {%c}.", gtd->repeat_char);
-}
-
 DO_HISTORY(history_delete)
 DO_HISTORY(history_delete)
 {
 {
 	if (ses->list[LIST_HISTORY]->used)
 	if (ses->list[LIST_HISTORY]->used)
@@ -251,7 +242,7 @@ DO_HISTORY(history_read)
 
 
 	if (file == NULL)
 	if (file == NULL)
 	{
 	{
-		show_message(ses, LIST_HISTORY, "#HISTORY: COULDN'T OPEN FILE {%s} TO READ.", arg1);
+		show_message(ses, LIST_HISTORY, "#HISTORY READ {%s}: COULDN'T OPEN FILE.", arg1);
 
 
 		return;
 		return;
 	}
 	}
@@ -277,21 +268,6 @@ DO_HISTORY(history_read)
 	return;
 	return;
 }
 }
 
 
-DO_HISTORY(history_size)
-{
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
-
-	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(arg1);
-	}
-	return;
-}
-
 DO_HISTORY(history_write)
 DO_HISTORY(history_write)
 {
 {
 	struct listroot *root = ses->list[LIST_HISTORY];
 	struct listroot *root = ses->list[LIST_HISTORY];
@@ -304,7 +280,7 @@ DO_HISTORY(history_write)
 
 
 	if (file == NULL)
 	if (file == NULL)
 	{
 	{
-		tintin_printf2(ses, "#HISTORY: COULDN'T OPEN FILE {%s} TO WRITE.", arg1);
+		tintin_printf2(ses, "#HISTORY WRITE {%s}: COULDN'T OPEN FILE.", arg1);
 
 
 		return;
 		return;
 	}
 	}

+ 10 - 4
src/input.c

@@ -1058,12 +1058,18 @@ void input_printf(char *format, ...)
 	}
 	}
 
 
 	va_start(args, format);
 	va_start(args, format);
-	vasprintf(&buf, format, args);
-	va_end(args);
 
 
-	print_stdout(0, 0, "%s", buf);
+	if (vasprintf(&buf, format, args) == -1)
+	{
+		syserr_printf(gtd->ses, "input_printf(%s): vasprintf:", format);
+	}
+	else
+	{
+		print_stdout(0, 0, "%s", buf);
 
 
-	free(buf);
+		free(buf);
+	}
+	va_end(args);
 
 
 	return;
 	return;
 }
 }

+ 23 - 23
src/line.c

@@ -108,7 +108,7 @@ DO_LINE(line_background)
 
 
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {BACKGROUND} {command}.");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {BACKGROUND} <COMMAND>");
 
 
 		return ses;
 		return ses;
 	}
 	}
@@ -130,7 +130,7 @@ DO_LINE(line_benchmark)
 
 
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {BENCHMARK} {command}.");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {BENCHMARK} <COMMAND>");
 
 
 		return ses;
 		return ses;
 	}
 	}
@@ -170,7 +170,7 @@ DO_LINE(line_capture)
 	}
 	}
 	else
 	else
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE CAPTURE {VARIABLE} {command}.");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE CAPTURE <VARIABLE> <COMMAND>");
 	}
 	}
 	return ses;
 	return ses;
 }
 }
@@ -181,7 +181,7 @@ DO_LINE(line_convert)
 
 
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {CONVERT} {command}.");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {CONVERT} <COMMAND>");
 
 
 		return ses;
 		return ses;
 	}
 	}
@@ -203,7 +203,7 @@ DO_LINE(line_debug)
 
 
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {DEBUG} {command}.");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {DEBUG} <COMMAND>");
 
 
 		return ses;
 		return ses;
 	}
 	}
@@ -252,7 +252,7 @@ DO_LINE(line_ignore)
 
 
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {IGNORE} {command}.");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {IGNORE} <COMMAND>");
 		
 		
 		return ses;
 		return ses;
 	}
 	}
@@ -272,7 +272,7 @@ DO_LINE(line_local)
 
 
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {LOCAL} {command}.");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {LOCAL} <COMMAND>");
 
 
 		return ses;
 		return ses;
 	}
 	}
@@ -329,7 +329,7 @@ DO_LINE(line_log)
 			}
 			}
 			else
 			else
 			{
 			{
-				show_error(ses, LIST_COMMAND, "#ERROR: #LINE LOG {%s} - COULDN'T OPEN FILE.", arg1);
+				show_error(ses, LIST_COMMAND, "#ERROR: #LINE LOG {%s}: COULDN'T OPEN FILE.", arg1);
 			}
 			}
 		}
 		}
 	}
 	}
@@ -355,12 +355,12 @@ DO_LINE(line_log)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#ERROR: #LINE LOG {%s} - COULDN'T OPEN FILE.", arg1);
+			show_error(ses, LIST_COMMAND, "#ERROR: #LINE LOG {%s}: COULDN'T OPEN FILE.", arg1);
 		}
 		}
 	}
 	}
 	else
 	else
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {LOG} {filename} [string]");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {LOG} <FILENAME> [TEXT]");
 	}
 	}
 	return ses;
 	return ses;
 }
 }
@@ -401,7 +401,7 @@ DO_LINE(line_logverbatim)
 			}
 			}
 			else
 			else
 			{
 			{
-				show_error(ses, LIST_COMMAND, "#ERROR: #LINE LOGVERBATIM {%s} - COULDN'T OPEN FILE.", arg1);
+				show_error(ses, LIST_COMMAND, "#ERROR: #LINE LOGVERBATIM {%s}: COULDN'T OPEN FILE.", arg1);
 			}
 			}
 		}
 		}
 	}
 	}
@@ -427,12 +427,12 @@ DO_LINE(line_logverbatim)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#ERROR: #LINE LOGVERBATIM {%s} - COULDN'T OPEN FILE.", arg1);
+			show_error(ses, LIST_COMMAND, "#ERROR: #LINE LOGVERBATIM {%s}: COULDN'T OPEN FILE.", arg1);
 		}
 		}
 	}
 	}
 	else
 	else
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {LOGVERBATIM} {filename} {string}");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {LOGVERBATIM} <FILENAME> <TEXT>");
 	}
 	}
 	return ses;
 	return ses;
 }
 }
@@ -469,7 +469,7 @@ DO_LINE(line_logmode)
 	}
 	}
 	else
 	else
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {LOGMODE} {HTML|PLAIN|RAW|STAMP} {command}.");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {LOGMODE} {HTML|PLAIN|RAW|STAMP} <COMMAND>");
 
 
 		return ses;
 		return ses;
 	}
 	}
@@ -489,7 +489,7 @@ DO_LINE(line_msdp)
 
 
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {MSDP} {command}.");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {MSDP} <COMMAND>");
 
 
 		return ses;
 		return ses;
 	}
 	}
@@ -508,7 +508,7 @@ DO_LINE(line_json)
 
 
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {JSON} {command}.");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {JSON} <VARIABLE> <COMMAND>");
 
 
 		return ses;
 		return ses;
 	}
 	}
@@ -556,7 +556,7 @@ DO_LINE(line_multishot)
 
 
 	if (!is_math(ses, arg1) || *arg2 == 0)
 	if (!is_math(ses, arg1) || *arg2 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {MULTISHOT} {number} {command}.");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {MULTISHOT} <NUMBER> <COMMAND>");
 		
 		
 		return ses;
 		return ses;
 	}
 	}
@@ -580,7 +580,7 @@ DO_LINE(line_oneshot)
 
 
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {ONESHOT} {command}.");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {ONESHOT} <COMMAND>");
 		
 		
 		return ses;
 		return ses;
 	}
 	}
@@ -602,7 +602,7 @@ DO_LINE(line_quiet)
 
 
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {QUIET} {command}.");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {QUIET} <COMMAND>");
 		
 		
 		return ses;
 		return ses;
 	}
 	}
@@ -622,7 +622,7 @@ DO_LINE(line_strip)
 
 
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {STRIP} {command}.");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {STRIP} <COMMAND>");
 
 
 		return ses;
 		return ses;
 	}
 	}
@@ -645,7 +645,7 @@ DO_LINE(line_substitute)
 	{
 	{
 		for (i = 0 ; *substitution_table[i].name ; i++)
 		for (i = 0 ; *substitution_table[i].name ; i++)
 		{
 		{
-			tintin_printf2(ses, "#SYNTAX: #LINE {SUBSTITUTE} {%s} {command}.", substitution_table[i].name);
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {SUBSTITUTE} {%s} <COMMAND>", substitution_table[i].name);
 		}
 		}
 		return ses;
 		return ses;
 	}
 	}
@@ -683,7 +683,7 @@ DO_LINE(line_verbatim)
 
 
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {VERBATIM} {command}.");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {VERBATIM} <COMMAND>");
 		
 		
 		return ses;
 		return ses;
 	}
 	}
@@ -703,7 +703,7 @@ DO_LINE(line_verbose)
 
 
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {VERBOSE} {command}.");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {VERBOSE} <COMMAND>");
 		
 		
 		return ses;
 		return ses;
 	}
 	}

+ 94 - 16
src/list.c

@@ -32,6 +32,7 @@
 extern DO_ARRAY(array_add);
 extern DO_ARRAY(array_add);
 extern DO_ARRAY(array_clear);
 extern DO_ARRAY(array_clear);
 extern DO_ARRAY(array_collapse);
 extern DO_ARRAY(array_collapse);
+extern DO_ARRAY(array_copy);
 extern DO_ARRAY(array_create);
 extern DO_ARRAY(array_create);
 extern DO_ARRAY(array_delete);
 extern DO_ARRAY(array_delete);
 extern DO_ARRAY(array_explode);
 extern DO_ARRAY(array_explode);
@@ -49,6 +50,7 @@ extern DO_ARRAY(array_shuffle);
 extern DO_ARRAY(array_simplify);
 extern DO_ARRAY(array_simplify);
 extern DO_ARRAY(array_size);
 extern DO_ARRAY(array_size);
 extern DO_ARRAY(array_sort);
 extern DO_ARRAY(array_sort);
+extern DO_ARRAY(array_swap);
 extern DO_ARRAY(array_tokenize);
 extern DO_ARRAY(array_tokenize);
 
 
 typedef struct session *ARRAY(struct session *ses, struct listnode *list, char *arg, char *var, char *arg1, char *arg2);
 typedef struct session *ARRAY(struct session *ses, struct listnode *list, char *arg, char *var, char *arg1, char *arg2);
@@ -66,6 +68,7 @@ struct array_type array_table[] =
 	{     "CLEAR",            array_clear,       "Clear a list"                            },
 	{     "CLEAR",            array_clear,       "Clear a list"                            },
 	{     "CLR",              array_clear,       NULL                                      },
 	{     "CLR",              array_clear,       NULL                                      },
 	{     "COLLAPSE",         array_collapse,    "Collapse the list into a variable"       },
 	{     "COLLAPSE",         array_collapse,    "Collapse the list into a variable"       },
+	{     "COPY",             array_copy,        "Copy a list to a list"                   },
 	{     "CREATE",           array_create,      "Create a list with given items"          },
 	{     "CREATE",           array_create,      "Create a list with given items"          },
 	{     "DELETE",           array_delete,      "Delete a list item with given index"     },
 	{     "DELETE",           array_delete,      "Delete a list item with given index"     },
 	{     "EXPLODE",          array_explode,     "Explode the variable into a list"        },
 	{     "EXPLODE",          array_explode,     "Explode the variable into a list"        },
@@ -86,6 +89,7 @@ struct array_type array_table[] =
 	{     "SIZE",             array_size,        NULL                                      },
 	{     "SIZE",             array_size,        NULL                                      },
 	{     "SORT",             array_sort,        "Sort a list table alphabetically"        },
 	{     "SORT",             array_sort,        "Sort a list table alphabetically"        },
 	{     "SRT",              array_sort,        NULL                                      },
 	{     "SRT",              array_sort,        NULL                                      },
+	{     "SWAP",             array_swap,        "Swap two list items"                     },
 	{     "TOKENIZE",         array_tokenize,    "Create a list with given characters"     },
 	{     "TOKENIZE",         array_tokenize,    "Create a list with given characters"     },
 	{     "",                 NULL,              ""                                        }
 	{     "",                 NULL,              ""                                        }
 };
 };
@@ -115,7 +119,7 @@ DO_COMMAND(do_list)
 	}
 	}
 	else if (*arg2 == 0)
 	else if (*arg2 == 0)
 	{
 	{
-		show_error(ses, LIST_VARIABLE, "#SYNTAX: #LIST {variable} {option} {argument}");
+		show_error(ses, LIST_VARIABLE, "#SYNTAX: #LIST <VARIABLE> <OPTION> <ARGUMENT>");
 	}
 	}
 	else
 	else
 	{
 	{
@@ -254,6 +258,47 @@ DO_ARRAY(array_collapse)
 	return ses;
 	return ses;
 }
 }
 
 
+DO_ARRAY(array_copy)
+{
+	struct listnode *from;
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
+
+	if (*arg1 == 0)
+	{
+		show_error(ses, LIST_VARIABLE, "#SYNTAX: #LIST {%s} COPY <VARIABLE>.", var);
+
+		return ses;
+	}
+
+	if ((from = search_nest_node_ses(ses, arg1)) == NULL)
+	{
+		show_error(ses, LIST_VARIABLE, "#LIST COPY: VARIABLE {%s} NOT FOUND.", arg1);
+		
+		return ses;
+	}
+
+	if (!strcmp(var, arg1))
+	{
+		return ses;
+	}
+
+	str_cpy(&list->arg2, from->arg2);
+	str_cpy(&list->arg3, from->arg3);
+	str_cpy(&list->arg4, from->arg4);
+
+	if (list->root)
+	{
+		free_list(list->root);
+
+		list->root = NULL;
+	}
+
+	copy_nest_node(ses->list[LIST_VARIABLE], list, from);
+
+	return ses;
+}
+
 DO_ARRAY(array_create)
 DO_ARRAY(array_create)
 {
 {
 	char *buf, *str;
 	char *buf, *str;
@@ -329,7 +374,7 @@ DO_ARRAY(array_delete)
 
 
 		if (index == -1)
 		if (index == -1)
 		{
 		{
-			show_error(ses, LIST_VARIABLE, "#LIST {%s} DELETE: INVALID INDEX: {%s}.", var, arg1);
+			show_error(ses, LIST_VARIABLE, "#LIST {%s} DELETE: INVALID INDEX {%s}.", var, arg1);
 
 
 			return ses;
 			return ses;
 		}
 		}
@@ -351,7 +396,7 @@ DO_ARRAY(array_delete)
 	}
 	}
 	else
 	else
 	{
 	{
-		show_error(ses, LIST_VARIABLE, "#LIST DELETE: {%s} is not a list.", var);
+		show_error(ses, LIST_VARIABLE, "#LIST DELETE: VARIABLE {%s} IS NOT A LIST.", var);
 	}
 	}
 	return ses;
 	return ses;
 }
 }
@@ -366,7 +411,7 @@ DO_ARRAY(array_explode)
 
 
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
-		show_error(ses, LIST_VARIABLE, "#SYNTAX: #LIST {%s} EXPLODE {<SEPARATOR>}.", var);
+		show_error(ses, LIST_VARIABLE, "#SYNTAX: #LIST {%s} EXPLODE <SEPARATOR>", var);
 
 
 		return ses;
 		return ses;
 	}
 	}
@@ -375,7 +420,7 @@ DO_ARRAY(array_explode)
 	{
 	{
 		if (*arg2 == 0)
 		if (*arg2 == 0)
 		{
 		{
-			show_error(ses, LIST_VARIABLE, "#LIST {%s} EXPLODE: VARIABLE %s IS ALREADY A LIST.", var, var);
+			show_error(ses, LIST_VARIABLE, "#LIST {%s} EXPLODE: VARIABLE {%s} IS ALREADY A LIST.", var, var);
 
 
 			return ses;
 			return ses;
 		}
 		}
@@ -422,7 +467,7 @@ DO_ARRAY(array_filter)
 
 
 	if (*arg1 == 0 && *arg2 == 0)
 	if (*arg1 == 0 && *arg2 == 0)
 	{
 	{
-		show_error(ses, LIST_VARIABLE, "#SYNTAX: #LIST {variable} FILTER {keep} {remove}");
+		show_error(ses, LIST_VARIABLE, "#SYNTAX: #LIST <VARIABLE> FILTER <KEEP> [REMOVE]");
 
 
 		return ses;
 		return ses;
 	}
 	}
@@ -478,7 +523,7 @@ DO_ARRAY(array_find)
 
 
 	if (*arg2 == 0)
 	if (*arg2 == 0)
 	{
 	{
-		show_error(ses, LIST_VARIABLE, "#SYNTAX: #LIST {variable} FIND {string} {variable}");
+		show_error(ses, LIST_VARIABLE, "#SYNTAX: #LIST <VARIABLE> FIND <TEXT> <VARIABLE>");
 
 
 		return ses;
 		return ses;
 	}
 	}
@@ -510,7 +555,7 @@ DO_ARRAY(array_get)
 
 
 	if (*arg2 == 0)
 	if (*arg2 == 0)
 	{
 	{
-		show_error(ses, LIST_VARIABLE, "#SYNTAX: #LIST {variable} GET {index} {variable}");
+		show_error(ses, LIST_VARIABLE, "#SYNTAX: #LIST <VARIABLE> GET <INDEX> <VARIABLE>");
 		
 		
 		return ses;
 		return ses;
 	}
 	}
@@ -604,7 +649,7 @@ DO_ARRAY(array_insert)
 
 
 	if (toi == 0)
 	if (toi == 0)
 	{
 	{
-		show_error(ses, LIST_VARIABLE, "#LIST INSERT: INVALID INDEX: {%s}.", arg1);
+		show_error(ses, LIST_VARIABLE, "#LIST INSERT: INVALID INDEX {%s}.", arg1);
 
 
 		return ses;
 		return ses;
 	}
 	}
@@ -725,7 +770,7 @@ DO_ARRAY(array_refine)
 
 
 	if (*arg1 == 0 && *arg2 == 0)
 	if (*arg1 == 0 && *arg2 == 0)
 	{
 	{
-		show_error(ses, LIST_VARIABLE, "#SYNTAX: #LIST {variable} REFINE {keep} {remove}");
+		show_error(ses, LIST_VARIABLE, "#SYNTAX: #LIST <VARIABLE> REFINE <KEEP> [REMOVE]");
 
 
 		return ses;
 		return ses;
 	}
 	}
@@ -833,7 +878,7 @@ DO_ARRAY(array_simplify)
 	}
 	}
 	else
 	else
 	{
 	{
-		show_error(ses, LIST_VARIABLE, "#LIST SIMPLIFY: {%s} is not a list.", list->arg1);
+		show_error(ses, LIST_VARIABLE, "#LIST SIMPLIFY: VARIABLE {%s} IS NOT A LIST.", list->arg1);
 	}
 	}
 
 
 	return ses;
 	return ses;
@@ -845,7 +890,7 @@ DO_ARRAY(array_size)
 
 
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
-		show_error(ses, LIST_VARIABLE, "#SYNTAX: #LIST {variable} SIZE {variable}");
+		show_error(ses, LIST_VARIABLE, "#SYNTAX: #LIST <VARIABLE> SIZE <VARIABLE>");
 		
 		
 		return ses;
 		return ses;
 	}
 	}
@@ -874,16 +919,18 @@ DO_ARRAY(array_set)
 
 
 		if (index == -1)
 		if (index == -1)
 		{
 		{
-			show_error(ses, LIST_VARIABLE, "#LIST {%s} SET: Invalid index: %s", var, arg1);
+			show_error(ses, LIST_VARIABLE, "#LIST {%s} SET: INVALID INDEX {%s}.", var, arg1);
 
 
 			return ses;
 			return ses;
 		}
 		}
-		str_cpy(&list->root->list[index]->arg2, arg2);
+		set_nest_node(list->root, list->root->list[index]->arg1, "%s", arg2);
+
+//		str_cpy(&list->root->list[index]->arg2, arg2);
 
 
 		return ses;
 		return ses;
 	}
 	}
 
 
-	show_error(ses, LIST_VARIABLE, "#LIST SET: {%s} is not a list.", var);
+	show_error(ses, LIST_VARIABLE, "#LIST SET: VARIABLE {%s} IS NOT A LIST.", var);
 
 
 	return ses;
 	return ses;
 }
 }
@@ -922,7 +969,7 @@ DO_ARRAY(array_sort)
 	{
 	{
 		if (*list->root->list[0]->arg2 == 0)
 		if (*list->root->list[0]->arg2 == 0)
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#ERROR: #LIST {%s} ORDER: LIST IS NOT INDEXED.", var);
+			show_error(ses, LIST_COMMAND, "#ERROR: #LIST {%s} SORT: LIST IS NOT INDEXED.", var);
 
 
 			return ses;
 			return ses;
 		}
 		}
@@ -981,6 +1028,37 @@ DO_ARRAY(array_sort)
 	return ses;
 	return ses;
 }
 }
 
 
+DO_ARRAY(array_swap)
+{
+	char *swap;
+	int index1, index2;
+	struct listroot *toor;
+
+	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);
+
+	if (list->root)
+	{
+		index1 = get_list_index(ses, list->root, arg1);
+		index2 = get_list_index(ses, list->root, arg2);
+
+		if (index1 == -1 || index2 == -1)
+		{
+			show_error(ses, LIST_VARIABLE, "#LIST {%s} SWAP: INVALID INDEX {%s} {%s}.", var, arg1, arg2);
+
+			return ses;
+		}
+		swap = list->root->list[index1]->arg2; list->root->list[index1]->arg2 = list->root->list[index2]->arg2; list->root->list[index2]->arg2 = swap;
+		toor = list->root->list[index1]->root; list->root->list[index1]->root = list->root->list[index2]->root; list->root->list[index2]->root = toor;
+
+		return ses;
+	}
+
+	show_error(ses, LIST_VARIABLE, "#LIST SWAP: VARIABLE {%s} IS NOT A LIST.", var);
+
+	return ses;
+}
+
 DO_ARRAY(array_tokenize)
 DO_ARRAY(array_tokenize)
 {
 {
 	char *buf;
 	char *buf;

+ 30 - 9
src/log.c

@@ -29,6 +29,7 @@
 
 
 DO_LOG(log_append);
 DO_LOG(log_append);
 DO_LOG(log_info);
 DO_LOG(log_info);
+DO_LOG(log_make);
 DO_LOG(log_move);
 DO_LOG(log_move);
 DO_LOG(log_overwrite);
 DO_LOG(log_overwrite);
 DO_LOG(log_off);
 DO_LOG(log_off);
@@ -48,10 +49,11 @@ struct log_type log_table[] =
 {
 {
 	{    "APPEND",            log_append,          "Start logging, appending to given file."        },
 	{    "APPEND",            log_append,          "Start logging, appending to given file."        },
 	{    "INFO",              log_info,            "Some logging related info."                     },
 	{    "INFO",              log_info,            "Some logging related info."                     },
+	{    "MAKE",              log_make,            "Make the given directory."                      },
 	{    "MOVE",              log_move,            "Move the given file."                           },
 	{    "MOVE",              log_move,            "Move the given file."                           },
 	{    "OFF",               log_off,             "Stop logging."                                  },
 	{    "OFF",               log_off,             "Stop logging."                                  },
 	{    "OVERWRITE",         log_overwrite,       "Start logging, overwriting the given file."     },
 	{    "OVERWRITE",         log_overwrite,       "Start logging, overwriting the given file."     },
-	{    "REMOVE",            log_remove,          "Remove the given file."                         },
+	{    "REMOVE",            log_remove,          "Remove the given file or directory."            },
 	{    "TIMESTAMP",         log_timestamp,       "Timestamp prepended to each log line."          },
 	{    "TIMESTAMP",         log_timestamp,       "Timestamp prepended to each log line."          },
 	{    "",                  NULL,                ""                                               }
 	{    "",                  NULL,                ""                                               }
 };
 };
@@ -123,7 +125,7 @@ DO_LOG(log_append)
 	}
 	}
 	else
 	else
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#ERROR: #LOG {%s} {%s} - COULDN'T OPEN FILE.", arg1, arg2);
+		show_error(ses, LIST_COMMAND, "#ERROR: #LOG {%s} {%s}: COULDN'T OPEN FILE.", arg1, arg2);
 	}
 	}
 }
 }
 
 
@@ -136,6 +138,25 @@ DO_LOG(log_info)
 	tintin_printf2(ses, "#LOG INFO: NEXT  = %s", ses->log->next_file ? ses->log->next_name : "");
 	tintin_printf2(ses, "#LOG INFO: NEXT  = %s", ses->log->next_file ? ses->log->next_name : "");
 }
 }
 
 
+DO_LOG(log_make)
+{
+	if (mkdir(arg2, 0755))
+	{
+		if (errno != EEXIST)
+		{
+			show_error(ses, LIST_COMMAND, "#ERROR: #LOG MAKE: FAILED TO CREATE DIRECTORY {%s} (%s).", arg2, strerror(errno));
+		}
+		else
+		{
+			show_message(ses, LIST_COMMAND, "#LOG MAKE: DIRECTORY {%s} ALREADY EXISTS.", arg2);
+		}
+	}
+	else
+	{
+		show_message(ses, LIST_COMMAND, "#LOG MAKE: CREATED DIRECTORY {%s}.", arg2);
+	}
+}
+
 DO_LOG(log_move)
 DO_LOG(log_move)
 {
 {
 	char *arg3;
 	char *arg3;
@@ -149,11 +170,11 @@ DO_LOG(log_move)
 
 
 	if (result == 0)
 	if (result == 0)
 	{
 	{
-		show_message(ses, LIST_COMMAND, "#LOG MOVE: FILE '%s' MOVED TO '%s'.", arg2, arg3);
+		show_message(ses, LIST_COMMAND, "#LOG MOVE: FILE {%s} MOVED TO {%s}.", arg2, arg3);
 	}
 	}
 	else
 	else
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#LOG MOVE: COULDN'T MOVE FILE '%s' TO '%s'.", arg2, arg3);
+		show_error(ses, LIST_COMMAND, "#LOG MOVE: COULDN'T MOVE FILE {%s} TO {%s}.", arg2, arg3);
 	}
 	}
 }
 }
 
 
@@ -172,11 +193,11 @@ DO_LOG(log_overwrite)
 
 
 		logheader(ses, ses->log->file, ses->log->mode);
 		logheader(ses, ses->log->file, ses->log->mode);
 
 
-		show_message(ses, LIST_COMMAND, "#LOG: LOGGING OUTPUT TO '%s'", arg2);
+		show_message(ses, LIST_COMMAND, "#LOG: LOGGING OUTPUT TO {%s}", arg2);
 	}
 	}
 	else
 	else
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#ERROR: #LOG {%s} {%s} - COULDN'T OPEN FILE.", arg1, arg2);
+		show_error(ses, LIST_COMMAND, "#ERROR: #LOG {%s} {%s}: COULDN'T OPEN FILE.", arg1, arg2);
 	}
 	}
 }
 }
 
 
@@ -203,11 +224,11 @@ DO_LOG(log_remove)
 
 
 	if (result == 0)
 	if (result == 0)
 	{
 	{
-		show_message(ses, LIST_COMMAND, "#LOG REMOVE: FILE '%s' REMOVED.", arg2);
+		show_message(ses, LIST_COMMAND, "#LOG REMOVE: FILE {%s} REMOVED.", arg2);
 	}
 	}
 	else
 	else
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#LOG REMOVE: COULDN'T REMOVE FILE '%s'.", arg2);
+		show_error(ses, LIST_COMMAND, "#LOG REMOVE: COULDN'T REMOVE FILE {%s}.", arg2);
 	}
 	}
 }
 }
 
 
@@ -216,7 +237,7 @@ DO_LOG(log_timestamp)
 	RESTRING(ses->log->stamp_strf, arg2);
 	RESTRING(ses->log->stamp_strf, arg2);
 	ses->log->stamp_time = 0;
 	ses->log->stamp_time = 0;
 
 
-	show_message(ses, LIST_COMMAND, "#LOG TIMESTAMP: FORMAT SET TO '%s'.", arg2);
+	show_message(ses, LIST_COMMAND, "#LOG TIMESTAMP: FORMAT SET TO {%s}.", arg2);
 }
 }
 
 
 void init_log(struct session *ses)
 void init_log(struct session *ses)

File diff suppressed because it is too large
+ 190 - 153
src/mapper.c


+ 19 - 19
src/math.c

@@ -115,7 +115,7 @@ DO_COMMAND(do_math)
 
 
 	if (*arg1 == 0 || *arg2 == 0)
 	if (*arg1 == 0 || *arg2 == 0)
 	{
 	{
-		show_error(ses, LIST_VARIABLE, "#SYNTAX: #MATH {variable} {expression}.");
+		show_error(ses, LIST_VARIABLE, "#SYNTAX: #MATH <VARIABLE> <EXPRESSION>");
 	}
 	}
 	else
 	else
 	{
 	{
@@ -473,7 +473,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 						{
 						{
 							if (debug)
 							if (debug)
 							{
 							{
-								show_debug(ses, LIST_VARIABLE, "MATH EXP: { FOUND INSIDE A NUMBER");
+								show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: \x7B FOUND INSIDE A NUMBER");
 							}
 							}
 							pop_call();
 							pop_call();
 							return FALSE;
 							return FALSE;
@@ -488,7 +488,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 						{
 						{
 							if (debug)
 							if (debug)
 							{
 							{
-								show_debug(ses, LIST_VARIABLE, "MATH EXP: \" FOUND INSIDE A NUMBER");
+								show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: \" FOUND INSIDE A NUMBER");
 							}
 							}
 							pop_call();
 							pop_call();
 							return FALSE;
 							return FALSE;
@@ -503,7 +503,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 						{
 						{
 							if (debug)
 							if (debug)
 							{
 							{
-								show_debug(ses, LIST_VARIABLE, "#MATH EXP: PARANTESES FOUND INSIDE A NUMBER");
+								show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: PARANTESES FOUND INSIDE A NUMBER");
 							}
 							}
 							pop_call();
 							pop_call();
 							return FALSE;
 							return FALSE;
@@ -523,7 +523,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 					case ':':
 					case ':':
 						if (debug && wonky == 0)
 						if (debug && wonky == 0)
 						{
 						{
-							show_error(gtd->ses, LIST_COMMAND, "\e[1;31m#WARNING: COMPUTING {%s}. THE : TIME OPERATOR IN #MATH WILL BE REMOVED IN FUTURE RELEASES.", str);
+							show_error(gtd->ses, LIST_COMMAND, "#WARNING: COMPUTING {%s}. THE : TIME OPERATOR IN #MATH WILL BE REMOVED IN FUTURE RELEASES.", str);
 						}
 						}
 						*pta++ = *pti++;
 						*pta++ = *pti++;
 						break;
 						break;
@@ -556,7 +556,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 							{
 							{
 								if (debug)
 								if (debug)
 								{
 								{
-									show_debug(ses, LIST_VARIABLE, "#MATH EXP: MORE THAN ONE POINT FOUND INSIDE A NUMBER");
+									show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: MORE THAN ONE POINT FOUND INSIDE A NUMBER");
 								}
 								}
 								precision = 0;
 								precision = 0;
 								pop_call();
 								pop_call();
@@ -587,7 +587,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 						{
 						{
 							if (debug)
 							if (debug)
 							{
 							{
-								show_debug(ses, LIST_VARIABLE, "#MATH EXP: EXPRESSION STARTED WITH AN OPERATOR.");
+								show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: EXPRESSION STARTED WITH AN OPERATOR.");
 							}
 							}
 							pop_call();
 							pop_call();
 							return FALSE;
 							return FALSE;
@@ -608,7 +608,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 
 
 							if (debug)
 							if (debug)
 							{
 							{
-								show_debug(ses, LIST_VARIABLE, "#MATH EXP {%s}: FOUND OPERATOR %s WHILE EXPECTING A VALUE.", str, buf3);
+								show_debug(ses, LIST_VARIABLE, "#DEBUG MATH {%s}: FOUND OPERATOR %s WHILE EXPECTING A VALUE.", str, buf3);
 							}
 							}
 							pop_call();
 							pop_call();
 							return FALSE;
 							return FALSE;
@@ -630,7 +630,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 
 
 							if (debug)
 							if (debug)
 							{
 							{
-								show_debug(ses, LIST_VARIABLE, "#MATH EXP {%s}: INVALID NUMBER %s.", str, buf3);
+								show_debug(ses, LIST_VARIABLE, "#DEBUG MATH {%s}: INVALID NUMBER %s.", str, buf3);
 							}
 							}
 
 
 							pop_call();
 							pop_call();
@@ -709,7 +709,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 
 
 						if (debug)
 						if (debug)
 						{
 						{
-							show_debug(ses, LIST_VARIABLE, "#MATH EXP {%s}: INVALID NUMBER %s.", str, buf3);
+							show_debug(ses, LIST_VARIABLE, "#DEBUG MATH {%s}: INVALID NUMBER %s.", str, buf3);
 						}
 						}
 						pop_call();
 						pop_call();
 						return FALSE;
 						return FALSE;
@@ -783,7 +783,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 						{
 						{
 							if (debug)
 							if (debug)
 							{
 							{
-								show_debug(ses, LIST_VARIABLE, "#MATH EXP: UNKNOWN OPERATOR: %c%c", pti[0], pti[1]);
+								show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: UNKNOWN OPERATOR: %c%c", pti[0], pti[1]);
 							}
 							}
 							pop_call();
 							pop_call();
 							return FALSE;
 							return FALSE;
@@ -956,7 +956,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 							default:
 							default:
 								if (debug)
 								if (debug)
 								{
 								{
-									show_debug(ses, LIST_VARIABLE, "#MATH EXP: UNKNOWN OPERATOR: %c%c", pti[-1], pti[0]);
+									show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: UNKNOWN OPERATOR: %c%c", pti[-1], pti[0]);
 								}
 								}
 								pop_call();
 								pop_call();
 								return FALSE;
 								return FALSE;
@@ -966,7 +966,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 					default:
 					default:
 						if (debug)
 						if (debug)
 						{
 						{
-							show_debug(ses, LIST_VARIABLE, "#MATH EXP: UNKNOWN OPERATOR: %c", *pti);
+							show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: UNKNOWN OPERATOR: %c", *pti);
 						}
 						}
 						pop_call();
 						pop_call();
 						return FALSE;
 						return FALSE;
@@ -979,7 +979,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 	{
 	{
 		if (debug)
 		if (debug)
 		{
 		{
-			show_debug(ses, LIST_VARIABLE, "#MATH EXP: UNMATCHED PARENTHESES, LEVEL: %d", level);
+			show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: UNMATCHED PARENTHESES, LEVEL: %d", level);
 		}
 		}
 		pop_call();
 		pop_call();
 		return FALSE;
 		return FALSE;
@@ -1070,7 +1070,7 @@ void mathexp_compute(struct session *ses, struct math_node *node)
 		case EXP_OP_DICE:
 		case EXP_OP_DICE:
 			if (node->next->val <= 0)
 			if (node->next->val <= 0)
 			{
 			{
-				show_debug(ses, LIST_VARIABLE, "#MATHEXP: INVALID DICE: %lld", (long long) node->next->val);
+				show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: INVALID DICE: %lld", (long long) node->next->val);
 				value = 0;
 				value = 0;
 			}
 			}
 			else
 			else
@@ -1094,7 +1094,7 @@ void mathexp_compute(struct session *ses, struct math_node *node)
 		case EXP_OP_DIVIDE:
 		case EXP_OP_DIVIDE:
 			if (node->next->val == 0)
 			if (node->next->val == 0)
 			{
 			{
-				show_debug(ses, LIST_VARIABLE, "#MATH ERROR: DIVISION ZERO.");
+				show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: DIVISION BY ZERO.");
 				value = 0;
 				value = 0;
 				precision = 0;
 				precision = 0;
 			}
 			}
@@ -1196,7 +1196,7 @@ void mathexp_compute(struct session *ses, struct math_node *node)
 			break;
 			break;
 
 
 		default:
 		default:
-			show_debug(ses, LIST_VARIABLE, "#MATH COMPUTE EXP: UNKNOWN OPERATOR: %c%c%c", (int) node->val % 128, (int) node->val % 16384 / 128, (int) node->val % 2097152 / 16384);
+			show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: UNKNOWN OPERATOR: %c%c%c", (int) node->val % 128, (int) node->val % 16384 / 128, (int) node->val % 2097152 / 16384);
 			value = 0;
 			value = 0;
 			break;
 			break;
 	}
 	}
@@ -1526,7 +1526,7 @@ long double tincmp(struct math_node *left, struct math_node *right)
 {
 {
 	if (left->type != right->type)
 	if (left->type != right->type)
 	{
 	{
-		show_debug(NULL, LIST_VARIABLE, "#MATH COMPUTE: COMPARING STRING WITH A NUMBER.");
+		show_debug(gtd->ses, LIST_VARIABLE, "#DEBUG MATH: COMPARING STRING WITH A NUMBER.");
 
 
 		return 0;
 		return 0;
 	}
 	}
@@ -1545,7 +1545,7 @@ long double tineval(struct session *ses, struct math_node *left, struct math_nod
 {
 {
 	if (left->type != right->type)
 	if (left->type != right->type)
 	{
 	{
-		show_debug(ses, LIST_VARIABLE, "#MATH COMPUTE: COMPARING %s WITH %s.", left->type == EXP_NUMBER ? "NUMBER" : "STRING", right->type == EXP_NUMBER ? "NUMBER" : "STRING");
+		show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: COMPARING %s WITH %s.", left->type == EXP_NUMBER ? "NUMBER" : "STRING", right->type == EXP_NUMBER ? "NUMBER" : "STRING");
 
 
 		return 0;
 		return 0;
 	}
 	}

+ 13 - 0
src/misc.c

@@ -151,6 +151,19 @@ DO_COMMAND(do_test)
 {
 {
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 
 
+	if (!strcmp(arg1, "pointers"))
+	{
+		char data = 'X';
+		char *test = &data;
+		unsigned long int index = (unsigned long int) test;
+
+		printf("data %c index %lu test %c\n", data, index, *test);
+
+		test = 0;
+
+		printf("data %c index %lu test %c\n", data, index, test[index]);
+	}
+
 	if (!strcmp(arg1, "gmcp"))
 	if (!strcmp(arg1, "gmcp"))
 	{
 	{
 		execute(ses, "%s", "#event {IAC SB GMCP} {#var {%0} {%1};#line debug #var {%0}}");
 		execute(ses, "%s", "#event {IAC SB GMCP} {#var {%0} {%1};#line debug #var {%0}}");

+ 17 - 1
src/net.c

@@ -322,7 +322,7 @@ void write_line_mud(struct session *ses, char *line, int size)
 	{
 	{
 		char buf[BUFFER_SIZE];
 		char buf[BUFFER_SIZE];
 
 
-		size = utf8_to_all(ses, line, buf);
+		size = utf8_to_all(ses, line, buf, size);
 
 
 		memcpy(line, buf, size);
 		memcpy(line, buf, size);
 
 
@@ -540,6 +540,7 @@ void readmud(struct session *ses)
 								str_cat(&ses->more_output, line);
 								str_cat(&ses->more_output, line);
 								ses->check_output = gtd->utime + (ses->packet_patch ? ses->packet_patch : 500000ULL);
 								ses->check_output = gtd->utime + (ses->packet_patch ? ses->packet_patch : 500000ULL);
 
 
+								check_all_events(ses, EVENT_FLAG_OUTPUT, 0, 0, "PACKET PATCH");
 								break;
 								break;
 							}
 							}
 						}
 						}
@@ -547,6 +548,8 @@ void readmud(struct session *ses)
 						{
 						{
 							str_cat(&ses->more_output, line);
 							str_cat(&ses->more_output, line);
 							ses->check_output = gtd->utime + (ses->packet_patch ? ses->packet_patch : 500000ULL);
 							ses->check_output = gtd->utime + (ses->packet_patch ? ses->packet_patch : 500000ULL);
+
+							check_all_events(ses, EVENT_FLAG_OUTPUT, 0, 0, "PACKET PATCH");
 							break;
 							break;
 						}
 						}
 					}
 					}
@@ -693,6 +696,19 @@ void process_mud_output(struct session *ses, char *linebuf, int prompt)
 		return;
 		return;
 	}
 	}
 
 
+	if (HAS_BIT(ses->event_flags, EVENT_FLAG_OUTPUT|EVENT_FLAG_CATCH))
+	{
+		strip_vt102_codes(linebuf, line);
+
+		check_all_events(ses, SUB_SEC|EVENT_FLAG_OUTPUT, 0, 3, "PROCESSED LINE", linebuf, line, ntos(prompt));
+
+		if (check_all_events(ses, SUB_SEC|EVENT_FLAG_CATCH, 0, 3, "CATCH PROCESSED LINE", linebuf, line, ntos(prompt)))
+		{
+			pop_call();
+			return;
+		}
+	}
+
 	add_line_buffer(ses, linebuf, prompt);
 	add_line_buffer(ses, linebuf, prompt);
 
 
 	if (ses == gtd->ses)
 	if (ses == gtd->ses)

+ 5 - 0
src/parse.c

@@ -1181,6 +1181,11 @@ void check_one_line_multi(struct session *ses, char *original, char *stripped)
 	{
 	{
 		check_all_actions_multi(ses, original, stripped, buf);
 		check_all_actions_multi(ses, original, stripped, buf);
 	}
 	}
+
+	if (!HAS_BIT(ses->list[LIST_SUBSTITUTE]->flags, LIST_FLAG_IGNORE))
+	{
+		check_all_substitutions_multi(ses, original, stripped);
+	}
 }
 }
 
 
 void check_one_line(struct session *ses, char *line)
 void check_one_line(struct session *ses, char *line)

+ 31 - 27
src/path.c

@@ -102,7 +102,7 @@ DO_PATH(path_start)
 {
 {
 	if (HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING))
 	if (HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING))
 	{
 	{
-		show_message(ses, LIST_COMMAND, "#PATH START: ERROR: YOU ARE ALREADY MAPPING A PATH.");
+		show_message(ses, LIST_COMMAND, "#ERROR: #PATH START: YOU ARE ALREADY MAPPING A PATH.");
 	}
 	}
 	else
 	else
 	{
 	{
@@ -300,7 +300,7 @@ DO_PATH(path_get)
 	}
 	}
 	else if (*arg2 == 0)
 	else if (*arg2 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH GET <INFO|LENGTH|MAPPING|POSITION|RUNNING> <VARIABLE NAME>");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH GET {INFO|LENGTH|MAPPING|POSITION|RUNNING} <VARIABLE>");
 	}
 	}
 	else if (is_abbrev(arg1, "INFO"))
 	else if (is_abbrev(arg1, "INFO"))
 	{
 	{
@@ -316,7 +316,7 @@ DO_PATH(path_get)
 			(root->list[root->update]->val64 - gtd->utime) < 10000 ? 0.01 :
 			(root->list[root->update]->val64 - gtd->utime) < 10000 ? 0.01 :
 			(root->list[root->update]->val64 - gtd->utime) / 1000000.0);
 			(root->list[root->update]->val64 - gtd->utime) / 1000000.0);
 
 
-		show_message(ses, LIST_COMMAND, "#PATH GET: PATH INFO SAVED TO {%s}", arg2);
+		show_message(ses, LIST_COMMAND, "#PATH GET: PATH INFO SAVED TO {%s}.", arg2);
 	}
 	}
 	else if (is_abbrev(arg1, "LENGTH"))
 	else if (is_abbrev(arg1, "LENGTH"))
 	{
 	{
@@ -324,7 +324,7 @@ DO_PATH(path_get)
 
 
 		set_nest_node_ses(ses, arg2, "%s", result);
 		set_nest_node_ses(ses, arg2, "%s", result);
 
 
-		show_message(ses, LIST_COMMAND, "#PATH GET: PATH LENGTH {%s} SAVED TO {%s}", result, arg2);
+		show_message(ses, LIST_COMMAND, "#PATH GET: PATH LENGTH {%s} SAVED TO {%s}.", result, arg2);
 	}
 	}
 	else if (is_abbrev(arg1, "MAPPING"))
 	else if (is_abbrev(arg1, "MAPPING"))
 	{
 	{
@@ -332,7 +332,7 @@ DO_PATH(path_get)
 
 
 		set_nest_node_ses(ses, arg2, "%s", result);
 		set_nest_node_ses(ses, arg2, "%s", result);
 
 
-		show_message(ses, LIST_COMMAND, "#PATH GET: PATH MAPPING {%s} SAVED TO {%s}", result, arg2);
+		show_message(ses, LIST_COMMAND, "#PATH GET: PATH MAPPING {%s} SAVED TO {%s}.", result, arg2);
 	}
 	}
 	else if (is_abbrev(arg1, "POSITION"))
 	else if (is_abbrev(arg1, "POSITION"))
 	{
 	{
@@ -340,7 +340,7 @@ DO_PATH(path_get)
 
 
 		set_nest_node_ses(ses, arg2, "%s", result);
 		set_nest_node_ses(ses, arg2, "%s", result);
 
 
-		show_message(ses, LIST_COMMAND, "#PATH GET: PATH POSITION {%s} SAVED TO {%s}", result, arg2);
+		show_message(ses, LIST_COMMAND, "#PATH GET: PATH POSITION {%s} SAVED TO {%s}.", result, arg2);
 	}
 	}
 	else if (is_abbrev(arg1, "RUNNING"))
 	else if (is_abbrev(arg1, "RUNNING"))
 	{
 	{
@@ -350,11 +350,11 @@ DO_PATH(path_get)
 			(root->list[root->update]->val64 - gtd->utime) < 10000 ? 0.01 :
 			(root->list[root->update]->val64 - gtd->utime) < 10000 ? 0.01 :
 			(root->list[root->update]->val64 - gtd->utime) / 1000000.0);
 			(root->list[root->update]->val64 - gtd->utime) / 1000000.0);
 
 
-		show_message(ses, LIST_COMMAND, "#PATH GET: PATH RUNNING {%s} SAVED TO {%s}", result, arg2);
+		show_message(ses, LIST_COMMAND, "#PATH GET: PATH RUNNING {%s} SAVED TO {%s}.", result, arg2);
 	}
 	}
 	else
 	else
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH GET <INFO|LENGTH|MAPPING|POSITION|RUNNING> <VARIABLE NAME>");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH GET {INFO|LENGTH|MAPPING|POSITION|RUNNING} <VARIABLE>");
 	}
 	}
 }
 }
 
 
@@ -373,7 +373,7 @@ DO_PATH(path_save)
 	}
 	}
 	else if (*arg1 == 0)
 	else if (*arg1 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH SAVE <BACKWARD|BOTH|FORWARD> <VARIABLE NAME>");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH SAVE {BACKWARD|BOTH|FORWARD} <VARIABLE>");
 	}
 	}
 	else if (*arg2 == 0)
 	else if (*arg2 == 0)
 	{
 	{
@@ -396,7 +396,7 @@ DO_PATH(path_save)
 		}
 		}
 		set_nest_node_ses(ses, arg2, "%s", result);
 		set_nest_node_ses(ses, arg2, "%s", result);
 
 
-		show_message(ses, LIST_COMMAND, "#PATH SAVE: BACKWARD PATH SAVED TO {%s}", arg2);
+		show_message(ses, LIST_COMMAND, "#PATH SAVE: BACKWARD PATH SAVED TO {%s}.", arg2);
 	}
 	}
 	else if (is_abbrev(arg1, "FORWARDS"))
 	else if (is_abbrev(arg1, "FORWARDS"))
 	{
 	{
@@ -427,7 +427,7 @@ DO_PATH(path_save)
 		}
 		}
 		set_nest_node_ses(ses, arg2, "%s", result);
 		set_nest_node_ses(ses, arg2, "%s", result);
 
 
-		show_message(ses, LIST_COMMAND, "#PATH SAVE: PATH SAVED TO {%s}", arg2);
+		show_message(ses, LIST_COMMAND, "#PATH SAVE: PATH SAVED TO {%s}.", arg2);
 	}
 	}
 	else if (is_abbrev(arg1, "LENGTH"))
 	else if (is_abbrev(arg1, "LENGTH"))
 	{
 	{
@@ -435,7 +435,7 @@ DO_PATH(path_save)
 
 
 		set_nest_node_ses(ses, arg2, "%s", result);
 		set_nest_node_ses(ses, arg2, "%s", result);
 
 
-		show_message(ses, LIST_COMMAND, "#PATH SAVE: PATH LENGTH SAVED TO {%s}", arg2);
+		show_message(ses, LIST_COMMAND, "#PATH SAVE: PATH LENGTH SAVED TO {%s}.", arg2);
 	}
 	}
 	else if (is_abbrev(arg1, "POSITION"))
 	else if (is_abbrev(arg1, "POSITION"))
 	{
 	{
@@ -443,11 +443,11 @@ DO_PATH(path_save)
 
 
 		set_nest_node_ses(ses, arg2, "%s", result);
 		set_nest_node_ses(ses, arg2, "%s", result);
 
 
-		show_message(ses, LIST_COMMAND, "#PATH SAVE: PATH POSITION SAVED TO {%s}", arg2);
+		show_message(ses, LIST_COMMAND, "#PATH SAVE: PATH POSITION SAVED TO {%s}.", arg2);
 	}
 	}
 	else
 	else
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH SAVE <BACKWARD|FORWARD> <VARIABLE NAME>");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH SAVE {BACKWARD|FORWARD} <VARIABLE>");
 	}
 	}
 }
 }
 
 
@@ -500,16 +500,12 @@ DO_PATH(path_delete)
 
 
 		delete_index_list(root, root->used - 1);
 		delete_index_list(root, root->used - 1);
 
 
-		if (root->update >= root->used)
-		{
-			root->update--;
-		}
+		root->update = URANGE(0, root->update, root->used);
 	}
 	}
 	else
 	else
 	{
 	{
 		tintin_printf(ses, "#PATH DELETE: NO MOVES LEFT.");
 		tintin_printf(ses, "#PATH DELETE: NO MOVES LEFT.");
 	}
 	}
-
 }
 }
 
 
 DO_PATH(path_insert)
 DO_PATH(path_insert)
@@ -522,7 +518,7 @@ DO_PATH(path_insert)
 
 
 	if (*arg1 == 0 && *arg2 == 0)
 	if (*arg1 == 0 && *arg2 == 0)
 	{
 	{
-		show_message(ses, LIST_COMMAND, "#PATH INSERT: ERROR: YOU MUST GIVE A COMMAND TO INSERT");
+		show_message(ses, LIST_COMMAND, "#ERROR: #PATH INSERT: YOU MUST GIVE A COMMAND TO INSERT.");
 	}
 	}
 	else
 	else
 	{
 	{
@@ -625,7 +621,7 @@ DO_PATH(path_walk)
 	}
 	}
 	else
 	else
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH WALK {FORWARD|BACKWARD}.");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH WALK {FORWARD|BACKWARD}");
 	}
 	}
 }
 }
 
 
@@ -638,7 +634,7 @@ DO_PATH(path_swap)
 
 
 	if (root->used == 0)
 	if (root->used == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#PATH SWAP: ERROR: PATH IS EMPTY.");
+		show_error(ses, LIST_COMMAND, "#ERROR: #PATH SWAP: PATH IS EMPTY.");
 
 
 		return;
 		return;
 	}
 	}
@@ -869,6 +865,10 @@ DO_PATH(path_goto)
 			show_message(ses, LIST_COMMAND, "#PATH GOTO: POSITION SET TO %d.", root->update + 1);
 			show_message(ses, LIST_COMMAND, "#PATH GOTO: POSITION SET TO %d.", root->update + 1);
 		}
 		}
 	}
 	}
+	else
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH GOTO {START|END|<POSITION>}");
+	}
 }
 }
 
 
 
 
@@ -913,6 +913,10 @@ DO_PATH(path_move)
 
 
 		show_message(ses, LIST_COMMAND, "#PATH MOVE: POSITION MOVED FROM %d TO %d.", last + 1, root->update + 1);
 		show_message(ses, LIST_COMMAND, "#PATH MOVE: POSITION MOVED FROM %d TO %d.", last + 1, root->update + 1);
 	}
 	}
+	else
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH MOVE <BACKWARD|FORWARD>");
+	}
 }
 }
 
 
 DO_PATH(path_undo)
 DO_PATH(path_undo)
@@ -921,21 +925,21 @@ DO_PATH(path_undo)
 
 
 	if (root->used == 0)
 	if (root->used == 0)
 	{
 	{
-		show_message(ses, LIST_COMMAND, "#PATH UNDO: ERROR: PATH IS EMPTY.");
+		show_message(ses, LIST_COMMAND, "#ERROR: #PATH UNDO: PATH IS EMPTY.");
 
 
 		return;
 		return;
 	}
 	}
 
 
 	if (root->update != root->used)
 	if (root->update != root->used)
 	{
 	{
-		show_message(ses, LIST_COMMAND, "#PATH UNDO: ERROR: YOUR POSITION IS NOT AT END OF PATH.");
+		show_message(ses, LIST_COMMAND, "#ERROR: #PATH UNDO: YOUR POSITION IS NOT AT END OF PATH.");
 	
 	
 		return;
 		return;
 	}
 	}
 
 
 	if (!HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING))
 	if (!HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING))
 	{
 	{
-		show_message(ses, LIST_COMMAND, "#PATH UNDO: ERROR: YOU ARE NOT CURRENTLY MAPPING A PATH.");
+		show_message(ses, LIST_COMMAND, "#ERROR: #PATH UNDO: YOU ARE NOT CURRENTLY MAPPING A PATH.");
 
 
 		return;
 		return;
 	}
 	}
@@ -1013,7 +1017,7 @@ DO_COMMAND(do_pathdir)
 	{
 	{
 		if (show_node_with_wild(ses, arg1, ses->list[LIST_PATHDIR]) == FALSE)
 		if (show_node_with_wild(ses, arg1, ses->list[LIST_PATHDIR]) == FALSE)
 		{
 		{
-			show_message(ses, LIST_PATHDIR, "#NO MATCH(ES) FOUND FOR {%s}.", arg1);
+			show_message(ses, LIST_PATHDIR, "#PATHDIR: #NO MATCHES FOUND FOR {%s}.", arg1);
 		}
 		}
 	}
 	}
 	else
 	else
@@ -1042,7 +1046,7 @@ DO_COMMAND(do_pathdir)
 
 
 		node->val32[0] = atoi(arg3);
 		node->val32[0] = atoi(arg3);
 
 
-		show_message(ses, LIST_PATHDIR, "#OK: DIRECTION {%s} WILL BE REVERSED AS {%s} @ {%d}.", arg1, arg2, atoi(arg3));
+		show_message(ses, LIST_PATHDIR, "#PATHDIR: DIRECTION {%s} WILL BE REVERSED AS {%s} @ {%d}.", arg1, arg2, atoi(arg3));
 	}
 	}
 	return ses;
 	return ses;
 }
 }

+ 9 - 1
src/port.c

@@ -65,7 +65,7 @@ DO_COMMAND(do_port)
 
 
 		if (port_table[cnt].fun != port_initialize && ses->port == NULL)
 		if (port_table[cnt].fun != port_initialize && ses->port == NULL)
 		{
 		{
-			tintin_printf(ses, "#PORT: You must initialize a port first.");
+			tintin_printf(ses, "#PORT: YOU MUST INITIALIZE A PORT FIRST.");
 
 
 			return ses;
 			return ses;
 		}
 		}
@@ -552,6 +552,14 @@ int process_port_input(struct session *ses, struct port_data *buddy)
 
 
 		input[size] = 0;
 		input[size] = 0;
 
 
+		check_all_events(ses, SUB_SEC|EVENT_FLAG_PORT, 0, 5, "PORT RECEIVED DATA", buddy->name, buddy->ip, ntos(buddy->port), input, ntos(size));
+
+		if (check_all_events(ses, SUB_SEC|EVENT_FLAG_CATCH, 0, 5, "CATCH PORT RECEIVED DATA", buddy->name, buddy->ip, ntos(buddy->port), input, ntos(size)))
+		{
+			pop_call();
+			return 0;
+		}
+
 		echo = buddy->intop;
 		echo = buddy->intop;
 
 
 		buddy->intop += server_translate_telopts(ses, buddy, (unsigned char *) input, size, (unsigned char *) buddy->inbuf, buddy->intop);
 		buddy->intop += server_translate_telopts(ses, buddy, (unsigned char *) input, size, (unsigned char *) buddy->inbuf, buddy->intop);

+ 15 - 15
src/regex.c

@@ -65,7 +65,7 @@ DO_COMMAND(do_regexp)
 
 
 	if (*arg3 == 0)
 	if (*arg3 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "SYNTAX: #REGEXP {string} {expression} {true} {false}.");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #REGEXP <TEXT> <EXPRESSION> <TRUE> [FALSE]");
 	}
 	}
 	else
 	else
 	{
 	{
@@ -90,14 +90,14 @@ DO_COMMAND(do_regexp)
 	return ses;
 	return ses;
 }
 }
 
 
-int regexp_compare(struct session *ses, pcre *nodepcre, char *str, char *exp, int option, int flag)
+int regexp_compare(struct session *ses, pcre *nodepcre, char *str, char *exp, int comp_option, int flag)
 {
 {
 	pcre *regex;
 	pcre *regex;
 	int i, j, matches;
 	int i, j, matches;
 
 
 	if (nodepcre == NULL)
 	if (nodepcre == NULL)
 	{
 	{
-		regex = regexp_compile(ses, exp, option);
+		regex = regexp_compile(ses, exp, comp_option);
 	}
 	}
 	else
 	else
 	{
 	{
@@ -189,17 +189,17 @@ int regexp_compare(struct session *ses, pcre *nodepcre, char *str, char *exp, in
 	return TRUE;
 	return TRUE;
 }
 }
 
 
-pcre *regexp_compile(struct session *ses, char *exp, int option)
+pcre *regexp_compile(struct session *ses, char *exp, int comp_option)
 {
 {
 	const char *error;
 	const char *error;
 	int i;
 	int i;
 /*
 /*
 	if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8))
 	if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8))
 	{
 	{
-		option |= PCRE_UTF8|PCRE_NO_UTF8_CHECK;
+		comp_option |= PCRE_UTF8|PCRE_NO_UTF8_CHECK;
 	}
 	}
 */
 */
-	return pcre_compile(exp, option, &error, &i, NULL);
+	return pcre_compile(exp, comp_option, &error, &i, NULL);
 }
 }
 
 
 
 
@@ -210,7 +210,7 @@ pcre *regexp_compile(struct session *ses, char *exp, int option)
 * in the text represented by the wildcards on success.                        *
 * in the text represented by the wildcards on success.                        *
 ******************************************************************************/
 ******************************************************************************/
 
 
-int check_one_regexp(struct session *ses, struct listnode *node, char *line, char *original, int option)
+int check_one_regexp(struct session *ses, struct listnode *node, char *line, char *original, int comp_option)
 {
 {
 	char *exp, *str;
 	char *exp, *str;
 
 
@@ -237,7 +237,7 @@ int check_one_regexp(struct session *ses, struct listnode *node, char *line, cha
 		str = line;
 		str = line;
 	}	
 	}	
 
 
-	return tintin_regexp(ses, node->regex, str, exp, option, REGEX_FLAG_ARG);
+	return tintin_regexp(ses, node->regex, str, exp, comp_option, REGEX_FLAG_ARG);
 }
 }
 
 
 /*
 /*
@@ -473,7 +473,7 @@ int tintin_regexp_check(struct session *ses, char *exp)
 //    3.4 If FIX is set the gtd->args index is used and valid tinexp is assumed
 //    3.4 If FIX is set the gtd->args index is used and valid tinexp is assumed
 //    3.4 return TRUE
 //    3.4 return TRUE
 
 
-int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int option, int flag)
+int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int comp_option, int flag)
 {
 {
 	char out[BUFFER_SIZE], *pti, *pto;
 	char out[BUFFER_SIZE], *pti, *pto;
 	int i, arg = 1, var = 1, fix = 0;
 	int i, arg = 1, var = 1, fix = 0;
@@ -518,7 +518,7 @@ int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int
 			case '\\':
 			case '\\':
 				if (pti[1] == 'n')
 				if (pti[1] == 'n')
 				{
 				{
-					SET_BIT(option, PCRE_MULTILINE);
+					SET_BIT(comp_option, PCRE_MULTILINE);
 				}
 				}
 				else if (pti[1] == 0)
 				else if (pti[1] == 0)
 				{
 				{
@@ -822,10 +822,10 @@ int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int
 	}
 	}
 	*pto = 0;
 	*pto = 0;
 
 
-	return regexp_compare(ses, nodepcre, str, out, option, flag + fix);
+	return regexp_compare(ses, nodepcre, str, out, comp_option, flag + fix);
 }
 }
 
 
-pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *exp, int option)
+pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *exp, int comp_option)
 {
 {
 	char out[BUFFER_SIZE], *pti, *pto;
 	char out[BUFFER_SIZE], *pti, *pto;
 
 
@@ -880,7 +880,7 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 				}
 				}
 				else if (pti[1] == 'n')
 				else if (pti[1] == 'n')
 				{
 				{
-					SET_BIT(option, PCRE_MULTILINE);
+					SET_BIT(comp_option, PCRE_MULTILINE);
 					SET_BIT(node->flags, NODE_FLAG_MULTI);
 					SET_BIT(node->flags, NODE_FLAG_MULTI);
 				}
 				}
 				else if (pti[1] == 0)
 				else if (pti[1] == 0)
@@ -1182,9 +1182,9 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 
 
 	if (HAS_BIT(node->flags, NODE_FLAG_COLOR) && *exp != '~')
 	if (HAS_BIT(node->flags, NODE_FLAG_COLOR) && *exp != '~')
 	{
 	{
-		show_error(ses, LIST_COMMAND, "\e[1;31mWARNING: REGEX MATCHES ESCAPE CODES BUT DOES NOT START WITH A '~' (%s)", exp);
+		show_error(ses, LIST_COMMAND, "#WARNING: REGEX {%s} MATCHES ESCAPE CODES BUT DOES NOT START WITH A '~'.", exp);
 	}
 	}
-	return regexp_compile(ses, out, option);
+	return regexp_compile(ses, out, comp_option);
 }
 }
 
 
 void tintin_macro_compile(char *input, char *output)
 void tintin_macro_compile(char *input, char *output)

+ 15 - 19
src/scan.c

@@ -105,7 +105,7 @@ DO_COMMAND(do_scan)
 		{
 		{
 			if (*arg1 == 0)
 			if (*arg1 == 0)
 			{
 			{
-				show_error(ses, LIST_COMMAND, "#SYNTAX: #SCAN {%s} {<FILENAME>}", scan_table[cnt].name);
+				show_error(ses, LIST_COMMAND, "#SYNTAX: #SCAN {%s} <FILENAME>", scan_table[cnt].name);
 
 
 				return ses;
 				return ses;
 			}
 			}
@@ -137,7 +137,7 @@ DO_COMMAND(do_scan)
 		return ses;
 		return ses;
 	}
 	}
 
 
-	show_error(ses, LIST_COMMAND, "\e[1;31mTHE SCAN COMMAND HAS CHANGED, EXECUTING #SCAN {TXT} {%s} INSTEAD.", cmd);
+	show_error(ses, LIST_COMMAND, "#WARNING: THE SCAN COMMAND HAS CHANGED, EXECUTING #SCAN {TXT} {%s} INSTEAD.", cmd);
 
 
 	ses = command(ses, do_scan, "{TXT} {%s}", cmd);
 	ses = command(ses, do_scan, "{TXT} {%s}", cmd);
 
 
@@ -254,21 +254,19 @@ DO_SCAN(scan_csv)
 
 
 		for (i = 1 ; i < 100 ; i++)
 		for (i = 1 ; i < 100 ; i++)
 		{
 		{
-			arg = get_arg_in_quotes(ses, arg, arg2, FALSE);
-
-			RESTRING(gtd->vars[i], arg2);
+			gtd->varc = i;
 
 
 			if (*arg == 0)
 			if (*arg == 0)
 			{
 			{
-				while (++i < 100)
+				while (i < 100)
 				{
 				{
-					if (*gtd->vars[i])
-					{
-						RESTRING(gtd->vars[i], "");
-					}
+					*gtd->vars[i++] = 0;
 				}
 				}
 				break;
 				break;
 			}
 			}
+			arg = get_arg_in_quotes(ses, arg, arg2, FALSE);
+
+			RESTRING(gtd->vars[i], arg2);
 		}
 		}
 
 
 		if (header == FALSE)
 		if (header == FALSE)
@@ -313,7 +311,7 @@ DO_SCAN(scan_dir)
 
 
 	if (*arg2 == 0)
 	if (*arg2 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "SYNTAX: #SCAN DIR {%s} <VARIABLE NAME>", arg1);
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCAN DIR {%s} <VARIABLE>", arg1);
 
 
 		return ses;
 		return ses;
 	}
 	}
@@ -522,21 +520,19 @@ DO_SCAN(scan_tsv)
 
 
 		for (i = 1 ; i < 100 ; i++)
 		for (i = 1 ; i < 100 ; i++)
 		{
 		{
-			arg = get_arg_stop_tabs(ses, arg, arg2, FALSE);
-
-			RESTRING(gtd->vars[i], arg2);
+			gtd->varc = i;
 
 
 			if (*arg == 0)
 			if (*arg == 0)
 			{
 			{
-				while (++i < 100)
+				while (i < 100)
 				{
 				{
-					if (*gtd->vars[i])
-					{
-						RESTRING(gtd->vars[i], "");
-					}
+					*gtd->vars[i++] = 0;
 				}
 				}
 				break;
 				break;
 			}
 			}
+			arg = get_arg_stop_tabs(ses, arg, arg2, FALSE);
+
+			RESTRING(gtd->vars[i], arg2);
 		}
 		}
 
 
 		if (header == FALSE)
 		if (header == FALSE)

+ 25 - 33
src/screen.c

@@ -441,7 +441,7 @@ DO_SCREEN(screen_clear)
 
 
 		if (bot_col == 0)
 		if (bot_col == 0)
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN CLEAR SQUARE {<ROW>} {<COL>} {<ROW>} {<COL>}");
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN CLEAR SQUARE <ROW> <COL> <ROW> <COL>");
 		}
 		}
 		else
 		else
 		{
 		{
@@ -587,7 +587,7 @@ DO_SCREEN(screen_fill)
 	}
 	}
 	else
 	else
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN FILL {TOP|BOT|LEFT|RIGHT|SCROLL|SPLIT|DEFAULT} {arg}");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN FILL {TOP|BOT|LEFT|RIGHT|SCROLL|SPLIT|DEFAULT} <ARGUMENT>");
 	}
 	}
 }
 }
 
 
@@ -616,16 +616,16 @@ DO_SCREEN(screen_get)
 {
 {
 	if (*arg1 == 0 || *arg2 == 0)
 	if (*arg1 == 0 || *arg2 == 0)
 	{
 	{
-		tintin_printf2(ses, "#SYNTAX: #SCREEN {GET} {FOCUS} {<VAR>}");
-		tintin_printf2(ses, "#SYNTAX: #SCREEN {GET} {ROWS|COLS|HEIGHT|WIDTH} {<VAR>}");
+		tintin_printf2(ses, "#SYNTAX: #SCREEN {GET} {FOCUS} <VAR>");
+		tintin_printf2(ses, "#SYNTAX: #SCREEN {GET} {ROWS|COLS|HEIGHT|WIDTH} <VAR>");
 		
 		
 		tintin_printf2(ses, "#SYNTAX: #SCREEN {GET} {CHAR_HEIGHT|CHAR_WIDTH}");
 		tintin_printf2(ses, "#SYNTAX: #SCREEN {GET} {CHAR_HEIGHT|CHAR_WIDTH}");
-		tintin_printf2(ses, "#SYNTAX: #SCREEN {GET} {SPLIT_TOP_BAR|SPLIT_BOT_BAR|SPLIT_LEFT_BAR|SPLIT_RIGHT_BAR} {<VAR>}");
-		tintin_printf2(ses, "#SYNTAX: #SCREEN {GET} {SCROLL_TOP_ROW|SCROLL_TOP_COL|SCROLL_BOT_ROW|SCROLL_BOT_COL} {<VAR>}");
-		tintin_printf2(ses, "#SYNTAX: #SCREEN {GET} {INPUT_TOP_ROW|INPUT_TOP_COL|INPUT_BOT_ROW|INPUT_BOT_COL} {<VAR>}");
-		tintin_printf2(ses, "#SYNTAX: #SCREEN {GET} {SCROLL_ROWS|SCROLL_COLS|INPUT_ROWS|INPUT_COLS} {<VAR>}");
-		tintin_printf2(ses, "#SYNTAX: #SCREEN {GET} {INPUT_NAME} {<VAR>}");
-		tintin_printf2(ses, "#SYNTAX: #SCREEN {GET} {CUR_ROW|CUR_COL} {<VAR>}");
+		tintin_printf2(ses, "#SYNTAX: #SCREEN {GET} {SPLIT_TOP_BAR|SPLIT_BOT_BAR|SPLIT_LEFT_BAR|SPLIT_RIGHT_BAR} <VAR>");
+		tintin_printf2(ses, "#SYNTAX: #SCREEN {GET} {SCROLL_TOP_ROW|SCROLL_TOP_COL|SCROLL_BOT_ROW|SCROLL_BOT_COL} <VAR>");
+		tintin_printf2(ses, "#SYNTAX: #SCREEN {GET} {INPUT_TOP_ROW|INPUT_TOP_COL|INPUT_BOT_ROW|INPUT_BOT_COL} <VAR>");
+		tintin_printf2(ses, "#SYNTAX: #SCREEN {GET} {SCROLL_ROWS|SCROLL_COLS|INPUT_ROWS|INPUT_COLS} <VAR>");
+		tintin_printf2(ses, "#SYNTAX: #SCREEN {GET} {INPUT_NAME} <VAR>");
+		tintin_printf2(ses, "#SYNTAX: #SCREEN {GET} {CUR_ROW|CUR_COL} <VAR>");
 
 
 		return;
 		return;
 	}
 	}
@@ -867,7 +867,7 @@ DO_SCREEN(screen_rescale)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {RESCALE} {HORIZONTALLY} {[WIDTH]}");
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {RESCALE} {HORIZONTALLY} [WIDTH]");
 		}
 		}
 	}
 	}
 	else if (is_abbrev(arg1, "VERTICALLY"))
 	else if (is_abbrev(arg1, "VERTICALLY"))
@@ -878,7 +878,7 @@ DO_SCREEN(screen_rescale)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {RESCALE} {VERTICALLY} {[HEIGHT]}");
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {RESCALE} {VERTICALLY} [HEIGHT]");
 		}
 		}
 	}
 	}
 	else if (*arg1 == 0 || is_math(ses, arg1))
 	else if (*arg1 == 0 || is_math(ses, arg1))
@@ -894,9 +894,9 @@ DO_SCREEN(screen_rescale)
 	}
 	}
 	else
 	else
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {RESCALE} {[HEIGHT]} {[WIDTH]}");
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {RESCALE} {VERTICALLY} {<HEIGHT>}");
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {RESCALE} {HORIZONTALLY} {<WIDTH>}");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {RESCALE} [HEIGHT] [WIDTH]");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {RESCALE} {VERTICALLY} <HEIGHT>");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {RESCALE} {HORIZONTALLY} <WIDTH>");
 	}
 	}
 }
 }
 
 
@@ -948,7 +948,7 @@ DO_SCREEN(screen_scrollregion)
 
 
 	if ((*arg1 && !is_math(ses, arg1)) || (*arg2 && !is_math(ses, arg2)))
 	if ((*arg1 && !is_math(ses, arg1)) || (*arg2 && !is_math(ses, arg2)))
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN SCROLLREGION {TOP ROW} {TOP COL} {BOT ROW} {BOT COL}");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN SCROLLREGION <TOP ROW> <TOP COL> <BOT ROW> <BOT COL>");
 
 
 		return;
 		return;
 	}
 	}
@@ -961,7 +961,7 @@ DO_SCREEN(screen_scrollregion)
 
 
 	if ((*arg1 && !is_math(ses, arg1)) || (*arg2 && !is_math(ses, arg2)))
 	if ((*arg1 && !is_math(ses, arg1)) || (*arg2 && !is_math(ses, arg2)))
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN SCROLL {TOP ROW} {TOP COL} {BOT ROW} {BOT COL}");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN SCROLL <TOP ROW> <TOP COL> <BOT ROW> <BOT COL>");
 
 
 		return;
 		return;
 	}
 	}
@@ -1002,7 +1002,7 @@ DO_SCREEN(screen_inputregion)
 
 
 	if (*arg1 == 0 || *arg2 == 0 || !is_math(ses, arg1) || !is_math(ses, arg2))
 	if (*arg1 == 0 || *arg2 == 0 || !is_math(ses, arg1) || !is_math(ses, arg2))
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN INPUTREGION {TOP ROW} {TOP COL} {BOT ROW} {BOT COL}");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN INPUTREGION <TOP ROW> <TOP COL> <BOT ROW> <BOT COL>");
 
 
 		return;
 		return;
 	}
 	}
@@ -1015,7 +1015,7 @@ DO_SCREEN(screen_inputregion)
 
 
 	if ((*arg1 && !is_math(ses, arg1)) || (*arg2 && !is_math(ses, arg2)))
 	if ((*arg1 && !is_math(ses, arg1)) || (*arg2 && !is_math(ses, arg2)))
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN INPUT {TOP ROW} {TOP COL} {BOT ROW} {BOT COL}");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN INPUT <TOP ROW> <TOP COL> <BOT ROW> <BOT COL>");
 
 
 		return;
 		return;
 	}
 	}
@@ -1076,7 +1076,7 @@ DO_SCREEN(screen_resize)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {SIZE} {HORIZONTALLY} {[COLS]}");
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {SIZE} {HORIZONTALLY} [COLS]");
 		}
 		}
 	}
 	}
 	else if (is_abbrev(arg1, "VERTICALLY"))
 	else if (is_abbrev(arg1, "VERTICALLY"))
@@ -1087,7 +1087,7 @@ DO_SCREEN(screen_resize)
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {SIZE} {VERTICALLY} {[ROWS]}");
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {SIZE} {VERTICALLY} [ROWS]");
 		}
 		}
 	}
 	}
 	else if (*arg1 != 0 || *arg2 != 0)
 	else if (*arg1 != 0 || *arg2 != 0)
@@ -1111,9 +1111,9 @@ DO_SCREEN(screen_resize)
 	}
 	}
 	else
 	else
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {SIZE} {[ROWS]} {[COLS]}");
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {SIZE} {VERTICALLY} {<ROWS>}");
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {SIZE} {HORIZONTALLY} {<COLS>}");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {SIZE} [ROWS] [COLS]");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {SIZE} {VERTICALLY} <ROWS>");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {SIZE} {HORIZONTALLY} <COLS>");
 	}
 	}
 }
 }
 
 
@@ -1173,7 +1173,7 @@ DO_SCREEN(screen_set)
 	}
 	}
 	else
 	else
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {SET} {COLS|ROWS|LABEL|NAME|TITLE} {<ARG>}");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {SET} {COLS|ROWS|LABEL|NAME|TITLE} <ARG>");
 	}
 	}
 }
 }
 
 
@@ -1440,16 +1440,9 @@ void screen_csit(struct session *ses, char *arg1, char *arg2, char *arg3)
 	}
 	}
 
 
 	print_stdout(0, 0, "\e[%s%s%s%s%st", arg1, *num1 ? XT_S : XT_V, *num1 && *num1 != ' ' ? num1 : "", *num2 ? XT_S : XT_V, *num2 && *num2 != ' ' ? num2 : "");
 	print_stdout(0, 0, "\e[%s%s%s%s%st", arg1, *num1 ? XT_S : XT_V, *num1 && *num1 != ' ' ? num1 : "", *num2 ? XT_S : XT_V, *num2 && *num2 != ' ' ? num2 : "");
-
-//	convert_meta(buf, debug, FALSE);
-
-//	tintin_printf2(gtd->ses, "\e[1;32m[%s] num1 (%s) num2 (%s) %s %s", num1, num2, debug, buf);
 }
 }
 
 
 
 
-
-
-
 /*
 /*
 	save cursor, goto top row, delete (bot - top) rows, restore cursor
 	save cursor, goto top row, delete (bot - top) rows, restore cursor
 */
 */
@@ -1570,7 +1563,6 @@ void erase_right_region(struct session *ses)
 	}
 	}
 }
 }
 
 
-
 void erase_square(struct session *ses, int top_row, int top_col, int bot_row, int bot_col)
 void erase_square(struct session *ses, int top_row, int top_col, int bot_row, int bot_col)
 {
 {
 	int row;
 	int row;

+ 21 - 19
src/session.c

@@ -145,7 +145,7 @@ DO_COMMAND(do_session)
 			return activate_session(sesptr);
 			return activate_session(sesptr);
 		}
 		}
 
 
-		tintin_puts2(ses, "#THAT SESSION IS NOT DEFINED.");
+		tintin_printf2(ses, "#SESSION {%s} IS NOT DEFINED.", arg1);
 	}
 	}
 	else
 	else
 	{
 	{
@@ -168,7 +168,7 @@ DO_COMMAND(do_snoop)
 
 
 		if (sesptr == NULL)
 		if (sesptr == NULL)
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#SNOOP: THERE'S NO SESSION NAMED {%s}", arg1);
+			show_error(ses, LIST_COMMAND, "#SNOOP: THERE'S NO SESSION NAMED {%s}.", arg1);
 			
 			
 			return ses;
 			return ses;
 		}
 		}
@@ -182,23 +182,23 @@ DO_COMMAND(do_snoop)
 	{
 	{
 		if (HAS_BIT(sesptr->flags, SES_FLAG_SNOOP))
 		if (HAS_BIT(sesptr->flags, SES_FLAG_SNOOP))
 		{
 		{
-			show_message(ses, LIST_COMMAND, "#SNOOP: NO LONGER SNOOPING SESSION '%s'", sesptr->name);
+			show_message(ses, LIST_COMMAND, "#SNOOP: NO LONGER SNOOPING SESSION '%s'.", sesptr->name);
 		}
 		}
 		else
 		else
 		{
 		{
-			show_message(ses, LIST_COMMAND, "#SNOOP: SNOOPING SESSION '%s'", sesptr->name);
+			show_message(ses, LIST_COMMAND, "#SNOOP: SNOOPING SESSION '%s'.", sesptr->name);
 		}
 		}
 		TOG_BIT(sesptr->flags, SES_FLAG_SNOOP);
 		TOG_BIT(sesptr->flags, SES_FLAG_SNOOP);
 	}
 	}
 	else if (is_abbrev(arg2, "ON"))
 	else if (is_abbrev(arg2, "ON"))
 	{
 	{
-		show_message(ses, LIST_COMMAND, "#SNOOP: SNOOPING SESSION '%s'", sesptr->name);
+		show_message(ses, LIST_COMMAND, "#SNOOP: SNOOPING SESSION '%s'.", sesptr->name);
 
 
 		SET_BIT(sesptr->flags, SES_FLAG_SNOOP);
 		SET_BIT(sesptr->flags, SES_FLAG_SNOOP);
 	}
 	}
 	else if (is_abbrev(arg2, "OFF"))
 	else if (is_abbrev(arg2, "OFF"))
 	{
 	{
-		show_message(ses, LIST_COMMAND, "#SNOOP: NO LONGER SNOOPING SESSION '%s'", sesptr->name);
+		show_message(ses, LIST_COMMAND, "#SNOOP: NO LONGER SNOOPING SESSION '%s'.", sesptr->name);
 		DEL_BIT(sesptr->flags, SES_FLAG_SNOOP);
 		DEL_BIT(sesptr->flags, SES_FLAG_SNOOP);
 	}
 	}
 	else if (is_abbrev(arg2, "SCROLL"))
 	else if (is_abbrev(arg2, "SCROLL"))
@@ -209,33 +209,33 @@ DO_COMMAND(do_snoop)
 		{
 		{
 			if (HAS_BIT(sesptr->flags, SES_FLAG_SNOOPSCROLL))
 			if (HAS_BIT(sesptr->flags, SES_FLAG_SNOOPSCROLL))
 			{
 			{
-				show_message(ses, LIST_COMMAND, "#SNOOP: NO LONGER SNOOPING SCROLL REGION OF SESSION '%s'", sesptr->name);
+				show_message(ses, LIST_COMMAND, "#SNOOP: NO LONGER SNOOPING SCROLL REGION OF SESSION '%s'.", sesptr->name);
 			}
 			}
 			else
 			else
 			{
 			{
-				show_message(ses, LIST_COMMAND, "#SNOOP: SNOOPING SCROLL REGION OF SESSION '%s'", sesptr->name);
+				show_message(ses, LIST_COMMAND, "#SNOOP: SNOOPING SCROLL REGION OF SESSION '%s'.", sesptr->name);
 			}
 			}
 			TOG_BIT(sesptr->flags, SES_FLAG_SNOOPSCROLL);
 			TOG_BIT(sesptr->flags, SES_FLAG_SNOOPSCROLL);
 		}
 		}
 		else if (is_abbrev(arg2, "ON"))
 		else if (is_abbrev(arg2, "ON"))
 		{
 		{
-			show_message(ses, LIST_COMMAND, "#SNOOP: SNOOPING SCROLL REGION OF SESSION '%s'", sesptr->name);
+			show_message(ses, LIST_COMMAND, "#SNOOP: SNOOPING SCROLL REGION OF SESSION '%s'.", sesptr->name);
 
 
 			SET_BIT(sesptr->flags, SES_FLAG_SNOOPSCROLL);
 			SET_BIT(sesptr->flags, SES_FLAG_SNOOPSCROLL);
 		}
 		}
 		else if (is_abbrev(arg2, "OFF"))
 		else if (is_abbrev(arg2, "OFF"))
 		{
 		{
-			show_message(ses, LIST_COMMAND, "#SNOOP: NO LONGER SNOOPING SCROLL REGION OF SESSION '%s'", sesptr->name);
+			show_message(ses, LIST_COMMAND, "#SNOOP: NO LONGER SNOOPING SCROLL REGION OF SESSION '%s'.", sesptr->name);
 			DEL_BIT(sesptr->flags, SES_FLAG_SNOOPSCROLL);
 			DEL_BIT(sesptr->flags, SES_FLAG_SNOOPSCROLL);
 		}
 		}
 		else
 		else
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: #SNOOP {session} {SCROLL} {ON|OFF}");
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #SNOOP <SESSION> {SCROLL} {ON|OFF}");
 		}
 		}
 	}
 	}
 	else
 	else
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #SNOOP {session} {ON|OFF|SCROLL}");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SNOOP <SESSION> {ON|OFF|SCROLL}");
 	}
 	}
 	return ses;
 	return ses;
 }
 }
@@ -376,7 +376,7 @@ struct session *new_session(struct session *ses, char *name, char *arg, int desc
 	{
 	{
 		if (*host == 0)
 		if (*host == 0)
 		{
 		{
-			tintin_puts2(ses, "#HEY! SPECIFY AN ADDRESS WILL YOU?");
+			show_error(ses, LIST_COMMAND, "#ERROR: #SESSION {%s} {%s}: YOU MUST SPECIFY AN ADDRESS.", name, host);
 
 
 			pop_call();
 			pop_call();
 			return ses;
 			return ses;
@@ -662,16 +662,18 @@ void cleanup_session(struct session *ses)
 
 
 	if (ses->socket)
 	if (ses->socket)
 	{
 	{
+		if (HAS_BIT(ses->flags, SES_FLAG_CONNECTED) && !HAS_BIT(ses->flags, SES_FLAG_LINKLOST))
+		{
+			if (shutdown(ses->socket, SHUT_RDWR) == -1)
+			{
+				syserr_printf(ses, "cleanup_session: shutdown");
+			}
+		}
+
 		if (close(ses->socket) == -1)
 		if (close(ses->socket) == -1)
 		{
 		{
 			syserr_printf(ses, "cleanup_session: close");
 			syserr_printf(ses, "cleanup_session: close");
 		}
 		}
-/*		else
-		{
-			int status;
-
-			wait(&status);
-		}*/
 
 
 		// the PID is stored in the session's port.
 		// the PID is stored in the session's port.
 
 

+ 47 - 6
src/show.c

@@ -104,6 +104,8 @@ DO_COMMAND(do_echo)
 		arg += strlen(arg);
 		arg += strlen(arg);
 	}
 	}
 
 
+	prompt = is_suffix(arg1, "\\") && !is_suffix(arg1, "\\\\");
+
 	substitute(ses, arg1, arg1, SUB_COL|SUB_ESC);
 	substitute(ses, arg1, 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, arg2, GET_ONE, SUB_VAR|SUB_FUN);
@@ -116,8 +118,6 @@ DO_COMMAND(do_echo)
 		return ses;
 		return ses;
 	}
 	}
 
 
-	prompt = is_suffix(arg1, "\\") && !is_suffix(arg1, "\\\\");
-
 	str_cpy_printf(&out, "%s%s%s", COLOR_TEXT, arg1, COLOR_TEXT);
 	str_cpy_printf(&out, "%s%s%s", COLOR_TEXT, arg1, COLOR_TEXT);
 
 
 	tintin_puts3(ses, out, prompt);
 	tintin_puts3(ses, out, prompt);
@@ -157,6 +157,11 @@ void show_message(struct session *ses, int index, char *format, ...)
 
 
 	display:
 	display:
 
 
+	if (check_all_events(ses, EVENT_FLAG_SYSTEM, 1, 0, "REFORMAT %s", format))
+	{
+		format = get_variable_def(ses, "result", format);
+	}
+
 	va_start(args, format);
 	va_start(args, format);
 
 
 	if (vasprintf(&buffer, format, args) == -1)
 	if (vasprintf(&buffer, format, args) == -1)
@@ -211,6 +216,11 @@ void show_error(struct session *ses, int index, char *format, ...)
 
 
 	push_call("show_error(%p,%p,%p)",ses,index,format);
 	push_call("show_error(%p,%p,%p)",ses,index,format);
 
 
+	if (check_all_events(ses, EVENT_FLAG_SYSTEM, 1, 0, "REFORMAT %s", format))
+	{
+		format = get_variable_def(ses, "result", format);
+	}
+
 	va_start(args, format);
 	va_start(args, format);
 	if (vasprintf(&buffer, format, args) == -1)
 	if (vasprintf(&buffer, format, args) == -1)
 	{
 	{
@@ -278,8 +288,19 @@ void show_debug(struct session *ses, int index, char *format, ...)
 		return;
 		return;
 	}
 	}
 
 
+	if (check_all_events(ses, EVENT_FLAG_SYSTEM, 1, 0, "REFORMAT %s", format))
+	{
+		format = get_variable_def(ses, "result", format);
+	}
+
 	va_start(args, format);
 	va_start(args, format);
-	vasprintf(&buffer, format, args);
+
+	if (vasprintf(&buffer, format, args) == -1)
+	{
+		syserr_printf(ses, "show_debug(%s): vasprintf:", format);
+
+		buffer = strdup("vasprintf error");
+	}
 	va_end(args);
 	va_end(args);
 
 
 	if (gtd->level->debug || HAS_BIT(root->flags, LIST_FLAG_DEBUG))
 	if (gtd->level->debug || HAS_BIT(root->flags, LIST_FLAG_DEBUG))
@@ -430,8 +451,18 @@ void tintin_header(struct session *ses, int width, char *format, ...)
 		return;
 		return;
 	}
 	}
 
 
+	if (check_all_events(ses, EVENT_FLAG_SYSTEM, 1, 0, "REFORMAT %s", format))
+	{
+		format = get_variable_def(ses, "result", format);
+	}
+
 	va_start(args, format);
 	va_start(args, format);
-	vasprintf(&title, format, args);
+	if (vasprintf(&title, format, args) == -1)
+	{
+		syserr_printf(ses, "tintin_header(%s): vasprintf:", format);
+
+		buffer = strdup("vasprintf error");
+	}
 	va_end(args);
 	va_end(args);
 
 
 	if ((int) strlen(title) > cols - 2)
 	if ((int) strlen(title) > cols - 2)
@@ -469,6 +500,11 @@ void tintin_printf(struct session *ses, char *format, ...)
 
 
 	push_call("tintin_printf(%p,%p,...)",ses,format);
 	push_call("tintin_printf(%p,%p,...)",ses,format);
 
 
+	if (check_all_events(ses, EVENT_FLAG_SYSTEM, 1, 0, "REFORMAT %s", format))
+	{
+		format = get_variable_def(ses, "result", format);
+	}
+
 	buffer = str_alloc_stack(0);
 	buffer = str_alloc_stack(0);
 
 
 	va_start(args, format);
 	va_start(args, format);
@@ -488,6 +524,11 @@ void tintin_printf2(struct session *ses, char *format, ...)
 
 
 	push_call("tintin_printf2(%p,%p,...)",ses,format);
 	push_call("tintin_printf2(%p,%p,...)",ses,format);
 
 
+	if (check_all_events(ses, EVENT_FLAG_SYSTEM, 1, 0, "REFORMAT %s", format))
+	{
+		format = get_variable_def(ses, "result", format);
+	}
+
 	va_start(args, format);
 	va_start(args, format);
 	if (vasprintf(&buffer, format, args) == -1)
 	if (vasprintf(&buffer, format, args) == -1)
 	{
 	{
@@ -511,12 +552,12 @@ void tintin_printf3(struct session *ses, char *format, ...)
 	char *buffer;
 	char *buffer;
 	va_list args;
 	va_list args;
 
 
-	push_call("tintin_printf2(%p,%p,...)",ses,format);
+	push_call("tintin_printf3(%p,%p,...)",ses,format);
 
 
 	va_start(args, format);
 	va_start(args, format);
 	if (vasprintf(&buffer, format, args) == -1)
 	if (vasprintf(&buffer, format, args) == -1)
 	{
 	{
-		syserr_printf(ses, "tintin_printf2: vasprintf:");
+		syserr_printf(ses, "tintin_printf3: vasprintf:");
 
 
 		pop_call();
 		pop_call();
 		return;
 		return;

+ 3 - 3
src/split.c

@@ -56,7 +56,7 @@ DO_COMMAND(do_split)
 
 
 		if ((*arg1 && !is_math(ses, arg1)) || (*arg2 && !is_math(ses, arg2)))
 		if ((*arg1 && !is_math(ses, arg1)) || (*arg2 && !is_math(ses, arg2)))
 		{
 		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: #SPLIT {TOP BAR} {BOT BAR} {LEFT BAR} {RIGHT BAR}");
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #SPLIT [TOP BAR] [BOTTOM BAR] [LEFT BAR] [RIGHT BAR] [INPUT BAR]");
 
 
 			return ses;
 			return ses;
 		}
 		}
@@ -162,12 +162,12 @@ void init_split(struct session *ses, int top_row, int top_col, int bot_row, int
 	ses->split->top_col = URANGE(1, ses->split->top_col, gtd->screen->cols - 2);
 	ses->split->top_col = URANGE(1, ses->split->top_col, gtd->screen->cols - 2);
 	ses->split->bot_row = URANGE(ses->split->top_row + 1,  ses->split->bot_row, gtd->screen->rows - 1);
 	ses->split->bot_row = URANGE(ses->split->top_row + 1,  ses->split->bot_row, gtd->screen->rows - 1);
 	ses->split->bot_col = URANGE(ses->split->top_col + 1, ses->split->bot_col, gtd->screen->cols);
 	ses->split->bot_col = URANGE(ses->split->top_col + 1, ses->split->bot_col, gtd->screen->cols);
-
+/*
 	ses->split->sav_top_row = ses->split->top_row - 1;
 	ses->split->sav_top_row = ses->split->top_row - 1;
 	ses->split->sav_top_col = ses->split->top_col - 1;
 	ses->split->sav_top_col = ses->split->top_col - 1;
 	ses->split->sav_bot_row = gtd->screen->rows - ses->split->bot_row - 1;
 	ses->split->sav_bot_row = gtd->screen->rows - ses->split->bot_row - 1;
 	ses->split->sav_bot_col = gtd->screen->cols - ses->split->bot_col;
 	ses->split->sav_bot_col = gtd->screen->cols - ses->split->bot_col;
-
+*/
 	ses->wrap = ses->split->bot_col - (ses->split->top_col - 1);
 	ses->wrap = ses->split->bot_col - (ses->split->top_col - 1);
 
 
 	scroll_region(ses, ses->split->top_row, ses->split->bot_row);
 	scroll_region(ses, ses->split->top_row, ses->split->bot_row);

+ 2 - 1
src/ssl.c

@@ -45,7 +45,7 @@ DO_COMMAND(do_ssl)
 
 
 	if (*arg1 == 0 || *arg == 0)
 	if (*arg1 == 0 || *arg == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #SSL {name} {host} {port}");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SSL <NAME> <HOST> <PORT>");
 	}
 	}
 	else
 	else
 	{
 	{
@@ -70,6 +70,7 @@ gnutls_session_t ssl_negotiate(struct session *ses)
 	gnutls_set_default_priority(ssl_ses);
 	gnutls_set_default_priority(ssl_ses);
 	gnutls_credentials_set(ssl_ses, GNUTLS_CRD_CERTIFICATE, ssl_cred);
 	gnutls_credentials_set(ssl_ses, GNUTLS_CRD_CERTIFICATE, ssl_cred);
 	gnutls_transport_set_ptr(ssl_ses, (gnutls_transport_ptr_t) (long int) ses->socket);
 	gnutls_transport_set_ptr(ssl_ses, (gnutls_transport_ptr_t) (long int) ses->socket);
+	gnutls_server_name_set(ssl_ses, GNUTLS_NAME_DNS, ses->session_host, strlen(ses->session_host));
 
 
 	do 
 	do 
 	{
 	{

+ 7 - 8
src/substitute.c

@@ -1201,22 +1201,21 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 
 
 					for (i = 1 ; i < 100 ; i++)
 					for (i = 1 ; i < 100 ; i++)
 					{
 					{
-						pte = get_arg_in_braces(ses, pte, temp, GET_ALL);
-
-						RESTRING(gtd->vars[i], temp);
-
-						gtd->varc = i + 1;
+						gtd->varc = i;
 
 
 						if (*pte == 0)
 						if (*pte == 0)
 						{
 						{
-							while (++i < 100)
+							while (i < 100)
 							{
 							{
-								*gtd->vars[i] = 0;
+								*gtd->vars[i++] = 0;
 							}
 							}
-
 							break;
 							break;
 						}
 						}
 
 
+						pte = get_arg_in_braces(ses, pte, temp, GET_ALL);
+
+						RESTRING(gtd->vars[i], temp);
+
 						if (*pte == COMMAND_SEPARATOR)
 						if (*pte == COMMAND_SEPARATOR)
 						{
 						{
 							pte++;
 							pte++;

+ 6 - 6
src/system.c

@@ -54,7 +54,7 @@ DO_COMMAND(do_run)
 
 
 	if (*arg1 == 0 || *arg2 == 0)
 	if (*arg1 == 0 || *arg2 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #RUN {NAME} {SYSTEM SHELL COMMAND}");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #RUN <NAME> <SHELL COMMAND>");
 		
 		
 		return ses;
 		return ses;
 	}
 	}
@@ -104,7 +104,7 @@ DO_COMMAND(do_script)
 
 
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SCRIPT: ONE ARGUMENT REQUIRED.");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCRIPT <VARIABLE> <SHELL COMMAND>");
 	}
 	}
 	else if (*arg2 == 0)
 	else if (*arg2 == 0)
 	{
 	{
@@ -282,12 +282,12 @@ DO_COMMAND(do_system)
 
 
 	if (*arg1 == 0)
 	if (*arg1 == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #SYSTEM {COMMAND}");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SYSTEM <COMMAND>");
 		
 		
 		return ses;
 		return ses;
 	}
 	}
 
 
-	show_message(ses, LIST_COMMAND, "#OK: EXECUTING '%s'", arg1);
+	show_message(ses, LIST_COMMAND, "#SYSTEM: EXECUTING {%s}.", arg1);
 
 
 	if (!HAS_BIT(gtd->ses->flags, SES_FLAG_READMUD) && IS_SPLIT(gtd->ses))
 	if (!HAS_BIT(gtd->ses->flags, SES_FLAG_READMUD) && IS_SPLIT(gtd->ses))
 	{
 	{
@@ -322,7 +322,7 @@ DO_COMMAND(do_textin)
 
 
 	if ((fp = fopen(arg1, "r")) == NULL)
 	if ((fp = fopen(arg1, "r")) == NULL)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#ERROR: #TEXTIN {%s} - FILE NOT FOUND.", arg1);
+		show_error(ses, LIST_COMMAND, "#ERROR: #TEXTIN {%s}: FILE NOT FOUND.", arg1);
 		
 		
 		return ses;
 		return ses;
 	}
 	}
@@ -345,7 +345,7 @@ DO_COMMAND(do_textin)
 	}
 	}
 	fclose(fp);
 	fclose(fp);
 
 
-	show_message(ses, LIST_COMMAND, "#TEXTIN {%s} - FILE READ.", arg1);
+	show_message(ses, LIST_COMMAND, "#TEXTIN {%s}: FILE READ.", arg1);
 
 
 	return ses;
 	return ses;
 }
 }

+ 4 - 2
src/tables.c

@@ -690,6 +690,7 @@ struct cursor_type cursor_table[] =
 	{     "RESET MACRO",        "",                                               "",            CURSOR_FLAG_GET_ALL,     cursor_macro,                 "RESET"     }, // obsolete
 	{     "RESET MACRO",        "",                                               "",            CURSOR_FLAG_GET_ALL,     cursor_macro,                 "RESET"     }, // obsolete
 	{     "SET",                "Insert given string at cursor",                  "",            CURSOR_FLAG_GET_ONE,     cursor_set,                   ""          },
 	{     "SET",                "Insert given string at cursor",                  "",            CURSOR_FLAG_GET_ONE,     cursor_set,                   ""          },
 	{     "SOFT ENTER",         "Create a new line in edit mode.",                "\e[13;2u",    CURSOR_FLAG_GET_ALL,     cursor_soft_enter,            ""          },
 	{     "SOFT ENTER",         "Create a new line in edit mode.",                "\e[13;2u",    CURSOR_FLAG_GET_ALL,     cursor_soft_enter,            ""          },
+	{     "ESCAPE ENTER",       "Process multi-line input.",                      "\e[13;5u",    CURSOR_FLAG_GET_ALL,     cursor_escape_enter,          ""          },
 	{     "SUSPEND",            "Suspend program, return with fg",                "",           CURSOR_FLAG_GET_ALL,     cursor_suspend,               ""          },
 	{     "SUSPEND",            "Suspend program, return with fg",                "",           CURSOR_FLAG_GET_ALL,     cursor_suspend,               ""          },
 	{     "TAB",                "<LIST|SCROLLBACK> <BACKWARD|FORWARD>",           "",            CURSOR_FLAG_GET_ONE,     cursor_tab,                   ""          },
 	{     "TAB",                "<LIST|SCROLLBACK> <BACKWARD|FORWARD>",           "",            CURSOR_FLAG_GET_ONE,     cursor_tab,                   ""          },
 	{     "TAB L S BACKWARD",   "",                                               "\e[Z",        CURSOR_FLAG_GET_ALL,     cursor_tab,                   "L S B"     }, // shift tab
 	{     "TAB L S BACKWARD",   "",                                               "\e[Z",        CURSOR_FLAG_GET_ALL,     cursor_tab,                   "L S B"     }, // shift tab
@@ -817,6 +818,7 @@ struct event_type event_table[] =
 	{    "MONTH",                                  0, EVENT_FLAG_TIME,     "TIME",      "month or given month"       },
 	{    "MONTH",                                  0, EVENT_FLAG_TIME,     "TIME",      "month or given month"       },
 	{    "MOVED ",                                 0, EVENT_FLAG_MOUSE,    "MOUSE",     "mouse is moved"             },
 	{    "MOVED ",                                 0, EVENT_FLAG_MOUSE,    "MOUSE",     "mouse is moved"             },
 	{    "NO SESSION ACTIVE",                      0, EVENT_FLAG_INPUT,    "INPUT",     "input on startup session"   },
 	{    "NO SESSION ACTIVE",                      0, EVENT_FLAG_INPUT,    "INPUT",     "input on startup session"   },
+	{    "PACKET PATCH",                           0, EVENT_FLAG_OUTPUT,   "OUTPUT",    "broken packet detected"     },
 	{    "PORT CONNECTION",                        0, EVENT_FLAG_PORT,     "PORT",      "socket connects"            },
 	{    "PORT CONNECTION",                        0, EVENT_FLAG_PORT,     "PORT",      "socket connects"            },
 	{    "PORT DISCONNECTION",                     0, EVENT_FLAG_PORT,     "PORT",      "socket disconnects"         },
 	{    "PORT DISCONNECTION",                     0, EVENT_FLAG_PORT,     "PORT",      "socket disconnects"         },
 	{    "PORT INITIALIZED",                       0, EVENT_FLAG_PORT,     "PORT",      "port is initialized"        },
 	{    "PORT INITIALIZED",                       0, EVENT_FLAG_PORT,     "PORT",      "port is initialized"        },
@@ -826,6 +828,7 @@ struct event_type event_table[] =
 	{    "PORT UNINITIALIZED",                     0, EVENT_FLAG_PORT,     "PORT",      "port is uninitialized"      },
 	{    "PORT UNINITIALIZED",                     0, EVENT_FLAG_PORT,     "PORT",      "port is uninitialized"      },
 	{    "PRESSED ",                               0, EVENT_FLAG_MOUSE,    "MOUSE",     "mouse button is pressed"    },
 	{    "PRESSED ",                               0, EVENT_FLAG_MOUSE,    "MOUSE",     "mouse button is pressed"    },
 	{    "PROCESSED KEYPRESS",                     0, EVENT_FLAG_INPUT,    "INPUT",     "after a regular keypress"   },
 	{    "PROCESSED KEYPRESS",                     0, EVENT_FLAG_INPUT,    "INPUT",     "after a regular keypress"   },
+	{    "PROCESSED LINE",                         0, EVENT_FLAG_OUTPUT,   "OUTPUT",    "after triggers have fired"  },
 	{    "PROGRAM START",                          0, EVENT_FLAG_SYSTEM,   "SYSTEM",    "main session starts"        },
 	{    "PROGRAM START",                          0, EVENT_FLAG_SYSTEM,   "SYSTEM",    "main session starts"        },
 	{    "PROGRAM TERMINATION",                    0, EVENT_FLAG_SYSTEM,   "SYSTEM",    "main session exits"         },
 	{    "PROGRAM TERMINATION",                    0, EVENT_FLAG_SYSTEM,   "SYSTEM",    "main session exits"         },
 	{    "READ ERROR",                             0, EVENT_FLAG_SYSTEM,   "SYSTEM",    "the read command fails"     },
 	{    "READ ERROR",                             0, EVENT_FLAG_SYSTEM,   "SYSTEM",    "the read command fails"     },
@@ -837,6 +840,7 @@ struct event_type event_table[] =
 	{    "RECEIVED LINE",                          0, EVENT_FLAG_OUTPUT,   "OUTPUT",    "a new line is received"     },
 	{    "RECEIVED LINE",                          0, EVENT_FLAG_OUTPUT,   "OUTPUT",    "a new line is received"     },
 	{    "RECEIVED OUTPUT",                        0, EVENT_FLAG_OUTPUT,   "OUTPUT",    "bulk output is received"    },
 	{    "RECEIVED OUTPUT",                        0, EVENT_FLAG_OUTPUT,   "OUTPUT",    "bulk output is received"    },
 	{    "RECEIVED PROMPT",                        0, EVENT_FLAG_OUTPUT,   "OUTPUT",    "a prompt is received"       },
 	{    "RECEIVED PROMPT",                        0, EVENT_FLAG_OUTPUT,   "OUTPUT",    "a prompt is received"       },
+	{    "REFORMAT ",                              0, EVENT_FLAG_SYSTEM,   "SYSTEM",    "system format message"      },
 	{    "RELEASED ",                              0, EVENT_FLAG_MOUSE,    "MOUSE",     "mouse button is released"   },
 	{    "RELEASED ",                              0, EVENT_FLAG_MOUSE,    "MOUSE",     "mouse button is released"   },
 	{    "SCAN CSV HEADER",                        0, EVENT_FLAG_SCAN,     "SCAN",      "scanning a csv file"        },
 	{    "SCAN CSV HEADER",                        0, EVENT_FLAG_SCAN,     "SCAN",      "scanning a csv file"        },
 	{    "SCAN CSV LINE",                          0, EVENT_FLAG_SCAN,     "SCAN",      "scanning a csv file"        },
 	{    "SCAN CSV LINE",                          0, EVENT_FLAG_SCAN,     "SCAN",      "scanning a csv file"        },
@@ -924,13 +928,11 @@ struct path_type path_table[] =
 
 
 struct history_type history_table[] =
 struct history_type history_table[] =
 {
 {
-//	{    "CHARACTER",         history_character,   "Set the character used for repeating commands." },
 	{    "DELETE",            history_delete,      "Delete last command history entry."             },
 	{    "DELETE",            history_delete,      "Delete last command history entry."             },
 	{    "GET",               history_get,         "Store in given variable a given index or range." },
 	{    "GET",               history_get,         "Store in given variable a given index or range." },
 	{    "INSERT",            history_insert,      "Insert a new command history entry."            },
 	{    "INSERT",            history_insert,      "Insert a new command history entry."            },
 	{    "LIST",              history_list,        "Display command history list."                  },
 	{    "LIST",              history_list,        "Display command history list."                  },
 	{    "READ",              history_read,        "Read a command history list from file."         },
 	{    "READ",              history_read,        "Read a command history list from file."         },
-//	{    "SIZE",              history_size,        "The size of the command history."               },
 	{    "WRITE",             history_write,       "Write a command history list to file."          },
 	{    "WRITE",             history_write,       "Write a command history list to file."          },
 	{    "",                  NULL,                ""                                               }
 	{    "",                  NULL,                ""                                               }
 };
 };

+ 20 - 20
src/telnet.h

@@ -29,26 +29,26 @@
 	telnet protocol.
 	telnet protocol.
 */
 */
 
 
-#define     IAC     255
-#define     DONT    254
-#define     DO      253
-#define     WONT    252
-#define     WILL    251
-#define     SB      250
-#define     GA      249   /* Used for prompt marking */
-#define     EL      248
-#define     EC      247
-#define     AYT     246
-#define     AO      245
-#define     IP      244
-#define     BREAK   243
-#define     DM      242
-#define     NOP     241
-#define     SE      240
-#define     EOR     239   /* Used for prompt marking */
-#define     ABORT   238
-#define     SUSP    237
-#define     xEOF    236
+#define     IAC     255 // FF
+#define     DONT    254 // FE
+#define     DO      253 // FD
+#define     WONT    252 // FC
+#define     WILL    251 // FB
+#define     SB      250 // FA
+#define     GA      249 // F9  Used for prompt marking
+#define     EL      248 // F8
+#define     EC      247 // F7
+#define     AYT     246 // F6
+#define     AO      245 // F5
+#define     IP      244 // F4
+#define     BREAK   243 // F3
+#define     DM      242 // F2
+#define     NOP     241 // F1
+#define     SE      240 // F0
+#define     EOR     239 // EF  Used for prompt marking
+#define     ABORT   238 // EE
+#define     SUSP    237 // ED
+#define     xEOF    236 // EC
 
 
 /*
 /*
 	telnet options
 	telnet options

+ 17 - 44
src/telopt_client.c

@@ -629,21 +629,7 @@ int client_recv_sb_ttype(struct session *ses, int cplen, unsigned char *cpsrc)
 	if (HAS_BIT(ses->telopts, TELOPT_FLAG_MTTS))
 	if (HAS_BIT(ses->telopts, TELOPT_FLAG_MTTS))
 	{
 	{
 		char mtts[BUFFER_SIZE];
 		char mtts[BUFFER_SIZE];
-/*
-		sprintf(mtts, "MTTS %d", 0
-			+ (ses->color > 0 ? 1 : 0)
-			+ (HAS_BIT(ses->flags, SES_FLAG_SPLIT) ? 0 : 2)
-			+ (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && !HAS_BIT(ses->charset, CHARSET_FLAG_ALL_TOUTF8) ? 4 : 0)
-			+ (ses->color > 16 ? 8 : 0)
-			+ (HAS_BIT(ses->flags, TINTIN_FLAG_MOUSETRACKING) ? 16 + 1024 : 0)
-			+ (HAS_BIT(ses->config_flags, CONFIG_FLAG_SCREENREADER) ? 64 : 0)
-			+ (ses->color > 256 ? 256 : 0)
-			+ 512
-#ifdef HAVE_GNUTLS_H
-			+ 2048
-#endif
-			);
-*/
+
 		sprintf(mtts, "MTTS %d", get_mtts_val(ses));
 		sprintf(mtts, "MTTS %d", get_mtts_val(ses));
 
 
 		telnet_printf(ses, 6 + strlen(mtts), "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 0, mtts, IAC, SE);
 		telnet_printf(ses, 6 + strlen(mtts), "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 0, mtts, IAC, SE);
@@ -1462,7 +1448,6 @@ int client_recv_sb_charset(struct session *ses, int cplen, unsigned char *src)
 	NEW-ENVIRON
 	NEW-ENVIRON
 */
 */
 
 
-
 char *get_charset_mnes(struct session *ses)
 char *get_charset_mnes(struct session *ses)
 {
 {
 	int index;
 	int index;
@@ -1490,8 +1475,6 @@ int client_recv_sb_new_environ(struct session *ses, int cplen, unsigned char *sr
 		return cplen + 1;
 		return cplen + 1;
 	}
 	}
 
 
-//	client_telopt_debug(ses, "RCVD IAC SB NEW-ENVIRON %d %d", src[3], src[4]);
-
 	switch (src[3])
 	switch (src[3])
 	{
 	{
 		case ENV_IS:
 		case ENV_IS:
@@ -1510,6 +1493,13 @@ int client_recv_sb_new_environ(struct session *ses, int cplen, unsigned char *sr
 
 
 	i = 4;
 	i = 4;
 
 
+	if (src[3] == ENV_SEND && src[4] == IAC)
+	{
+		strcpy(sub2, "VAR");
+
+		goto shortcut;
+	}
+
 	while (i < cplen && src[i] != IAC)
 	while (i < cplen && src[i] != IAC)
 	{
 	{
 		switch (src[i])
 		switch (src[i])
@@ -1533,6 +1523,9 @@ int client_recv_sb_new_environ(struct session *ses, int cplen, unsigned char *sr
 			case ENV_VAR:
 			case ENV_VAR:
 			case ENV_USR:
 			case ENV_USR:
 				i++;
 				i++;
+
+				shortcut:
+
 				pto = buf;
 				pto = buf;
 
 
 				while (i < cplen && src[i] >= 4 && src[i] != IAC)
 				while (i < cplen && src[i] >= 4 && src[i] != IAC)
@@ -1543,7 +1536,7 @@ int client_recv_sb_new_environ(struct session *ses, int cplen, unsigned char *sr
 
 
 				substitute(ses, buf, var, SUB_SEC);
 				substitute(ses, buf, var, SUB_SEC);
 
 
-				if (src[3] == ENV_SEND)
+				if (src[3] == ENV_SEND && !strcmp(sub2, "VAR"))
 				{
 				{
 					client_telopt_debug(ses, "RCVD IAC SB NEW-ENVIRON SEND %s %s", sub2, var);
 					client_telopt_debug(ses, "RCVD IAC SB NEW-ENVIRON SEND %s %s", sub2, var);
 
 
@@ -1555,51 +1548,31 @@ int client_recv_sb_new_environ(struct session *ses, int cplen, unsigned char *sr
 
 
 						if (!check_all_events(ses, EVENT_FLAG_CATCH, 1, 4, "CATCH IAC SB NEW-ENVIRON SEND %s", var, sub1, sub2, var, ""))
 						if (!check_all_events(ses, EVENT_FLAG_CATCH, 1, 4, "CATCH IAC SB NEW-ENVIRON SEND %s", var, sub1, sub2, var, ""))
 						{
 						{
-							if (!strcmp(var, ""))
-							{
-								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->system->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->system->term,
-										IAC, SE);
-								}
-							}
-							else if (!strcmp(var, "CHARSET"))
+							if (*var == 0 || !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_mnes(ses), IAC, SE);
 								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_mnes(ses), IAC, SE);
 
 
 								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", "CHARSET", get_charset(ses));
 							}
 							}
-							else if (!strcmp(var, "CLIENT_NAME"))
+							if (*var == 0 || !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);
 								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);
 								client_telopt_debug(ses, "SENT IAC SB NEW-ENVIRON IS VAR %s VAL %s", "CLIENT_NAME", CLIENT_NAME);
 							}
 							}
-							else if (!strcmp(var, "CLIENT_VERSION"))
+							if (*var == 0 || !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);
 								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);
 								client_telopt_debug(ses, "SENT IAC SB NEW-ENVIRON IS VAR %s VAL %s", "CLIENT_VERSION", CLIENT_VERSION);
 							}
 							}
-							else if (!strcmp(var, "MTTS") || *var == 0)
+							if (*var == 0 || !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);
 								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));
 								client_telopt_debug(ses, "SENT IAC SB NEW-ENVIRON IS VAR MTTS VAL %d", get_mtts_val(ses));
 							}
 							}
-							else if (!strcmp(var, "TERMINAL_TYPE"))
+							if (*var == 0 || !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->system->term, IAC, SE);
 								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->system->term, IAC, SE);
 
 

+ 51 - 27
src/telopt_server.c

@@ -96,6 +96,21 @@ struct iac_type iac_server_table [] =
 	{ 0, NULL,                                                                  NULL}
 	{ 0, NULL,                                                                  NULL}
 };
 };
 
 
+void server_telopt_debug(struct session *ses, char *format, ...)
+{
+	char buf[BUFFER_SIZE];
+	va_list args;
+
+	if (HAS_BIT(ses->telopts, TELOPT_FLAG_DEBUG))
+	{
+		va_start(args, format);
+		vsprintf(buf, format, args);
+		va_end(args);
+
+		tintin_puts(ses, buf);
+	}
+}
+
 /*
 /*
 	Call this to announce support for telopts marked as such in tables.c
 	Call this to announce support for telopts marked as such in tables.c
 */
 */
@@ -105,17 +120,21 @@ void announce_support(struct session *ses, struct port_data *buddy)
 	int i;
 	int i;
 
 
 	push_call("announce_support(%p,%p)",ses,buddy);
 	push_call("announce_support(%p,%p)",ses,buddy);
-	
+
 	for (i = 0 ; i < 255 ; i++)
 	for (i = 0 ; i < 255 ; i++)
 	{
 	{
 		if (telopt_table[i].flags)
 		if (telopt_table[i].flags)
 		{
 		{
 			if (HAS_BIT(telopt_table[i].flags, ANNOUNCE_WILL))
 			if (HAS_BIT(telopt_table[i].flags, ANNOUNCE_WILL))
 			{
 			{
+				server_telopt_debug(ses, "SENT IAC WILL %s", telopt_table[i].name);
+
 				port_telnet_printf(ses, buddy, 3, "%c%c%c", IAC, WILL, i);
 				port_telnet_printf(ses, buddy, 3, "%c%c%c", IAC, WILL, i);
 			}
 			}
 			if (HAS_BIT(telopt_table[i].flags, ANNOUNCE_DO))
 			if (HAS_BIT(telopt_table[i].flags, ANNOUNCE_DO))
 			{
 			{
+				server_telopt_debug(ses, "SENT IAC DO %s", telopt_table[i].name);
+
 				port_telnet_printf(ses, buddy, 3, "%c%c%c", IAC, DO, i);
 				port_telnet_printf(ses, buddy, 3, "%c%c%c", IAC, DO, i);
 			}
 			}
 		}
 		}
@@ -276,6 +295,12 @@ int server_translate_telopts(struct session *ses, struct port_data *buddy, unsig
 		switch (*pti)
 		switch (*pti)
 		{
 		{
 			case IAC:
 			case IAC:
+				if (!HAS_BIT(ses->config_flags, CONFIG_FLAG_TELNET))
+				{
+					*pto++ = *pti++;
+					srclen--;
+					break;
+				}
 				skip = 2;
 				skip = 2;
 
 
 				debug_telopts(ses, buddy, pti, srclen);
 				debug_telopts(ses, buddy, pti, srclen);
@@ -400,12 +425,12 @@ void telopt_debug(struct session *ses, char *format, ...)
 
 
 void debug_telopts(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen)
 void debug_telopts(struct session *ses, struct port_data *buddy, unsigned char *src, int srclen)
 {
 {
-	if (srclen > 1 && TELOPT_DEBUG)
+	if (srclen > 1)
 	{
 	{
 		switch(src[1])
 		switch(src[1])
 		{
 		{
 			case IAC:
 			case IAC:
-				tintin_printf2(ses, "RCVD IAC IAC");
+				server_telopt_debug(ses, "RCVD IAC IAC");
 				break;
 				break;
 
 
 			case DO:
 			case DO:
@@ -419,39 +444,39 @@ void debug_telopts(struct session *ses, struct port_data *buddy, unsigned char *
 					{
 					{
 						if (skip_sb(ses, buddy, src, srclen) == srclen + 1)
 						if (skip_sb(ses, buddy, src, srclen) == srclen + 1)
 						{
 						{
-							tintin_printf2(ses, "RCVD IAC SB %s ?", TELOPT(src[2]));
+							server_telopt_debug(ses, "RCVD IAC SB %s ?", TELOPT(src[2]));
 						}
 						}
 						else
 						else
 						{
 						{
-							tintin_printf2(ses, "RCVD IAC SB %s IAC SE", TELOPT(src[2]));
+							server_telopt_debug(ses, "RCVD IAC SB %s IAC SE", TELOPT(src[2]));
 						}
 						}
 					}
 					}
 					else
 					else
 					{
 					{
-						tintin_printf2(ses, "RCVD IAC %s %s", TELCMD(src[1]), TELOPT(src[2]));
+						server_telopt_debug(ses, "RCVD IAC %s %s", TELCMD(src[1]), TELOPT(src[2]));
 					}
 					}
 				}
 				}
 				else
 				else
 				{
 				{
-					tintin_printf2(ses, "RCVD IAC %s ?", TELCMD(src[1]));
+					server_telopt_debug(ses, "RCVD IAC %s ?", TELCMD(src[1]));
 				}
 				}
 				break;
 				break;
 
 
 			default:
 			default:
 				if (TELCMD_OK(src[1]))
 				if (TELCMD_OK(src[1]))
 				{
 				{
-					tintin_printf2(ses, "RCVD IAC %s", TELCMD(src[1]));
+					server_telopt_debug(ses, "RCVD IAC %s", TELCMD(src[1]));
 				}
 				}
 				else
 				else
 				{
 				{
-					tintin_printf2(ses, "RCVD IAC %d", src[1]);
+					server_telopt_debug(ses, "RCVD IAC %d", src[1]);
 				}
 				}
 				break;
 				break;
 		}
 		}
 	}
 	}
 	else
 	else
 	{
 	{
-		tintin_printf2(ses, "RCVD IAC ?");
+		server_telopt_debug(ses, "RCVD IAC ?");
 	}
 	}
 }
 }
 
 
@@ -544,7 +569,7 @@ int process_sb_ttype_is(struct session *ses, struct port_data *buddy, unsigned c
 
 
 				if (TELOPT_DEBUG)
 				if (TELOPT_DEBUG)
 				{
 				{
-					tintin_printf2(ses, "INFO IAC SB TTYPE RCVD VAL %s.", val);
+					server_telopt_debug(ses, "INFO IAC SB TTYPE RCVD VAL %s.", val);
 				}
 				}
 
 
 				if (*buddy->ttype == 0)
 				if (*buddy->ttype == 0)
@@ -611,10 +636,7 @@ int process_sb_naws(struct session *ses, struct port_data *buddy, unsigned char
 		}
 		}
 	}
 	}
 
 
-	if (TELOPT_DEBUG)
-	{
-		tintin_printf2(ses, "INFO IAC SB NAWS RCVD ROWS %d COLS %d", buddy->rows, buddy->cols);
-	}
+	server_telopt_debug(ses, "INFO IAC SB NAWS RCVD ROWS %d COLS %d", buddy->rows, buddy->cols);
 
 
 	return skip_sb(ses, buddy, src, srclen);
 	return skip_sb(ses, buddy, src, srclen);
 }
 }
@@ -627,6 +649,8 @@ int process_will_new_environ(struct session *ses, struct port_data *buddy, unsig
 {
 {
 	port_socket_printf(ses, buddy, "%c%c%c%c%c%s%c%c", IAC, SB, TELOPT_NEW_ENVIRON, ENV_SEND, ENV_VAR, "SYSTEMTYPE", IAC, SE);
 	port_socket_printf(ses, buddy, "%c%c%c%c%c%s%c%c", IAC, SB, TELOPT_NEW_ENVIRON, ENV_SEND, ENV_VAR, "SYSTEMTYPE", IAC, SE);
 
 
+	port_socket_printf(ses, buddy, "%c%c%c%c%c%c", IAC, SB, TELOPT_NEW_ENVIRON, ENV_SEND, IAC, SE);
+
 	return 3;
 	return 3;
 }
 }
 
 
@@ -662,7 +686,7 @@ int process_sb_new_environ(struct session *ses, struct port_data *buddy, unsigne
 
 
 				if (src[i] != ENV_VAL)
 				if (src[i] != ENV_VAL)
 				{
 				{
-					tintin_printf2(ses, "INFO IAC SB NEW-ENVIRON RCVD %d VAR %s", src[3], var);
+					server_telopt_debug(ses, "INFO IAC SB NEW-ENVIRON RCVD %s KEY %s VAL (EMPTY)", src[3] == ENV_VAR ? "VAR" : "USERVAR", var);
 				}
 				}
 				break;
 				break;
 
 
@@ -676,10 +700,7 @@ int process_sb_new_environ(struct session *ses, struct port_data *buddy, unsigne
 				}
 				}
 				*pto = 0;
 				*pto = 0;
 
 
-				if (TELOPT_DEBUG)
-				{
-					tintin_printf2(ses, "INFO IAC SB NEW-ENVIRON RCVD %d VAR %s VAL %s", src[3], var, val);
-				}
+				server_telopt_debug(ses, "INFO IAC SB NEW-ENVIRON RCVD %s KEY %s VAL %s", src[3] == ENV_VAR ? "VAR" : "USERVAR", var, val);
 
 
 				if (src[3] == ENV_IS)
 				if (src[3] == ENV_IS)
 				{
 				{
@@ -757,13 +778,10 @@ int process_sb_charset(struct session *ses, struct port_data *buddy, unsigned ch
 		}
 		}
 		*pto = 0;
 		*pto = 0;
 
 
-		if (TELOPT_DEBUG)
-		{
-			tintin_printf2(ses, "INFO IAC SB CHARSET RCVD %d VAL %s", src[3], val);
-		}
-
 		if (src[3] == CHARSET_ACCEPTED)
 		if (src[3] == CHARSET_ACCEPTED)
 		{
 		{
+			server_telopt_debug(ses, "INFO IAC SB CHARSET RCVD ACCEPED VAL %s", val);
+
 			if (!strcasecmp(val, "UTF-8"))
 			if (!strcasecmp(val, "UTF-8"))
 			{
 			{
 				SET_BIT(buddy->comm_flags, COMM_FLAG_UTF8);
 				SET_BIT(buddy->comm_flags, COMM_FLAG_UTF8);
@@ -771,11 +789,17 @@ int process_sb_charset(struct session *ses, struct port_data *buddy, unsigned ch
 		}
 		}
 		else if (src[3] == CHARSET_REJECTED)
 		else if (src[3] == CHARSET_REJECTED)
 		{
 		{
+			server_telopt_debug(ses, "INFO IAC SB CHARSET RCVD REJECTED VAL %s", val);
+
 			if (!strcasecmp(val, "UTF-8"))
 			if (!strcasecmp(val, "UTF-8"))
 			{
 			{
 				DEL_BIT(buddy->comm_flags, COMM_FLAG_UTF8);
 				DEL_BIT(buddy->comm_flags, COMM_FLAG_UTF8);
 			}
 			}
 		}
 		}
+		else
+		{
+			server_telopt_debug(ses, "INFO IAC SB CHARSET RCVD %d VAL %s", src[3], val);
+		}
 		i++;
 		i++;
 	}
 	}
 	return i + 1;
 	return i + 1;
@@ -806,7 +830,7 @@ int process_do_msdp(struct session *ses, struct port_data *buddy, unsigned char
 		buddy->msdp_data[index]->value = strdup("");
 		buddy->msdp_data[index]->value = strdup("");
 	}
 	}
 
 
-	tintin_printf2(ses, "INFO MSDP INITIALIZED");
+	server_telopt_debug(ses, "INFO MSDP INITIALIZED");
 
 
 	// Easiest to handle variable initialization here.
 	// Easiest to handle variable initialization here.
 
 
@@ -905,7 +929,7 @@ int process_do_gmcp(struct session *ses, struct port_data *buddy, unsigned char
 	{
 	{
 		return 3;
 		return 3;
 	}
 	}
-	tintin_printf2(ses, "INFO MSDP OVER GMCP INITIALIZED");
+	server_telopt_debug(ses, "INFO MSDP OVER GMCP INITIALIZED");
 
 
 	SET_BIT(buddy->comm_flags, COMM_FLAG_GMCP);
 	SET_BIT(buddy->comm_flags, COMM_FLAG_GMCP);
 
 

+ 20 - 18
src/tintin.h

@@ -212,7 +212,7 @@
 
 
 
 
 #define CLIENT_NAME              "TinTin++"
 #define CLIENT_NAME              "TinTin++"
-#define CLIENT_VERSION           "2.02.31 "
+#define CLIENT_VERSION           "2.02.40 "
 
 
 
 
 #define XT_E                            0x27
 #define XT_E                            0x27
@@ -651,7 +651,7 @@ enum operators
 #define SES_FLAG_BUFFERUPDATE         BV01
 #define SES_FLAG_BUFFERUPDATE         BV01
 #define SES_FLAG_CLOSED               BV02
 #define SES_FLAG_CLOSED               BV02
 #define SES_FLAG_CONNECTED            BV03
 #define SES_FLAG_CONNECTED            BV03
-#define SES_FLAG_GAG                  BV04 // unused
+#define SES_FLAG_LINKLOST             BV04
 #define SES_FLAG_PATHMAPPING          BV05
 #define SES_FLAG_PATHMAPPING          BV05
 #define SES_FLAG_PRINTBUFFER          BV06
 #define SES_FLAG_PRINTBUFFER          BV06
 #define SES_FLAG_PRINTLINE            BV07
 #define SES_FLAG_PRINTLINE            BV07
@@ -774,6 +774,7 @@ enum operators
 #define MAP_FLAG_READ                 BV18
 #define MAP_FLAG_READ                 BV18
 #define MAP_FLAG_PANCAKE              BV19
 #define MAP_FLAG_PANCAKE              BV19
 #define MAP_FLAG_FAST                 BV20
 #define MAP_FLAG_FAST                 BV20
+#define MAP_FLAG_AUTOLINK             BV21
 
 
 #define MAP_SEARCH_NAME                0
 #define MAP_SEARCH_NAME                0
 #define MAP_SEARCH_EXITS               1
 #define MAP_SEARCH_EXITS               1
@@ -2013,6 +2014,7 @@ extern DO_CURSOR(cursor_echo);
 extern DO_CURSOR(cursor_end);
 extern DO_CURSOR(cursor_end);
 extern DO_CURSOR(cursor_enter);
 extern DO_CURSOR(cursor_enter);
 extern DO_CURSOR(cursor_enter_finish);
 extern DO_CURSOR(cursor_enter_finish);
+extern DO_CURSOR(cursor_escape_enter);
 extern DO_CURSOR(cursor_flag);
 extern DO_CURSOR(cursor_flag);
 extern DO_CURSOR(cursor_get);
 extern DO_CURSOR(cursor_get);
 extern DO_CURSOR(cursor_history_find);
 extern DO_CURSOR(cursor_history_find);
@@ -2305,12 +2307,10 @@ extern struct session *repeat_history(struct session *ses, char *line);
 extern int write_history(struct session *ses, char *filename);
 extern int write_history(struct session *ses, char *filename);
 extern int read_history(struct session *ses, char *filename);
 extern int read_history(struct session *ses, char *filename);
 
 
-DO_HISTORY(history_character);
 DO_HISTORY(history_delete);
 DO_HISTORY(history_delete);
 DO_HISTORY(history_get);
 DO_HISTORY(history_get);
 DO_HISTORY(history_insert);
 DO_HISTORY(history_insert);
 DO_HISTORY(history_list);
 DO_HISTORY(history_list);
-DO_HISTORY(history_size);
 DO_HISTORY(history_read);
 DO_HISTORY(history_read);
 DO_HISTORY(history_write);
 DO_HISTORY(history_write);
 
 
@@ -2937,6 +2937,7 @@ extern void check_all_gags(struct session *ses, char *original, char *line);
 extern void check_all_highlights(struct session *ses, char *original, char *line);
 extern void check_all_highlights(struct session *ses, char *original, char *line);
 extern  int check_all_prompts(struct session *ses, char *original, char *line);
 extern  int check_all_prompts(struct session *ses, char *original, char *line);
 extern void check_all_substitutions(struct session *ses, char *original, char *line);
 extern void check_all_substitutions(struct session *ses, char *original, char *line);
+extern void check_all_substitutions_multi(struct session *ses, char *original, char *line);
 
 
 #endif
 #endif
 
 
@@ -2998,7 +2999,7 @@ extern int get_utf8_index(char *str, int *index);
 extern int unicode_to_utf8(int index, char *out);
 extern int unicode_to_utf8(int index, char *out);
 extern int utf8_strlen(char *str, int *width);
 extern int utf8_strlen(char *str, int *width);
 
 
-extern int utf8_to_all(struct session *ses, char *in, char *out);
+extern int utf8_to_all(struct session *ses, char *in, char *out, int size);
 extern int all_to_utf8(struct session *ses, char *in, char *out);
 extern int all_to_utf8(struct session *ses, char *in, char *out);
 extern int cp1251_to_utf8(char *input, char *output);
 extern int cp1251_to_utf8(char *input, char *output);
 extern int utf8_to_cp1251(char *input, char *output);
 extern int utf8_to_cp1251(char *input, char *output);
@@ -3017,7 +3018,7 @@ extern int big5_to_utf8(char *input, char *output);
 extern int utf8_to_big5(char *input, char *output);
 extern int utf8_to_big5(char *input, char *output);
 extern int is_gbk1(char *str);
 extern int is_gbk1(char *str);
 extern int gbk1_to_utf8(char *input, char *output);
 extern int gbk1_to_utf8(char *input, char *output);
-extern int utf8_to_gbk1(char *input, char *output);
+extern int utf8_to_gbk1(char *input, char *output, int length);
 extern int is_cp949(char *str);
 extern int is_cp949(char *str);
 extern int cp949_to_utf8(char *input, char *output);
 extern int cp949_to_utf8(char *input, char *output);
 extern int utf8_to_cp949(char *input, char *output);
 extern int utf8_to_cp949(char *input, char *output);
@@ -3029,18 +3030,19 @@ extern int utf8_to_cp949(char *input, char *output);
 
 
 extern DO_COMMAND(do_replace);
 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);
-extern  int translate_color_names(struct session *ses, char *string, char *result);
-extern  int get_color_names(struct session *ses, char *htype, char *result);
-extern void lowerstring(char *str);
-extern void upperstring(char *str);
-extern void numbertocharacter(struct session *ses, char *str);
-extern void charactertonumber(struct session *ses, char *str);
-extern  int delete_variable(struct session *ses, char *variable);
-extern void justify_string(struct session *ses, char *in, char *out, int align, int cut);
-extern void format_string(struct session *ses, char *format, char *arg, char *out);
+extern char *get_variable_def(struct session *ses, char *var, char *def);
+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);
+extern  int  translate_color_names(struct session *ses, char *string, char *result);
+extern  int  get_color_names(struct session *ses, char *htype, char *result);
+extern void  lowerstring(char *str);
+extern void  upperstring(char *str);
+extern void  numbertocharacter(struct session *ses, char *str);
+extern void  charactertonumber(struct session *ses, char *str);
+extern  int  delete_variable(struct session *ses, char *variable);
+extern void  justify_string(struct session *ses, char *in, char *out, int align, int cut);
+extern void  format_string(struct session *ses, char *format, char *arg, char *out);
 extern struct listnode *search_variable(struct session *ses, char *variable);
 extern struct listnode *search_variable(struct session *ses, char *variable);
 extern struct listnode *get_variable(struct session *ses, char *variable, char *result);
 extern struct listnode *get_variable(struct session *ses, char *variable, char *result);
 extern struct listnode *set_variable(struct session *ses, char *variable, char *format, ...);
 extern struct listnode *set_variable(struct session *ses, char *variable, char *format, ...);

+ 7 - 7
src/tokenize.c

@@ -402,7 +402,7 @@ char *addregextoken(struct scriptroot *root, int lvl, int type, int cmd, char *s
 
 
 	if (*arg3 == 0)
 	if (*arg3 == 0)
 	{
 	{
-		show_error(root->ses, LIST_COMMAND, "#SYNTAX: #REGEXP {string} {expression} {true} {false}");
+		show_error(root->ses, LIST_COMMAND, "#SYNTAX: #REGEXP <TEXT> <EXPRESSION> <TRUE> [FALSE]");
 	}
 	}
 	addtoken(root, lvl, type, cmd, arg1);
 	addtoken(root, lvl, type, cmd, arg1);
 
 
@@ -634,7 +634,7 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 
 
 						if (*str == 0 || *str == COMMAND_SEPARATOR)
 						if (*str == 0 || *str == COMMAND_SEPARATOR)
 						{
 						{
-							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #FOREACH {list} {variable} {commands}");
+							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #FOREACH <LIST> <VARIABLE> <COMMANDS>");
 						}
 						}
 
 
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
@@ -649,7 +649,7 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 
 
 						if (*str == 0 || *str == COMMAND_SEPARATOR)
 						if (*str == 0 || *str == COMMAND_SEPARATOR)
 						{
 						{
-							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #IF {conditional} {true} {false}");
+							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #IF <CONDITIONAL> <TRUE> [FALSE]");
 						}
 						}
 
 
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
@@ -673,7 +673,7 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 
 
 						if (*str == 0 || *str == COMMAND_SEPARATOR)
 						if (*str == 0 || *str == COMMAND_SEPARATOR)
 						{
 						{
-							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #LOOP {start} {finish} {commands}");
+							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #LOOP <START> <END> <COMMANDS>");
 						}
 						}
 
 
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
@@ -687,7 +687,7 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 
 
 						if (*str == 0 || *str == COMMAND_SEPARATOR)
 						if (*str == 0 || *str == COMMAND_SEPARATOR)
 						{
 						{
-							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #PARSE {string} {variable} {commands}");
+							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #PARSE <TEXT> <VARIABLE> <COMMANDS>");
 						}
 						}
 
 
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
@@ -721,7 +721,7 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 
 
 						if (*str == 0 || *str == COMMAND_SEPARATOR)
 						if (*str == 0 || *str == COMMAND_SEPARATOR)
 						{
 						{
-							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #SWITCH {conditional} {arguments}");
+							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #SWITCH <CONDITIONAL> <ARGUMENTS>");
 						}
 						}
 
 
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
@@ -736,7 +736,7 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 
 
 						if (*str == 0 || *str == COMMAND_SEPARATOR)
 						if (*str == 0 || *str == COMMAND_SEPARATOR)
 						{
 						{
-							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #WHILE {conditional} {commands}");
+							show_error(root->ses, LIST_COMMAND, "#SYNTAX: #WHILE <CONDITIONAL> <COMMANDS>");
 							deltoken(root, root->prev);
 							deltoken(root, root->prev);
 							break;
 							break;
 						}
 						}

+ 142 - 33
src/trigger.c

@@ -41,19 +41,19 @@ DO_COMMAND(do_action)
 	{
 	{
 		if (show_node_with_wild(ses, arg1, ses->list[LIST_ACTION]) == FALSE)
 		if (show_node_with_wild(ses, arg1, ses->list[LIST_ACTION]) == FALSE)
 		{
 		{
-			show_message(ses, LIST_ACTION, "#ACTION: NO MATCH(ES) FOUND FOR {%s}.", arg1);
+			show_message(ses, LIST_ACTION, "#ACTION: NO MATCHES FOUND FOR {%s}.", arg1);
 		}
 		}
 	}
 	}
 	else
 	else
 	{
 	{
 		if (*arg3 && (atof(arg3) < 1 || atof(arg3) >= 10))
 		if (*arg3 && (atof(arg3) < 1 || atof(arg3) >= 10))
 		{
 		{
-			show_error(ses, LIST_ACTION, "\e[1;31m#WARNING: #ACTION {%s} {..} {%s} SHOULD HAVE A PRIORITY BETWEEN 1.000 and 9.999.", arg1, arg3);
+			show_error(ses, LIST_ACTION, "#WARNING: #ACTION {%s} {..} {%s} SHOULD HAVE A PRIORITY BETWEEN 1.000 and 9.999.", arg1, arg3);
 		}
 		}
 
 
 		update_node_list(ses->list[LIST_ACTION], arg1, arg2, arg3, "");
 		update_node_list(ses->list[LIST_ACTION], arg1, arg2, arg3, "");
 
 
-		show_message(ses, LIST_ACTION, "#OK. #ACTION {%s} NOW TRIGGERS {%s} @ {%s}.", arg1, arg2, arg3);
+		show_message(ses, LIST_ACTION, "#OK: #ACTION {%s} NOW TRIGGERS {%s} @ {%s}.", arg1, arg2, arg3);
 	}
 	}
 	return ses;
 	return ses;
 }
 }
@@ -103,7 +103,7 @@ void check_all_actions_multi(struct session *ses, char *original, char *stripped
 {
 {
 	struct listroot *root = ses->list[LIST_ACTION];
 	struct listroot *root = ses->list[LIST_ACTION];
 	struct listnode *node;
 	struct listnode *node;
-	char *pto, *pts;
+	char *pto, *pts, *ptm;
 
 
 	for (root->multi_update = 0 ; root->multi_update < root->used ; root->multi_update++)
 	for (root->multi_update = 0 ; root->multi_update < root->used ; root->multi_update++)
 	{
 	{
@@ -152,6 +152,13 @@ void check_all_actions_multi(struct session *ses, char *original, char *stripped
 				}
 				}
 			}
 			}
 			script_driver(ses, LIST_ACTION, buf);
 			script_driver(ses, LIST_ACTION, buf);
+
+			ptm = node->arg1 + (*node->arg1 == '~');
+
+			if (ptm[0] == '\\' && ptm[1] == 'A')
+			{
+				break;
+			}
 		}
 		}
 	}
 	}
 }
 }
@@ -178,7 +185,7 @@ DO_COMMAND(do_alias)
 	{
 	{
 		if (show_node_with_wild(ses, arg1, ses->list[LIST_ALIAS]) == FALSE)
 		if (show_node_with_wild(ses, arg1, ses->list[LIST_ALIAS]) == FALSE)
 		{
 		{
-			show_message(ses, LIST_ALIAS, "#ALIAS: NO MATCH(ES) FOUND FOR {%s}.", arg1);
+			show_message(ses, LIST_ALIAS, "#ALIAS: NO MATCHES FOUND FOR {%s}.", arg1);
 		}
 		}
 	}
 	}
 	else
 	else
@@ -250,21 +257,20 @@ int check_all_aliases(struct session *ses, char *input)
 
 
 				for (i = 1 ; i < 100 ; i++)
 				for (i = 1 ; i < 100 ; i++)
 				{
 				{
-					arg = get_arg_in_braces(ses, arg, buf, GET_ONE);
-
-					RESTRING(gtd->vars[i], buf);
-
-					gtd->varc = i + 1;
+					gtd->varc = i;
 
 
 					if (*arg == 0)
 					if (*arg == 0)
 					{
 					{
-						while (++i < 100)
+						while (i < 100)
 						{
 						{
-							*gtd->vars[i] = 0;
+							*gtd->vars[i++] = 0;
 						}
 						}
 						break;
 						break;
 					}
 					}
 
 
+					arg = get_arg_in_braces(ses, arg, buf, GET_ONE);
+
+					RESTRING(gtd->vars[i], buf);
 				}
 				}
 			}
 			}
 
 
@@ -306,7 +312,7 @@ DO_COMMAND(do_button)
 	struct listnode *node;
 	struct listnode *node;
 	int index;
 	int index;
 
 
-	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
+	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, arg2, GET_ALL);
 	arg = get_arg_in_braces(ses, arg, arg3, GET_ALL);
 	arg = get_arg_in_braces(ses, arg, arg3, GET_ALL);
 
 
@@ -318,7 +324,7 @@ DO_COMMAND(do_button)
 	{
 	{
 		if (show_node_with_wild(ses, arg1, ses->list[LIST_BUTTON]) == FALSE)
 		if (show_node_with_wild(ses, arg1, ses->list[LIST_BUTTON]) == FALSE)
 		{
 		{
-			show_message(ses, LIST_BUTTON, "#BUTTON: NO MATCH(ES) FOUND FOR {%s}.", arg1);
+			show_message(ses, LIST_BUTTON, "#BUTTON: NO MATCHES FOUND FOR {%s}.", arg1);
 		}
 		}
 	}
 	}
 	else
 	else
@@ -328,7 +334,7 @@ DO_COMMAND(do_button)
 
 
 		node = update_node_list(ses->list[LIST_BUTTON], arg1, arg2, arg3, "");
 		node = update_node_list(ses->list[LIST_BUTTON], arg1, arg2, arg3, "");
 
 
-		show_message(ses, LIST_BUTTON, "#OK. BUTTON {%s} NOW TRIGGERS {%s} @ {%s}.", arg1, arg2, arg3);
+		show_message(ses, LIST_BUTTON, "#OK: BUTTON {%s} NOW TRIGGERS {%s} @ {%s}.", arg1, arg2, arg3);
 
 
 		arg = arg1;
 		arg = arg1;
 
 
@@ -468,7 +474,7 @@ DO_COMMAND(do_delay)
 	{
 	{
 		if (show_node_with_wild(ses, arg1, ses->list[LIST_DELAY]) == FALSE)
 		if (show_node_with_wild(ses, arg1, ses->list[LIST_DELAY]) == FALSE)
 		{
 		{
-			show_message(ses, LIST_DELAY, "#DELAY: NO MATCH(ES) FOUND FOR {%s}.", arg1);
+			show_message(ses, LIST_DELAY, "#DELAY: NO MATCHES FOUND FOR {%s}.", arg1);
 		}
 		}
 	}
 	}
 	else
 	else
@@ -483,7 +489,7 @@ DO_COMMAND(do_delay)
 
 
 			create_node_list(ses->list[LIST_DELAY], time, arg2, arg1, arg3);
 			create_node_list(ses->list[LIST_DELAY], time, arg2, arg1, arg3);
 
 
-			show_message(ses, LIST_DELAY, "#OK, IN {%s} SECONDS {%s} IS EXECUTED.", arg1, arg2);
+			show_message(ses, LIST_DELAY, "#DELAY: IN {%s} SECONDS {%s} IS EXECUTED.", arg1, arg2);
 
 
 		}
 		}
 		else
 		else
@@ -498,7 +504,7 @@ DO_COMMAND(do_delay)
 
 
 			node->shots = 1;
 			node->shots = 1;
 
 
-			show_message(ses, LIST_TICKER, "#ONESHOT: #TICK {%s} WILL EXECUTE {%s} IN {%s} SECONDS.", arg1, arg2, time);
+			show_message(ses, LIST_TICKER, "#ONESHOT: #TICKER {%s} WILL EXECUTE {%s} IN {%s} SECONDS.", arg1, arg2, time);
 		}
 		}
 	}
 	}
 	return ses;
 	return ses;
@@ -544,14 +550,14 @@ DO_COMMAND(do_function)
 	{
 	{
 		if (show_node_with_wild(ses, arg1, ses->list[LIST_FUNCTION]) == FALSE)
 		if (show_node_with_wild(ses, arg1, ses->list[LIST_FUNCTION]) == FALSE)
 		{
 		{
-			show_message(ses, LIST_FUNCTION, "#FUNCTION: NO MATCH(ES) FOUND FOR {%s}.", arg1);
+			show_message(ses, LIST_FUNCTION, "#FUNCTION: NO MATCHES FOUND FOR {%s}.", arg1);
 		}
 		}
 	}
 	}
 	else
 	else
 	{
 	{
 		update_node_list(ses->list[LIST_FUNCTION], arg1, arg2, "", "");
 		update_node_list(ses->list[LIST_FUNCTION], arg1, arg2, "", "");
 
 
-		show_message(ses, LIST_FUNCTION, "#OK. FUNCTION {%s} NOW TRIGGERS {%s}.", arg1, arg2);
+		show_message(ses, LIST_FUNCTION, "#OK: FUNCTION {%s} NOW TRIGGERS {%s}.", arg1, arg2);
 	}
 	}
 	return ses;
 	return ses;
 }
 }
@@ -585,7 +591,7 @@ DO_COMMAND(do_gag)
 	{
 	{
 		update_node_list(ses->list[LIST_GAG], arg1, "", "", "");
 		update_node_list(ses->list[LIST_GAG], arg1, "", "", "");
 
 
-		show_message(ses, LIST_GAG, "#OK. {%s} IS NOW GAGGED.", arg1);
+		show_message(ses, LIST_GAG, "#OK: {%s} IS NOW GAGGED.", arg1);
 	}
 	}
 	return ses;
 	return ses;
 }
 }
@@ -647,7 +653,7 @@ DO_COMMAND(do_highlight)
 	{
 	{
 		if (show_node_with_wild(ses, arg1, ses->list[LIST_HIGHLIGHT]) == FALSE)
 		if (show_node_with_wild(ses, arg1, ses->list[LIST_HIGHLIGHT]) == FALSE)
 		{
 		{
-			show_message(ses, LIST_HIGHLIGHT, "#HIGHLIGHT: NO MATCH(ES) FOUND FOR {%s}.", arg1);
+			show_message(ses, LIST_HIGHLIGHT, "#HIGHLIGHT: NO MATCHES FOUND FOR {%s}.", arg1);
 		}
 		}
 	}
 	}
 	else
 	else
@@ -661,7 +667,7 @@ DO_COMMAND(do_highlight)
 		{
 		{
 			update_node_list(ses->list[LIST_HIGHLIGHT], arg1, arg2, arg3, "");
 			update_node_list(ses->list[LIST_HIGHLIGHT], arg1, arg2, arg3, "");
 
 
-			show_message(ses, LIST_HIGHLIGHT, "#OK. {%s} NOW HIGHLIGHTS {%s} @ {%s}.", arg1, arg2, arg3);
+			show_message(ses, LIST_HIGHLIGHT, "#OK: {%s} NOW HIGHLIGHTS {%s} @ {%s}.", arg1, arg2, arg3);
 		}
 		}
 	}
 	}
 	return ses;
 	return ses;
@@ -773,7 +779,7 @@ DO_COMMAND(do_macro)
 	{
 	{
 		if (show_node_with_wild(ses, arg1, ses->list[LIST_MACRO]) == FALSE)
 		if (show_node_with_wild(ses, arg1, ses->list[LIST_MACRO]) == FALSE)
 		{
 		{
-			show_message(ses, LIST_MACRO, "#MACRO: NO MATCH(ES) FOUND FOR {%s}.", arg1);
+			show_message(ses, LIST_MACRO, "#MACRO: NO MATCHES FOUND FOR {%s}.", arg1);
 		}
 		}
 	}
 	}
 	else
 	else
@@ -782,7 +788,7 @@ DO_COMMAND(do_macro)
 
 
 		update_node_list(ses->list[LIST_MACRO], arg1, arg2, "", arg3);
 		update_node_list(ses->list[LIST_MACRO], arg1, arg2, "", arg3);
 
 
-		show_message(ses, LIST_MACRO, "#OK. MACRO {%s} NOW TRIGGERS {%s}.", arg1, arg2);
+		show_message(ses, LIST_MACRO, "#OK: MACRO {%s} NOW TRIGGERS {%s}.", arg1, arg2);
 	}
 	}
 	return ses;
 	return ses;
 }
 }
@@ -818,7 +824,7 @@ DO_COMMAND(do_prompt)
 	{
 	{
 		if (show_node_with_wild(ses, arg1, ses->list[LIST_PROMPT]) == FALSE)
 		if (show_node_with_wild(ses, arg1, ses->list[LIST_PROMPT]) == FALSE)
 		{
 		{
-			show_message(ses, LIST_PROMPT, "#PROMPT: NO MATCH(ES) FOUND FOR {%s}.", arg1);
+			show_message(ses, LIST_PROMPT, "#PROMPT: NO MATCHES FOUND FOR {%s}.", arg1);
 		}
 		}
 	}
 	}
 	else
 	else
@@ -831,7 +837,7 @@ DO_COMMAND(do_prompt)
 
 
 		update_node_list(ses->list[LIST_PROMPT], arg1, arg2, arg3, arg4);
 		update_node_list(ses->list[LIST_PROMPT], arg1, arg2, arg3, arg4);
 
 
-		show_message(ses, LIST_PROMPT, "#OK. {%s} NOW PROMPTS {%s} @ {%s} {%s}.", arg1, arg2, arg3, arg4);
+		show_message(ses, LIST_PROMPT, "#OK: {%s} NOW PROMPTS {%s} @ {%s} {%s}.", arg1, arg2, arg3, arg4);
 	}
 	}
 	return ses;
 	return ses;
 }
 }
@@ -915,14 +921,14 @@ DO_COMMAND(do_substitute)
 	{
 	{
 		if (show_node_with_wild(ses, arg1, ses->list[LIST_SUBSTITUTE]) == FALSE)
 		if (show_node_with_wild(ses, arg1, ses->list[LIST_SUBSTITUTE]) == FALSE)
 		{
 		{
-			show_message(ses, LIST_SUBSTITUTE, "#SUBSTITUTE: NO MATCH(ES) FOUND FOR {%s}.", arg1);
+			show_message(ses, LIST_SUBSTITUTE, "#SUBSTITUTE: NO MATCHES FOUND FOR {%s}.", arg1);
 		}
 		}
 	}
 	}
 	else
 	else
 	{
 	{
 		update_node_list(ses->list[LIST_SUBSTITUTE], arg1, arg2, arg3, "");
 		update_node_list(ses->list[LIST_SUBSTITUTE], arg1, arg2, arg3, "");
 
 
-		show_message(ses, LIST_SUBSTITUTE, "#OK. {%s} IS NOW SUBSTITUTED AS {%s} @ {%s}.", arg1, arg2, arg3);
+		show_message(ses, LIST_SUBSTITUTE, "#OK: {%s} IS NOW SUBSTITUTED AS {%s} @ {%s}.", arg1, arg2, arg3);
 	}
 	}
 	return ses;
 	return ses;
 }
 }
@@ -953,6 +959,11 @@ void check_all_substitutions(struct session *ses, char *original, char *line)
 	{
 	{
 		node = root->list[root->update];
 		node = root->list[root->update];
 
 
+		if (HAS_BIT(node->flags, NODE_FLAG_MULTI))
+		{
+			continue;
+		}
+
 		if (check_one_regexp(ses, node, line, original, 0))
 		if (check_one_regexp(ses, node, line, original, 0))
 		{
 		{
 			pto = original;
 			pto = original;
@@ -996,8 +1007,106 @@ void check_all_substitutions(struct session *ses, char *original, char *line)
 				pto = ptm + len;
 				pto = ptm + len;
 
 
 				show_debug(ses, LIST_SUBSTITUTE, COLOR_DEBUG "#DEBUG SUBSTITUTE " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1, match);
 				show_debug(ses, LIST_SUBSTITUTE, COLOR_DEBUG "#DEBUG SUBSTITUTE " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1, match);
+
+				ptm = node->arg1 + (*node->arg1 == '~');
+
+				if (ptm[0] == '\\' && ptm[1] == 'A')
+				{
+					break;
+				}
+			}
+			while (*pto && check_one_regexp(ses, node, ptl, pto, PCRE_NOTBOL));
+
+			if (node->shots && --node->shots == 0)
+			{
+				delete_node_list(ses, LIST_SUBSTITUTE, node);
+			}
+			strcpy(ptr, pto);
+
+			strcpy(original, result);
+
+			strip_vt102_codes(original, line);
+		}
+	}
+	pop_call();
+	return;
+}
+
+void check_all_substitutions_multi(struct session *ses, char *original, char *line)
+{
+	char *match, *subst, *result, *temp, *ptl, *ptm, *pto, *ptr;
+	struct listroot *root = ses->list[LIST_SUBSTITUTE];
+	struct listnode *node;
+	int len;
+
+	push_call("check_all_substitutions(%p,%p,%p)",ses,original,line);
+
+	match  = str_alloc_stack(0);
+	subst  = str_alloc_stack(0);
+	result = str_alloc_stack(0);
+	temp   = str_alloc_stack(0);
+
+	for (root->multi_update = 0 ; root->multi_update < root->used ; root->multi_update++)
+	{
+		node = root->list[root->multi_update];
+
+		if (!HAS_BIT(node->flags, NODE_FLAG_MULTI))
+		{
+			continue;
+		}
+
+		if (check_one_regexp(ses, node, line, original, 0))
+		{
+			pto = original;
+			ptl = line;
+			ptr = result;
+
+			*result = *gtd->color_reset = 0;
+
+			do
+			{
+				if (*gtd->vars[0] == 0)
+				{
+					break;
+				}
+
+				strcpy(match, gtd->vars[0]);
+
+				substitute(ses, node->arg2, temp, SUB_ARG);
+
+				if (*node->arg1 == '~')
+				{
+					ptm = strstr(pto, match);
+
+					len = strlen(match);
+				}
+				else
+				{
+					ptm = strip_vt102_strstr(pto, match, &len);
+
+					ptl = strstr(ptl, match) + strlen(match);
+				}
+
+				*ptm = 0;
+
+				get_color_codes(gtd->color_reset, pto, gtd->color_reset, GET_ALL);
+
+				substitute(ses, temp, subst, SUB_VAR|SUB_FUN|SUB_COL|SUB_ESC);
+
+				ptr += sprintf(ptr, "%s%s", pto, subst);
+
+				pto = ptm + len;
+
+				show_debug(ses, LIST_SUBSTITUTE, COLOR_DEBUG "#DEBUG SUBSTITUTE " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1, match);
+
+				ptm = node->arg1 + (*node->arg1 == '~');
+
+				if (ptm[0] == '\\' && ptm[1] == 'A')
+				{
+					break;
+				}
 			}
 			}
-			while (*pto && check_one_regexp(ses, node, ptl, pto, 0));
+			while (*pto && check_one_regexp(ses, node, ptl, pto, PCRE_NOTBOL));
 
 
 			if (node->shots && --node->shots == 0)
 			if (node->shots && --node->shots == 0)
 			{
 			{
@@ -1034,7 +1143,7 @@ DO_COMMAND(do_tab)
 	{
 	{
 		update_node_list(ses->list[LIST_TAB], arg1, "", "", "");
 		update_node_list(ses->list[LIST_TAB], arg1, "", "", "");
 
 
-		show_message(ses, LIST_TAB, "#OK. {%s} IS NOW A TAB.", arg1);
+		show_message(ses, LIST_TAB, "#OK: {%s} IS NOW A TAB.", arg1);
 	}
 	}
 	return ses;
 	return ses;
 }
 }
@@ -1087,14 +1196,14 @@ DO_COMMAND(do_tick)
 	{
 	{
 		if (show_node_with_wild(ses, arg1, ses->list[LIST_TICKER]) == FALSE) 
 		if (show_node_with_wild(ses, arg1, ses->list[LIST_TICKER]) == FALSE) 
 		{
 		{
-			show_message(ses, LIST_TICKER, "#TICK, NO MATCH(ES) FOUND FOR {%s}.", arg1);
+			show_message(ses, LIST_TICKER, "#TICKER: NO MATCHES FOUND FOR {%s}.", arg1);
 		}
 		}
 	}
 	}
 	else
 	else
 	{
 	{
 		update_node_list(ses->list[LIST_TICKER], arg1, arg2, time, arg3);
 		update_node_list(ses->list[LIST_TICKER], arg1, arg2, time, arg3);
 
 
-		show_message(ses, LIST_TICKER, "#OK. #TICK {%s} NOW EXECUTES {%s} EVERY {%s} SECONDS.", arg1, arg2, time);
+		show_message(ses, LIST_TICKER, "#OK: #TICKER {%s} NOW EXECUTES {%s} EVERY {%s} SECONDS.", arg1, arg2, time);
 	}
 	}
 	return ses;
 	return ses;
 }
 }

+ 8 - 10
src/update.c

@@ -403,14 +403,6 @@ void update_sessions(void)
 					if (rv < 0)
 					if (rv < 0)
 					{
 					{
 						break; // bug report after removal.
 						break; // bug report after removal.
-
-						syserr_printf(ses, "update_sessions: select:");
-
-						cleanup_session(ses);
-
-						gtd->mud_output_len = 0;
-
-						break;
 					}
 					}
 
 
 					if (rv == 0)
 					if (rv == 0)
@@ -424,6 +416,8 @@ void update_sessions(void)
 						{
 						{
 							readmud(ses);
 							readmud(ses);
 
 
+							SET_BIT(ses->flags, SES_FLAG_LINKLOST);
+
 							cleanup_session(ses);
 							cleanup_session(ses);
 
 
 							gtd->mud_output_len = 0;
 							gtd->mud_output_len = 0;
@@ -436,6 +430,8 @@ void update_sessions(void)
 					{
 					{
 						FD_CLR(ses->socket, &read_fd);
 						FD_CLR(ses->socket, &read_fd);
 
 
+						SET_BIT(ses->flags, SES_FLAG_LINKLOST);
+
 						cleanup_session(ses);
 						cleanup_session(ses);
 
 
 						gtd->mud_output_len = 0;
 						gtd->mud_output_len = 0;
@@ -481,8 +477,10 @@ void update_sessions(void)
 				}
 				}
 				else
 				else
 				{
 				{
+/*
 					if (HAS_BIT(ses->flags, SES_FLAG_SNOOPSCROLL))
 					if (HAS_BIT(ses->flags, SES_FLAG_SNOOPSCROLL))
 					{
 					{
+
 						if (HAS_BIT(ses->scroll->flags, SCROLL_FLAG_RESIZE))
 						if (HAS_BIT(ses->scroll->flags, SCROLL_FLAG_RESIZE))
 						{
 						{
 							buffer_refresh(ses, "", "", "");
 							buffer_refresh(ses, "", "", "");
@@ -492,9 +490,9 @@ void update_sessions(void)
 							print_scroll_region(ses);
 							print_scroll_region(ses);
 						}
 						}
 					}
 					}
+*/
 					buffer_end(ses, "", "", "");
 					buffer_end(ses, "", "", "");
 				}
 				}
-
 				DEL_BIT(ses->flags, SES_FLAG_PRINTBUFFER);
 				DEL_BIT(ses->flags, SES_FLAG_PRINTBUFFER);
 			}
 			}
 
 
@@ -897,7 +895,7 @@ void tick_update(void)
 			{
 			{
 				node->val64 += (long long) (get_number(ses, node->arg3) * 1000000LL);
 				node->val64 += (long long) (get_number(ses, node->arg3) * 1000000LL);
 
 
-				show_info(ses, LIST_TICKER, "#INFO TICK {%s} INITIALIZED WITH TIMESTAMP {%lld}", node->arg1, node->val64);
+				show_info(ses, LIST_TICKER, "#INFO TICKER {%s} INITIALIZED WITH TIMESTAMP {%lld}", node->arg1, node->val64);
 
 
 				if (node->val64 < gtd->utime_next_tick)
 				if (node->val64 < gtd->utime_next_tick)
 				{
 				{

+ 5 - 4
src/utf8.c

@@ -473,7 +473,7 @@ int utf8_strlen(char *str, int *str_len)
 	return raw_len;
 	return raw_len;
 }
 }
 
 
-int utf8_to_all(struct session *ses, char *in, char *out)
+int utf8_to_all(struct session *ses, char *in, char *out, int size)
 {
 {
 	switch (HAS_BIT(ses->charset, CHARSET_FLAG_ALL_TOUTF8))
 	switch (HAS_BIT(ses->charset, CHARSET_FLAG_ALL_TOUTF8))
 	{
 	{
@@ -487,7 +487,7 @@ int utf8_to_all(struct session *ses, char *in, char *out)
 			return utf8_to_cp949(in, out);
 			return utf8_to_cp949(in, out);
 
 
 		case CHARSET_FLAG_GBK1TOUTF8:
 		case CHARSET_FLAG_GBK1TOUTF8:
-			return utf8_to_gbk1(in, out);
+			return utf8_to_gbk1(in, out, size);
 
 
 		case CHARSET_FLAG_FANSITOUTF8:
 		case CHARSET_FLAG_FANSITOUTF8:
 			return sprintf(out, "%s", in);
 			return sprintf(out, "%s", in);
@@ -1343,7 +1343,7 @@ int is_gbk1(char *str)
 	return ptu[0] > 128 && ptu[0] < 255 && ptu[1] > 64 && ptu[1] < 255;
 	return ptu[0] > 128 && ptu[0] < 255 && ptu[1] > 64 && ptu[1] < 255;
 }
 }
 
 
-int utf8_to_gbk1(char *input, char *output)
+int utf8_to_gbk1(char *input, char *output, int length)
 {
 {
 	char *pti, *pto;
 	char *pti, *pto;
 	int size, index, result;
 	int size, index, result;
@@ -1351,7 +1351,8 @@ int utf8_to_gbk1(char *input, char *output)
 	pti = input;
 	pti = input;
 	pto = output;
 	pto = output;
 
 
-	while (*pti)
+//	while (*pti)
+	while (length--)
 	{
 	{
 		size = get_utf8_index(pti, &index);
 		size = get_utf8_index(pti, &index);
 
 

+ 31 - 13
src/variable.c

@@ -64,7 +64,7 @@ DO_COMMAND(do_variable)
 		}
 		}
 		else if (show_node_with_wild(ses, arg1, ses->list[LIST_VARIABLE]) == FALSE)
 		else if (show_node_with_wild(ses, arg1, ses->list[LIST_VARIABLE]) == FALSE)
 		{
 		{
-			show_message(ses, LIST_VARIABLE, "#VARIABLE: NO MATCH(ES) FOUND FOR {%s}.", arg1);
+			show_message(ses, LIST_VARIABLE, "#VARIABLE: NO MATCHES FOUND FOR {%s}.", arg1);
 		}
 		}
 	}
 	}
 	else
 	else
@@ -93,7 +93,7 @@ DO_COMMAND(do_variable)
 
 
 		show_nest_node(node, &str, 1);
 		show_nest_node(node, &str, 1);
 
 
-		show_message(ses, LIST_VARIABLE, "#OK. VARIABLE {%s} HAS BEEN SET TO {%s}.", arg1, str);
+		show_message(ses, LIST_VARIABLE, "#OK: VARIABLE {%s} HAS BEEN SET TO {%s}.", arg1, str);
 	}
 	}
 	return ses;
 	return ses;
 }
 }
@@ -106,7 +106,7 @@ DO_COMMAND(do_unvariable)
 	{
 	{
 		if (delete_nest_node(ses->list[LIST_VARIABLE], arg1))
 		if (delete_nest_node(ses->list[LIST_VARIABLE], arg1))
 		{
 		{
-			show_message(ses, LIST_VARIABLE, "#OK. {%s} IS NO LONGER A VARIABLE.", arg1);
+			show_message(ses, LIST_VARIABLE, "#OK: {%s} IS NO LONGER A VARIABLE.", arg1);
 		}
 		}
 		else
 		else
 		{
 		{
@@ -157,7 +157,7 @@ DO_COMMAND(do_local)
 		}
 		}
 		else if (show_node_with_wild(ses, arg1, root) == FALSE)
 		else if (show_node_with_wild(ses, arg1, root) == FALSE)
 		{
 		{
-			show_message(ses, LIST_VARIABLE, "#LOCAL: NO MATCH(ES) FOUND FOR {%s}.", arg1);
+			show_message(ses, LIST_VARIABLE, "#LOCAL: NO MATCHES FOUND FOR {%s}.", arg1);
 		}
 		}
 	}
 	}
 	else
 	else
@@ -184,7 +184,7 @@ DO_COMMAND(do_local)
 
 
 		show_nest_node(node, &str, 1);
 		show_nest_node(node, &str, 1);
 
 
-		show_message(ses, LIST_VARIABLE, "#OK. LOCAL VARIABLE {%s} HAS BEEN SET TO {%s}.", arg1, str);
+		show_message(ses, LIST_VARIABLE, "#OK: LOCAL VARIABLE {%s} HAS BEEN SET TO {%s}.", arg1, str);
 	}
 	}
 	return ses;
 	return ses;
 }
 }
@@ -241,7 +241,7 @@ DO_COMMAND(do_cat)
 
 
 	if (*arg1 == 0 || *arg == 0)
 	if (*arg1 == 0 || *arg == 0)
 	{
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: CAT {<VARIABLE>} {<ARGUMENT>}");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #CAT <VARIABLE> <ARGUMENT>");
 	}
 	}
 	else
 	else
 	{
 	{
@@ -280,7 +280,7 @@ DO_COMMAND(do_replace)
 
 
 	if (*arg1 == 0 || *arg2 == 0)
 	if (*arg1 == 0 || *arg2 == 0)
 	{
 	{
-		show_error(ses, LIST_VARIABLE, "#SYNTAX: #REPLACE {VARIABLE} {OLD TEXT} {NEW TEXT}");
+		show_error(ses, LIST_VARIABLE, "#SYNTAX: #REPLACE <VARIABLE> <OLD TEXT> <NEW TEXT>");
 
 
 		return ses;
 		return ses;
 	}
 	}
@@ -320,6 +320,11 @@ DO_COMMAND(do_replace)
 			str_cat_printf(&str, "%s%s", pti, tmp);
 			str_cat_printf(&str, "%s%s", pti, tmp);
 
 
 			pti = ptm;
 			pti = ptm;
+
+			if (arg2[0] == '\\' && arg2[1] == 'A')
+			{
+				break;
+			}
 		}
 		}
 		while (tintin_regexp(ses, NULL, pti, arg2, 0, REGEX_FLAG_CMD));
 		while (tintin_regexp(ses, NULL, pti, arg2, 0, REGEX_FLAG_CMD));
 
 
@@ -331,6 +336,19 @@ DO_COMMAND(do_replace)
 	return ses;
 	return ses;
 }
 }
 
 
+char *get_variable_def(struct session *ses, char *var, char *def)
+{
+	struct listnode *node;
+
+	node = search_nest_node_ses(ses, var);
+
+	if (node)
+	{
+		return node->arg2;
+	}
+	return def;
+}
+
 int valid_variable(struct session *ses, char *arg)
 int valid_variable(struct session *ses, char *arg)
 {
 {
 	if (*arg == 0)
 	if (*arg == 0)
@@ -350,7 +368,7 @@ int valid_variable(struct session *ses, char *arg)
 
 
 	if (is_digit(*arg))
 	if (is_digit(*arg))
 	{
 	{
-		show_error(ses, LIST_COMMAND, "\e[1;31m#WARNING: VALIDATE {%s}: VARIABLES SHOULD NOT START WITH A NUMBER.", arg);
+		show_error(ses, LIST_COMMAND, "#WARNING: VALIDATE {%s}: VARIABLES SHOULD NOT START WITH A NUMBER.", arg);
 	}
 	}
 
 
 	return TRUE;
 	return TRUE;
@@ -379,7 +397,7 @@ void stringtobase(char *str, char *base)
 			break;
 			break;
 
 
 		default:
 		default:
-			tintin_printf2(gtd->ses, "#FORMAT: Unknown base conversion {%s}.", base);
+			tintin_printf2(gtd->ses, "#FORMAT: UNKNOWN BASE CONVERSION {%s}.", base);
 			break;
 			break;
 	}
 	}
 	free(buf);
 	free(buf);
@@ -407,7 +425,7 @@ void basetostring(char *str, char *base)
 			break;
 			break;
 
 
 		default:
 		default:
-			tintin_printf2(gtd->ses, "#FORMAT: Unknown base conversion {%s}.", base);
+			tintin_printf2(gtd->ses, "#FORMAT: UNKNOWN BASE CONVERSION {%s}.", base);
 			break;
 			break;
 	}
 	}
 	pop_call();
 	pop_call();
@@ -433,7 +451,7 @@ void stringtobasez(char *str, char *base)
 			break;
 			break;
 
 
 		default:
 		default:
-			tintin_printf2(gtd->ses, "#FORMAT: Unknown base conversion {%s}.", base);
+			tintin_printf2(gtd->ses, "#FORMAT: UNKNOWN BASE CONVERSION {%s}.", base);
 			break;
 			break;
 	}
 	}
 	free(buf);
 	free(buf);
@@ -461,7 +479,7 @@ void basetostringz(char *str, char *base)
 			break;
 			break;
 
 
 		default:
 		default:
-			tintin_printf2(gtd->ses, "#FORMAT: Unknown base conversion {%s}.", base);
+			tintin_printf2(gtd->ses, "#FORMAT: UNKNOWN BASE CONVERSION {%s}.", base);
 			break;
 			break;
 	}
 	}
 	pop_call();
 	pop_call();
@@ -1645,7 +1663,7 @@ DO_COMMAND(do_format)
 
 
 	if (*argvar == 0)
 	if (*argvar == 0)
 	{
 	{
-		show_error(ses, LIST_VARIABLE, "#SYNTAX: #format {variable} {format} {arg1} {arg2}");
+		show_error(ses, LIST_VARIABLE, "#SYNTAX: #FORMAT <VARIABLE> <FORMAT> [ARG1] [ARG2] .. [ARG29] [ARG30]");
 
 
 		return ses;
 		return ses;
 	}
 	}

Some files were not shown because too many files changed in this diff