Przeglądaj źródła

Feat: cumulative update

dzp 6 miesięcy temu
rodzic
commit
637c57efbc
60 zmienionych plików z 1551 dodań i 780 usunięć
  1. 123 29
      SCRIPTS
  2. 9 77
      TODO
  3. 30 23
      docs/help.html
  4. 4 3
      docs/tutorial.html
  5. 41 1
      mods/igr.mods
  6. 11 11
      src/advertise.c
  7. 37 68
      src/banner.c
  8. 20 18
      src/base.c
  9. 2 2
      src/buffer.c
  10. 14 12
      src/chat.c
  11. 71 4
      src/class.c
  12. 1 1
      src/command.c
  13. 5 5
      src/config.c
  14. 187 18
      src/cursor.c
  15. 3 3
      src/daemon.c
  16. 29 26
      src/data.c
  17. 10 27
      src/draw.c
  18. 10 5
      src/edit.c
  19. 8 5
      src/event.c
  20. 5 5
      src/files.c
  21. 138 0
      src/gui.h
  22. 78 70
      src/help.c
  23. 3 3
      src/history.c
  24. 14 20
      src/input.c
  25. 24 25
      src/line.c
  26. 30 10
      src/main.c
  27. 33 24
      src/mapper.c
  28. 25 25
      src/math.c
  29. 1 1
      src/mccp.c
  30. 1 1
      src/memory.c
  31. 48 0
      src/misc.c
  32. 6 6
      src/msdp.c
  33. 3 3
      src/nest.c
  34. 3 3
      src/net.c
  35. 30 19
      src/parse.c
  36. 12 13
      src/path.c
  37. 11 7
      src/port.c
  38. 6 8
      src/regex.c
  39. 224 14
      src/scan.c
  40. 8 8
      src/screen.c
  41. 8 3
      src/session.c
  42. 11 8
      src/show.c
  43. 6 6
      src/sort.c
  44. 4 4
      src/split.c
  45. 16 12
      src/ssl.c
  46. 3 3
      src/string.c
  47. 7 7
      src/substitute.c
  48. 12 6
      src/system.c
  49. 33 30
      src/tables.c
  50. 7 7
      src/telopt_client.c
  51. 1 1
      src/telopt_server.c
  52. 1 1
      src/terminal.c
  53. 9 6
      src/tintin.h
  54. 29 17
      src/tokenize.c
  55. 19 18
      src/trigger.c
  56. 19 14
      src/update.c
  57. 1 1
      src/utf8.c
  58. 15 1
      src/utils.c
  59. 6 6
      src/variable.c
  60. 26 26
      src/vt102.c

+ 123 - 29
SCRIPTS

@@ -7,14 +7,17 @@
 #nop static (16) flag to <168>.
 #nop -------------------------------------------------------------------------
 
-#loop 1 1000 vnum
+#alias {color_static}
 {
-	#map at $vnum
+	#loop 1 1000 vnum
 	{
-		#map get roomflags result;
-		#if {$result & 16}
+		#map at $vnum
 		{
-			#map set roomcolor <168>
+			#map get roomflags result;
+			#if {$result & 16}
+			{
+				#map set roomcolor <168>
+			}
 		}
 	}
 }
@@ -152,7 +155,7 @@
 }
 {60}
 
-#alias {ticklist}
+#alias {tickers}
 {
 	#info tickers save;
 
@@ -242,33 +245,35 @@
 #nop Show xterm 256 colors.
 #nop -------------------------------------------------------------------------
 
-#var temp {}
-
-#foreach {0;1;2;3;4;5;6;7;8;9;10;11;12;13;14;15} {var1}
+#alias {color_table}
 {
-	#showme {$var1 \e[38;5;${var1}m}
-}
+	#var temp {};
 
-#foreach {a;b;c;d;e;f} {var1}
-{
-	#foreach {a;b;c;d;e;f} {var2}
+	#foreach {0;1;2;3;4;5;6;7;8;9;10;11;12;13;14;15} {var1}
 	{
-		#foreach {a;b;c;d;e;f} {var3}
+		#showme {$var1 \e[38;5;${var1}m}
+	};
+
+	#foreach {a;b;c;d;e;f} {var1}
+	{
+		#foreach {a;b;c;d;e;f} {var2}
 		{
-			#var temp {$temp <$var1$var2$var3><<888>$var1$var2$var3>}
-		};
-		#showme $temp;
-		#var temp {}
-	}
-}
+			#foreach {a;b;c;d;e;f} {var3}
+			{
+				#var temp {$temp <$var1$var2$var3><<888>$var1$var2$var3>}
+			};
+			#showme $temp;
+			#var temp {}
+		}
+	};
 
-#loop 0 23 cnt
-{
-	#format temp {$temp <g%+02s><<888>g%+02s} {$cnt} {$cnt};
+	#loop 0 23 cnt
+	{
+		#format temp {$temp <g%+02s><<888>g%+02s} {$cnt} {$cnt};
+	};
+	#showme $temp
 }
 
-#showme $temp
-
 #nop -------------------------------------------------------------------------
 #nop Draw a health bar. Alternatively: #draw bar -2 1 -2 20 {%1;%2;<faa><afa>}
 #nop -------------------------------------------------------------------------
@@ -437,7 +442,7 @@
 	#line gag
 }
 
-#alias {repeat_check}
+#alias {repeat_show}
 {
 	#if {$repeat[cnt] <= 1}
 	{
@@ -445,7 +450,7 @@
 	};
 	#else
 	{
-		#line ignore #showme {($repeat[cnt]) %0}
+		#line ignore #showme {<128>($repeat[cnt]) <088>$repeat[str]}
 	};
 	#var repeat[str] {};
 	#var repeat[cnt] 1
@@ -848,7 +853,7 @@
 
 			#draw red teed line $SCROLL[BOT_ROW]+1 $SCROLL[TOP_COL] $SCROLL[BOT_ROW]+1 $SCROLL[BOT_COL];
 
-			#screen clear square $SCROLL[BOT_ROW]+2 $SCROLL[TOP_COL] $SCROLL[OLD_ROW] $SCROLL[BOT_COL];
+			#nop #screen clear square $SCROLL[BOT_ROW]+2 $SCROLL[TOP_COL] $SCROLL[OLD_ROW] $SCROLL[BOT_COL];
 		};
 	};
 	#if {$SCROLL[MODE] == 1}
@@ -1038,6 +1043,95 @@
 	#line ignore #showme <118>wton %0 = $wton
 }
 
+#nop -------------------------------------------------------------------------
+#nop Utility aliases to save variables as json, and load json as variables.
+#nop -------------------------------------------------------------------------
+
+#alias {json_save}
+{
+	#if {"%1" == "" || "%2" == ""}
+	{
+		#showme Syntax: json_save <variable> <filename>;
+		#return
+	};
+
+	#line quiet #log remove %2;
+	#line json {%1} {#line log {%2} {&0}}
+}
+
+#alias {json_load}
+{
+	#if {"%1" == "" || "%2" == ""}
+	{
+		#showme Syntax: json_load <variable> <filename>;
+		#return
+	};
+	#line quiet #unvar {%2};
+	#scan json {%2} {%1}
+}
+
+#nop -------------------------------------------------------------------------
+#nop Example of switching to an editing window, with mouse support. Use #edit
+#nop create to start editing. After editing is finished you can use #edit save
+#nop to store the data to a variable.
+#nop -------------------------------------------------------------------------
+
+#config mouse on
+
+#event {PROGRAM START}
+{
+	#screen raise {SCREEN RESIZE}
+}
+
+#event {SCREEN RESIZE}
+{
+	#screen clear all;
+
+	#screen scroll  2 2 -10 -2;
+	#screen input  -7 2 -2 -2;
+
+	#draw azure rounded left right bot top side 1 1 -9 -1;
+	#draw azure rounded left right bot top side -8 1 -1 -1
+}
+
+#event {PRESSED INPUT MOUSE BUTTON ONE}
+{
+	#cursor position %0 %1
+}
+
+#event {EDIT STARTED}
+{
+	#screen inputregion 2 2 -10 -2;
+	#screen scrollregion -7 2 -2 -2
+}
+
+#event {CATCH EDIT FINISHED}
+{
+	#screen input  -7 2 -2 -2;
+	#screen scroll  2 2 -10 -2;
+	#showme <138>EDIT FINISHED %0. LINES: %1  SIZE: %2
+}
+
+#nop -------------------------------------------------------------------------
+#nop Example script for drawing health bars
+#nop -------------------------------------------------------------------------
+
+#split 26 0
+#screen clear top
+
+#alias {draw_bar}
+{
+	#math value 0;
+	#loop 1 26 cnt
+	{
+		#draw ralign tile $cnt 1 $cnt 8 <178>$value/100;
+		#draw horizontal bar $cnt 10 $cnt 20 {$value;100;%0};
+		#math value $value + 4
+	}
+}
+
+draw_bar <faa><afa>
+
 #nop -------------------------------------------------------------------------
 #nop 
 #nop -------------------------------------------------------------------------

+ 9 - 77
TODO

@@ -1,80 +1,32 @@
-- switch to pcre2
-
-- #alias test {#if {1} {%1}} gives an error on an empty input.
-
-- check if #scan file is escaping braces
-
-- If I set #config log_level low then it ignores #log timestamp {%Y-%m-%d-%H:%M:%S}
-
-- Update script's --time-style=full-iso doesn't work on Mac.
-
-- Investigate: EVENT_FLAG_UPDATE running as gtd->level->quiet++ in check_all_events
-
-- Add an example #edit script to SCRIPTS
-
-- #map offset 10 10 doesn't generate an error
-
-- strip [ ] from auto tab completion
+- Add full script highlighting of nested commands as well as variables,
+  indicate missing variables and functions. Add #info <list> show.
 
-- #draw tile 1 1 1 1 {\x7B}
+- #config {COMMAND ECHO} mode that echoes all commands as sent to the mud.
 
-- #screen scroll 10 1 -3 -1;#showme {bla} {-2}
+- make roomdata searchable in #map
 
-#draw RED ROUNDED BOX {1 1 2 2} gives a poor error message
+- #split 0 0 -100 -100 should do something sensible
 
-- #var foo {{}{aaa}} creates no assignment
+- Add blight to msdp/gmcp/mssp listing
 
-- With internet down, #session reconnect events might fail
-
-- Write an example script that makes tintin mimic Discord, with soft enters, emoticons, etc.
-
-- Add an example script to display time left on tickers using #info tickers save
+- switch to pcre2
 
 - comprehensive memory breakdown for variables/triggers/mapper/etc
 
-- #draw calign grid table {2} {2} {8} {42} {n;s;w;e} {n;s;w;e}; doesn't work properly.
-
 - a better trigger stack debug buffer
 
-- Problem with restoring true color subs.
-#sub bla {<F00AA00>bla}
-#high blo <118>
-#showme <158>test bli bla blo test
-
-- named delays don't work in gts
-
-- #SPLIT when you give the top bar a negative value for its size, TinTin isn’t drawing the white box around it
-
-- Add an option to insert multiple items to a list
-
 - allow setting output encoding for #port
 
 - https://github.com/mintty/mintty/wiki/CtrlSeqs#audio-support
 - mintty --configdir DIRNAME
 
-- Fix: #ERROR: UNKNOWN TOKEN TYPE: 14 (#info tokenizer)
-
-- split screen scrollback setting in #screen
-
-- terrain based weight modifier
-- weightless mode for #map list and #map find
-
 - Make #draw scroll grid table work properly.
 
-
 - update https://tintin.mudhalla.net/info/ansicolor/
 
 - Make sure #config compact also applies to the log file.
 
-- Add an #event that triggers when a function/variable is not found.
-
-- tab completion on input history
-
-- look into handling VARIABLE UPDATE event better
-
-- catch event to handle #map global exceptions
-
-
+- catch event for #map global to handle exceptions
 
 - Add routine to escape 0x00 in port.c RECEIVED DATA event.
 
@@ -112,20 +64,14 @@
 
 - #line escape {variables;functions}
 
-- look into a #debug flag for #class
-
 - Another nice thing would be if there was some flag to make a trigger match newlines as space.
 
-- fix up named delays and undelay
-
 - add a #regex like command for #cursor to update the input line.
 
 - custom mapping for unicode table to set width
 
 - color code for dynamic color ranges
 
-- #MACRO {\cz} {#cursor get t;#var t} does not handle { } in input.
-
 - Look into delete_index_list leaving a table with ->used set to 0 causing #list crashes
 
 - #daemon attach fails under high cpu load
@@ -139,7 +85,7 @@
   - 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
+
 
   - check: #var bla { x};#draw scroll box 1 1 3 40 $bla
 
@@ -157,10 +103,6 @@
 
   - vertical bar drawing
 
-  - error: cursor_check_line_modified1: 
-  - https://tintin.sourceforge.io/forum/viewtopic.php?f=10&t=2811 (possible
-    issue with initiating input buffer for a new session)
-
   - finish BUFFER_SIZE replacement.
 
   - WSL sound, double check soundpack scripts for lag/stutter
@@ -175,10 +117,6 @@
 
 * STUFF THAT IS PROBABLY GONNA GET DONE
 
-  - #line timeshot to auto destroy a trigger after given interval.
-
-  - make named delays proper delays
-
   - Finish port proxy support: resizing, input, security
 
   - look into transparent drawing
@@ -225,8 +163,6 @@
 
   - Remote script loading
 
-  - add class specific debug
-  - better class event and class size handling ?
 
   - more potent long-click handling including held down ticks.
 
@@ -234,16 +170,12 @@
 
   - Add SESSIONS to the list table.
 
-  - Add debugger to syntax highlighter, substitution highlighing, 256 color support, and variable expansion.
-
   - add packets patched counter
 
   - reportable_sounds
 
   - TELNET documentation.
 
-  - Add JSON support to #scan
-
   - see if #break 2 is possible, maybe #continue 2 as well.
 
   - IPv6 for chat

+ 30 - 23
docs/help.html

@@ -94,10 +94,6 @@ a:active {color:#b06}
          arguments. The priority part is optional and determines the priority
          of the alias, it defaults to 5.
 
-         If no % variable is used in the commands section any argument will be
-         appended to the end as if %0 was used. This feature might be removed
-         in the future, and shouldn't be used.
-
 </span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #alias {k} {kill %1;kick}
 
          Typing 'k orc' would result in attacking the orc followed by a kick.
@@ -417,7 +413,7 @@ a:active {color:#b06}
          clients, typically for the purpose of chatting and sending files.
          This is a decentralized chat system, meaning you have to exchange ip
          addresses and port numbers with other users in order to connect to
-         them.
+         them. Chat events are triggered in the startup session.
 
          </span><span style='color:#FFF'>#chat {init} {port}
 </span><span style='color:#AAA'>           #chat initialize launches your chat server. The port number is
@@ -472,8 +468,8 @@ a:active {color:#b06}
            used instead of the connection's name when sending someone a message
            The second column shows the connection's name. The third column
            shows flags set for the connection, (P)rivate, (I)gnore, (S)erve,
-           (F)orward to user, and (f)orward from user. The next columns show
-           ip, port, and client name.
+           Forward(A)ll to user, (F)orward to user, and (f)orward from user.
+           The next columns show ip, port, and client name.
          </span><span style='color:#FFF'>#chat {zap}        {buddy}            Close a connection
 
 Related</span><span style='color:#AAA'>: <a href='#PORT'>port</a>
@@ -492,6 +488,8 @@ Related</span><span style='color:#AAA'>: <a href='#PORT'>port</a>
 </span><span style='color:#AAA'>           Will delete all triggers associated with the given class.
          </span><span style='color:#FFF'>#class {&lt;name&gt;} {close}
 </span><span style='color:#AAA'>           Close the given class, opening the last open class, if any.
+         </span><span style='color:#FFF'>#class {&lt;name&gt;} {debug} {on|off}
+</span><span style='color:#AAA'>           Toggle debug mode for given class.
          </span><span style='color:#FFF'>#class {&lt;name&gt;} {kill}
 </span><span style='color:#AAA'>           Will clear, close, and remove the class.
          </span><span style='color:#FFF'>#class {&lt;name&gt;} {list}
@@ -714,6 +712,7 @@ Related</span><span style='color:#AAA'>: <a href='#PORT'>port</a>
          COMPLETE    makes tab completion work while editing
 
          DICTIONARY  performs tab completion on the dictionary
+         INPUT       performs tab completion on the input history
          LIST        performs tab completion on the tab completion list
          SCROLLBACK  performs tab completion on the scrollback buffer
 
@@ -882,7 +881,7 @@ Command</span><span style='color:#AAA'>: #delay </span><span style='color:#FFF'>
          [BOXED] </span><span style='color:#FFF'>MAP
 </span><span style='color:#AAA'>           will draw the map
          </span><span style='color:#FFF'>RAIN</span><span style='color:#AAA'> {&lt;VARIABLE&gt;} {[SPAWN]} {[FADE]} {[LEGEND]}
-           will draw digital rain.
+           will draw digital rain SPAWN (0.01-100) FADE (1-100).
          [JOINTED|TOP|LEFT|BOTTOM|RIGHT] </span><span style='color:#FFF'>SIDE
 </span><span style='color:#AAA'>           will draw one or more sides of a box.
          [GRID] </span><span style='color:#FFF'>TABLE</span><span style='color:#AAA'> {[LIST1]} {[LIST2]}
@@ -1177,6 +1176,9 @@ Command</span><span style='color:#AAA'>: #delay </span><span style='color:#FFF'>
 </span><span style='color:#AAA'>         </span><span style='color:#FFF'>EDIT STARTED, EDIT FINISHED
 </span><span style='color:#AAA'>           %0 name  %1 lines %2 size %3 data
 
+         </span><span style='color:#FFF'>EDIT RESUMED, EDIT SUSPENDED
+</span><span style='color:#AAA'>           %0 name
+
          </span><span style='color:#FFF'>HISTORY UPDATE
 </span><span style='color:#AAA'>           %0 command
 
@@ -1251,12 +1253,13 @@ Command</span><span style='color:#AAA'>: #delay </span><span style='color:#FFF'>
 
          </span><span style='color:#5F5'>PORT EVENTS
 
-</span><span style='color:#AAA'>         </span><span style='color:#FFF'>CHAT MESSAGE</span><span style='color:#AAA'>, </span><span style='color:#FFF'>PORT MESSAGE
-</span><span style='color:#AAA'>           %0 raw text  %1 plain text
+</span><span style='color:#AAA'>         </span><span style='color:#FFF'>CHAT MESSAGE           </span><span style='color:#AAA'>%0 raw text  %1 plain text
+         </span><span style='color:#FFF'>CHAT SNOOP REQUEST     </span><span style='color:#AAA'>%0 name %1 ip %2 port
 
          </span><span style='color:#FFF'>PORT CONNECTION        </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 MESSAGE           </span><span style='color:#AAA'>%0 raw text %1 plain text
          </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
 
@@ -1467,7 +1470,7 @@ Command</span><span style='color:#AAA'>: #delay </span><span style='color:#FFF'>
 
 </span><span style='color:#0AA'>      ####################################################################
       #</span><span style='color:#AAA'>                                                                  </span><span style='color:#0AA'>#
-      #</span><span style='color:#AAA'>                    T I N T I N + +   2.02.42                     </span><span style='color:#0AA'>#
+      #</span><span style='color:#AAA'>                    T I N T I N + +   2.02.51                     </span><span style='color:#0AA'>#
       #</span><span style='color:#AAA'>                                                                  </span><span style='color:#0AA'>#
       #</span><span style='color:#AAA'>      Code by Peter Unold, Bill Reis, and Igor van den Hoven      </span><span style='color:#0AA'>#
       #</span><span style='color:#AAA'>                                                                  </span><span style='color:#0AA'>#
@@ -3269,7 +3272,7 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
          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>
 
 </span><span style='color:#FF5'>         MSDP
@@ -3748,12 +3751,11 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
 
 </span><span style='color:#FFF'>Command</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'>         Reads a commands file into memory.  The coms file is merged in with
-         the currently loaded commands.  Duplicate commands are overwritten.
+</span><span style='color:#AAA'>         Reads a commands file into memory.  The commands are merged with the
+         currently loaded commands.  Duplicate commands are overwritten.
 
-         If you uses braces, { and } you can use several lines for 1 commands.
-         This however means you must always match every { with a } for the read
-         command to work.
+         If you uses braces you can use several lines for each command.  You
+         must match every { with a } for the read command to work.
 
          You can comment out triggers using /* text */
 
@@ -3833,12 +3835,13 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
 
 </span><span style='color:#FF5'>         REPEAT
 
-</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'>} {</span><span style='color:#AAA'>..</span><span style='color:#FFF'>}
 
 </span><span style='color:#AAA'>        Sometimes you want to repeat the same command multiple times. This is
         the easiest way to accomplish that.
 
 </span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #10 {buy bread}
+</span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #2 {buy bread} {buy apple}
 
 </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>
@@ -3915,8 +3918,12 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
 
 </span><span style='color:#FFF'>         #scan {dir} &lt;filename&gt; &lt;variable&gt;
 
-</span><span style='color:#AAA'>          The scan dir command will read the given filename or directory and
-          store any gathered information into the provided variable.
+</span><span style='color:#AAA'>           The scan dir command will read the given filename or directory and
+           store any gathered information into the provided variable.
+
+</span><span style='color:#FFF'>         #scan {json} &lt;filename&gt; &lt;variable&gt;
+</span><span style='color:#AAA'>           The scan json command will read the given filename and store the data
+           in the provided tintin variable.
 
          </span><span style='color:#FFF'>#scan {tsv} &lt;filename&gt;
 
@@ -3928,9 +3935,9 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
          </span><span style='color:#FFF'>#scan {file} &lt;filename&gt; {commands}
 
 </span><span style='color:#AAA'>           The scan file command reads the given files and executes the
-            commands argument. &amp;0 contains the raw content of the file and
-            &amp;1 contains the plain content. &amp;2 contains the raw byte size of the
-            file and &amp;3 the plain byte size. &amp;5 contains the line count.
+           commands argument. &amp;0 contains the raw content of the file and
+           &amp;1 contains the plain content. &amp;2 contains the raw byte size of the
+           file and &amp;3 the plain byte size. &amp;5 contains the line count.
 
          </span><span style='color:#FFF'>#scan {txt} &lt;filename&gt;
 

+ 4 - 3
docs/tutorial.html

@@ -614,7 +614,7 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
 
 </span><span style='color:#0AA'>      ####################################################################
       #</span><span style='color:#AAA'>                                                                  </span><span style='color:#0AA'>#
-      #</span><span style='color:#AAA'>                    T I N T I N + +   2.02.42                     </span><span style='color:#0AA'>#
+      #</span><span style='color:#AAA'>                    T I N T I N + +   2.02.51                     </span><span style='color:#0AA'>#
       #</span><span style='color:#AAA'>                                                                  </span><span style='color:#0AA'>#
       #</span><span style='color:#AAA'>      Code by Peter Unold, Bill Reis, and Igor van den Hoven      </span><span style='color:#0AA'>#
       #</span><span style='color:#AAA'>                                                                  </span><span style='color:#0AA'>#
@@ -1217,7 +1217,7 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
          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>
 
 </span><span style='color:#FF5'>         MSDP
@@ -1506,12 +1506,13 @@ Example</span><span style='color:#AAA'>: #high </span><span style='color:#FFF'>{
 
 </span><span style='color:#FF5'>         REPEAT
 
-</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'>} {</span><span style='color:#AAA'>..</span><span style='color:#FFF'>}
 
 </span><span style='color:#AAA'>        Sometimes you want to repeat the same command multiple times. This is
         the easiest way to accomplish that.
 
 </span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #10 {buy bread}
+</span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #2 {buy bread} {buy apple}
 
 </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>

+ 41 - 1
mods/igr.mods

@@ -1,5 +1,45 @@
-Jan 2025        2.02.50
+Jun 2025        2.02.52
 ------------------------------------------------------------------------------
+base.c          Fixed a bug in the base64 conversion code. People using
+                tt++ -g will have to update their character passwords.
+
+Jan 2025        2.02.51
+------------------------------------------------------------------------------
+WinTin++        You can play .wav files in WinTin++ by creating the 'sounds'
+                directory in the 'bin' directory. Wav files stored in the
+                sounds directory can be played by executing:
+                #showme {\e]440;<filename>\a\}. To avoid playing multiple
+                sounds at once you can use:
+                #showme {\e]440;<filename>:async:nostop\a\}. You can cancel
+                an async sound using #showme {\e]440\a\}.
+
+data.c          #info system will report WINTIN++ as the OS for WinTin++.
+
+parse.c         Added support for multiple braced arguments to the repeat
+                option. #1 {#showme bli} {#showme bla}
+
+main.c          Added tt++ -l regex startup option to load a regex tester.
+
+input.c         Added the MODIFIED INPUT event. Triggers whenever the input
+                line is modified.
+
+vt102.c         Fixed true color handling for #highlight.
+
+cursor.c        Added automatic tab support on the input history.
+
+scan.c          Fixed a bug where #scan dir was storing invalid timestamps
+                on 32 bit systems.
+
+scan.c          The plain text argument of #scan file will have braces
+                substituted with \x7B \x7D.
+
+trigger.c       Using an alias that doesn't contain %0-%99 and providing an
+                an argument will generate a warning.
+
+class.c         Added #class <name> debug <on|off> option.
+
+scan.c          Added the #scan json <file> <variable> option. It will load
+                the given json file and store the data in the given variable.
 
 Jan 2024        2.02.42
 ------------------------------------------------------------------------------

+ 11 - 11
src/advertise.c

@@ -153,7 +153,7 @@ struct advertisement_type advertisement_table[] =
                 "\n"
                 "<178>To connect to 3Kingdoms enter:  #session 3K 3k.org 3000\n"
                 "\n",
- 
+
                 "\n"
                 "<138>3Kingdoms\n"
                 "<168>http://3k.org\n"
@@ -165,8 +165,8 @@ struct advertisement_type advertisement_table[] =
 	},
 
 	{
-		1400000000,  /* 2014 */ 
-		1800000000,  /* 2027 */ 
+		1400000000,  /* 2014 */
+		1800000000,  /* 2027 */
 		100,
 
 		"\n"
@@ -244,7 +244,7 @@ struct advertisement_type advertisement_table[] =
 		"\n"
 		"<178>To connect to Primal Darkness enter: #session pd mud.primaldarkness.com 5000\n"
 		"\n",
-		
+
 		"\n"
 		"<138>Primal Darkness\n"
 		"<168>http://www.primaldarkness.com\n"
@@ -318,8 +318,8 @@ struct advertisement_type advertisement_table[] =
 
 /*
 	{
-		1400000000, 
-		1700000000, 
+		1400000000,
+		1700000000,
 		100,
 		"\n"
 		"<138>               Carrion Fields  -  http://carrionfields.net\n"
@@ -333,12 +333,12 @@ struct advertisement_type advertisement_table[] =
 		"\n"
                 "<178>To connect to Carrion Fields enter: #session cf carrionfields.net 4449\n"
                 "\n"
-		                
+
 	},
 
 	{
-		1400000000, 
-		1700000000, 
+		1400000000,
+		1700000000,
 		100,
 		"\n"
 		"<138>                 Alter Aeon  -  http://www.alteraeon.com\n"
@@ -356,7 +356,7 @@ struct advertisement_type advertisement_table[] =
 	},
 
 	{
-		1388166000, 
+		1388166000,
 		1600000000,
 		100,
 		"\n"
@@ -520,7 +520,7 @@ DO_COMMAND(do_advertise)
 		"\n"
                 "<178>To connect to Lost Souls enter: #session ls lostsouls.org 23\n"
                 "\n"
-		                
+
 	},
 
 	{

+ 37 - 68
src/banner.c

@@ -25,8 +25,6 @@
 
 #include "tintin.h"
 
-#include "gui.h"
-
 #define BANNER_FLAG_DUPLICATE BV01
 
 void banner_create(struct session *ses, char *name, char *arg)
@@ -129,7 +127,7 @@ void banner_init(struct session *ses, char *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_expires(ses, "New Worlds Ateraan", "2030", arg1);
 
 
 	banner_create(ses, "Untold Dawn", arg1);
@@ -145,24 +143,23 @@ void banner_init(struct session *ses, char *arg1)
 	banner_address(ses, "Untold Dawn", "ud www.untold-dawn.com 4000", arg1);
 	banner_expires(ses, "Untold Dawn", "2030", arg1);
 
-/*
-	banner_create(ses, "Lost Souls", arg1);
 
-	banner_desc(ses, "Lost Souls",
-		"\"Lost Souls is not for the faint of heart.\" -- Net Games\n"
-		"\n"
-		"\"The depth of Lost Souls can be amazing.\" -- Playing MUDs On The Internet\n"
-		"\n"
-		"\"Have you ever come upon a place on the Net that's so incredible that you\n"
-		"can't believe such entertainment is free? This MUD will blow your mind with\n"
-		"its marvelous attention to detail and incredible role-playing atmosphere!\"\n"
-		"\n"
-		"  -- Yahoo! Wild Web Rides", arg1);
+	banner_create(ses, "Northern Crossroads", arg1);
 
-	banner_website(ses, "Lost Souls", "https://lostsouls.org", arg1);
-	banner_address(ses, "Lost Souls", "ls lostsouls.org 23", arg1);
-	banner_expires(ses, "Lost Souls", "2029", arg1);
+	banner_desc(ses, "Northern Crossroads",
+		"Northern Crossroads is a diverse world of blade wielders, assassins\n"
+		"and magic users who use their powers together to seek out the darkest\n"
+		"dungeons for hack'n'slash action. Decide between many classes, as\n"
+		"allowed by your choice of ten races, and prove your strength to ascend\n"
+		"to an Advanced class. Venture to dangerous zones with other mortals,\n"
+		"claim the rarest of items, join one of several clubs and build your character\n"
+		"to challenge other mortals. NC has enthralled players with hundreds of\n"
+		"detailed areas of various themes since 1993 and is one of the oldest\n"
+		"MUDs in the world.\n", arg1);
 
+	banner_website(ses, "Northern Crossroads", "https://www.ncmud.org", arg1);
+	banner_address(ses, "Northern Crossroads", "NC ncmud.org 9000", arg1);
+	banner_expires(ses, "Northern Crossroads", "2031", arg1);
 
 	banner_create(ses, "Kallisti MUD", arg1);
 
@@ -179,7 +176,7 @@ void banner_init(struct session *ses, char *arg1)
 
 	banner_website(ses, "Kallisti MUD", "https://www.KallistiMUD.com", arg1);
 	banner_address(ses, "Kallisti MUD", "LoK kallistimud.com 4000", arg1);
-	banner_expires(ses, "Kallisti MUD", "2029", arg1);
+	banner_expires(ses, "Kallisti MUD", "2031", arg1);
 	banner_flag(ses, "Kallisti MUD", BANNER_FLAG_DUPLICATE);
 
 
@@ -198,7 +195,26 @@ void banner_init(struct session *ses, char *arg1)
 
 	banner_website(ses, "Legends of Kallisti", "https://legendsofkallisti.com", arg1);
 	banner_address(ses, "Legends of Kallisti", "LoK legendsofkallisti.com 4000", arg1);
-	banner_expires(ses, "Legends of Kallisti", "2029", arg1);
+	banner_expires(ses, "Legends of Kallisti", "2031", arg1);
+
+/*
+	banner_create(ses, "Lost Souls", arg1);
+
+	banner_desc(ses, "Lost Souls",
+		"\"Lost Souls is not for the faint of heart.\" -- Net Games\n"
+		"\n"
+		"\"The depth of Lost Souls can be amazing.\" -- Playing MUDs On The Internet\n"
+		"\n"
+		"\"Have you ever come upon a place on the Net that's so incredible that you\n"
+		"can't believe such entertainment is free? This MUD will blow your mind with\n"
+		"its marvelous attention to detail and incredible role-playing atmosphere!\"\n"
+		"\n"
+		"  -- Yahoo! Wild Web Rides", arg1);
+
+	banner_website(ses, "Lost Souls", "https://lostsouls.org", arg1);
+	banner_address(ses, "Lost Souls", "ls lostsouls.org 23", arg1);
+	banner_expires(ses, "Lost Souls", "2029", arg1);
+
 
 
 	banner_create(ses, "3Kingdoms", arg1);
@@ -490,49 +506,6 @@ void banner_test(struct session *ses, char *arg1)
 	tintin_header(ses, 80, "");
 }
 
-struct session *banner_gui(struct session *ses, char *arg1)
-{
-	char data[BUFFER_SIZE];
-	FILE *file;
-	size_t len;
-
-	strcpy(data, tt_gui);
-
-	len = strlen(data);
-
-	file = fmemopen(data, len, "r");
-
-	gtd->level->quiet++;
-
-	ses = read_file(ses, file, "tt_gui.h");
-
-	gtd->level->quiet--;
-
-	fclose(file);
-
-	return ses;
-
-/*
-	char filename[PATH_SIZE];
-	FILE *file;
-
-	sprintf(filename, "%s/gui.tin", gtd->system->tt_dir);
-
-	if ((file = fopen(filename, "w")) == NULL)
-	{
-		tintin_printf2(ses, "#BANNER GUI: FAILED TO CREATE {%s}.", filename);
-
-		return ses;
-	}
-
-	fputs(tt_gui, file);
-
-	fclose(file);
-
-	return command(ses, do_line, "quiet #read %s", filename);
-*/
-}
-
 DO_COMMAND(do_banner)
 {
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
@@ -545,10 +518,6 @@ DO_COMMAND(do_banner)
 	{
 		banner_init(ses, arg1);
 	}
-	else if (is_abbrev(arg1, "GUI"))
-	{
-		return banner_gui(ses, arg1);
-	}
 	else if (is_abbrev(arg1, "LIST"))
 	{
 		banner_list(ses, arg1);
@@ -563,7 +532,7 @@ DO_COMMAND(do_banner)
 	}
 	else if (is_abbrev(arg1, "HELP"))
 	{
-		tintin_printf2(ses, "#SYNTAX: #BANNER {GUI|INIT|LIST|RANDOM|SAVE|TEST}");
+		tintin_printf2(ses, "#SYNTAX: #BANNER {INIT|LIST|RANDOM|SAVE|TEST}");
 	}
 	else
 	{

+ 20 - 18
src/base.c

@@ -28,22 +28,22 @@
 char base64_table[64] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };
 
 char str64_table[256] =
-{ 
+{
 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 62,  0,  0,  0, 63,
 	52, 53, 54, 55, 56, 57, 58, 59, 60, 61,  0,  0,  0,  0,  0,  0,
 	 0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
 	15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,  0,  0,  0,  0,  0,
-	 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,	 
-	41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,  0,  0,  0,  0,  0,	 
+	 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+	41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,  0,  0,  0,  0,  0,
 
 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,	 
 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,	 
 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,	 
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
 };
@@ -142,6 +142,7 @@ int decompress_data(char *in, size_t size_in, char *out, size_t size_out)
 int str_to_base64(char *in, char *out, size_t size)
 {
 	char *pto;
+	unsigned char *uin = (unsigned char *) in;
 	int cnt;
 
 	push_call("str_to_base64(%p,%p,%zu)",in,out,size);
@@ -150,24 +151,24 @@ int str_to_base64(char *in, char *out, size_t size)
 
 	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 + (unsigned char) in[cnt + 1] % 16 * 4];
-		*pto++ = base64_table[(unsigned char) in[cnt + 1] / 16 + (unsigned char) in[cnt + 2] % 4 * 16];
-		*pto++ = base64_table[(unsigned char) in[cnt + 2] /  4];
+		*pto++ = base64_table[uin[cnt + 0] / 4];
+		*pto++ = base64_table[uin[cnt + 0] % 4 * 16 + uin[cnt + 1] / 16];
+		*pto++ = base64_table[uin[cnt + 1] % 16 * 4 + uin[cnt + 2] / 64];
+		*pto++ = base64_table[uin[cnt + 2] % 64];
 	}
 
 	switch (size - cnt)
 	{
 		case 1:
-			*pto++ = base64_table[(unsigned char) in[cnt + 0] % 64];
-			*pto++ = base64_table[(unsigned char) in[cnt + 0] / 64];
+			*pto++ = base64_table[uin[cnt + 0] / 4];
+			*pto++ = base64_table[uin[cnt + 0] % 4 * 16];
 			*pto++ = '=';
 			*pto++ = '=';
 			break;
 		case 2:
-			*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 + 1] / 16];
+			*pto++ = base64_table[uin[cnt + 0] / 4];
+			*pto++ = base64_table[uin[cnt + 0] % 4 * 16 + uin[cnt + 1] / 16];
+			*pto++ = base64_table[uin[cnt + 1] % 16 * 4];
 			*pto++ = '=';
 			break;
 	}
@@ -182,27 +183,28 @@ int str_to_base64(char *in, char *out, size_t size)
 int base64_to_str(char *in, char *out, size_t size)
 {
 	char *pto;
+	unsigned char *uin = (unsigned char *) in;
 	int cnt;
 
 	pto = out;
 
 	for (cnt = 0 ; cnt + 4 <= size ; cnt += 4)
 	{
-		*pto++ = str64_table[(unsigned char) in[cnt + 0]] + str64_table[(unsigned char) in[cnt + 1]] % 4 * 64;
+		*pto++ = str64_table[uin[cnt + 0]] * 4 + str64_table[uin[cnt + 1]] / 16;
 
 		if (in[cnt + 1] == '=')
 		{
 			break;
 		}
 
-		*pto++ = str64_table[(unsigned char) in[cnt + 1]] / 4 + str64_table[(unsigned char) in[cnt + 2]] % 16 * 16;
+		*pto++ = str64_table[uin[cnt + 1]] % 16 * 16 + str64_table[uin[cnt + 2]] / 4;
 
 		if (in[cnt + 2] == '=')
 		{
 			break;
 		}
 
-		*pto++ = str64_table[(unsigned char) in[cnt + 2]] / 16 + str64_table[(unsigned char) in[cnt + 3]] * 4;
+		*pto++ = str64_table[uin[cnt + 2]] % 4 * 64 + str64_table[uin[cnt + 3]];
 	}
 	*pto++ = 0;
 

+ 2 - 2
src/buffer.c

@@ -1172,7 +1172,7 @@ DO_BUFFER(buffer_info)
 
 	check_buffer(ses);
 
-	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);
 	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
 
 	if (*arg1 == 0)
@@ -1331,7 +1331,7 @@ DO_COMMAND(do_grep)
 				if (grep_cnt + grep_add >= grep_min)
 				{
 					grep_cnt += grep_add;
-					
+
 					tintin_puts2(ses, ses->scroll->buffer[scroll_cnt]->str);
 
 					if (grep_cnt + grep_add > grep_max)

+ 14 - 12
src/chat.c

@@ -151,7 +151,7 @@ DO_CHAT(chat_initialize)
 		syserr_printf(gtd->ses, "chat_initialize: setsockopt");
 	}
 
-	ld.l_onoff  = 0; 
+	ld.l_onoff  = 0;
 	ld.l_linger = 100;
 
 	setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *) &ld, sizeof(ld));
@@ -639,9 +639,9 @@ void chat_printf(char *format, ...)
 	}
 	str_cpy_printf(&tmp, "%s%s%s", gtd->chat->color, buf, "\e[0m");
 
-	check_all_events(gtd->ses, SUB_SEC|EVENT_FLAG_PORT, 0, 2, "CHAT MESSAGE", tmp, buf);
+	check_all_events(gts, SUB_SEC|EVENT_FLAG_PORT, 0, 2, "CHAT MESSAGE", tmp, buf);
 
-	if (!check_all_events(gtd->ses, SUB_SEC|EVENT_FLAG_CATCH, 0, 2, "CATCH CHAT MESSAGE", tmp, buf))
+	if (!check_all_events(gts, SUB_SEC|EVENT_FLAG_CATCH, 0, 2, "CATCH CHAT MESSAGE", tmp, buf))
 	{
 		tintin_printf(gtd->ses, "%s", tmp);
 	}
@@ -740,9 +740,9 @@ int process_chat_input(struct chat_data *buddy)
 		else
 		{
 			chat_socket_printf(buddy, "%c\n%s has refused your connection due to an invalid handshake. (%s)\n%c", CHAT_MESSAGE, gtd->chat->name, buf, CHAT_END_OF_COMMAND);
-			
+
 			chat_printf("Refusing connection from %.21s:%d, invalid handshake.", buddy->ip, buddy->port);
-			
+
 			pop_call();
 			return -1;
 		}
@@ -965,6 +965,7 @@ void get_chat_commands(struct chat_data *buddy, char *buf, int len)
 				break;
 
 			case CHAT_SNOOP_START:
+				check_all_events(gts, EVENT_FLAG_PORT, 0, 3, "CHAT SNOOP REQUEST", buddy->name, buddy->ip, ntos(buddy->port));
 				break;
 
 			case CHAT_SNOOP_DATA:
@@ -1478,7 +1479,7 @@ DO_CHAT(chat_paste)
 			if ((buddy = find_buddy(name)) != NULL)
 			{
 				chat_printf("You paste to %s:\n%s", buddy->name, gtd->chat->paste_buf);
-	
+
 				chat_socket_printf(buddy, "%c\n%s pastes to you:\n%s\n%c", CHAT_TEXT_EVERYBODY, gtd->chat->name, gtd->chat->paste_buf, CHAT_END_OF_COMMAND);
 			}
 			else if (find_group(name) != NULL)
@@ -1654,12 +1655,12 @@ DO_CHAT(chat_serve)
 	if (HAS_BIT(buddy->flags, CHAT_FLAG_SERVE))
 	{
 		chat_printf("You are now chat serving %s.", buddy->name);
-		chat_socket_printf(buddy, "%c\n%s is now chat serving you.\n%c", CHAT_MESSAGE, gtd->chat->name, CHAT_END_OF_COMMAND); 
+		chat_socket_printf(buddy, "%c\n%s is now chat serving you.\n%c", CHAT_MESSAGE, gtd->chat->name, CHAT_END_OF_COMMAND);
 	}
 	else
 	{
 		chat_printf("You are no longer chat serving %s.", buddy->name);
-		chat_socket_printf(buddy, "%c\n%s is no longer chat serving you.\n%c", CHAT_MESSAGE, gtd->chat->name, CHAT_END_OF_COMMAND); 
+		chat_socket_printf(buddy, "%c\n%s is no longer chat serving you.\n%c", CHAT_MESSAGE, gtd->chat->name, CHAT_END_OF_COMMAND);
 	}
 }
 
@@ -1680,6 +1681,7 @@ DO_CHAT(chat_who)
 			HAS_BIT(buddy->flags, CHAT_FLAG_PRIVATE)   ? "P" : " ",
 			HAS_BIT(buddy->flags, CHAT_FLAG_IGNORE)    ? "I" : " ",
 			HAS_BIT(buddy->flags, CHAT_FLAG_SERVE)     ? "S" : " ",
+			HAS_BIT(buddy->flags, CHAT_FLAG_FORWARDALL) ? "A" :
 			HAS_BIT(buddy->flags, CHAT_FLAG_FORWARD)   ? "F" :
 			HAS_BIT(buddy->flags, CHAT_FLAG_FORWARDBY) ? "f" : " ",
 			" ",
@@ -1918,7 +1920,7 @@ void chat_receive_file(char *arg, struct chat_data *buddy)
 		deny_file(buddy, "\nFile protocol error. (no file size was transmitted)\n");
 
 		pop_call();
-		return;	
+		return;
 	}
 	*comma = 0;
 
@@ -2112,7 +2114,7 @@ void file_cleanup(struct chat_data *buddy)
 	if (buddy->file_name)
 	{
 		free(buddy->file_name);
-		
+
 		buddy->file_name = NULL;
 	}
 }
@@ -2358,7 +2360,7 @@ DO_CHAT(chat_private)
 			{
 				chat_socket_printf(buddy, "%c\n%s marked your connection private.\n%c", CHAT_MESSAGE, gtd->chat->name, CHAT_END_OF_COMMAND);
 
-				chat_printf("Your connection with %s is now private.", buddy->name);				
+				chat_printf("Your connection with %s is now private.", buddy->name);
 
 				SET_BIT(buddy->flags, CHAT_FLAG_PRIVATE);
 			}
@@ -2396,7 +2398,7 @@ DO_CHAT(chat_public)
 			{
 				chat_socket_printf(buddy, "%c\n%s marked your connection public.\n%c", CHAT_MESSAGE, gtd->chat->name, CHAT_END_OF_COMMAND);
 
-				chat_printf("Your connection with %s is now public.", buddy->name);				
+				chat_printf("Your connection with %s is now public.", buddy->name);
 
 				DEL_BIT(buddy->flags, CHAT_FLAG_PRIVATE);
 			}

+ 71 - 4
src/class.c

@@ -31,6 +31,7 @@
 extern DO_CLASS(class_assign);
 extern DO_CLASS(class_clear);
 extern DO_CLASS(class_close);
+extern DO_CLASS(class_debug);
 extern DO_CLASS(class_kill);
 extern DO_CLASS(class_list);
 extern DO_CLASS(class_load);
@@ -54,6 +55,7 @@ struct class_type class_table[] =
 	{    "ASSIGN",            class_assign,   "Execute command with given class opened."        },
 	{    "CLEAR",             class_clear,    "Delete triggers associated with given class."    },
 	{    "CLOSE",             class_close,    "Close given class."                              },
+	{    "DEBUG",             class_debug,    "Show debug messages for 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."                 },
@@ -195,7 +197,7 @@ DO_CLASS(class_assign)
 
 	ses->group = strdup(arg1);
 
-	script_driver(ses, LIST_COMMAND, arg2);
+	script_driver(ses, LIST_COMMAND, node, arg2);
 
 	free(ses->group);
 
@@ -273,6 +275,71 @@ DO_CLASS(class_close)
 	return ses;
 }
 
+DO_CLASS(class_debug)
+{
+	if (node == NULL)
+	{
+		node = search_node_list(ses->list[LIST_CLASS], arg1);
+
+		if (node == NULL)
+		{
+			show_message(ses, LIST_CLASS, "#CLASS {%s} DOES NOT EXIST.", arg1);
+			return ses;
+		}
+	}
+
+	if (*arg2 == 0)
+	{
+		TOG_BIT(node->flags, NODE_FLAG_DEBUG);
+	}
+	else if (!strcasecmp(arg2, "ON"))
+	{
+		SET_BIT(node->flags, NODE_FLAG_DEBUG);
+	}
+	else if (!strcasecmp(arg2, "OFF"))
+	{
+		DEL_BIT(node->flags, NODE_FLAG_DEBUG);
+	}
+	else
+	{
+		show_error(ses, LIST_CLASS, "#SYNTAX: #CLASS {%s} DEBUG {ON|OFF}", arg1);
+		return ses;
+	}
+
+	if (HAS_BIT(node->flags, NODE_FLAG_DEBUG))
+	{
+		show_message(ses, LIST_CLASS, "#CLASS {%s} IS NOW BEING DEBUGGED.", arg1);
+	}
+	else
+	{
+		show_message(ses, LIST_CLASS, "#CLASS {%s} IS NO LONGER BEING DEBUGGED.", arg1);
+	}
+
+	for (int i = 0 ; i < LIST_MAX ; i++)
+	{
+		if (!HAS_BIT(ses->list[i]->flags, LIST_FLAG_CLASS))
+		{
+			continue;
+		}
+
+		for (int j = 0 ; j < ses->list[i]->used ; j++)
+		{
+			if (!strcmp(ses->list[i]->list[j]->group, node->arg1))
+			{
+				if (HAS_BIT(node->flags, NODE_FLAG_DEBUG))
+				{
+					SET_BIT(ses->list[i]->list[j]->flags, NODE_FLAG_DEBUG);
+				}
+				else
+				{
+					DEL_BIT(ses->list[i]->list[j]->flags, NODE_FLAG_DEBUG);
+				}
+			}
+		}
+	}
+	return ses;
+}
+
 
 DO_CLASS(class_list)
 {
@@ -459,14 +526,14 @@ DO_CLASS(class_save)
 	show_message(ses, LIST_CLASS, "#CLASS {%s} HAS BEEN SAVED TO MEMORY.", arg1);
 
 	return ses;
-}	
+}
 
 DO_CLASS(class_size)
 {
 	if (*arg1 == 0 || *arg2 == 0)
 	{
 		show_error(ses, LIST_CLASS, "#SYNTAX: #CLASS <NAME> SIZE <VARIABLE>");
-		
+
 		return ses;
 	}
 
@@ -491,7 +558,7 @@ DO_CLASS(class_write)
 	if (*arg2 == 0 || (file = fopen(arg2, "w")) == NULL)
 	{
 		show_error(ses, LIST_CLASS, "#ERROR: #CLASS WRITE {%s}: COULDN'T OPEN FILE.", arg2);
-		
+
 		return ses;
 	}
 

+ 1 - 1
src/command.c

@@ -170,7 +170,7 @@ struct session *execute(struct session *ses, char *format, ...)
 		get_arg_all(ses, buffer, buffer, FALSE);
 	}
 
-	ses = script_driver(ses, LIST_COMMAND, buffer);
+	ses = script_driver(ses, LIST_COMMAND, NULL, buffer);
 
 	free(buffer);
 

+ 5 - 5
src/config.c

@@ -533,7 +533,7 @@ DO_CONFIG(config_childlock)
 DO_CONFIG(config_colormode)
 {
 	if (*arg2)
-	{	
+	{
 		if (is_abbrev(arg2, "NONE") || is_abbrev(arg2, "OFF"))
 		{
 			ses->color = 0;
@@ -888,7 +888,7 @@ DO_CONFIG(config_mousetracking)
 	{
 		DEL_BIT(ses->config_flags, CONFIG_FLAG_MOUSEDEBUG);
 		DEL_BIT(ses->config_flags, CONFIG_FLAG_MOUSEINFO);
-		DEL_BIT(ses->config_flags, CONFIG_FLAG_MOUSEPIXELS);	
+		DEL_BIT(ses->config_flags, CONFIG_FLAG_MOUSEPIXELS);
 		DEL_BIT(ses->config_flags, CONFIG_FLAG_MOUSEPIXELS);
 		DEL_BIT(gtd->flags, TINTIN_FLAG_MOUSETRACKING);
 
@@ -1124,7 +1124,7 @@ DO_CONFIG(config_screenreader)
 DO_CONFIG(config_scrolllock)
 {
 	if (*arg2)
-	{	
+	{
 		if (is_abbrev(arg2, "ON"))
 		{
 			SET_BIT(ses->config_flags, CONFIG_FLAG_SCROLLLOCK);
@@ -1140,7 +1140,7 @@ DO_CONFIG(config_scrolllock)
 			return NULL;
 		}
 	}
-	strcpy(arg2, HAS_BIT(ses->config_flags, CONFIG_FLAG_SCROLLLOCK) ? "ON" : "OFF");	
+	strcpy(arg2, HAS_BIT(ses->config_flags, CONFIG_FLAG_SCROLLLOCK) ? "ON" : "OFF");
 
 	return ses;
 }
@@ -1198,7 +1198,7 @@ DO_CONFIG(config_tabwidth)
 
 	return ses;
 }
-	
+
 DO_CONFIG(config_telnet)
 {
 	if (*arg2)

+ 187 - 18
src/cursor.c

@@ -709,7 +709,7 @@ DO_CURSOR(cursor_check_line_modified)
 
 	if (gtd->ses->input->str_len != width)
 	{
-		tintin_printf2(ses, "\e[1;31merror: cursor_check_line_modified2: str: %d vs %d", gtd->ses->input->str_len, width);
+		tintin_printf2(ses, "\e[1;31merror: cursor_check_line_modified2: str: %d vs %d raw: %d", gtd->ses->input->str_len, width, gtd->ses->input->raw_len);
 	}
 
 	if (gtd->ses->input->str_pos > gtd->ses->input->str_len)
@@ -854,9 +854,9 @@ DO_CURSOR(cursor_delete)
 				remove_line(gtd->ses->input->edit, gtd->ses->input->edit->update);
 
 				inputline_set(gtd->ses->input->edit->line[gtd->ses->input->edit->update]->str, 0);
-				
+
 				cursor_redraw_edit(ses, arg);
-				
+
 				modified_input();
 			}
 		}
@@ -1166,6 +1166,11 @@ DO_CURSOR(cursor_escape_enter)
 						}
 						pti += 2;
 					}
+					else if (pti[1] == 't')
+					{
+						*pto++ = '\t';
+						pti += 2;
+					}
 					else if (pti[1])
 					{
 						*pto++ = *pti++;
@@ -1185,7 +1190,7 @@ DO_CURSOR(cursor_escape_enter)
 	}
 	cursor_enter(ses, "");
 }
-	
+
 DO_CURSOR(cursor_soft_enter)
 {
 	if (!inputline_editor())
@@ -1217,7 +1222,7 @@ DO_CURSOR(cursor_enter_finish)
 	if (inputline_editor())
 	{
 		cursor_redraw_line(gtd->ses, "");
-		
+
 		return;
 	}
 
@@ -1387,7 +1392,7 @@ DO_CURSOR(cursor_history_next)
 				inputline_max_str_len() - inputline_cur_off() - inputline_cur_str_len(),
 				UMAX(0, inputline_max_str_len() - inputline_cur_off() - inputline_cur_str_len() - 4),
 				root->list[root->update]->arg1);
-			
+
 			goto_pos(gtd->ses, inputline_cur_row(), inputline_cur_col());
 		}
 		return;
@@ -1459,7 +1464,7 @@ DO_CURSOR(cursor_history_prev)
 				inputline_max_str_len() - inputline_cur_off() - inputline_cur_str_len(),
 				UMAX(0, inputline_max_str_len() - inputline_cur_off() - inputline_cur_str_len() - 4),
 				root->list[root->update]->arg1);
-			
+
 			goto_pos(gtd->ses, inputline_cur_row(), inputline_cur_col());
 		}
 		return;
@@ -1546,6 +1551,17 @@ DO_CURSOR(cursor_history_find)
 
 	push_call("cursor_history_find(%s)", gtd->ses->input->buf);
 
+	if (HAS_BIT(gtd->ses->event_flags, EVENT_FLAG_INPUT))
+	{
+		check_all_events(gtd->ses, EVENT_FLAG_INPUT, 0, 0, "MODIFIED INPUT");
+	}
+
+	if (!HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
+	{
+		pop_call();
+		return;
+	}
+
 	if (inputline_str_chk(0, gtd->ses->input->raw_len) == FALSE)
 	{
 		pop_call();
@@ -1608,7 +1624,7 @@ DO_CURSOR(cursor_home)
 		if (gtd->ses->input->str_pos)
 		{
 			gtd->ses->input->str_pos = 0;
-			
+
 			return cursor_redraw_line(ses, arg);
 		}
 		return;
@@ -1651,7 +1667,7 @@ DO_CURSOR(cursor_move_page_up)
 	int rows = UMAX(1, inputline_rows(gtd->ses) / 2);
 
 	DEL_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH);
-	
+
 	cursor_move_up(ses, ntos(rows));
 }
 
@@ -1712,7 +1728,7 @@ DO_CURSOR(cursor_move_page_down)
 	int rows = UMAX(1, inputline_rows(gtd->ses) / 2);
 
 	DEL_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH);
-	
+
 	cursor_move_down(ses, ntos(rows));
 }
 
@@ -2372,7 +2388,7 @@ DO_CURSOR(cursor_set)
 {
 	char arg1[BUFFER_SIZE];
 
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN|SUB_ESC);
 
 	if (*arg1 == 0)
 	{
@@ -2522,10 +2538,146 @@ int cursor_scrollback_tab_add(int flag)
 
 		while (*ptb)
 		{
-			while (*ptb && is_space(*ptb))
+			while (*ptb)
+			{
+				switch (*ptb)
+				{
+					case ' ':
+					case '[':
+					case ']':
+					case '"':
+					case ':':
+					case '\t':
+					case '\n':
+					case '\r':
+					case '\v':
+					case '\f':
+						ptb++;
+						continue;
+				}
+				break;
+			}
+
+			if (HAS_BIT(flag, TAB_FLAG_CASELESS))
+			{
+				if (strncasecmp(ptb, tail, tail_len) != 0)
+				{
+					goto end;
+				}
+			}
+			else
+			{
+				if (*ptb != *tail || strncmp(ptb, tail, tail_len) != 0)
+				{
+					goto end;
+				}
+			}
+			ptt = tab;
+
+			for (tab_len = 0 ; tab_len < tail_len ; tab_len++)
+			{
+				*ptt++ = *ptb++;
+			}
+
+			while (*ptb && *ptb != ' ')
+			{
+				switch (*ptb)
+				{
+					case ';':
+					case '.':
+					case ',':
+					case '!':
+					case '?':
+					case ':':
+					case '"':
+					case '[':
+					case ']':
+						*ptt++ = 0;
+						ptb++;
+						break;
+
+					default:
+						*ptt++ = *ptb++;
+						break;
+				}
+			}
+			*ptt = 0;
+
+			if (search_node_list(gtd->ses->list[LIST_COMMAND], tab))
+			{
+				goto end;
+			}
+
+			node = create_node_list(gtd->ses->list[LIST_COMMAND], tab, "", "", "");
+
+			node->val32[0] = scroll_cnt;
+
+			if (HAS_BIT(flag, TAB_FLAG_FORWARD))
+			{
+				return TRUE;
+			}
+
+			if (root->used > 100)
+			{
+				return FALSE;
+			}
+
+			end:
+
+			while (*ptb && !is_space(*ptb))
 			{
 				ptb++;
 			}
+		}
+	}
+	return FALSE;
+}
+
+int cursor_input_tab_add(int flag)
+{
+	char tab[BUFFER_SIZE];
+	struct listroot *root = gtd->ses->list[LIST_COMMAND];
+	struct listnode *node;
+	int scroll_cnt, tab_len, tail_len;
+	char *ptb, *ptt, *tail;
+
+	tail     = root->list[0]->arg1;
+	tail_len = str_len(tail);
+
+	if (root->list[root->used - 1]->val32[0])
+	{
+		scroll_cnt = UMIN(root->list[root->used - 1]->val32[0], gtd->ses->list[LIST_HISTORY]->used - 1);
+	}
+	else
+	{
+		scroll_cnt = gtd->ses->list[LIST_HISTORY]->used - 1;
+	}
+
+	for ( ; scroll_cnt > 0 ; scroll_cnt--)
+	{
+		ptb = gtd->ses->list[LIST_HISTORY]->list[scroll_cnt]->arg1;
+
+		while (*ptb)
+		{
+			while (*ptb)
+			{
+				switch (*ptb)
+				{
+					case ' ':
+					case '[':
+					case ']':
+					case '"':
+					case ':':
+					case '\t':
+					case '\n':
+					case '\r':
+					case '\v':
+					case '\f':
+						ptb++;
+						continue;
+				}
+				break;
+			}
 
 			if (HAS_BIT(flag, TAB_FLAG_CASELESS))
 			{
@@ -2559,6 +2711,8 @@ int cursor_scrollback_tab_add(int flag)
 					case '?':
 					case ':':
 					case '"':
+					case '[':
+					case ']':
 						*ptt++ = 0;
 						ptb++;
 						break;
@@ -2631,6 +2785,11 @@ void cursor_tab_forward(struct session *ses, int flag)
 		tab_found = cursor_scrollback_tab_add(flag);
 	}
 
+	if (tab_found == 0 && HAS_BIT(flag, TAB_FLAG_INPUT))
+	{
+		tab_found = cursor_input_tab_add(flag);
+	}
+
 	if (tab_found == 0 && HAS_BIT(flag, TAB_FLAG_DICTIONARY))
 	{
 		tab_found = cursor_dictionary_tab_add(flag);
@@ -2681,6 +2840,11 @@ void cursor_tab_backward(struct session *ses, int flag)
 			cursor_scrollback_tab_add(flag);
 		}
 
+		if (HAS_BIT(flag, TAB_FLAG_INPUT))
+		{
+			cursor_input_tab_add(flag);
+		}
+
 		if (HAS_BIT(flag, TAB_FLAG_DICTIONARY))
 		{
 			cursor_dictionary_tab_add(flag);
@@ -2708,6 +2872,7 @@ DO_CURSOR(cursor_tab)
 		tintin_printf2(ses, "  [%-18s] %s", "CASELESS", "Make the tab completion caseless");
 		tintin_printf2(ses, "  [%-18s] %s", "COMPLETE", "Make the tab completion work while editing");
 		tintin_printf2(ses, "  [%-18s] %s", "DICTIONARY", "Make the tab completion include the dictionary");
+		tintin_printf2(ses, "  [%-18s] %s", "INPUT", "Make the tab completion include the input history");
 		tintin_printf2(ses, "  [%-18s] %s", "LIST", "Make the tab completion include the tab completion list");
 		tintin_printf2(ses, "  [%-18s] %s", "SCROLLBACK", "Make the tab completion include the scrollback buffer");
 		tintin_printf2(ses, "  [%-18s] %s", "BACKWARD", "Make the tab completion go backward");
@@ -2738,6 +2903,10 @@ DO_CURSOR(cursor_tab)
 		{
 			SET_BIT(flag, TAB_FLAG_LIST);
 		}
+		else if (is_abbrev(arg1, "INPUT"))
+		{
+			SET_BIT(flag, TAB_FLAG_INPUT);
+		}
 		else if (is_abbrev(arg1, "SCROLLBACK"))
 		{
 			SET_BIT(flag, TAB_FLAG_SCROLLBACK);
@@ -2764,9 +2933,9 @@ DO_CURSOR(cursor_tab)
 			return cursor_redraw_line(ses, arg);
 		}
 
-		if (!HAS_BIT(flag, TAB_FLAG_DICTIONARY|TAB_FLAG_LIST|TAB_FLAG_SCROLLBACK))
+		if (!HAS_BIT(flag, TAB_FLAG_DICTIONARY|TAB_FLAG_INPUT|TAB_FLAG_LIST|TAB_FLAG_SCROLLBACK))
 		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB {<DICTIONARY|LIST|SCROLLBACK> FORWARD}");
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB {<DICTIONARY|INPUT|LIST|SCROLLBACK> FORWARD}");
 		}
 		else
 		{
@@ -2780,15 +2949,15 @@ DO_CURSOR(cursor_tab)
 		if (!HAS_BIT(flag, TAB_FLAG_COMPLETE) && inputline_editor())
 		{
 			snprintf(arg1, BUFFER_SIZE, "%*s", gtd->ses->tab_width, "");
-			
+
 			inputline_insert(arg1, 0);
 
 			return cursor_redraw_line(ses, arg);
 		}
 
-		if (!HAS_BIT(flag, TAB_FLAG_DICTIONARY|TAB_FLAG_LIST|TAB_FLAG_SCROLLBACK))
+		if (!HAS_BIT(flag, TAB_FLAG_DICTIONARY|TAB_FLAG_INPUT|TAB_FLAG_LIST|TAB_FLAG_SCROLLBACK))
 		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB {<DICTIONARY|LIST|SCROLLBACK> BACKWARD}");
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB {<DICTIONARY|INPUT|LIST|SCROLLBACK> BACKWARD}");
 		}
 		else
 		{
@@ -2797,6 +2966,6 @@ DO_CURSOR(cursor_tab)
 	}
 	else
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB {<DICTIONARY|LIST|SCROLLBACK> <BACKWARD|FORWARD>}");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB {<DICTIONARY|INPUT|LIST|SCROLLBACK> <BACKWARD|FORWARD>}");
 	}
 }

+ 3 - 3
src/daemon.c

@@ -32,7 +32,7 @@
 #include <util.h>
 #endif
 #endif
-#include <fcntl.h>  
+#include <fcntl.h>
 #include <dirent.h>
 #include <termios.h>
 #include <sys/un.h>
@@ -223,7 +223,7 @@ DO_DAEMON(daemon_attach)
 	if (pid == getpid())
 	{
 		show_error(ses, LIST_COMMAND, "#ERROR: #DAEMON ATTACH: {%s} CANNOT ATTACH TO ITSELF.", filename);
-		
+
 		return;
 	}
 
@@ -313,7 +313,7 @@ DO_DAEMON(daemon_attach)
 
 		gtd->attach_sock = 0;
 //		gtd->attach_sock = close(gtd->attach_sock);
-		
+
 		return;
 	}
 

+ 29 - 26
src/data.c

@@ -420,12 +420,15 @@ void delete_node(struct session *ses, int type, struct listnode *node)
 
 	insert_index_list(gtd->dispose_list, node, gtd->dispose_list->used);
 
-	switch (type)
+	if (!HAS_BIT(ses->flags, SES_FLAG_CLOSED))
 	{
-		case LIST_CLASS:
-			check_all_events(ses, EVENT_FLAG_CLASS, 0, 1, "CLASS DESTROYED", node->arg1);
-			check_all_events(ses, EVENT_FLAG_CLASS, 1, 1, "CLASS DESTROYED %s", node->arg1, node->arg1);
-			break;
+		switch (type)
+		{
+			case LIST_CLASS:
+				check_all_events(ses, EVENT_FLAG_CLASS, 0, 1, "CLASS DESTROYED", node->arg1);
+				check_all_events(ses, EVENT_FLAG_CLASS, 1, 1, "CLASS DESTROYED %s", node->arg1, node->arg1);
+				break;
+		}
 	}
 }
 
@@ -494,7 +497,7 @@ int search_index_list(struct listroot *root, char *text, char *priority)
 		case SORT_ALPHA:
 		case SORT_STABLE:
 			return bsearch_alpha_list(root, text, 0);
-		
+
 		case SORT_ALNUM:
 			return bsearch_alnum_list(root, text, 0);
 
@@ -508,7 +511,7 @@ int search_index_list(struct listroot *root, char *text, char *priority)
 
 	return nsearch_list(root, text);
 }
- 
+
 /*
 	Return insertion index.
 */
@@ -1148,7 +1151,7 @@ DO_COMMAND(do_message)
 			else
 			{
 				show_error(ses, LIST_COMMAND, "#SYNTAX: #MESSAGE {%s} [ON|OFF]",  arg1);
-				
+
 				return ses;
 			}
 			show_message(ses, LIST_COMMAND, "#OK: #MESSAGE STATUS FOR %s HAS BEEN SET TO: %s.", list_table[index].name_multi, HAS_BIT(ses->list[index]->flags, LIST_FLAG_MESSAGE) ? "ON" : "OFF");
@@ -1221,7 +1224,7 @@ DO_COMMAND(do_ignore)
 				else
 				{
 					show_error(ses, LIST_COMMAND, "#SYNTAX: #IGNORE {%s} [ON|OFF]", arg1);
-				
+
 					return ses;
 				}
 				show_message(ses, LIST_COMMAND, "#OK: #IGNORE STATUS FOR %s HAS BEEN SET TO: %s.", list_table[index].name_multi, HAS_BIT(ses->list[index]->flags, LIST_FLAG_IGNORE) ? "ON" : "OFF");
@@ -1299,7 +1302,7 @@ DO_COMMAND(do_debug)
 			else
 			{
 				show_error(ses, LIST_COMMAND, "#SYNTAX: #DEBUG {%s} [ON|OFF|LOG]", arg1);
-				
+
 				return ses;
 			}
 			show_message(ses, LIST_COMMAND, "#OK: #DEBUG STATUS FOR %s HAS BEEN SET TO: %s.", list_table[index].name_multi, is_abbrev(arg2, "LOG") ? "LOG" : HAS_BIT(ses->list[index]->flags, LIST_FLAG_DEBUG) ? "ON" : "OFF");
@@ -1708,14 +1711,14 @@ DO_COMMAND(do_info)
 					}
 					else
 					{
-						tintin_printf2(ses, "{NAME}{%s}", ses->name);
-						tintin_printf2(ses, "{ACTIVE}{%d}", gtd->ses == ses);
-						tintin_printf2(ses, "{CLASS}{%s}", ses->group);
-						tintin_printf2(ses, "{CREATED}{%d}", ses->created);
-						tintin_printf2(ses, "{HOST} {%s}", ses->session_host);
-						tintin_printf2(ses, "{IP} {%s}", ses->session_ip);
-						tintin_printf2(ses, "{MTTS} {%d}", get_mtts_val(ses));
-						tintin_printf2(ses, "{PORT} {%s}", ses->session_port);
+						tintin_printf2(ses, "#INFO SESSION: {NAME}{%s}", ses->name);
+						tintin_printf2(ses, "#INFO SESSION: {ACTIVE}{%d}", gtd->ses == ses);
+						tintin_printf2(ses, "#INFO SESSION: {CLASS}{%s}", ses->group);
+						tintin_printf2(ses, "#INFO SESSION: {CREATED}{%d}", ses->created);
+						tintin_printf2(ses, "#INFO SESSION: {HOST} {%s}", ses->session_host);
+						tintin_printf2(ses, "#INFO SESSION: {IP} {%s}", ses->session_ip);
+						tintin_printf2(ses, "#INFO SESSION: {MTTS} {%d}", get_mtts_val(ses));
+						tintin_printf2(ses, "#INFO SESSION: {PORT} {%s}", ses->session_port);
 					}
 				}
 				else if (is_abbrev(arg1, "SESSIONS"))
@@ -1745,14 +1748,14 @@ DO_COMMAND(do_info)
 					{
 						for (sesptr = gts ; sesptr ; sesptr = sesptr->next)
 						{
-							tintin_printf2(ses, "{%s}{NAME}{%s}", sesptr->name, sesptr->name);
-							tintin_printf2(ses, "{%s}{ACTIVE}{%d}", sesptr->name, gtd->ses == sesptr);
-							tintin_printf2(ses, "{%s}{CLASS}{%s}", sesptr->name, sesptr->group);
-							tintin_printf2(ses, "{%s}{CREATED}{%d}", sesptr->name, sesptr->created);
-							tintin_printf2(ses, "{%s}{HOST} {%s}", sesptr->name, sesptr->session_host);
-							tintin_printf2(ses, "{%s}{IP} {%s}", sesptr->name, sesptr->session_ip);
-							tintin_printf2(ses, "{%s}{MTTS} {%d}", sesptr->name, get_mtts_val(ses));
-							tintin_printf2(ses, "{%s}{PORT} {%s}", sesptr->name, sesptr->session_port);
+							tintin_printf2(ses, "#INFO SESSIONS: {%s}{NAME}{%s}", sesptr->name, sesptr->name);
+							tintin_printf2(ses, "#INFO SESSIONS: {%s}{ACTIVE}{%d}", sesptr->name, gtd->ses == sesptr);
+							tintin_printf2(ses, "#INFO SESSIONS: {%s}{CLASS}{%s}", sesptr->name, sesptr->group);
+							tintin_printf2(ses, "#INFO SESSIONS: {%s}{CREATED}{%d}", sesptr->name, sesptr->created);
+							tintin_printf2(ses, "#INFO SESSIONS: {%s}{HOST} {%s}", sesptr->name, sesptr->session_host);
+							tintin_printf2(ses, "#INFO SESSIONS: {%s}{IP} {%s}", sesptr->name, sesptr->session_ip);
+							tintin_printf2(ses, "#INFO SESSIONS: {%s}{MTTS} {%d}", sesptr->name, get_mtts_val(ses));
+							tintin_printf2(ses, "#INFO SESSIONS: {%s}{PORT} {%s}", sesptr->name, sesptr->session_port);
 						}
 					}
 				}

+ 10 - 27
src/draw.c

@@ -458,15 +458,10 @@ DO_COMMAND(do_draw)
 			if (!is_math(ses, arg1) || !is_math(ses, arg2) || !is_math(ses, arg3) || !is_math(ses, arg4))
 			{
 				show_error(ses, LIST_COMMAND, "#ERROR: #DRAW: INVALID SQUARE: %s {%s} {%s} {%s} {%s}", draw_table[index].name, arg1, arg2, arg3, arg4);
-//					is_math(ses, arg1) ? ntos(top_row) : arg1,
-//					is_math(ses, arg2) ? ntos(top_col) : arg2,
-//					is_math(ses, arg3) ? ntos(bot_row) : arg3,
-//					is_math(ses, arg4) ? ntos(bot_col) : arg4);
 
 				return ses;
 			}
 
-
 			if (top_row == 0 && top_col == 0)
 			{
 				show_error(ses, LIST_COMMAND, "#SYNTAX: #DRAW [COLOR] [OPTIONS] {%s} <TOP_ROW> <TOP_COL> <BOT_ROW> <BOT_COL> [TEXT]", draw_table[index].name);
@@ -476,8 +471,6 @@ DO_COMMAND(do_draw)
 
 			if (top_row == 0)
 			{
-				top_row = 1;
-
 				SET_BIT(flags, DRAW_FLAG_SCROLL);
 			}
 			else
@@ -490,20 +483,10 @@ DO_COMMAND(do_draw)
 				}
 			}
 
-			if (top_col == 0)
-			{
-				top_col = 1;
-			}
-
-			if (bot_row == 0)
-			{
-				bot_row = 1;
-			}
-
-			if (bot_col == 0)
-			{
-				bot_col = 1;
-			}
+			if (top_row == 0) top_row = 1;
+			if (top_col == 0) top_col = 1;
+			if (bot_row == 0) bot_row = 1;
+			if (bot_col == 0) bot_col = 1;
 
 			if (top_row > bot_row || top_col > bot_col)
 			{
@@ -772,7 +755,7 @@ void string_to_font(struct session *ses, long long flags, char *in, char *out)
 			pto += sprintf(pto, "%.*s", skip, pti);
 
 			pti += skip;
-			
+
 			continue;
 		}
 
@@ -963,7 +946,7 @@ void string_to_stamp(struct session *ses, long long flags, char *in, char *out)
 			get_color_codes(color, pti, color, GET_ONE);
 
 			pti += skip;
-			
+
 			continue;
 		}
 		pti = get_char(ses, pti, chr1);
@@ -1543,7 +1526,7 @@ DO_DRAW(draw_corner)
 	else
 	{
 		goto_pos(ses, top_row, top_col);
-		
+
 		print_stdout(top_row, top_col, "%s%s", box_color, arg1);
 	}
 }
@@ -1731,7 +1714,7 @@ DO_DRAW(draw_line)
 	if (top_col == bot_col)
 	{
 		draw_line_vertical(ses, top_row, top_col, bot_row, bot_col, rows, cols, flags, box_color, txt_color, arg, arg1, arg2, arg3);
-		
+
 		return;
 	}
 
@@ -1791,7 +1774,7 @@ DO_DRAW(draw_map)
 // 3 use calign for centered bar
 // 4 use box drawing modifiers if no box is specified.
 // 4.1 rounded = (###)
-// 4.2 teed    = [---] 
+// 4.2 teed    = [---]
 // 4.3 jeweled = <###>
 // 4.4 crossed = +++++
 // 4.5 circled = OOOOO
@@ -2365,7 +2348,7 @@ DO_DRAW(draw_table_grid)
 						{
 							strcat(buf3, arg2);
 						}
-	
+
 						if (*str == COMMAND_SEPARATOR)
 						{
 							str++;

+ 10 - 5
src/edit.c

@@ -114,7 +114,7 @@ DO_EDIT(edit_load)
 	if ((node = search_nest_node_ses(ses, arg1)) == NULL)
 	{
 		show_error(ses, LIST_COMMAND, "#EDIT LOAD: VARIABLE {%s} NOT FOUND.", arg1);
-		
+
 		return ses;
 	}
 
@@ -260,6 +260,8 @@ DO_EDIT(edit_resume)
 
 	inputline_set(edit->line[edit->update]->str, 0);
 
+	check_all_events(gtd->ses, EVENT_FLAG_INPUT, 0, 1, "EDIT RESUMED", gtd->ses->input->edit_name);
+
 	cursor_redraw_edit(ses, "");
 
 	return ses;
@@ -284,6 +286,8 @@ DO_EDIT(edit_suspend)
 
 	cursor_redraw_edit(ses, "");
 
+	check_all_events(gtd->ses, EVENT_FLAG_INPUT, 0, 1, "EDIT SUSPENDED", gtd->ses->input->edit_name);
+
 	return ses;
 }
 
@@ -347,14 +351,15 @@ void enable_editor(struct edit_data *edit)
 
 	filesize = str_save_editor(gtd->ses->input->edit, &str1);
 
-	cursor_redraw_edit(gtd->ses, "");
-
-	check_all_events(gtd->ses, EVENT_FLAG_INPUT, 0, 4, "STARTED EDITING", gtd->ses->input->edit_name, ntos(edit->used), ntos(filesize), str1);
+	check_all_events(gtd->ses, EVENT_FLAG_INPUT, 0, 4, "EDIT STARTED", gtd->ses->input->edit_name, ntos(edit->used), ntos(filesize), str1);
 
 	if (*gtd->ses->input->edit_name)
 	{
-		check_all_events(gtd->ses, EVENT_FLAG_INPUT, 1, 4, "STARTED EDITING %s", gtd->ses->input->edit_name, gtd->ses->input->edit_name, ntos(edit->used), ntos(filesize), str1);
+		check_all_events(gtd->ses, EVENT_FLAG_INPUT, 1, 4, "EDIT STARTED %s", gtd->ses->input->edit_name, gtd->ses->input->edit_name, ntos(edit->used), ntos(filesize), str1);
 	}
+
+	cursor_redraw_edit(gtd->ses, "");
+
 }
 
 int str_save_editor(struct edit_data *edit, char **str)

+ 8 - 5
src/event.c

@@ -215,7 +215,7 @@ int check_all_events(struct session *ses, int flags, int args, int vars, char *f
 			syserr_printf(ses, "check_all_events: vasprintf:");
 		}
 
-		va_end(list); 
+		va_end(list);
 	}
 	else
 	{
@@ -268,9 +268,12 @@ int check_all_events(struct session *ses, int flags, int args, int vars, char *f
 
 				substitute(ses_ptr, node->arg2, buf, sub);
 
-				if (!HAS_BIT(flags, EVENT_FLAG_UPDATE) && HAS_BIT(ses_ptr->list[LIST_EVENT]->flags, LIST_FLAG_DEBUG))
+				if (!HAS_BIT(flags, EVENT_FLAG_UPDATE))
 				{
-					show_debug(ses_ptr, LIST_EVENT, COLOR_DEBUG "#DEBUG EVENT " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
+					if (HAS_BIT(ses_ptr->list[LIST_EVENT]->flags, LIST_FLAG_DEBUG) || HAS_BIT(node->flags, NODE_FLAG_DEBUG))
+					{
+						show_debug(ses_ptr, LIST_EVENT, node, COLOR_DEBUG "#DEBUG EVENT " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
+					}
 				}
 
 				if (node->shots && --node->shots == 0)
@@ -280,7 +283,7 @@ int check_all_events(struct session *ses, int flags, int args, int vars, char *f
 
 				gtd->level->quiet += HAS_BIT(flags, EVENT_FLAG_UPDATE) ? 1 : 0;
 
-				script_driver(ses_ptr, LIST_EVENT, buf);
+				script_driver(ses_ptr, LIST_EVENT, node, buf);
 
 				gtd->level->quiet -= HAS_BIT(flags, EVENT_FLAG_UPDATE) ? 1 : 0;
 
@@ -576,7 +579,7 @@ void mouse_handler(struct session *ses, int flags, int row, int col)
 			{
 				strcpy(dir, swipe[9] > 0 ? "NE" : "NW");
 			}
-			check_all_events(ses, EVENT_FLAG_MOUSE, 0, 12, "SWIPED", dir, arg2, ntos(swipe[0]), ntos(swipe[1]), ntos(swipe[2]), ntos(swipe[3]), ntos(swipe[4]), ntos(swipe[5]), ntos(swipe[6]), ntos(swipe[7]), ntos(swipe[8]), ntos(swipe[9]));			
+			check_all_events(ses, EVENT_FLAG_MOUSE, 0, 12, "SWIPED", dir, arg2, ntos(swipe[0]), ntos(swipe[1]), ntos(swipe[2]), ntos(swipe[3]), ntos(swipe[4]), ntos(swipe[5]), ntos(swipe[6]), ntos(swipe[7]), ntos(swipe[8]), ntos(swipe[9]));
 			check_all_events(ses, EVENT_FLAG_MOUSE, 1, 12, "SWIPED %s", dir, dir, arg2, ntos(swipe[0]), ntos(swipe[1]), ntos(swipe[2]), ntos(swipe[3]), ntos(swipe[4]), ntos(swipe[5]), ntos(swipe[6]), ntos(swipe[7]), ntos(swipe[8]), ntos(swipe[9]));
 			check_all_events(ses, EVENT_FLAG_MOUSE, 2, 12, "SWIPED %s %s", arg2, dir, dir, arg2, ntos(swipe[0]), ntos(swipe[1]), ntos(swipe[2]), ntos(swipe[3]), ntos(swipe[4]), ntos(swipe[5]), ntos(swipe[6]), ntos(swipe[7]), ntos(swipe[8]), ntos(swipe[9]));
 		}

+ 5 - 5
src/files.c

@@ -98,7 +98,7 @@ struct session *read_file(struct session *ses, FILE *file, char *filename)
 	if (fread(bufi, 1, size, file) <= 0)
 	{
 		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "READ ERROR", filename, "FREAD FAILURE");
-		
+
 		tintin_printf(ses, "#ERROR: #READ {%s}: FREAD FAILURE.", filename);
 
 		return ses;
@@ -332,7 +332,7 @@ struct session *read_file(struct session *ses, FILE *file, char *filename)
 
 		gtd->level->quiet++;
 
-		script_driver(ses, LIST_COMMAND, temp);
+		script_driver(ses, LIST_COMMAND, NULL, temp);
 
 		gtd->level->quiet--;
 	}
@@ -360,12 +360,12 @@ struct session *read_file(struct session *ses, FILE *file, char *filename)
 
 		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, NULL, "#WARNING: #READ {%s}: POSSIBLE BUFFER OVERFLOW AT COMMAND: %.30s", filename, bufi);
 		}
 
 		if (bufi[0])
 		{
-			ses = script_driver(ses, LIST_COMMAND, bufi);
+			ses = script_driver(ses, LIST_COMMAND, NULL, bufi);
 		}
 		pto = bufi;
 		pti++;
@@ -426,7 +426,7 @@ DO_COMMAND(do_write)
 
 		return ses;
 	}
-	
+
 	if (is_suffix(arg1, ".map") && !is_abbrev(arg2, "FORCE"))
 	{
 		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "WRITE ERROR", arg1, "INVALID FILE EXTENSION");

+ 138 - 0
src/gui.h

@@ -731,3 +731,141 @@ char *tt_gui = "#line quiet #port init gui 0\n"
 "}\n"
 
 "#delay 0 gui_init\n";
+
+
+char *tt_regex = "#event {PROGRAM START}\n"
+"{\n"
+"	#var tab {{i}{0}{0}{}{1}{}};\n"
+"	#info matches save;\n"
+"	draw_gui;\n"
+"	#config mouse on\n"
+"}\n"
+"\n"
+"#event {SCREEN RESIZE}\n"
+"{\n"
+"	draw_gui;\n"
+"	#buffer end\n"
+"}\n"
+"\n"
+"#alias {draw_gui}\n"
+"{\n"
+"	#screen clear scroll;\n"
+"	#screen scroll 7 1 -4 -1;\n"
+"	#draw jade Silver rounded talign box 1 1 3 -1;\n"
+"	#draw jade Azure scaled tile 1 3 1 6 {REGULAR EXPRESSION};\n"
+"	#draw jade Silver rounded talign box 4 1 6 -1;\n"
+"	#draw jade Azure scaled tile 4 3 4 6 {TEST STRING};\n"
+"	#draw jade Green rounded calign box -3 -6 -1 -1 {exit};\n"
+"	#draw jade Green rounded calign box -3 -12 -1 -7 {help};\n"
+"\n"
+"	#screen inputregion 5 2 5 -2 TAB_2;\n"
+"	next_tab;\n"
+"	next_tab\n"
+"}\n"
+"\n"
+"#alias {next_tab}\n"
+"{\n"
+"	#if {$tab[i] == 0}\n"
+"	{\n"
+"		#screen inputregion 5 2 5 -2 TAB_2;\n"
+"		#cursor clear;\n"
+"		#cursor set $tab[1];\n"
+"	};\n"
+"	#if {$tab[i] == 1}\n"
+"	{\n"
+"		#screen inputregion 2 2 2 -2 TAB_1;\n"
+"		#cursor clear;\n"
+"		#cursor set $tab[0];\n"
+"	};\n"
+"	#math tab[i] ($tab[i] + 1) % 2;\n"
+"}\n"
+"\n"
+"#alias {mouse_tab}\n"
+"{\n"
+"	#var tab[i] %1;\n"
+"	#if {%1 == 0}\n"
+"	{\n"
+"		#screen inputregion 2 2 2 -2;\n"
+"		#cursor clear;\n"
+"		#cursor set $tab[0]\n"
+"	};\n"
+"	#if {%1 == 1}\n"
+"	{\n"
+"		#screen inputregion 5 2 5 -2;\n"
+"		#cursor clear;\n"
+"		#cursor set $tab[1]\n"
+"	};\n"
+"	#cursor position %2\n"
+"}\n"
+"\n"
+"#button {2;2;2;-2;PRESSED MOUSE BUTTON ONE} {mouse_tab 0 %3-1}\n"
+"#button {5;2;5;-2;PRESSED MOUSE BUTTON ONE} {mouse_tab 1 %3-1}\n"
+"#button {-3;-6;-1;-1} {#end}\n"
+"#button {-3;-12;-1;-7} {#buffer clear;#help regex}\n"
+"\n"
+"#event {SCROLLED MOUSE WHEEL DOWN} {#buffer down 3}\n"
+"#event {SCROLLED MOUSE WHEEL UP} {#buffer up 3}\n"
+"\n"
+"#macro {\t}\n"
+"{\n"
+"	next_tab\n"
+"}\n"
+"\n"
+"#alias {matches}\n"
+"{\n"
+"	#var result {};\n"
+"\n"
+"	#foreach {*info[MATCHES][]} {index}\n"
+"	{\n"
+"		#format temp {\\n%+3s %s} {<138>%$index} {<178>$info[MATCHES][$index]};\n"
+"		#cat result {$temp}\n"
+"	};\n"
+"	#if {{$last} === {$result}}\n"
+"	{\n"
+"		#return\n"
+"	};\n"
+"	#buffer clear;\n"
+"	#screen clear scroll;\n"
+"	#line ignore #showme {$result};\n"
+"\n"
+"	#var last {$result}\n"
+"}\n"
+"\n"
+"#event {GAG NO SESSION ACTIVE} {#nop}\n"
+"\n"
+"#event {PROCESSED KEYPRESS}\n"
+"{\n"
+"	#cursor get temp;\n"
+"	#replace temp {\\\\x7B%*\\\\x7D} {{&1}};\n"
+"	#replace temp {\\\\x7B%*\\\\x7D} {{&1}};\n"
+"\n"
+"	#if {{$temp} !== {$tab[$tab[i]]}}\n"
+"	{\n"
+"		#cursor get tab[$tab[i]];\n"
+"		#delay {input} {input_update} {0.1}\n"
+"	}\n"
+"}\n"
+"\n"
+"#alias {input_update}\n"
+"{\n"
+"	#replace tab[0] {\\\\x7B%*\\\\x7D} {{&1}};\n"
+"	#replace tab[0] {\\\\x7B%*\\\\x7D} {{&1}};\n"
+"	#replace tab[1] {\\\\x7B%*\\\\x7D} {{&1}};\n"
+"	#replace tab[1] {\\\\x7B%*\\\\x7D} {{&1}};\n"
+"\n"
+"	#regex {$tab[1]} {$tab[0]}\n"
+"	{\n"
+"		#info matches save\n"
+"	}\n"
+"	{\n"
+"		#if {{$last} !== {}}\n"
+"		{\n"
+"			#buffer clear;\n"
+"			#screen clear scroll;\n"
+"			#line ignore #showme {<118>The regular expression does not match the test string.\n};\n"
+"			#var last {}\n"
+"		};\n"
+"		#return\n"
+"	};\n"
+"	matches\n"
+"}\n";

+ 78 - 70
src/help.c

@@ -71,8 +71,8 @@ char *help_related(struct session *ses, int index, int html)
 
 	push_call("help_related(%p,%d,%d)",ses,index,html);
 
-	tmp  = str_alloc_stack(0);
-	link = str_alloc_stack(0);
+	tmp   = str_alloc_stack(0);
+	link  = str_alloc_stack(0);
 
 	arg  = help_table[index].also;
 
@@ -84,7 +84,7 @@ char *help_related(struct session *ses, int index, int html)
 
 		if (html == 1)
 		{
-			sprintf(link, "\\c<a href='%s.php'\\c>%s\\c</a\\c>", tmp, tmp);
+			sprintf(link, "\\c<a href='%s.php'\\c>%s\\c</a\\c>", decapitalize(tmp), tmp);
 		}
 		else if (html == 2)
 		{
@@ -216,7 +216,7 @@ DO_COMMAND(do_help)
 
 		FILE *logfile = fopen("../docs/help.html", "w");
 
-		script_driver(ses, LIST_COMMAND, "#config {log} {html}");
+		script_driver(ses, LIST_COMMAND, NULL, "#config {log} {html}");
 
 		if (HAS_BIT(ses->log->mode, LOG_FLAG_HTML))
 		{
@@ -415,7 +415,7 @@ DO_COMMAND(do_help)
 	{
 		FILE *logfile;
 
-		script_driver(ses, LIST_COMMAND, "#config {log} {html}");
+		script_driver(ses, LIST_COMMAND, NULL, "#config {log} {html}");
 
 		*buf = 0;
 
@@ -544,10 +544,6 @@ struct help_type help_table[] =
 		"<278>         arguments. The priority part is optional and determines the priority\n"
 		"<278>         of the alias, it defaults to 5.\n"
 		"\n"
-		"<278>         If no % variable is used in the commands section any argument will be\n"
-		"<278>         appended to the end as if %0 was used. This feature might be removed\n"
-		"<278>         in the future, and shouldn't be used.\n"
-		"\n"
 		"<178>Example<278>: #alias {k} {kill %1;kick}\n"
 		"\n"
 		"<278>         Typing 'k orc' would result in attacking the orc followed by a kick.\n"
@@ -639,7 +635,7 @@ struct help_type help_table[] =
 		"<278>         to the next.\n"
 		"\n"
 		"<178>Example<278>: #while {1} {#math cnt $cnt + 1;#if {$cnt == 20} {#break}}\n",
-		
+
 		"statements"
 	},
 	{
@@ -869,7 +865,7 @@ struct help_type help_table[] =
 		"<278>         clients, typically for the purpose of chatting and sending files.\n"
 		"<278>         This is a decentralized chat system, meaning you have to exchange ip\n"
 		"<278>         addresses and port numbers with other users in order to connect to\n"
-		"<278>         them.\n"
+		"<278>         them. Chat events are triggered in the startup session.\n"
 		"\n"
 		"<278>         <178>#chat {init} {port}\n"
 		"<278>           #chat initialize launches your chat server. The port number is\n"
@@ -924,10 +920,10 @@ struct help_type help_table[] =
 		"<278>           used instead of the connection's name when sending someone a message\n"
 		"<278>           The second column shows the connection's name. The third column\n"
 		"<278>           shows flags set for the connection, (P)rivate, (I)gnore, (S)erve,\n"
-		"<278>           (F)orward to user, and (f)orward from user. The next columns show\n"
-		"<278>           ip, port, and client name.\n"
+		"<278>           Forward(A)ll to user, (F)orward to user, and (f)orward from user.\n"
+		"<278>           The next columns show ip, port, and client name.\n"
 		"<278>         <178>#chat {zap}        {buddy}            Close a connection\n",
-		
+
 		"port"
 	},
 	{
@@ -944,6 +940,8 @@ struct help_type help_table[] =
 		"<278>           Will delete all triggers associated with the given class.\n"
 		"<278>         <178>#class {<name>} {close}\n"
 		"<278>           Close the given class, opening the last open class, if any.\n"
+		"<278>         <178>#class {<name>} {debug} {on|off}\n"
+		"<278>           Toggle debug mode for given class.\n"
 		"<278>         <178>#class {<name>} {kill}\n"
 		"<278>           Will clear, close, and remove the class.\n"
 		"<278>         <178>#class {<name>} {list}\n"
@@ -968,7 +966,7 @@ struct help_type help_table[] =
 		"<178>Example<278>: #class rich kill;#class rich read poor.tin\n"
 		"<278>         Deletes all triggers of 'rich' class if any. Read 'poor.tin' file,\n"
 		"<278>         all triggers loaded will be assigned to the 'rich' class.\n",
-		
+
 		"config debug ignore info kill line message"
 	},
 	{
@@ -1078,7 +1076,7 @@ struct help_type help_table[] =
 		"<278>         reiterate the command.\n"
 		"\n"
 		"<178>Example<278>: #loop 1 10 cnt {#if {$cnt % 2 == 0} {#continue} {say $cnt}}\n",
-		
+
 		"break foreach list loop parse repeat return while"
 	},
 	{
@@ -1166,6 +1164,7 @@ struct help_type help_table[] =
 		"<278>         COMPLETE    makes tab completion work while editing\n"
 		"\n"
 		"<278>         DICTIONARY  performs tab completion on the dictionary\n"
+		"<278>         INPUT       performs tab completion on the input history\n"
 		"<278>         LIST        performs tab completion on the tab completion list\n"
 		"<278>         SCROLLBACK  performs tab completion on the scrollback buffer\n"
 		"\n"
@@ -1201,7 +1200,7 @@ struct help_type help_table[] =
 		"\n"
 		"<278>         You can launch tintin and attach the first daemonized instance using\n"
 		"<278>         tt++ -R. To attach a named instance use tt++ -R<name>.\n",
-		
+
 		"script system run"
 	},
 	{
@@ -1219,7 +1218,7 @@ struct help_type help_table[] =
 		"<278>         the log file, you must be logging in order for this to work.\n"
 		"\n"
 		"<278>         Not every list has debug support yet.\n",
-		
+
 		"class ignore info kill message"
 	},
 	{
@@ -1230,7 +1229,7 @@ struct help_type help_table[] =
 		"<278>         The default command can only be used within the switch command. When\n"
 		"<278>         the conditional argument of non of the case commands matches the switch\n"
 		"<278>         command's conditional statement the default command is executed.\n",
-		
+
 		"case default else elseif if switch regexp"
 	},
 	{
@@ -1254,7 +1253,7 @@ struct help_type help_table[] =
 		"<278>         a name as the first argument, be aware this changes the syntax. If\n"
 		"<278>         the name is a number keep in mind that delays with the same numeric\n"
 		"<278>         name will not be overwritten\n",
-		
+
 		"event ticker"
 	},
 
@@ -1335,7 +1334,7 @@ struct help_type help_table[] =
 		"<278>         [BOXED] <178>MAP\n"
 		"<278>           will draw the map\n"
 		"<278>         <178>RAIN<278> {<VARIABLE>} {[SPAWN]} {[FADE]} {[LEGEND]}\n"
-		"<278>           will draw digital rain.\n"
+		"<278>           will draw digital rain SPAWN (0.01-100) FADE (1-100).\n"
 		"<278>         [JOINTED|TOP|LEFT|BOTTOM|RIGHT] <178>SIDE\n"
 		"<278>           will draw one or more sides of a box.\n"
 		"<278>         [GRID] <178>TABLE<278> {[LIST1]} {[LIST2]}\n"
@@ -1369,7 +1368,7 @@ struct help_type help_table[] =
 		"<178>Example<278>: #echo {The current date is %t.} {%Y-%m-%d %H:%M:%S}\n"
 		"<278>         #echo {[%38s][%-38s]} {Hello World} {Hello World}\n"
 		"<278>         #echo {{this is %s on the top row} {1}} {printed}\n",
-		
+
 		"buffer format grep showme"
 	},
 	{
@@ -1403,7 +1402,7 @@ struct help_type help_table[] =
 		"<278>           Write the editor content to file.\n"
 		"\n"
 		"<178>Example<278>: #edit create {bla.txt} {line 1} {line 2}\n",
-		
+
 		"cursor macro"
 	},
 	{
@@ -1479,13 +1478,13 @@ struct help_type help_table[] =
 		"<268>├─────────────────────────┤├────────────────────────────────────────────┤\n"
 		"<268>│<178>arrow down               <268>││<178>next input line                             <268>│\n"
 		"<268>└─────────────────────────┘└────────────────────────────────────────────┘\n"
-		
+
 		"<268>┌─────────────────────────┐┌────────────────────────────────────────────┐\n"
 		"<268>│<178>ctrl arrow left          <268>││<178>cursor left word                            <268>│\n"
 		"<268>├─────────────────────────┤├────────────────────────────────────────────┤\n"
 		"<268>│<178>ctrl arrow right         <268>││<178>cursor right word                           <268>│\n"
 		"<268>└─────────────────────────┘└────────────────────────────────────────────┘\n"
-		
+
 		"<268>┌─────────────────────────┐┌────────────────────────────────────────────┐\n"
 		"<268>│<178>backspace                <268>││<178>backspace                                   <268>│\n"
 		"<268>├─────────────────────────┤├────────────────────────────────────────────┤\n"
@@ -1493,38 +1492,38 @@ struct help_type help_table[] =
 		"<268>├─────────────────────────┤├────────────────────────────────────────────┤\n"
 		"<268>│<178>ctrl backspace           <268>││<178>clear line                                  <268>│\n"
 		"<268>└─────────────────────────┘└────────────────────────────────────────────┘\n"
-		
+
 		"<268>┌─────────────────────────┐┌────────────────────────────────────────────┐\n"
 		"<268>│<178>delete                   <268>││<178>delete                                      <268>│\n"
 		"<268>├─────────────────────────┤├────────────────────────────────────────────┤\n"
 		"<268>│<178>ctrl delete              <268>││<178>delete word right                           <268>│\n"
 		"<268>└─────────────────────────┘└────────────────────────────────────────────┘\n"
-		
-		"<268>┌─────────────────────────┐┌────────────────────────────────────────────┐\n"	
+
+		"<268>┌─────────────────────────┐┌────────────────────────────────────────────┐\n"
 		"<268>│<178>end                      <268>││<178>cursor end                                  <268>│\n"
 		"<268>├─────────────────────────┤├────────────────────────────────────────────┤\n"
 		"<268>│<178>ctrl end                 <268>││<178>scroll buffer end                           <268>│\n"
 		"<268>└─────────────────────────┘└────────────────────────────────────────────┘\n"
 
-		"<268>┌─────────────────────────┐┌────────────────────────────────────────────┐\n"	
+		"<268>┌─────────────────────────┐┌────────────────────────────────────────────┐\n"
 		"<268>│<178>enter                    <268>││<178>enter                                       <268>│\n"
 		"<268>├─────────────────────────┤├────────────────────────────────────────────┤\n"
 		"<268>│<178>shift-enter              <268>││<178>soft enter                                  <268>│\n"
 		"<268>└─────────────────────────┘└────────────────────────────────────────────┘\n"
-		
+
 		"<268>┌─────────────────────────┐┌────────────────────────────────────────────┐\n"
 		"<268>│<178>home                     <268>││<178>cursor home                                 <268>│\n"
 		"<268>├─────────────────────────┤├────────────────────────────────────────────┤\n"
 		"<268>│<178>ctrl home                <268>││<178>scroll buffer home                          <268>│\n"
 		"<268>└─────────────────────────┘└────────────────────────────────────────────┘\n"
-		
-		"<268>┌─────────────────────────┐┌────────────────────────────────────────────┐\n"	
+
+		"<268>┌─────────────────────────┐┌────────────────────────────────────────────┐\n"
 		"<268>│<178>page up                  <268>││<178>scroll buffer up                            <268>│\n"
 		"<268>├─────────────────────────┤├────────────────────────────────────────────┤\n"
 		"<268>│<178>page down                <268>││<178>scroll buffer down                          <268>│\n"
 		"<268>└─────────────────────────┘└────────────────────────────────────────────┘\n"
 
-		"<268>┌─────────────────────────┐┌────────────────────────────────────────────┐\n"	
+		"<268>┌─────────────────────────┐┌────────────────────────────────────────────┐\n"
 		"<268>│<178>tab                      <268>││<178>complete word forward                       <268>│\n"
 		"<268>├─────────────────────────┤├────────────────────────────────────────────┤\n"
 		"<268>│<178>shift-tab                <268>││<178>complete word backward                      <268>│\n"
@@ -1542,7 +1541,7 @@ struct help_type help_table[] =
 		"<278>         only called if the proceeding #IF or #ELSEIF is false.\n"
 		"\n"
 		"<178>Example<278>: #if {1d2 == 1} {smile};#else {grin}\n",
-		
+
 		"case default elseif if switch regexp"
 	},
 	{
@@ -1555,7 +1554,7 @@ struct help_type help_table[] =
 		"<278>         #ELSEIF statements are false.\n"
 		"\n"
 		"<178>Example<278>: #if {1d3 == 1} {smirk};#elseif {1d2 == 1} {snicker}\n",
-		
+
 		"case default else if switch regexp"
 	},
 	{
@@ -1568,7 +1567,7 @@ struct help_type help_table[] =
 		"\n"
 		"<278>         The message is optional and is printed before tintin exits. When\n"
 		"<278>         using #end {\\} tintin will terminate silently.\n",
-		
+
 		"zap"
 	},
 	{
@@ -1593,7 +1592,7 @@ struct help_type help_table[] =
 		"\n"
 		"<278>         Ending a line with \\ will stop tintin from appending a line feed.\n"
 		"<278>         To escape arguments in an alias or action use %%0 %%1 %%2 etc.\n",
-		
+
 		"characters colors coordinates mathematics pcre"
 	},
 	{
@@ -1642,6 +1641,9 @@ struct help_type help_table[] =
 		"<278>         <178>EDIT STARTED, EDIT FINISHED\n"
 		"<278>           %0 name  %1 lines %2 size %3 data\n"
 		"\n"
+		"<278>         <178>EDIT RESUMED, EDIT SUSPENDED\n"
+		"<278>           %0 name\n"
+		"\n"
 		"<278>         <178>HISTORY UPDATE\n"
 		"<278>           %0 command\n"
 		"\n"
@@ -1716,12 +1718,13 @@ struct help_type help_table[] =
 		"\n"
 		"<278>         <128>PORT EVENTS\n"
 		"\n"
-		"<278>         <178>CHAT MESSAGE<278>, <178>PORT MESSAGE\n"
-		"<278>           %0 raw text  %1 plain text\n"
+		"<278>         <178>CHAT MESSAGE           <278>%0 raw text  %1 plain text\n"
+		"<278>         <178>CHAT SNOOP REQUEST     <278>%0 name %1 ip %2 port\n"
 		"\n"
 		"<278>         <178>PORT CONNECTION        <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 MESSAGE           <278>%0 raw text %1 plain text\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"
@@ -1771,6 +1774,7 @@ struct help_type help_table[] =
 		"<278>         <178>WRITE ERROR            <278>%0 filename %1 error message\n"
 		"<278>         <178>WRITE FILE             <278>%0 filename\n"
 		"\n"
+		"<278>         <178>RECEIVED ERROR         <278>%0 message\n"
 		"<278>         <178>SYSTEM CRASH           <278>%0 message\n"
 		"<278>         <178>SYSTEM ERROR           <278>%0 name %1 system msg %2 error %3 error msg\n"
 		"<278>         <178>UNKNOWN COMMAND        <278>%0 raw text\n"
@@ -1814,7 +1818,7 @@ struct help_type help_table[] =
 		"<178>Example<278>: #event {SESSION CONNECTED} {#read mychar.tin}\n"
 		"\n"
 		"<178>Comment<278>: You can remove an event with the #unevent command.\n",
-		
+
 		"button delay ticker"
 	},
 	{
@@ -1828,7 +1832,7 @@ struct help_type help_table[] =
 		"\n"
 		"<178>Example<278>: #foreach {bob;tim;kim} {name} {tell $name Hello}\n"
 		"<178>Example<278>: #foreach {{bob}{tim}{kim}} {name} {tell $name Hello}\n",
-		
+
 		"break continue list loop parse repeat return while"
 	},
 	{
@@ -1876,7 +1880,7 @@ struct help_type help_table[] =
 		"<278>         #format {test} {%%}             a literal % character\n"
 		"\n"
 		"<178>Comment<278>: See #help TIME for help on the %t argument.\n",
-		
+
 		"cat echo function local math replace script time variable"
 	},
 
@@ -1910,7 +1914,7 @@ struct help_type help_table[] =
 		"<278>         #show The current time is @gettime{}\n"
 		"\n"
 		"<178>Comment<278>: You can remove a function with the #unfunction command.\n",
-		
+
 		"format local math replace script variable"
 	},
 	{
@@ -1925,7 +1929,7 @@ struct help_type help_table[] =
 		"<278>         There are a system messages that can be gagged using gag events.\n"
 		"\n"
 		"<178>Comment<278>: You can remove a gag with the #ungag command.\n",
-		
+
 		"action highlight prompt substitute"
 	},
 	{
@@ -1940,7 +1944,7 @@ struct help_type help_table[] =
 		"<268>      #<278>      Code by Peter Unold, Bill Reis, and Igor van den Hoven      <268>#\n"
 		"<268>      #<278>                                                                  <268>#\n"
 		"<268>      #<268>##################################################################<268>#<288>\n",
-		
+
 		""
 	},
 	{
@@ -1959,7 +1963,7 @@ struct help_type help_table[] =
 		"\n"
 		"<178>Example<278>: #grep Bubba tells you\n"
 		"<278>         This will show all occasions where bubba tells you something.\n",
-		
+
 		"buffer echo showme"
 	},
 	{
@@ -1970,7 +1974,7 @@ struct help_type help_table[] =
 		"<278>         Without an argument #help will list all available help subjects.\n"
 		"\n"
 		"<278>         Using #help %* will display all help entries.\n",
-		
+
 		"commands debug ignore info message statements"
 	},
 	{
@@ -2039,7 +2043,7 @@ struct help_type help_table[] =
 		"<178>Comment<278>: This command only works with ANSI/VT100 terminals or emulators.\n"
 		"\n"
 		"<178>Comment<278>: You can remove a highlight with the #unhighlight command.\n",
-		
+
 		"action gag prompt substitute"
 	},
 	{
@@ -2074,7 +2078,7 @@ struct help_type help_table[] =
 		"<278>         the history list by default. You can bind these with a macro yourself\n"
 		"<278>         using #cursor {history next} and #cursor {history prev}. Many #cursor\n"
 		"<278>         commands only work properly when bound with a macro.\n",
-		
+
 		"alias cursor keypad macro speedwalk tab"
 	},
 	{
@@ -2101,7 +2105,7 @@ struct help_type help_table[] =
 		"<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"
 	},
 	{
@@ -2984,10 +2988,10 @@ struct help_type help_table[] =
 		"<278>                 }\n"
 		"<278>             }\n"
 		"        }\n",
-		
+
 		"break continue foreach loop parse repeat return while"
 	},
-	
+
 	{
 		"LOCAL",
 		TOKEN_TYPE_COMMAND,
@@ -3760,8 +3764,8 @@ struct help_type help_table[] =
 		"<278>         In order to copy/paste, most terminals require that you press the shift\n"
 		"<278>         key during selection.\n"
 		"\n",
-		
-		"button draw event MSLP"
+
+		"button draw event mslp"
 	},
 
 	{
@@ -3929,7 +3933,7 @@ struct help_type help_table[] =
 		"<278>         #pathdir {dw} {ue} {40}\n"
 		"\n"
 		"<178>Comment<278>: You can remove a pathdir with the #unpathdir command.\n",
-		
+
 		"map path"
 	},
 	{
@@ -3972,7 +3976,7 @@ struct help_type help_table[] =
 		"<278>         is used.\n"
 		"\n"
 		"<178>TinTin++ <178>Description                                      POSIX\n"
-		"<178>      %a <278>Match zero or more characters including newlines ([^\\0]*?)\n"       
+		"<178>      %a <278>Match zero or more characters including newlines ([^\\0]*?)\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>      %d <278>Match zero or more digits                        ([0-9]*?)\n"
@@ -4245,12 +4249,11 @@ struct help_type help_table[] =
 		TOKEN_TYPE_COMMAND,
 		"<178>Command<278>: #read <178>{<278>filename<178>}\n"
 		"\n"
-		"<278>         Reads a commands file into memory.  The coms file is merged in with\n"
-		"<278>         the currently loaded commands.  Duplicate commands are overwritten.\n"
+		"<278>         Reads a commands file into memory.  The commands are merged with the\n"
+		"<278>         currently loaded commands.  Duplicate commands are overwritten.\n"
 		"\n"
-		"<278>         If you uses braces, { and } you can use several lines for 1 commands.\n"
-		"<278>         This however means you must always match every { with a } for the read\n"
-		"<278>         command to work.\n"
+		"<278>         If you uses braces you can use several lines for each command.  You\n"
+		"<278>         must match every { with a } for the read command to work.\n"
 		"\n"
 		"<278>         You can comment out triggers using /* text */\n"
 		,
@@ -4331,13 +4334,14 @@ struct help_type help_table[] =
 	{
 		"REPEAT",
 		TOKEN_TYPE_STRING,
-		"<178>Command<278>: #<178>[<078>number<178>] {<278>commands<178>}\n"
+		"<178>Command<278>: #<178>[<078>number<178>] {<278>commands<178>} {<278>..<178>}\n"
 		"\n"
 		"<278>        Sometimes you want to repeat the same command multiple times. This is\n"
 		"<278>        the easiest way to accomplish that.\n"
 		"\n"
-		"<178>Example<278>: #10 {buy bread}\n",
-		
+		"<178>Example<278>: #10 {buy bread}\n"
+		"<178>Example<278>: #2 {buy bread} {buy apple}\n",
+
 		"mathematics statements"
 	},
 	{
@@ -4413,8 +4417,12 @@ struct help_type help_table[] =
 		"\n"
 		"<178>         #scan {dir} <filename> <variable>\n"
 		"\n"
-		"<278>          The scan dir command will read the given filename or directory and\n"
-		"<278>          store any gathered information into the provided variable.\n"
+		"<278>           The scan dir command will read the given filename or directory and\n"
+		"<278>           store any gathered information into the provided variable.\n"
+		"\n"
+		"<178>         #scan {json} <filename> <variable>\n"
+		"<278>           The scan json command will read the given filename and store the data\n"
+		"<278>           in the provided tintin variable.\n"
 		"\n"
 		"<278>         <178>#scan {tsv} <filename>\n"
 		"\n"
@@ -4426,9 +4434,9 @@ struct help_type help_table[] =
 		"<278>         <178>#scan {file} <filename> {commands}\n"
 		"\n"
 		"<278>           The scan file command reads the given files and executes the\n"
-		"<278>            commands argument. &0 contains the raw content of the file and\n"
-		"<278>            &1 contains the plain content. &2 contains the raw byte size of the\n"
-		"<278>            file and &3 the plain byte size. &5 contains the line count.\n"
+		"<278>           commands argument. &0 contains the raw content of the file and\n"
+		"<278>           &1 contains the plain content. &2 contains the raw byte size of the\n"
+		"<278>           file and &3 the plain byte size. &5 contains the line count.\n"
 		"\n"
 		"<278>         <178>#scan {txt} <filename>\n"
 		"\n"
@@ -5208,7 +5216,7 @@ struct help_type help_table[] =
 		"<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>         existent nested variable will report itself as 0.\n"
-		"\n" 
+		"\n"
 		"<178>Example<278>: #show {Number of targets starting with A: &targets[A%*]\n"
 		"\n"
 		"<278>         In some scripts you need to know the name of a nested variable. This\n"

+ 3 - 3
src/history.c

@@ -113,14 +113,14 @@ struct session *repeat_history(struct session *ses, char *line)
 
 			gtd->level->repeat++;
 
-			ses = script_driver(ses, LIST_COMMAND, root->list[root->used - 1]->arg1);
+			ses = script_driver(ses, LIST_COMMAND, NULL, root->list[root->used - 1]->arg1);
 
 			gtd->level->repeat--;
 
 			return ses;
 		}
 	}
-	tintin_printf2(ses, "#REPEAT: NO MATCH FOUND FOR '%s'", line);	
+	tintin_printf2(ses, "#REPEAT: NO MATCH FOUND FOR '%s'", line);
 
 	return ses;
 }
@@ -258,7 +258,7 @@ DO_HISTORY(history_read)
 
 	fclose(file);
 
-	if (ses->list[LIST_HISTORY]->used > gtd->history_size) 
+	if (ses->list[LIST_HISTORY]->used > gtd->history_size)
 	{
 		command(gts, do_configure, "{HISTORY SIZE} {%d}", UMIN(ses->list[LIST_HISTORY]->used, 9999));
 	}

+ 14 - 20
src/input.c

@@ -174,7 +174,7 @@ void process_input(void)
 	}
 	else
 	{
-		gtd->ses = script_driver(gtd->ses, LIST_COMMAND, gtd->ses->input->buf);
+		gtd->ses = script_driver(gtd->ses, LIST_COMMAND, NULL, gtd->ses->input->buf);
 	}
 
 	if (HAS_BIT(input_ses->telopts, TELOPT_FLAG_ECHO))
@@ -311,7 +311,7 @@ void read_line(char *input, int len)
 					cursor_delete(gtd->ses, "");
 				}
 
-				
+
 				str_ins_printf(&gtd->ses->input->buf, gtd->ses->input->raw_pos, "%.*s", size, gtd->macro_buf);
 
 				gtd->ses->input->str_pos += width;
@@ -337,10 +337,8 @@ void read_line(char *input, int len)
 
 				kill_list(gtd->ses->list[LIST_COMMAND]);
 
-				if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
-				{
-					cursor_history_find(gtd->ses, "");
-				}
+				cursor_history_find(gtd->ses, "");
+
 				break;
 		}
 	}
@@ -459,14 +457,14 @@ int check_key(char *input, int len)
 				{
 					strcpy(buf, node->arg2);
 
-					show_debug(gtd->ses, LIST_MACRO, COLOR_DEBUG "#DEBUG MACRO " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
+					show_debug(gtd->ses, LIST_MACRO, node, COLOR_DEBUG "#DEBUG MACRO " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
 
 					if (node->shots && --node->shots == 0)
 					{
 						delete_node_list(gtd->ses, LIST_MACRO, node);
 					}
 
-					script_driver(gtd->ses, LIST_MACRO, buf);
+					script_driver(gtd->ses, LIST_MACRO, node, buf);
 
 					if (HAS_BIT(gtd->flags, TINTIN_FLAG_PRESERVEMACRO))
 					{
@@ -528,11 +526,11 @@ int check_key(char *input, int len)
 					gtd->macro_buf[0] = 0;
 
 					gtd->screen->focus = 1;
-					
+
 					check_all_events(gtd->ses, EVENT_FLAG_SCREEN, 0, 1, "SCREEN FOCUS", ntos(gtd->screen->focus));
 
 					msdp_update_all("SCREEN_FOCUS", "%d", gtd->screen->focus);
-					
+
 					pop_call();
 					return TRUE;
 				}
@@ -542,11 +540,11 @@ int check_key(char *input, int len)
 					gtd->macro_buf[0] = 0;
 
 					gtd->screen->focus = 0;
-					
+
 					check_all_events(gtd->ses, EVENT_FLAG_SCREEN, 0, 1, "SCREEN FOCUS", ntos(gtd->screen->focus));
-					
+
 					msdp_update_all("SCREEN_FOCUS", "%d", gtd->screen->focus);
-					 
+
 					pop_call();
 					return TRUE;
 				}
@@ -700,8 +698,8 @@ int check_key(char *input, int len)
 									}
 									pop_call();
 									return FALSE;
-										
-									
+
+
 								default:
 									pop_call();
 									return FALSE;
@@ -1078,14 +1076,10 @@ void modified_input(void)
 {
 	kill_list(gtd->ses->list[LIST_COMMAND]);
 
-	if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
-	{
-		cursor_history_find(gtd->ses, "");
-	}
+	cursor_history_find(gtd->ses, "");
 
 	if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYBROWSE))
 	{
 		DEL_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYBROWSE);
 	}
-
 }

+ 24 - 25
src/line.c

@@ -113,7 +113,7 @@ DO_LINE(line_background)
 
 	gtd->level->background++;
 
-	ses = script_driver(ses, LIST_COMMAND, arg1);
+	ses = script_driver(ses, LIST_COMMAND, NULL, arg1);
 
 	gtd->level->background--;
 
@@ -135,7 +135,7 @@ DO_LINE(line_benchmark)
 
 	start = utime();
 
-	ses = script_driver(ses, LIST_COMMAND, arg1);
+	ses = script_driver(ses, LIST_COMMAND, NULL, arg1);
 
 	end = utime();
 
@@ -158,7 +158,7 @@ DO_LINE(line_capture)
 		ses->line_capturefile  = strdup(arg1);
 		ses->line_captureindex = 1;
 
-		ses = script_driver(ses, LIST_COMMAND, arg2);
+		ses = script_driver(ses, LIST_COMMAND, NULL, arg2);
 
 		if (ses->line_capturefile)
 		{
@@ -188,7 +188,7 @@ DO_LINE(line_convert)
 
 	gtd->level->convert++;
 
-	ses = script_driver(ses, LIST_COMMAND, arg1);
+	ses = script_driver(ses, LIST_COMMAND, NULL, arg1);
 
 	gtd->level->convert--;
 
@@ -208,7 +208,7 @@ DO_LINE(line_debug)
 
 	gtd->level->debug++;
 
-	ses = script_driver(ses, LIST_COMMAND, arg1);
+	ses = script_driver(ses, LIST_COMMAND, NULL, arg1);
 
 	gtd->level->debug--;
 
@@ -239,7 +239,7 @@ DO_LINE(line_gag)
 	{
 		ses->gagline = 0;
 	}
-	show_debug(ses, LIST_GAG, COLOR_DEBUG "#DEBUG LINE GAG " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} " COLOR_COMMAND "[" COLOR_STRING "%d" COLOR_COMMAND "]", arg1, ses->gagline);
+	show_debug(ses, LIST_GAG, NULL, COLOR_DEBUG "#DEBUG LINE GAG " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} " COLOR_COMMAND "[" COLOR_STRING "%d" COLOR_COMMAND "]", arg1, ses->gagline);
 
 	return ses;
 }
@@ -251,13 +251,13 @@ DO_LINE(line_ignore)
 	if (*arg1 == 0)
 	{
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {IGNORE} <COMMAND>");
-		
+
 		return ses;
 	}
 
 	gtd->level->ignore++;
 
-	ses = script_driver(ses, LIST_COMMAND, arg1);
+	ses = script_driver(ses, LIST_COMMAND, NULL, arg1);
 
 	gtd->level->ignore--;
 
@@ -279,7 +279,7 @@ DO_LINE(line_local)
 
 	SET_BIT(gtd->flags, TINTIN_FLAG_LOCAL);
 
-	ses = script_driver(ses, LIST_COMMAND, arg1);
+	ses = script_driver(ses, LIST_COMMAND, NULL, arg1);
 
 	gtd->level->local--;
 
@@ -474,7 +474,7 @@ DO_LINE(line_logmode)
 
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
 
-	active_ses = script_driver(ses, LIST_COMMAND, arg1);
+	active_ses = script_driver(ses, LIST_COMMAND, NULL, arg1);
 
 	ses->log->mode = old_mode;
 
@@ -494,7 +494,7 @@ DO_LINE(line_msdp)
 
 	tintin2msdp(arg1, arg2);
 
-	ses = script_driver(ses, LIST_COMMAND, arg2);
+	ses = script_driver(ses, LIST_COMMAND, NULL, arg2);
 
 	return ses;
 }
@@ -538,11 +538,11 @@ DO_LINE(line_json)
 
 	substitute(ses, arg2, str_sub, SUB_CMD);
 
-	ses = script_driver(ses, LIST_COMMAND, str_sub);
+	ses = script_driver(ses, LIST_COMMAND, NULL, str_sub);
 
 	return ses;
 }
-	
+
 DO_LINE(line_multishot)
 {
 	unsigned int shots;
@@ -555,7 +555,7 @@ DO_LINE(line_multishot)
 	if (!is_math(ses, arg1) || *arg2 == 0)
 	{
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {MULTISHOT} <NUMBER> <COMMAND>");
-		
+
 		return ses;
 	}
 
@@ -563,7 +563,7 @@ DO_LINE(line_multishot)
 
 	gtd->level->mshot = shots;
 
-	ses = script_driver(ses, LIST_COMMAND, arg2);
+	ses = script_driver(ses, LIST_COMMAND, NULL, arg2);
 
 	gtd->level->mshot = 1;
 
@@ -579,7 +579,7 @@ DO_LINE(line_oneshot)
 	if (*arg1 == 0)
 	{
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {ONESHOT} <COMMAND>");
-		
+
 		return ses;
 	}
 
@@ -587,7 +587,7 @@ DO_LINE(line_oneshot)
 
 	gtd->level->mshot = 1;
 
-	ses = script_driver(ses, LIST_COMMAND, arg1);
+	ses = script_driver(ses, LIST_COMMAND, NULL, arg1);
 
 	gtd->level->shots--;
 
@@ -601,13 +601,13 @@ DO_LINE(line_quiet)
 	if (*arg1 == 0)
 	{
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {QUIET} <COMMAND>");
-		
+
 		return ses;
 	}
 
 	gtd->level->quiet++;
 
-	ses = script_driver(ses, LIST_COMMAND, arg1);
+	ses = script_driver(ses, LIST_COMMAND, NULL, arg1);
 
 	gtd->level->quiet--;
 
@@ -627,7 +627,7 @@ DO_LINE(line_strip)
 
 	strip_vt102_codes(arg1, arg2);
 
-	ses = script_driver(ses, LIST_COMMAND, arg2);
+	ses = script_driver(ses, LIST_COMMAND, NULL, arg2);
 
 	return ses;
 }
@@ -670,7 +670,7 @@ DO_LINE(line_substitute)
 
 	substitute(ses, arg2, arg3, flags);
 
-	ses = script_driver(ses, LIST_COMMAND, arg3);
+	ses = script_driver(ses, LIST_COMMAND, NULL, arg3);
 
 	return ses;
 }
@@ -682,7 +682,7 @@ DO_LINE(line_verbatim)
 	if (*arg1 == 0)
 	{
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {VERBATIM} <COMMAND>");
-		
+
 		return ses;
 	}
 
@@ -702,17 +702,16 @@ DO_LINE(line_verbose)
 	if (*arg1 == 0)
 	{
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {VERBOSE} <COMMAND>");
-		
+
 		return ses;
 	}
 
 	gtd->level->verbose++;
 
-	ses = script_driver(ses, LIST_COMMAND, arg1);
+	ses = script_driver(ses, LIST_COMMAND, NULL, arg1);
 
 	gtd->level->verbose--;
 
 	return ses;
 }
 
-	

+ 30 - 10
src/main.c

@@ -250,7 +250,7 @@ int main(int argc, char **argv)
 
 	if (argc > 1)
 	{
-		while ((c = getopt(argc, argv, "a: e: g G h H M:: r: R:: s t: T v V")) != EOF)
+		while ((c = getopt(argc, argv, "a: e: g G h l H M:: r: R:: s t: T v V")) != EOF)
 		{
 			switch (c)
 			{
@@ -263,7 +263,7 @@ int main(int argc, char **argv)
 					printf("  -G  Don't show the greeting screen.\n");
 					printf("  -h  This help section.\n");
 					printf("  -H  Nohup compatible mode.\n");
-					printf("  -M  Matrix Digital Rain.\n");
+					printf("  -l  <rain|regex>\n");
 					printf("  -r  Read given file.\n");
 					printf("  -R  Reattach to daemonized process.\n");
 					printf("  -s  Enable screen reader mode.\n");
@@ -302,6 +302,13 @@ int main(int argc, char **argv)
 
 	init_tintin(greeting);
 
+	gtd->system->exec = strdup(argv[0]);
+
+	if (!strcmp(gtd->system->exec, "././tt++"))
+	{
+		RESTRING(gtd->system->os, "WINTIN++");
+	}
+
 	RESTRING(gtd->vars[1], argv[0]);
 
 	if (argc > 1)
@@ -310,7 +317,7 @@ int main(int argc, char **argv)
 
 		RESTRING(gtd->vars[2], argv[1]);
 
-		while ((c = getopt(argc, argv, "a: e: g G h H M:: r: R:: s t: T v")) != EOF)
+		while ((c = getopt(argc, argv, "a: e: g G h H l: M:: r: R:: s t: T v")) != EOF)
 		{
 			switch (c)
 			{
@@ -321,19 +328,34 @@ int main(int argc, char **argv)
 
 				case 'e':
 					gtd->level->input++;
-					gtd->ses = script_driver(gtd->ses, LIST_COMMAND, optarg);
+					gtd->ses = script_driver(gtd->ses, LIST_COMMAND, NULL, optarg);
 					gtd->level->input--;
 					break;
 
 				case 'g':
-					gtd->ses = command(gtd->ses, do_banner, "gui");
+					gtd->ses = command(gtd->ses, do_test, "gui");
 					break;
 
 				case 'G':
 					break;
 
+				case 'l':
+					if (!strcasecmp(optarg, "rain"))
+					{
+						command(gts, do_test, "rain %s", optarg ? optarg : "");
+					}
+					else if (!strcasecmp(optarg, "regex"))
+					{
+						gtd->ses = command(gtd->ses, do_test, "regex");
+					}
+					else
+					{
+						tintin_printf2(NULL, "Option arguments are: -l <rain|regex>.");
+						exit(1);
+					}
+					break;
+
 				case 'M':
-					command(gts, do_test, "rain %s", optarg ? optarg : "");
 					break;
 
 				case 'r':
@@ -380,8 +402,6 @@ int main(int argc, char **argv)
 		command(gts, do_screen, "SET BOTH TinTin++");
 	}
 
-	gtd->system->exec = strdup(argv[0]);
-
 	if (argc > 2)
 	{
 		RESTRING(gtd->vars[3], argv[2]);
@@ -469,7 +489,7 @@ void init_tintin(int greeting)
 	gtd->system         = (struct system_data *) calloc(1, sizeof(struct system_data));
 
 	gtd->system->os     = strdup(getenv("OS")   ? getenv("OS")   : "UNKNOWN");
-	gtd->system->home   = strdup(getenv("HOME") ? getenv("HOME") : "~/");
+	gtd->system->home   = strdup(getenv("HOME") ? getenv("HOME") : ".");
 	gtd->system->lang   = strdup(getenv("LANG") ? getenv("LANG") : "UNKNOWN");
 	gtd->system->term   = strdup(getenv("TERM") ? getenv("TERM") : "UNKNOWN");
 
@@ -733,7 +753,7 @@ void syserr_printf(struct session *ses, char *fmt, ...)
 	char buf[BUFFER_SIZE], name[BUFFER_SIZE], *errstr;
 
 	errstr = strerror(errno);
-	
+
 	va_list args;
 
 	va_start(args, fmt);

+ 33 - 24
src/mapper.c

@@ -397,11 +397,11 @@ void delete_room_data(struct room_data *room)
 	free(room->desc);
 	free(room->note);
 	free(room->terrain);
-	free(room->data); 
+	free(room->data);
 
 	return;
 }
-	
+
 void delete_room(struct session *ses, int room, int exits)
 {
 	struct exit_data *exit, *exit_next;
@@ -957,7 +957,7 @@ int get_terrain_density(struct room_data *room, int width)
 							case TERRAIN_FLAG_WIDE:
 								flag = TERRAIN_FLAG_AMPLE;
 								break;
-								
+
 							case TERRAIN_FLAG_WIDE|TERRAIN_FLAG_VAST:
 								flag = TERRAIN_FLAG_SPARSE;
 								break;
@@ -1885,7 +1885,7 @@ int follow_map(struct session *ses, char *argument)
 			else
 			{
 				ses->map->nofollow++;
-				script_driver(ses, LIST_COMMAND, exit->cmd);
+				script_driver(ses, LIST_COMMAND, NULL, exit->cmd);
 				ses->map->nofollow--;
 			}
 		}
@@ -1965,7 +1965,7 @@ int follow_map(struct session *ses, char *argument)
 		{
 			ses->map->nofollow++;
 
-			script_driver(ses, LIST_COMMAND, argument);
+			script_driver(ses, LIST_COMMAND, NULL, argument);
 
 			ses->map->nofollow--;
 		}
@@ -3865,7 +3865,7 @@ void search_keywords(struct session *ses, char *arg, char *out, char *var)
 		}
 	}
 
-	if (buf[MAP_SEARCH_DESC])
+	if (*buf[MAP_SEARCH_DESC])
 	{
 		str = buf[MAP_SEARCH_DESC];
 
@@ -4394,7 +4394,7 @@ int find_location(struct session *ses, char *arg)
 	struct listnode *dir;
 	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE];
 	int x, y, z;
-	
+
 	push_call("find_location(%p,%p)",ses,arg);
 
 	if (find_exit(ses, ses->map->in_room, arg))
@@ -4618,7 +4618,7 @@ int check_global(struct session *ses, int room)
 	{
 		return FALSE;
 	}
-	
+
 	if (ses->map->room_list[ses->map->global_vnum] == NULL)
 	{
 		return FALSE;
@@ -5336,7 +5336,7 @@ void map_mouse_handler(struct session *ses, char *arg1, char *arg2, int row, int
 			check_all_events(ses, EVENT_FLAG_MOUSE, 0, 6, "MAP MOUSE LOCATION", ntos(row), ntos(col), exit, ntos(rev_row), ntos(rev_col), ntos(vnum), exit);
 		}
 	}
-		
+
 	pop_call();
 	return;
 }
@@ -5401,7 +5401,7 @@ DO_MAP(map_at)
 
 	ses->map->in_room = new_room;
 
-	script_driver(ses, LIST_COMMAND, arg2);
+	script_driver(ses, LIST_COMMAND, NULL, arg2);
 
 	if (ses->map)
 	{
@@ -5580,7 +5580,7 @@ DO_MAP(map_delete)
 	if (room == ses->map->in_room || room == ses->map->at_room)
 	{
 		show_error(ses, LIST_COMMAND, "#MAP DELETE: YOU MUST FIRST LEAVE THE ROOM YOU'RE TRYING TO DELETE.");
-		
+
 		return;
 	}
 
@@ -5766,7 +5766,7 @@ DO_MAP(map_dig)
 		if (room == ses->map->size)
 		{
 			show_error(ses, LIST_COMMAND, "#MAP DIG: MAXIMUM NUMBER OF ROOMS OF %d REACHED.", ses->map->size);
-			
+
 			return;
 		}
 		add_undo(ses, "%d %d %d", room, ses->map->in_room, MAP_UNDO_CREATE|MAP_UNDO_LINK);
@@ -5856,7 +5856,7 @@ void exit_edit(struct session *ses, struct exit_data *exit, char *opt, char *arg
 		else if ((dir = get_exit_dir(ses, arg3)) == 0)
 		{
 			show_error(ses, LIST_COMMAND, "#MAP %s {%s}: DIRECTION {%s} NOT FOUND.", opt, arg1, arg3);
-			
+
 			return;
 		}
 
@@ -5969,7 +5969,7 @@ DO_MAP(map_entrance)
 	if (exit == NULL)
 	{
 		show_message(ses, LIST_COMMAND, "#MAP ENTRANCE: CAN'T FIND EXIT {%s}.", arg1);
-		
+
 		return;
 	}
 
@@ -6585,6 +6585,8 @@ DO_MAP(map_info)
 		add_nest_node_ses(ses, "info[MAP]", "{ROOMS}{%d}", cnt);
 		add_nest_node_ses(ses, "info[MAP]", "{ROOMS_MAX}{%d}", ses->map->size);
 
+		show_message(ses, LIST_COMMAND, "#MAP INFO: DATA WRITTEN TO {info[MAP]}");
+
 		return;
 	}
 
@@ -6846,7 +6848,7 @@ DO_MAP(map_landmark)
 
 			show_message(ses, LIST_COMMAND, "#OK: LANDMARK {%s} HAS VNUM {%d} AND IS DESCRIBED AS {%s} WITH SIZE {%s}.", arg1, room, arg3, arg4);
 		}
-	} 
+	}
 }
 
 DO_MAP(map_unlandmark)
@@ -7394,7 +7396,7 @@ DO_MAP(map_map)
 					case 'O':
 						logit(ses, gtd->out, logfile, LOG_FLAG_LINEFEED);
 						break;
-					
+
 					case 'L':
 						cat_sprintf(arg1, "{%02d}{%s}", ++row, gtd->out);
 						break;
@@ -7538,7 +7540,7 @@ DO_MAP(map_map)
 					logit(ses, gtd->out, logfile, LOG_FLAG_LINEFEED);
 //					fprintf(logfile, "%s\n", gtd->out);
 					break;
-				
+
 				case 'L':
 					cat_sprintf(arg1, "{%02d}{%s}", ++row, gtd->out);
 					break;
@@ -7551,7 +7553,7 @@ DO_MAP(map_map)
 				case 'V':
 					cat_sprintf(arg1, "%s\n", gtd->out);
 					break;
-				
+
 				default:
 					tintin_puts2(ses, gtd->out);
 					break;
@@ -7634,6 +7636,13 @@ DO_MAP(map_offset)
 			ses->map->sav_top_col = get_number(ses, arg2);
 			ses->map->sav_bot_row = get_number(ses, arg3);
 			ses->map->sav_bot_col = get_number(ses, arg4);
+
+			if (ses->map->sav_top_row == 0 || ses->map->sav_top_col == 0 || ses->map->sav_bot_row == 0 || ses->map->sav_bot_col == 0)
+			{
+				show_error(ses, LIST_COMMAND, "#ERROR: #MAP OFFSET: INVALID SQUARE: {%s} {%s} {%s} {%s}", arg1, arg2, arg3, arg4);
+
+				return;
+			}
 		}
 		else
 		{
@@ -7683,7 +7692,7 @@ DO_MAP(map_read)
 		show_error(ses, LIST_COMMAND, "#MAP: INVALID READ ON LINE %d. ABORTING READ.", line);
 
 		fclose(myfile);
-		
+
 		return;
 	}
 
@@ -7845,7 +7854,7 @@ DO_MAP(map_read)
 
 			case '#':
 				buffer[0] = gtd->tintin_char;
-				ses = script_driver(ses, LIST_COMMAND, buffer);
+				ses = script_driver(ses, LIST_COMMAND, NULL, buffer);
 				break;
 
 			case  0:
@@ -8058,7 +8067,7 @@ DO_MAP(map_roomflag)
 
 	if (*arg2 == 0)
 	{
-		TOG_BIT(ses->map->room_list[ses->map->in_room]->flags, flag);	
+		TOG_BIT(ses->map->room_list[ses->map->in_room]->flags, flag);
 	}
 	else if (is_abbrev(arg2, "ON"))
 	{
@@ -8745,7 +8754,7 @@ DO_MAP(map_vnum)
 	{
 		vnum2 = vnum1;
 	}
-	
+
 	if (vnum1 <= 0 || vnum1 >= ses->map->size || vnum2 <= 0 || vnum2 >= ses->map->size)
 	{
 		show_error(ses, LIST_COMMAND, "#MAP VNUM {%s} {%s} - VNUMS MUST BE BETWEEN {1} and {%d}", arg1, arg2, ses->map->size - 1);
@@ -8867,7 +8876,7 @@ DO_MAP(map_write)
 	{
 		fprintf(file, "LM {%s} {%d} {%s} {%s}\n", root->list[index]->arg1, root->list[index]->val32[0], root->list[index]->arg3, root->list[index]->arg4);
 	}
-	fprintf(file, "\n\n");	
+	fprintf(file, "\n\n");
 
 	root = ses->list[LIST_TERRAIN];
 
@@ -8875,7 +8884,7 @@ DO_MAP(map_write)
 	{
 		fprintf(file, "T {%s} {%s} {%s}\n", root->list[index]->arg1, root->list[index]->arg2, root->list[index]->arg3);
 	}
-	fprintf(file, "\n\n");	
+	fprintf(file, "\n\n");
 
 	for (index = 0 ; index < ses->map->size ; index++)
 	{

+ 25 - 25
src/math.c

@@ -204,7 +204,7 @@ long double get_root(long double value, long double power)
 	{
 		mid = top / 2;
 		sum = bot + mid;
-		
+
 		if (powl(sum, power) <= value)
 		{
 			bot += mid;
@@ -223,7 +223,7 @@ long double get_double(struct session *ses, char *str)
 
 	return val;
 }
-	
+
 void get_number_string(struct session *ses, char *str, char *result)
 {
 	long double val = get_number(ses, str);
@@ -242,7 +242,7 @@ long double mathswitch(struct session *ses, char *left, char *right)
 
 /*
 	Flexible tokenized mathematical expression interpreter
-	
+
 	If seed is set it forces floating point math
 */
 
@@ -473,7 +473,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 						{
 							if (debug)
 							{
-								show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: \x7B FOUND INSIDE A NUMBER");
+								show_debug(ses, LIST_VARIABLE, NULL, "#DEBUG MATH: \x7B FOUND INSIDE A NUMBER");
 							}
 							pop_call();
 							return FALSE;
@@ -488,7 +488,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 						{
 							if (debug)
 							{
-								show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: \" FOUND INSIDE A NUMBER");
+								show_debug(ses, LIST_VARIABLE, NULL, "#DEBUG MATH: \" FOUND INSIDE A NUMBER");
 							}
 							pop_call();
 							return FALSE;
@@ -503,7 +503,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 						{
 							if (debug)
 							{
-								show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: PARANTESES FOUND INSIDE A NUMBER");
+								show_debug(ses, LIST_VARIABLE, NULL, "#DEBUG MATH: PARANTESES FOUND INSIDE A NUMBER");
 							}
 							pop_call();
 							return FALSE;
@@ -527,7 +527,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 						}
 						*pta++ = *pti++;
 						break;
-						
+
 					case '.':
 						if (pti[1] == '.')
 						{
@@ -556,7 +556,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 							{
 								if (debug)
 								{
-									show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: MORE THAN ONE POINT FOUND INSIDE A NUMBER");
+									show_debug(ses, LIST_VARIABLE, NULL, "#DEBUG MATH: MORE THAN ONE POINT FOUND INSIDE A NUMBER");
 								}
 								precision = 0;
 								pop_call();
@@ -587,7 +587,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 						{
 							if (debug)
 							{
-								show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: EXPRESSION STARTED WITH AN OPERATOR.");
+								show_debug(ses, LIST_VARIABLE, NULL, "#DEBUG MATH: EXPRESSION STARTED WITH AN OPERATOR.");
 							}
 							pop_call();
 							return FALSE;
@@ -608,7 +608,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 
 							if (debug)
 							{
-								show_debug(ses, LIST_VARIABLE, "#DEBUG MATH {%s}: FOUND OPERATOR %s WHILE EXPECTING A VALUE.", str, buf3);
+								show_debug(ses, LIST_VARIABLE, NULL, "#DEBUG MATH {%s}: FOUND OPERATOR %s WHILE EXPECTING A VALUE.", str, buf3);
 							}
 							pop_call();
 							return FALSE;
@@ -630,7 +630,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 
 							if (debug)
 							{
-								show_debug(ses, LIST_VARIABLE, "#DEBUG MATH {%s}: INVALID NUMBER %s.", str, buf3);
+								show_debug(ses, LIST_VARIABLE, NULL, "#DEBUG MATH {%s}: INVALID NUMBER %s.", str, buf3);
 							}
 
 							pop_call();
@@ -709,7 +709,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 
 						if (debug)
 						{
-							show_debug(ses, LIST_VARIABLE, "#DEBUG MATH {%s}: INVALID NUMBER %s.", str, buf3);
+							show_debug(ses, LIST_VARIABLE, NULL, "#DEBUG MATH {%s}: INVALID NUMBER %s.", str, buf3);
 						}
 						pop_call();
 						return FALSE;
@@ -783,7 +783,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 						{
 							if (debug)
 							{
-								show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: UNKNOWN OPERATOR: %c%c", pti[0], pti[1]);
+								show_debug(ses, LIST_VARIABLE, NULL, "#DEBUG MATH: UNKNOWN OPERATOR: %c%c", pti[0], pti[1]);
 							}
 							pop_call();
 							return FALSE;
@@ -815,13 +815,13 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 								*pta++ = *pti++;
 								MATH_NODE(EXP_OPERATOR, EXP_PR_INTMUL, EXP_NUMBER);
 								break;
-							
+
 							default:
 								MATH_NODE(EXP_OPERATOR, EXP_PR_INTMUL, EXP_NUMBER);
 								break;
 						}
 						break;
-	
+
 					case '/':
 						*pta++ = *pti++;
 
@@ -956,7 +956,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 							default:
 								if (debug)
 								{
-									show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: UNKNOWN OPERATOR: %c%c", pti[-1], pti[0]);
+									show_debug(ses, LIST_VARIABLE, NULL, "#DEBUG MATH: UNKNOWN OPERATOR: %c%c", pti[-1], pti[0]);
 								}
 								pop_call();
 								return FALSE;
@@ -966,7 +966,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 					default:
 						if (debug)
 						{
-							show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: UNKNOWN OPERATOR: %c", *pti);
+							show_debug(ses, LIST_VARIABLE, NULL, "#DEBUG MATH: UNKNOWN OPERATOR: %c", *pti);
 						}
 						pop_call();
 						return FALSE;
@@ -979,7 +979,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 	{
 		if (debug)
 		{
-			show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: UNMATCHED PARENTHESES, LEVEL: %d", level);
+			show_debug(ses, LIST_VARIABLE, NULL, "#DEBUG MATH: UNMATCHED PARENTHESES, LEVEL: %d", level);
 		}
 		pop_call();
 		return FALSE;
@@ -1070,7 +1070,7 @@ void mathexp_compute(struct session *ses, struct math_node *node)
 		case EXP_OP_DICE:
 			if (node->next->val <= 0)
 			{
-				show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: INVALID DICE: %lld", (long long) node->next->val);
+				show_debug(ses, LIST_VARIABLE, NULL, "#DEBUG MATH: INVALID DICE: %lld", (long long) node->next->val);
 				value = 0;
 			}
 			else
@@ -1094,7 +1094,7 @@ void mathexp_compute(struct session *ses, struct math_node *node)
 		case EXP_OP_DIVIDE:
 			if (node->next->val == 0)
 			{
-				show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: DIVISION BY ZERO.");
+				show_debug(ses, LIST_VARIABLE, NULL, "#DEBUG MATH: DIVISION BY ZERO.");
 				value = 0;
 				precision = 0;
 			}
@@ -1182,7 +1182,7 @@ void mathexp_compute(struct session *ses, struct math_node *node)
 		case EXP_OP_EQUAL:
 			value = tineval(ses, node->prev, node->next) != 0;
 			break;
-		
+
 		case EXP_OP_COMPARE:
 			value = tincmp(node->prev, node->next) == 0;
 			break;
@@ -1190,13 +1190,13 @@ void mathexp_compute(struct session *ses, struct math_node *node)
 		case EXP_OP_NOT_EQUAL:
 			value = tineval(ses, node->prev, node->next) == 0;
 			break;
-		
+
 		case EXP_OP_NOT_COMPARE:
 			value = tincmp(node->prev, node->next) != 0;
 			break;
 
 		default:
-			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);
+			show_debug(ses, LIST_VARIABLE, NULL, "#DEBUG MATH: UNKNOWN OPERATOR: %c%c%c", (int) node->val % 128, (int) node->val % 16384 / 128, (int) node->val % 2097152 / 16384);
 			value = 0;
 			break;
 	}
@@ -1526,7 +1526,7 @@ long double tincmp(struct math_node *left, struct math_node *right)
 {
 	if (left->type != right->type)
 	{
-		show_debug(gtd->ses, LIST_VARIABLE, "#DEBUG MATH: COMPARING STRING WITH A NUMBER.");
+		show_debug(gtd->ses, LIST_VARIABLE, NULL, "#DEBUG MATH: COMPARING STRING WITH A NUMBER.");
 
 		return 0;
 	}
@@ -1545,7 +1545,7 @@ long double tineval(struct session *ses, struct math_node *left, struct math_nod
 {
 	if (left->type != right->type)
 	{
-		show_debug(ses, LIST_VARIABLE, "#DEBUG MATH: COMPARING %s WITH %s.", left->type == EXP_NUMBER ? "NUMBER" : "STRING", right->type == EXP_NUMBER ? "NUMBER" : "STRING");
+		show_debug(ses, LIST_VARIABLE, NULL, "#DEBUG MATH: COMPARING %s WITH %s.", left->type == EXP_NUMBER ? "NUMBER" : "STRING", right->type == EXP_NUMBER ? "NUMBER" : "STRING");
 
 		return 0;
 	}

+ 1 - 1
src/mccp.c

@@ -36,7 +36,7 @@ void *zlib_alloc( void *opaque, unsigned int items, unsigned int size )
 }
 
 
-void zlib_free( void *opaque, void *address ) 
+void zlib_free( void *opaque, void *address )
 {
 	free(address);
 }

+ 1 - 1
src/memory.c

@@ -423,7 +423,7 @@ char *str_cat_printf(char **str, char *fmt, ...)
 	int len;
 
 	va_start(args, fmt);
-	
+
 	len = vasprintf(&arg, fmt, args);
 
 	va_end(args);

+ 48 - 0
src/misc.c

@@ -26,6 +26,7 @@
 
 #include "tintin.h"
 
+#include "gui.h"
 
 DO_COMMAND(do_bell)
 {
@@ -214,6 +215,53 @@ DO_COMMAND(do_test)
 		return ses;
 	}
 
+	if (!strcmp(arg1, "gui"))
+	{
+		char data[BUFFER_SIZE];
+		FILE *file;
+		size_t len;
+
+		strcpy(data, tt_gui);
+
+		len = strlen(data);
+
+		file = fmemopen(data, len, "r");
+
+		gtd->level->quiet++;
+
+		ses = read_file(ses, file, "tt_gui.h");
+
+		gtd->level->quiet--;
+
+		fclose(file);
+
+		return ses;
+	}
+
+	if (!strcmp(arg1, "regex"))
+	{
+		char data[BUFFER_SIZE];
+		FILE *file;
+		size_t len;
+
+		strcpy(data, tt_regex);
+
+		len = strlen(data);
+
+		file = fmemopen(data, len, "r");
+
+		gtd->level->quiet++;
+
+		ses = read_file(ses, file, "tt_regex.h");
+
+		gtd->level->quiet--;
+
+		fclose(file);
+
+		return ses;
+
+	}
+
 	return ses;
 }
 

+ 6 - 6
src/msdp.c

@@ -277,7 +277,7 @@ void process_msdp_index_val(struct session *ses, struct port_data *buddy, int va
 			msdp_table[var_index].fun(ses, buddy, val_index);
 		}
 	}
-} 
+}
 
 // 1d array support for commands
 
@@ -377,7 +377,7 @@ void process_msdp_varval(struct session *ses, struct port_data *buddy, char *var
 		}
 		return;
 	}
-} 
+}
 
 void msdp_command_list(struct session *ses, struct port_data *buddy, int index)
 {
@@ -462,7 +462,7 @@ void msdp_command_send(struct session *ses, struct port_data *buddy, int index)
 {
 	if (HAS_BIT(buddy->msdp_data[index]->flags, MSDP_FLAG_SENDABLE))
 	{
-		SET_BIT(buddy->msdp_data[index]->flags, MSDP_FLAG_UPDATED);	
+		SET_BIT(buddy->msdp_data[index]->flags, MSDP_FLAG_UPDATED);
 		SET_BIT(buddy->comm_flags, COMM_FLAG_MSDPUPDATE);
 	}
 }
@@ -613,7 +613,7 @@ void msdp_configure_arachnos(struct session *ses, struct port_data *buddy, int i
 				{
 					timeval_t = (time_t) atoll(val);
 					timeval_tm = *localtime(&timeval_t);
-					
+
 					strftime(msg_time, 20, "%T %D", &timeval_tm);
 				}
 				else if (!strcmp(var, "MSG_BODY"))
@@ -624,14 +624,14 @@ void msdp_configure_arachnos(struct session *ses, struct port_data *buddy, int i
 				{
 					timeval_t = (time_t) atoll(val);
 					timeval_tm = *localtime(&timeval_t);
-					
+
 					strftime(mud_uptime, 20, "%T %D", &timeval_tm);
 				}
 				else if (!strcmp(var, "MUD_UPDATE"))
 				{
 					timeval_t = (time_t) atoll(val);
 					timeval_tm = *localtime(&timeval_t);
-					
+
 					strftime(mud_update, 20, "%T %D", &timeval_tm);
 				}
 				else if (!strcmp(var, "MUD_PLAYERS"))

+ 3 - 3
src/nest.c

@@ -137,7 +137,7 @@ struct listnode *search_nest_node_ses(struct session *ses, char *variable)
 	return NULL;
 }
 
-	
+
 struct listnode *search_nest_node(struct listroot *root, char *variable)
 {
 	char name[BUFFER_SIZE], *arg;
@@ -282,7 +282,7 @@ void update_nest_node(struct listroot *root, char *arg)
 		{
 			update_nest_node(update_nest_root(root, arg1), arg2);
 		}
-		else if (*arg1)
+		else //if (*arg1)
 		{
 			update_node_list(root, arg1, arg2, "", "");
 		}
@@ -370,7 +370,7 @@ int delete_nest_node_with_wild(struct listroot *root, char *variable)
 				{
 					show_message(root->ses, LIST_VARIABLE, "#OK. {%s} IS NO LONGER A VARIABLE.", root->list[index]->arg1);
 				}
-				
+
 				delete_index_list(root, index);
 
 				found = TRUE;

+ 3 - 3
src/net.c

@@ -354,7 +354,7 @@ void write_line_mud(struct session *ses, char *line, int size)
 				syserr_printf(ses, "write_line_mud: write");
 			}
 		}
-		
+
 		if (result == -1)
 		{
 			cleanup_session(ses);
@@ -690,7 +690,7 @@ void process_one_line(struct session *ses, char *linebuf, int prompt)
 
 		strip_vt102_codes(linebuf, temp);
 
-		show_debug(ses, LIST_GAG, COLOR_DEBUG "#DEBUG GAG " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} " COLOR_COMMAND "[" COLOR_STRING "%d" COLOR_COMMAND "]", temp, ses->gagline + 1);
+		show_debug(ses, LIST_GAG, NULL, COLOR_DEBUG "#DEBUG GAG " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} " COLOR_COMMAND "[" COLOR_STRING "%d" COLOR_COMMAND "]", temp, ses->gagline + 1);
 
 		pop_call();
 		return;
@@ -714,7 +714,7 @@ void process_one_line(struct session *ses, char *linebuf, int prompt)
 	if (ses == gtd->ses)
 	{
 		char *output = str_alloc_stack(0);
-		
+
 		str_cpy(&output, linebuf);
 
 		print_line(ses, &output, prompt);

+ 30 - 19
src/parse.c

@@ -183,6 +183,7 @@ int is_vowel(char *str)
 struct session *parse_input(struct session *ses, char *input)
 {
 	char *line;
+	struct listnode *node;
 
 	push_call("parse_input(%s,%s)",ses->name,input);
 /*
@@ -200,9 +201,11 @@ struct session *parse_input(struct session *ses, char *input)
 	{
 		sub_arg_all(ses, input, line, 1, SUB_SEC);
 
-		if (check_all_aliases(ses, line))
+		node = check_all_aliases(ses, line);
+
+		if (node)
 		{
-			ses = script_driver(ses, LIST_ALIAS, line);
+			ses = script_driver(ses, LIST_ALIAS, node, line);
 		}
 		else if (HAS_BIT(ses->config_flags, CONFIG_FLAG_SPEEDWALK) && is_speedwalk(ses, line))
 		{
@@ -233,21 +236,25 @@ struct session *parse_input(struct session *ses, char *input)
 
 		if (parse_command(ses, line))
 		{
-			ses = script_driver(ses, LIST_COMMAND, line);
-		}
-		else if (check_all_aliases(ses, line))
-		{
-			ses = script_driver(ses, LIST_ALIAS, line);
-		}
-		else if (HAS_BIT(ses->config_flags, CONFIG_FLAG_SPEEDWALK) && is_speedwalk(ses, line))
-		{
-			process_speedwalk(ses, line);
+			ses = script_driver(ses, LIST_COMMAND, NULL, line);
 		}
 		else
 		{
-			write_mud(ses, line, SUB_VAR|SUB_FUN|SUB_ESC|SUB_EOL);
-		}
+			node = check_all_aliases(ses, line);
 
+			if (node)
+			{
+				ses = script_driver(ses, LIST_ALIAS, node, line);
+			}
+			else if (HAS_BIT(ses->config_flags, CONFIG_FLAG_SPEEDWALK) && is_speedwalk(ses, line))
+			{
+				process_speedwalk(ses, line);
+			}
+			else
+			{
+				write_mud(ses, line, SUB_VAR|SUB_FUN|SUB_ESC|SUB_EOL);
+			}
+		}
 		if (*input == COMMAND_SEPARATOR)
 		{
 			input++;
@@ -452,9 +459,13 @@ struct session *parse_tintin_command(struct session *ses, char *input)
 
 		input = get_arg_in_braces(ses, input, line, GET_ALL);
 
-		while (cnt-- > 0)
+		while (*line)
 		{
-			ses = script_driver(ses, LIST_COMMAND, line);
+			for (int i = cnt ; i > 0 ; i--)
+			{
+				ses = script_driver(ses, LIST_COMMAND, NULL, line);
+			}
+			input = get_arg_in_braces(ses, input, line, GET_ALL);
 		}
 		return ses;
 	}
@@ -469,7 +480,7 @@ struct session *parse_tintin_command(struct session *ses, char *input)
 
 			substitute(ses, line, line, SUB_VAR|SUB_FUN);
 
-			script_driver(sesptr, LIST_COMMAND, line);
+			script_driver(sesptr, LIST_COMMAND, NULL, line);
 
 			return ses;
 		}
@@ -598,7 +609,7 @@ char *get_arg_all(struct session *ses, char *string, char *result, int verbatim)
 			break;
 		}
 	}
-	*pto = '\0'; 
+	*pto = '\0';
 
 	return pti;
 }
@@ -709,7 +720,7 @@ char *sub_arg_in_braces(struct session *ses, char *string, char *result, int fla
 	if (*string == 0)
 	{
 		*result = 0;
-		
+
 		return string;
 	}
 
@@ -775,7 +786,7 @@ char *get_arg_with_spaces(struct session *ses, char *string, char *result, int f
 		}
 		*pto++ = *pti++;
 	}
-	*pto = '\0'; 
+	*pto = '\0';
 
 	return pti;
 }

+ 12 - 13
src/path.c

@@ -546,7 +546,7 @@ DO_PATH(path_run)
 	{
 		if (*arg1)
 		{
-		
+
 			delay = (long long) (get_number(ses, arg1) * 1000000.0);
 			total = 0;
 
@@ -565,7 +565,7 @@ DO_PATH(path_run)
 		{
 			while (root->update < root->used)
 			{
-				script_driver(ses, LIST_COMMAND, root->list[root->update++]->arg1);
+				script_driver(ses, LIST_COMMAND, NULL, root->list[root->update++]->arg1);
 			}
 			check_all_events(ses, EVENT_FLAG_MAP, 0, 0, "END OF RUN");
 		}
@@ -593,7 +593,7 @@ DO_PATH(path_walk)
 		}
 		else
 		{
-			script_driver(ses, LIST_COMMAND, root->list[--root->update]->arg2);
+			script_driver(ses, LIST_COMMAND, NULL, root->list[--root->update]->arg2);
 
 			if (root->update == 0)
 			{
@@ -609,7 +609,7 @@ DO_PATH(path_walk)
 		}
 		else
 		{
-			script_driver(ses, LIST_COMMAND, root->list[root->update++]->arg1);
+			script_driver(ses, LIST_COMMAND, NULL, root->list[root->update++]->arg1);
 
 			if (root->update == root->used)
 			{
@@ -931,7 +931,7 @@ DO_PATH(path_undo)
 	if (root->update != root->used)
 	{
 		show_message(ses, LIST_COMMAND, "#ERROR: #PATH UNDO: YOUR POSITION IS NOT AT END OF PATH.");
-	
+
 		return;
 	}
 
@@ -944,7 +944,7 @@ DO_PATH(path_undo)
 
 	DEL_BIT(ses->flags, SES_FLAG_PATHMAPPING);
 
-	script_driver(ses, LIST_COMMAND, root->list[root->used - 1]->arg2);
+	script_driver(ses, LIST_COMMAND, NULL, root->list[root->used - 1]->arg2);
 
 	SET_BIT(ses->flags, SES_FLAG_PATHMAPPING);
 
@@ -965,7 +965,7 @@ void check_append_path(struct session *ses, char *forward, char *backward, doubl
 	{
 		if ((node = search_node_list(ses->list[LIST_PATHDIR], forward)))
 		{
-			show_debug(ses, LIST_PATHDIR, "#DEBUG PATHDIR {%s} {%s}", node->arg1, node->arg2);
+			show_debug(ses, LIST_PATHDIR, node, "#DEBUG PATHDIR {%s} {%s}", node->arg1, node->arg2);
 
 			create_node_list(root, node->arg1, node->arg2, ftos(delay), "");
 
@@ -973,25 +973,25 @@ void check_append_path(struct session *ses, char *forward, char *backward, doubl
 		}
 		else if (force)
 		{
-			show_debug(ses, LIST_PATHDIR, "#DEBUG PATHDIR {%s} {%s}", forward, backward);
-				
+			show_debug(ses, LIST_PATHDIR, NULL, "#DEBUG PATHDIR {%s} {%s}", forward, backward);
+
 			create_node_list(root, forward, backward, ftos(delay), "");
 
 			root->update = root->used;
 		}
-				
+
 	}
 	else
 	{
 		if ((node = search_node_list(ses->list[LIST_PATHDIR], forward)))
 		{
-			show_debug(ses, LIST_PATHDIR, "#DEBUG PATHDIR {%s} {%s}", node->arg1, node->arg2);
+			show_debug(ses, LIST_PATHDIR, node, "#DEBUG PATHDIR {%s} {%s}", node->arg1, node->arg2);
 
 			create_node_list(root, node->arg1, node->arg2, ftos(delay), "");
 		}
 		else
 		{
-			show_debug(ses, LIST_PATHDIR, "#DEBUG PATHDIR {%s} {%s}", forward, backward);
+			show_debug(ses, LIST_PATHDIR, NULL, "#DEBUG PATHDIR {%s} {%s}", forward, backward);
 
 			create_node_list(root, forward, backward, ftos(delay), "");
 		}
@@ -1166,4 +1166,3 @@ DO_PATH(path_end)
 		show_message(ses, LIST_COMMAND, "#PATH: YOU ARE NOT MAPPING A PATH.");
 	}
 }
-	

+ 11 - 7
src/port.c

@@ -95,7 +95,7 @@ DO_PORT(port_initialize)
 	if (*arg1 == 0 || *arg2 == 0)
 	{
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #PORT INITIALIZE {NAME} {PORT} {FILE}");
-		
+
 		return ses;
 	}
 
@@ -141,7 +141,7 @@ DO_PORT(port_initialize)
 			return ses;
 		}
 
-		ld.l_onoff  = 0; 
+		ld.l_onoff  = 0;
 		ld.l_linger = 100;
 
 		setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *) &ld, sizeof(ld));
@@ -392,6 +392,8 @@ void process_port_connections(struct session *ses, fd_set *read_set, fd_set *wri
 			FD_CLR(buddy->fd, read_set);
 
 			close_port(ses, buddy, TRUE);
+
+			continue;
 		}
 		else if (FD_ISSET(buddy->fd, read_set))
 		{
@@ -401,6 +403,8 @@ void process_port_connections(struct session *ses, fd_set *read_set, fd_set *wri
 				FD_CLR(buddy->fd, read_set);
 
 				close_port(ses, buddy, TRUE);
+
+				continue;
 			}
 		}
 
@@ -693,7 +697,7 @@ DO_PORT(port_call)
 		if (error)
 		{
 			port_printf(ses, "Failed to call %s, unknown host.", host);
-			
+
 			return ses;
 		}
 	}
@@ -1054,7 +1058,7 @@ DO_PORT(port_flag)
 		else
 		{
 			tintin_printf2(ses, "#SYNTAX: #PORT FLAG DND [ON|OFF]");
-			
+
 			return ses;
 		}
 
@@ -1084,7 +1088,7 @@ DO_PORT(port_flag)
 		else
 		{
 			tintin_printf2(ses, "#SYNTAX: #PORT FLAG PRIVATE [ON|OFF]");
-			
+
 			return ses;
 		}
 
@@ -1169,7 +1173,7 @@ DO_PORT(port_ignore)
 	{
 		port_printf(ses, "You are no longer ignoring %s.", buddy->name);
 	}
-	
+
 	return ses;
 }
 
@@ -1281,7 +1285,7 @@ DO_PORT(port_rank)
 	else
 	{
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #PORT RANK <NAME> <SPY|SCOUT>");
-		
+
 		return ses;
 	}
 

+ 6 - 8
src/regex.c

@@ -73,7 +73,7 @@ DO_COMMAND(do_regexp)
 		{
 			substitute(ses, arg3, arg3, SUB_CMD);
 
-			ses = script_driver(ses, LIST_COMMAND, arg3);
+			ses = script_driver(ses, LIST_COMMAND, NULL, arg3);
 		}
 		else
 		{
@@ -83,7 +83,7 @@ DO_COMMAND(do_regexp)
 
 			if (*arg4)
 			{
-				ses = script_driver(ses, LIST_COMMAND, arg4);
+				ses = script_driver(ses, LIST_COMMAND, NULL, arg4);
 			}
 		}
 	}
@@ -212,12 +212,10 @@ pcre *regexp_compile(struct session *ses, char *exp, int comp_option)
 
 int check_one_regexp(struct session *ses, struct listnode *node, char *line, char *original, int comp_option)
 {
-	char *exp, *str;
+	char *exp, *str, result[BUFFER_SIZE];
 
 	if (node->regex == NULL)
 	{
-		char result[BUFFER_SIZE];
-
 		substitute(ses, node->arg1, result, SUB_VAR|SUB_FUN);
 
 		exp = result;
@@ -235,7 +233,7 @@ int check_one_regexp(struct session *ses, struct listnode *node, char *line, cha
 	else
 	{
 		str = line;
-	}	
+	}
 
 	return tintin_regexp(ses, node->regex, str, exp, comp_option, REGEX_FLAG_ARG);
 }
@@ -931,7 +929,7 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 				}
 				{
 					int i = 1;
-	
+
 					while (pti[i] == '$') i++;
 
 					if (pti[i])
@@ -1013,7 +1011,7 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 						pti += 2;
 						pto += sprintf(pto, "%s", *pti == 0 ? "([^\\x20-\\xfe]*)" : "([^\\x20-\\xfe]*?)");
 						break;
-						
+
 					case 's':
 						pti += 2;
 						pto += sprintf(pto, "%s", *pti == 0 ? "(\\s*)" : "(\\s*?)");

+ 224 - 14
src/scan.c

@@ -42,6 +42,7 @@ DO_SCAN(scan_csv);
 DO_SCAN(scan_dir);
 DO_SCAN(scan_file);
 DO_SCAN(scan_forward);
+DO_SCAN(scan_json);
 DO_SCAN(scan_tsv);
 DO_SCAN(scan_txt);
 
@@ -66,6 +67,7 @@ struct scan_type scan_table[] =
 	{       "DIR",              scan_dir,     SCAN_FLAG_NONE,                "Scan a directory to a variable."    },
 	{       "FILE",             scan_file,    SCAN_FLAG_FILE,                "Scan a file all at once."           },
 	{       "FORWARD",          scan_forward, SCAN_FLAG_FILE,                "Scan a file and send each line."    },
+	{       "JSON",             scan_json,    SCAN_FLAG_FILE,                "Scan a json file."                  },
 	{       "TSV",              scan_tsv,     SCAN_FLAG_FILE|SCAN_FLAG_SCAN, "Scan a tab separated value file."   },
 	{       "TXT",              scan_txt,     SCAN_FLAG_FILE|SCAN_FLAG_SCAN, "Scan a text file line by line."     },
 	{       "",                 NULL,         0,                             ""                                   }
@@ -239,7 +241,7 @@ DO_SCAN(scan_csv)
 		}
 		else
 		{
-		
+
 			arg = strchr(line, '\n');
 
 			if (arg)
@@ -347,12 +349,12 @@ DO_SCAN(scan_dir)
 			arg = strchr(arg, '\\');
 		}
 
-		add_nest_node_ses(ses, arg2, "{%s}{{FILE}{%d}{MODE}{%u}{SIZE}{%u}{TIME}{%lld}}",
+		add_nest_node_ses(ses, arg2, "{%s}{{FILE}{%d}{MODE}{%u}{SIZE}{%lld}{TIME}{%lld}}",
 			arg,
 			!S_ISDIR(info.st_mode),
 			info.st_mode,
-			info.st_size,
-			info.st_mtime);
+			(long long) info.st_size,
+			(long long) info.st_mtime);
 
 		return ses;
 	}
@@ -368,12 +370,12 @@ DO_SCAN(scan_dir)
 			continue;
 		}
 
-		add_nest_node_ses(ses, arg2, "{%s}{{FILE}{%d}{MODE}{%u}{SIZE}{%u}{TIME}{%lld}}",
+		add_nest_node_ses(ses, arg2, "{%s}{{FILE}{%d}{MODE}{%u}{SIZE}{%lld}{TIME}{%lld}}",
 			dirlist[index]->d_name,
 			!S_ISDIR(info.st_mode),
 			info.st_mode,
-			info.st_size,
-			info.st_mtime);
+			(long long) info.st_size,
+			(long long) info.st_mtime);
 	}
 
 	for (index = 0 ; index < size ; index++)
@@ -403,24 +405,24 @@ DO_SCAN(scan_file)
 	}
 
 	str_rip = str_alloc_stack(str_len(str_out));
+	str_sub = str_alloc_stack(str_len(str_rip) * 4 + BUFFER_SIZE);
 
 	strip_vt102_codes(str_out, str_rip);
+	substitute(ses, str_rip, str_sub, SUB_SEC);
 
 	RESTRING(gtd->cmds[0], str_out);
-	RESTRING(gtd->cmds[1], str_rip);
+	RESTRING(gtd->cmds[1], str_sub);
 	RESTRING(gtd->cmds[2], ntos(str_len(str_out)));
-	RESTRING(gtd->cmds[3], ntos(strlen(str_rip)));
+	RESTRING(gtd->cmds[3], ntos(strlen(str_sub)));
 	RESTRING(gtd->cmds[4], ntos(cnt));
 
 	gtd->cmdc = 5;
 
-	str_sub = str_alloc_stack(strlen(arg) * 2);
-
 	substitute(ses, arg2, str_sub, SUB_CMD);
 
 	show_message(ses, LIST_COMMAND, "#SCAN FILE: FILE {%s} SCANNED.", arg1);
 
-	ses = script_driver(ses, LIST_COMMAND, str_sub);
+	ses = script_driver(ses, LIST_COMMAND, NULL, str_sub);
 
 	return ses;
 }
@@ -465,6 +467,214 @@ DO_SCAN(scan_forward)
 	return ses;
 }
 
+DO_SCAN(scan_json)
+{
+	char *src, *pto, mod[STRING_SIZE];
+	int i, size, state[100], nest, type;
+
+	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
+
+	if (*arg2 == 0)
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCAN JSON <%s> <VARIABLE>.", arg1);
+
+		return ses;
+	}
+
+	mod[0] = state[0] = nest = type = 0;
+
+	fseek(fp, 0, SEEK_END);
+	size = ftell(fp);
+	fseek(fp, 0, SEEK_SET);
+
+	src = malloc(size + 1);
+
+	fread(src, size, 1, fp);
+
+	src[size] = 0;
+
+	i = 0;
+	pto = mod;
+
+	while (i < size && nest < 99 && nest >= 0)
+	{
+		switch (src[i])
+		{
+			case ' ':
+			case '\t':
+			case '\n':
+			case '\r':
+				i++;
+				break;
+
+			case '{':
+				if (state[nest])
+				{
+					pto += sprintf(pto, "{%d}", state[nest]++);
+				}
+				if (nest != 0)
+				{
+					*pto++ = '{';
+				}
+				i++;
+				state[++nest] = 0;
+				break;
+
+			case '}':
+				nest--;
+				i++;
+				if (nest != 0)
+				{
+					*pto++ = '}';
+				}
+				break;
+
+			case '[':
+				if (nest != 0)
+				{
+					*pto++ = '{';
+				}
+				i++;
+				state[++nest] = 1;
+//				pto += sprintf(pto, "{%d}", state[nest]);
+				break;
+
+			case ']':
+				nest--;
+				i++;
+				if (nest != 0)
+				{
+					*pto++ = '}';
+				}
+				break;
+
+			case ':':
+				i++;
+				break;
+
+			case ',':
+				i++;
+				break;
+
+			case '"':
+				i++;
+				if (state[nest])
+				{
+					pto += sprintf(pto, "{%d}", state[nest]++);
+				}
+				if (nest)
+				{
+					*pto++ = '{';
+				}
+				type = 1;
+
+				while (i < size && type == 1)
+				{
+					switch (src[i])
+					{
+						case '\\':
+							i++;
+
+							if (i < size && src[i] == '"')
+							{
+								*pto++ = src[i++];
+							}
+							else
+							{
+								*pto++ = '\\';
+							}
+							break;
+
+						case '"':
+							i++;
+							type = 0;
+							break;
+
+						case '{':
+							i++;
+							*pto++ = '\\';
+							*pto++ = 'x';
+							*pto++ = '7';
+							*pto++ = 'B';
+							break;
+
+						case '}':
+							i++;
+							*pto++ = '\\';
+							*pto++ = 'x';
+							*pto++ = '7';
+							*pto++ = 'D';
+							break;
+
+						case COMMAND_SEPARATOR:
+							i++;
+							*pto++ = '\\';
+							*pto++ = COMMAND_SEPARATOR;
+							break;
+
+						default:
+							*pto++ = src[i++];
+							break;
+					}
+				}
+
+				if (nest)
+				{
+					*pto++ = '}';
+				}
+				break;
+
+			default:
+				if (state[nest])
+				{
+					pto += sprintf(pto, "{%d}", state[nest]++);
+				}
+				if (nest)
+				{
+					*pto++ = '{';
+				}
+
+				type = 1;
+
+				while (i < size && type == 1)
+				{
+					switch (src[i])
+					{
+						case '}':
+						case ']':
+						case ',':
+						case ':':
+							type = 0;
+							break;
+
+						case ' ':
+							i++;
+							break;
+
+						default:
+							*pto++ = src[i++];
+							break;
+					}
+				}
+
+				if (nest)
+				{
+					*pto++ = '}';
+				}
+				break;
+		}
+	}
+	*pto = 0;
+
+	free(src);
+
+	show_message(ses, LIST_COMMAND, "#SCAN JSON: FILE {%s} SCANNED AND SAVED TO VARIABLE {%s}.", arg1, arg2);
+
+	add_nest_node_ses(ses, arg2, mod);
+
+	return ses;
+}
+
 /* support routines for tab separated value files */
 
 char *get_arg_stop_tabs(struct session *ses, char *string, char *result, int flag)
@@ -505,7 +715,7 @@ DO_SCAN(scan_tsv)
 		}
 		else
 		{
-		
+
 			arg = strchr(line, '\n');
 
 			if (arg)
@@ -581,7 +791,7 @@ DO_SCAN(scan_txt)
 		}
 		else
 		{
-		
+
 			arg = strchr(line, '\n');
 
 			if (arg)

+ 8 - 8
src/screen.c

@@ -377,7 +377,7 @@ DO_SCREEN(screen_cursor)
 	else
 	{
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN {CURSOR} {HIDE|SHOW|BLINK|STEADY}");
-	}	
+	}
 }
 
 DO_SCREEN(screen_clear)
@@ -483,9 +483,9 @@ DO_SCREEN(screen_fill)
 			command(ses, do_screen, "CLEAR SPLIT");
 		}
 
-		if (ses->split->sav_top_row > 0)
+		if (ses->split->top_row > 1)
 		{
-			if (ses->split->sav_top_row == 1)
+			if (ses->split->top_row == 2)
 			{
 				command(ses, do_draw, "%s LINE %d %d %d %d", arg2, 1, 1, ses->split->top_row - 1, gtd->screen->cols);
 			}
@@ -499,9 +499,9 @@ DO_SCREEN(screen_fill)
 
 		if (ses->split->sav_bot_row)
 		{
-			if (ses->split->sav_bot_row - inputline_max_row() >= 0)
+			if (ses->split->bot_row + inputline_max_row() < gtd->screen->rows)
 			{
-				if (ses->split->sav_bot_row - inputline_max_row() == 0)
+				if (ses->split->bot_row + inputline_max_row() == gtd->screen->rows - 1)
 				{
 					command(ses, do_draw, "%s LINE %d %d %d %d", arg2, ses->split->bot_row + 1, 1, gtd->screen->rows - inputline_max_row(), gtd->screen->cols);
 				}
@@ -539,7 +539,7 @@ DO_SCREEN(screen_fill)
 				{
 					if (ses->split->sav_top_row > 1)
 					{
-						command(ses, do_draw, "%s HORIZONTAL TEED TOP RIGHT CORNER %d %d %d %d", arg2, ses->split->top_row - 1, ses->split->bot_col + 1, ses->split->bot_row + 1, ses->split->bot_col + 1);						
+						command(ses, do_draw, "%s HORIZONTAL TEED TOP RIGHT CORNER %d %d %d %d", arg2, ses->split->top_row - 1, ses->split->bot_col + 1, ses->split->bot_row + 1, ses->split->bot_col + 1);
 					}
 					if (ses->split->sav_bot_row > 1)
 					{
@@ -618,7 +618,7 @@ DO_SCREEN(screen_get)
 	{
 		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} {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>");
@@ -1712,7 +1712,7 @@ DO_SCREEN(screen_info)
 		set_nest_node_ses(ses, arg2, "{SCROLLMODE}{%d}", HAS_BIT(gtd->screen->flags, SCREEN_FLAG_SCROLLMODE));
 
 		show_message(ses, LIST_COMMAND, "#INFO: DATA WRITTEN TO {info[SCREEN]}");
-		
+
 		return;
 	}
 	if (*arg1)

+ 8 - 3
src/session.c

@@ -43,7 +43,7 @@ DO_COMMAND(do_all)
 
 			if (!HAS_BIT(sesptr->flags, SES_FLAG_CLOSED))
 			{
-				script_driver(sesptr, LIST_COMMAND, arg1);
+				script_driver(sesptr, LIST_COMMAND, NULL, arg1);
 			}
 		}
 	}
@@ -161,7 +161,7 @@ DO_COMMAND(do_snoop)
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
-	
+
 	if (*arg1)
 	{
 		sesptr = find_session(arg1);
@@ -169,7 +169,7 @@ DO_COMMAND(do_snoop)
 		if (sesptr == NULL)
 		{
 			show_error(ses, LIST_COMMAND, "#SNOOP: THERE'S NO SESSION NAMED {%s}.", arg1);
-			
+
 			return ses;
 		}
 	}
@@ -775,6 +775,11 @@ void dispose_session(struct session *ses)
 		delete_map(ses);
 	}
 
+	for (index = 0 ; index < LIST_MAX ; index++)
+	{
+		kill_list(ses->list[index]);
+	}
+
 	for (index = 0 ; index < LIST_MAX ; index++)
 	{
 		free_list(ses->list[index]);

+ 11 - 8
src/show.c

@@ -61,7 +61,7 @@ DO_COMMAND(do_showme)
 	{
 		ses->gagline--;
 
-		show_debug(ses, LIST_GAG, COLOR_DEBUG "#DEBUG GAG " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} " COLOR_COMMAND "[" COLOR_STRING "%d" COLOR_COMMAND "]", arg1, ses->gagline + 1);
+		show_debug(ses, LIST_GAG, NULL, COLOR_DEBUG "#DEBUG GAG " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} " COLOR_COMMAND "[" COLOR_STRING "%d" COLOR_COMMAND "]", arg1, ses->gagline + 1);
 
 		return ses;
 	}
@@ -272,7 +272,7 @@ void show_error(struct session *ses, int index, char *format, ...)
 	return;
 }
 
-void show_debug(struct session *ses, int index, char *format, ...)
+void show_debug(struct session *ses, int index, struct listnode *node, char *format, ...)
 {
 	struct listroot *root;
 	char *buffer;
@@ -282,10 +282,13 @@ void show_debug(struct session *ses, int index, char *format, ...)
 
 	root = ses->list[index];
 
-	if (gtd->level->debug == 0 && !HAS_BIT(root->flags, LIST_FLAG_DEBUG) && !HAS_BIT(root->flags, LIST_FLAG_LOG))
+	if (node == NULL || !HAS_BIT(node->flags, NODE_FLAG_DEBUG))
 	{
-		pop_call();
-		return;
+		if (gtd->level->debug == 0 && !HAS_BIT(root->flags, LIST_FLAG_DEBUG) && !HAS_BIT(root->flags, LIST_FLAG_LOG))
+		{
+			pop_call();
+			return;
+		}
 	}
 
 	if (HAS_BIT(gtd->event_flags, EVENT_FLAG_REFORMAT) && check_all_events(ses, EVENT_FLAG_REFORMAT, 1, 0, "REFORMAT %s", format))
@@ -303,7 +306,7 @@ void show_debug(struct session *ses, int index, char *format, ...)
 	}
 	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) || (node != NULL && HAS_BIT(node->flags, NODE_FLAG_DEBUG)))
 	{
 		gtd->level->verbose++;
 
@@ -322,7 +325,7 @@ void show_debug(struct session *ses, int index, char *format, ...)
 		}
 	}
 	end:
-	
+
 	free(buffer);
 
 	pop_call();
@@ -589,7 +592,7 @@ void tintin_puts(struct session *ses, char *string)
 
 		gtd->level->ignore++;
 
-		show_debug(ses, LIST_GAG, COLOR_DEBUG "#DEBUG GAG " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} " COLOR_COMMAND "[" COLOR_STRING "%d" COLOR_COMMAND "]", string, ses->gagline + 1);
+		show_debug(ses, LIST_GAG, NULL, COLOR_DEBUG "#DEBUG GAG " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} " COLOR_COMMAND "[" COLOR_STRING "%d" COLOR_COMMAND "]", string, ses->gagline + 1);
 
 		gtd->level->ignore--;
 	}

+ 6 - 6
src/sort.c

@@ -218,7 +218,7 @@ void quad_swap32(int *array, int *swap, size_t nmemb, CMPFUNC *cmp)
 
 				pta -= 8;
 
-				*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; 
+				*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++;
 
 				pta += 8;
 
@@ -226,7 +226,7 @@ void quad_swap32(int *array, int *swap, size_t nmemb, CMPFUNC *cmp)
 
 				pta -= 8;
 
-				*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; 
+				*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++;
 
 				pta += 4;
 
@@ -238,7 +238,7 @@ void quad_swap32(int *array, int *swap, size_t nmemb, CMPFUNC *cmp)
 
 			pta -= 8;
 
-			*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; 
+			*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++;
 
 			pta += 4;
 		}
@@ -562,7 +562,7 @@ void quad_swap64(long long *array, long long *swap, size_t nmemb, CMPFUNC *cmp)
 
 				pta -= 8;
 
-				*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; 
+				*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++;
 
 				pta += 8;
 
@@ -570,7 +570,7 @@ void quad_swap64(long long *array, long long *swap, size_t nmemb, CMPFUNC *cmp)
 
 				pta -= 8;
 
-				*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; 
+				*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++;
 
 				pta += 4;
 
@@ -582,7 +582,7 @@ void quad_swap64(long long *array, long long *swap, size_t nmemb, CMPFUNC *cmp)
 
 			pta -= 8;
 
-			*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; 
+			*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++;
 
 			pta += 4;
 		}

+ 4 - 4
src/split.c

@@ -68,7 +68,7 @@ DO_COMMAND(do_split)
 	if (*arg)
 	{
 		arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
-		
+
 		input = get_number(ses, arg1);
 
 		input *= -1;
@@ -331,8 +331,8 @@ void split_show(struct session *ses, char *prompt, char *row_str, char *col_str)
 	{
 		snprintf(buf1, BUFFER_SIZE, "%.*s", raw_len_str(ses, prompt, 0, gtd->screen->cols - col), prompt);
 
-		show_debug(ses, LIST_PROMPT, "#DEBUG PROMPT {%s}", prompt);
-		show_debug(ses, LIST_PROMPT, "#PROMPT WIDTH %d WITH OFFSET %d LONGER THAN ROW SIZE %d.", width, col, gtd->screen->cols);
+		show_debug(ses, LIST_PROMPT, NULL, "#DEBUG PROMPT {%s}", prompt);
+		show_debug(ses, LIST_PROMPT, NULL, "#PROMPT WIDTH %d WITH OFFSET %d LONGER THAN ROW SIZE %d.", width, col, gtd->screen->cols);
 	}
 
 	save_pos(ses);
@@ -358,7 +358,7 @@ void split_show(struct session *ses, char *prompt, char *row_str, char *col_str)
 		{
 			erase_cols(gtd->screen->cols);
 		}
-	
+
 		print_stdout(0, 0, "%s", buf1);
 	}
 

+ 16 - 12
src/ssl.c

@@ -59,7 +59,7 @@ gnutls_session_t ssl_negotiate(struct session *ses)
 	gnutls_session_t ssl_ses;
 
 	int ret;
-	
+
 	if (!ssl_cred)
 	{
 		gnutls_global_init();
@@ -72,7 +72,7 @@ gnutls_session_t ssl_negotiate(struct session *ses)
 	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
 	{
 		ret = gnutls_handshake(ssl_ses);
 	}
@@ -137,7 +137,7 @@ static void load_cert(struct session *ses, gnutls_x509_crt_t *cert)
 	char cert_file[STRING_SIZE];
 	FILE *fp;
 	gnutls_datum_t bptr;
-	
+
 	if (!get_cert_file(ses, cert_file))
 	{
 		return;
@@ -152,7 +152,7 @@ static void load_cert(struct session *ses, gnutls_x509_crt_t *cert)
 	bptr.data = (unsigned char *) cert_file;
 
 	fclose(fp);
-	
+
 	gnutls_x509_crt_init(cert);
 
 	if (gnutls_x509_crt_import(*cert, &bptr, GNUTLS_X509_FMT_PEM))
@@ -168,7 +168,7 @@ static void save_cert(struct session *ses, gnutls_x509_crt_t cert, int new)
 	char filename[BUFFER_SIZE], buf[STRING_SIZE];
 	FILE *fp;
 	size_t len;
-	
+
 	len = STRING_SIZE;
 
 	if (gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_PEM, buf, &len))
@@ -233,7 +233,7 @@ static int diff_certs(gnutls_x509_crt_t c1, gnutls_x509_crt_t c2)
 {
 	char buf1[STRING_SIZE], buf2[STRING_SIZE];
 	size_t len1, len2;
-	
+
 	len1 = len2 = STRING_SIZE;
 
 	if (gnutls_x509_crt_export(c1, GNUTLS_X509_FMT_DER, buf1, &len1))
@@ -262,7 +262,7 @@ static int ssl_check_cert(struct session *ses, gnutls_session_t ssl_ses)
 	gnutls_x509_crt_t cert, oldcert;
 	const gnutls_datum_t *cert_list;
 	unsigned int cert_list_size;
-	char *err = 0;
+	char *err = NULL;
 
 	oldcert = 0;
 
@@ -273,13 +273,13 @@ static int ssl_check_cert(struct session *ses, gnutls_session_t ssl_ses)
 		err = "#SSL: SERVER DOES NOT USE x509 -> NO KEY RETENTION.";
 		goto nocert;
 	}
-	
+
 	if ((cert_list = gnutls_certificate_get_peers(ssl_ses, &cert_list_size)) == NULL)
 	{
 		err = "#SSL: SERVER HAS NO x509 CERTIFICATE -> NO KEY RETENTION.";
 		goto nocert;
 	}
-	
+
 	gnutls_x509_crt_init(&cert);
 
 	if (gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0)
@@ -296,7 +296,7 @@ static int ssl_check_cert(struct session *ses, gnutls_session_t ssl_ses)
 
 		err = buf2;
 	}
-	
+
 	if (gnutls_x509_crt_get_expiration_time(cert) < t)
 	{
 		sprintf(buf2, "CERTIFICATE HAS EXPIRED (%s)", str_time(ses, "%c", gnutls_x509_crt_get_expiration_time(cert)));
@@ -316,7 +316,11 @@ static int ssl_check_cert(struct session *ses, gnutls_session_t ssl_ses)
 		{
 			if (err)
 			{
-				sprintf(buf2, "CERTIFICATE MISMATCH, AND NEW %s", err);
+				char temp[BUFFER_SIZE];
+
+				snprintf(temp, BUFFER_SIZE - 1, "CERTIFICATE MISMATCH, AND NEW %s", err);
+
+				strcpy(buf2, temp);
 			}
 			else
 			{
@@ -351,7 +355,7 @@ static int ssl_check_cert(struct session *ses, gnutls_session_t ssl_ses)
 
 badcert:
 	gnutls_x509_crt_deinit(cert);
-	
+
 nocert:
 	if (oldcert)
 	{

+ 3 - 3
src/string.c

@@ -169,7 +169,7 @@ int raw_len_str(struct session *ses, char *str, int start, int end)
 			continue;
 		}
 		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&str[raw_cnt]))
-		{ 
+		{
 			tmp_cnt = get_utf8_width(&str[raw_cnt], &width, NULL);
 
 			if (str_cnt >= start)
@@ -228,7 +228,7 @@ int raw_len_str_min(struct session *ses, char *str, int start, int end)
 			continue;
 		}
 		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&str[raw_cnt]))
-		{    
+		{
 			tmp_cnt = get_utf8_width(&str[raw_cnt], &width, NULL);
 
 			if (str_cnt >= start)
@@ -287,7 +287,7 @@ int raw_len_str_opt(struct session *ses, char *str, int start, int end)
 		}
 
 		if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&str[raw_cnt]))
-		{    
+		{
 			tmp_cnt = get_utf8_width(&str[raw_cnt], &width, NULL);
 
 			if (str_cnt >= start)

+ 7 - 7
src/substitute.c

@@ -937,7 +937,7 @@ int color_gradient(char *pti, int min, int max)
 						}
 						lvl++;
 					}
-					
+
 					if (buf[1] > 'a' && pti[6] < buf[1])
 					{
 						buf[1]--;
@@ -1004,7 +1004,7 @@ int color_gradient(char *pti, int min, int max)
 						}
 						lvl++;
 					}
-					
+
 					if (pti[6] < buf[1])
 					{
 						buf[1]--;
@@ -1193,7 +1193,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 					{
 						substitute(ses, temp, buf, flags_neol);
 					}
-					show_debug(ses, LIST_FUNCTION, COLOR_DEBUG "#DEBUG FUNCTION " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
+					show_debug(ses, LIST_FUNCTION, node, COLOR_DEBUG "#DEBUG FUNCTION " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
 
 					RESTRING(gtd->vars[0], buf);
 
@@ -1228,7 +1228,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 						delete_node_list(ses, LIST_FUNCTION, node);
 					}
 
-					script_driver(ses, LIST_FUNCTION, buf);
+					script_driver(ses, LIST_FUNCTION, node, buf);
 
 					node = search_nest_node_ses(ses, "result");
 
@@ -1823,7 +1823,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 						else if (pti[1] >= 'a' && pti[1] <= 'f' && pti[2] >= 'a' && pti[2] <= 'f' && pti[3] >= 'a' && pti[3] <= 'f' && pti[4] == '>')
 						{
 							cnt = 16 + (pti[1] - 'a') * 36 + (pti[2] - 'a') * 6 + (pti[3] - 'a');
-							
+
 							if (ses->color >= 256)
 							{
 								pto += sprintf(pto, "\e[22;38;5;%dm", cnt);
@@ -2234,7 +2234,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 				{
 					*pto++ = *pti++;
 				}
-				break;	
+				break;
 
 			default:
 				*pto++ = *pti++;
@@ -2516,7 +2516,7 @@ int get_color_names(struct session *ses, char *string, char *result)
 				result += substitute(ses, result, result, SUB_COL);
 
 				continue;
-			
+
 			case '\\':
 				skip = find_escaped_color_code(string);
 

+ 12 - 6
src/system.c

@@ -33,7 +33,7 @@
 #include <util.h>
 #endif
 #endif
-#include <fcntl.h>  
+#include <fcntl.h>
 #include <dirent.h>
 #include <termios.h>
 #include <sys/un.h>
@@ -55,7 +55,7 @@ DO_COMMAND(do_run)
 	if (*arg1 == 0 || *arg2 == 0)
 	{
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #RUN <NAME> <SHELL COMMAND>");
-		
+
 		return ses;
 	}
 
@@ -121,7 +121,7 @@ DO_COMMAND(do_script)
 					*cptr = 0;
 				}
 
-				ses = script_driver(ses, LIST_COMMAND, buf);
+				ses = script_driver(ses, LIST_COMMAND, NULL, buf);
 			}
 
 			pclose(script);
@@ -170,6 +170,12 @@ DO_COMMAND(do_script)
 
 DO_COMMAND(do_suspend)
 {
+	if (!strcmp(gtd->system->os, "WINTIN++"))
+	{
+		show_error(gtd->ses, LIST_COMMAND, "#ERROR: #SUSPEND / ctrl-z is not supported for WinTin++.");
+
+		return ses;
+	}
 	print_stdout(0, 0, "\e[?1049l\e[r\e[%d;%dH", gtd->screen->rows, 1);
 
 	fflush(NULL);
@@ -203,7 +209,7 @@ DO_COMMAND(do_system)
 	if (*arg1 == 0)
 	{
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #SYSTEM {SHELL COMMAND}");
-		
+
 		return ses;
 	}
 
@@ -281,7 +287,7 @@ DO_COMMAND(do_system)
 	if (*arg1 == 0)
 	{
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #SYSTEM <COMMAND>");
-		
+
 		return ses;
 	}
 
@@ -321,7 +327,7 @@ DO_COMMAND(do_textin)
 	if ((fp = fopen(arg1, "r")) == NULL)
 	{
 		show_error(ses, LIST_COMMAND, "#ERROR: #TEXTIN {%s}: FILE NOT FOUND.", arg1);
-		
+
 		return ses;
 	}
 

+ 33 - 30
src/tables.c

@@ -213,7 +213,7 @@ char character_table[256] =
 	CHAR_FLAG_PRINT|CHAR_FLAG_VAR|CHAR_FLAG_CSI|CHAR_FLAG_ALPHA,
 
 	CHAR_FLAG_PRINT|CHAR_FLAG_VAR|CHAR_FLAG_CSI|CHAR_FLAG_ALPHA, // 104 h
-	CHAR_FLAG_PRINT|CHAR_FLAG_VAR|CHAR_FLAG_CSI|CHAR_FLAG_ALPHA, 
+	CHAR_FLAG_PRINT|CHAR_FLAG_VAR|CHAR_FLAG_CSI|CHAR_FLAG_ALPHA,
 	CHAR_FLAG_PRINT|CHAR_FLAG_VAR|CHAR_FLAG_CSI|CHAR_FLAG_ALPHA,
 	CHAR_FLAG_PRINT|CHAR_FLAG_VAR|CHAR_FLAG_CSI|CHAR_FLAG_ALPHA,
 	CHAR_FLAG_PRINT|CHAR_FLAG_VAR|CHAR_FLAG_CSI|CHAR_FLAG_ALPHA,
@@ -384,7 +384,7 @@ char character_table[256] =
 	CHAR_FLAG_PRINT
 };
 
-	
+
 struct color_type color_table[] =
 {
 	{    "azure",         "<abd>",  5 },
@@ -693,8 +693,8 @@ struct cursor_type cursor_table[] =
 	{     "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,               ""          },
 	{     "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 FORWARD",    "",                                               "\t",          CURSOR_FLAG_GET_ALL,     cursor_tab,                   "L S F"     },
+	{     "TAB L S BACKWARD",   "",                                               "\e[Z",        CURSOR_FLAG_GET_ALL,     cursor_tab,                   "L I S B"   }, // shift tab
+	{     "TAB L S FORWARD",    "",                                               "\t",          CURSOR_FLAG_GET_ALL,     cursor_tab,                   "L I S F"   },
 	{     "UP",                 "Move cursor up",                                 "\e[A",        CURSOR_FLAG_GET_ALL,     cursor_move_up,               ""          },
 	{     "",                   "",                                               "\e[6~",                          0,    cursor_buffer_down,           ""          },
 	{     "",                   "",                                               "\e[1;5F",                        0,    cursor_buffer_end,            ""          },
@@ -770,7 +770,7 @@ struct timer_type timer_table[] =
 
 struct event_type event_table[] =
 {
-	{    "BUFFER UPDATE",                          0, EVENT_FLAG_UPDATE,   "UPDATE",    "scrollback buffer update"   },	
+	{    "BUFFER UPDATE",                          0, EVENT_FLAG_UPDATE,   "UPDATE",    "scrollback buffer update"   },
 	{    "CATCH ",                                 0, EVENT_FLAG_CATCH,    "CATCH",     "prefix for catch events"    },
 	{    "CHAT MESSAGE",                           0, EVENT_FLAG_PORT,     "PORT",      "any chat related message"   },
 	{    "CLASS ACTIVATED",                        0, EVENT_FLAG_CLASS,    "CLASS",     "class activations"          },
@@ -786,7 +786,9 @@ struct event_type event_table[] =
 	{    "DISPLAY UPDATE",                         0, EVENT_FLAG_UPDATE,   "UPDATE",    "when display is updated"    },
 	{    "DOUBLE-CLICKED ",                        0, EVENT_FLAG_MOUSE,    "MOUSE",     "mouse is double-clicked"    },
 	{    "EDIT FINISHED",                          0, EVENT_FLAG_INPUT,    "INPUT",     "when editing is finished"   },
+	{    "EDIT RESUMED",                           0, EVENT_FLAG_INPUT,    "INPUT",     "when editing is resumed"    },
 	{    "EDIT STARTED",                           0, EVENT_FLAG_INPUT,    "INPUT",     "when editing is started"    },
+	{    "EDIT SUSPENDED",                         0, EVENT_FLAG_INPUT,    "INPUT",     "when editing is suspended"  },
 	{    "END OF PATH",                            0, EVENT_FLAG_MAP,      "MAP",       "walking the last room"      },
 	{    "END OF RUN",                             0, EVENT_FLAG_MAP,      "MAP",       "running the last room"      },
 	{    "GAG ",                                   0, EVENT_FLAG_GAG,      "GAG",       "prefix for gag events"      },
@@ -806,7 +808,7 @@ struct event_type event_table[] =
 	{    "MAP FOLLOW MAP",                         0, EVENT_FLAG_MAP,      "MAP",       "moving to a map room"       },
 	{    "MAP LOCATION",                           0, EVENT_FLAG_MOUSE,    "MOUSE",     "vt map click"               },
 	{    "MAP LONG-CLICKED ",                      0, EVENT_FLAG_MOUSE,    "MOUSE",     "vt map click"               },
-	{    "MAP MOUSE LOCATION",                     0, EVENT_FLAG_MOUSE,    "MOUSE",     "called by #screen raise"    }, 
+	{    "MAP MOUSE LOCATION",                     0, EVENT_FLAG_MOUSE,    "MOUSE",     "called by #screen raise"    },
 	{    "MAP MOVED ",                             0, EVENT_FLAG_MOUSE,    "MOUSE",     "vt map mouse move"          },
 	{    "MAP PRESSED ",                           0, EVENT_FLAG_MOUSE,    "MOUSE",     "vt map click"               },
 	{    "MAP REGION ",                            0, EVENT_FLAG_MOUSE,    "MOUSE",     "vt map mouse events"        },
@@ -817,6 +819,7 @@ struct event_type event_table[] =
 	{    "MAP TRIPLE-CLICKED ",                    0, EVENT_FLAG_MOUSE,    "MOUSE",     "vt map click"               },
 	{    "MAP UPDATED VTMAP",                      0, EVENT_FLAG_MAP,      "MAP",       "vt map update"              },
 	{    "MINUTE",                                 0, EVENT_FLAG_TIME,     "TIME",      "minute or given minute"     },
+	{    "MODIFIED INPUT",                         0, EVENT_FLAG_INPUT,    "INPUT",     "input line was modified"    },
 	{    "MONTH",                                  0, EVENT_FLAG_TIME,     "TIME",      "month or given month"       },
 	{    "MOVED ",                                 0, EVENT_FLAG_MOUSE,    "MOUSE",     "mouse is moved"             },
 	{    "NO SESSION ACTIVE",                      0, EVENT_FLAG_INPUT,    "INPUT",     "input on startup session"   },
@@ -1439,31 +1442,31 @@ struct map_legend_type map_legend_table[] =
 
         { "NO DIAGONAL",        "UNICODE GRAPHICS",     "2x5",  "2x5"   },
 	{ "SE",                 "UNICODE GRAPHICS",     "⸌",    "2x5"   },
-	{ "NE",                 "UNICODE GRAPHICS",     "⸝",    "2x5"   }, 
-	{ "SE NE",              "UNICODE GRAPHICS",     ">",    "2x5"   }, 
-	{ "SW",                 "UNICODE GRAPHICS",     "⸍",    "2x5"   }, 
-	{ "SE SW",              "UNICODE GRAPHICS",     "⸌⸍",   "2x5"   }, 
-	{ "NE SW",              "UNICODE GRAPHICS",     "/",   "2x5"   }, 
-	{ "SE NE SW",           "UNICODE GRAPHICS",     ">⸍",   "2x5"   }, 
-	{ "NW",                 "UNICODE GRAPHICS",     "⸜",    "2x5"   }, 
-	{ "SE NW",              "UNICODE GRAPHICS",     "\",   "2x5"   }, 
-	{ "NE NW",              "UNICODE GRAPHICS",     "⸝⸜",   "2x5"   }, 
-	{ "SE NE NW",           "UNICODE GRAPHICS",     ">⸜",   "2x5"   }, 
+	{ "NE",                 "UNICODE GRAPHICS",     "⸝",    "2x5"   },
+	{ "SE NE",              "UNICODE GRAPHICS",     ">",    "2x5"   },
+	{ "SW",                 "UNICODE GRAPHICS",     "⸍",    "2x5"   },
+	{ "SE SW",              "UNICODE GRAPHICS",     "⸌⸍",   "2x5"   },
+	{ "NE SW",              "UNICODE GRAPHICS",     "/",   "2x5"   },
+	{ "SE NE SW",           "UNICODE GRAPHICS",     ">⸍",   "2x5"   },
+	{ "NW",                 "UNICODE GRAPHICS",     "⸜",    "2x5"   },
+	{ "SE NW",              "UNICODE GRAPHICS",     "\",   "2x5"   },
+	{ "NE NW",              "UNICODE GRAPHICS",     "⸝⸜",   "2x5"   },
+	{ "SE NE NW",           "UNICODE GRAPHICS",     ">⸜",   "2x5"   },
 	{ "SW NW",              "UNICODE GRAPHICS",     "<",    "2x5"   },
-	{ "SE SW NW",           "UNICODE GRAPHICS",     "⸌<",   "2x5"   }, 
-	{ "NE SW NW",           "UNICODE GRAPHICS",     "⸝<",   "2x5"   }, 
-	{ "SE NE SW NW",        "UNICODE GRAPHICS",     "><",   "2x5"   }, 
-	{ "D",                  "UNICODE GRAPHICS",     "-",    "2x5"   }, 
-	{ "N",                  "UNICODE GRAPHICS",     "↑",    "2x5"   }, 
-	{ "S",                  "UNICODE GRAPHICS",     "↓",    "2x5"   }, 
-	{ "N S",                "UNICODE GRAPHICS",     "│",    "2x5"   }, 
-	{ "U",                  "UNICODE GRAPHICS",     "+",    "2x5"   }, 
-	{ "E",                  "UNICODE GRAPHICS",     "🠆",    "2x5"   }, 
-	{ "W",                  "UNICODE GRAPHICS",     "🠄",    "2x5"   }, 
-	{ "E W",                "UNICODE GRAPHICS",     "─",    "2x5"   }, 
-	{ "ROOM L",             "UNICODE GRAPHICS",     "[",    "2x5"   }, 
-	{ "ROOM L CURVED",      "UNICODE GRAPHICS",     "(",    "2x5"   }, 
-	{ "ROOM R",             "UNICODE GRAPHICS",     "]",    "2x5"   }, 
+	{ "SE SW NW",           "UNICODE GRAPHICS",     "⸌<",   "2x5"   },
+	{ "NE SW NW",           "UNICODE GRAPHICS",     "⸝<",   "2x5"   },
+	{ "SE NE SW NW",        "UNICODE GRAPHICS",     "><",   "2x5"   },
+	{ "D",                  "UNICODE GRAPHICS",     "-",    "2x5"   },
+	{ "N",                  "UNICODE GRAPHICS",     "↑",    "2x5"   },
+	{ "S",                  "UNICODE GRAPHICS",     "↓",    "2x5"   },
+	{ "N S",                "UNICODE GRAPHICS",     "│",    "2x5"   },
+	{ "U",                  "UNICODE GRAPHICS",     "+",    "2x5"   },
+	{ "E",                  "UNICODE GRAPHICS",     "🠆",    "2x5"   },
+	{ "W",                  "UNICODE GRAPHICS",     "🠄",    "2x5"   },
+	{ "E W",                "UNICODE GRAPHICS",     "─",    "2x5"   },
+	{ "ROOM L",             "UNICODE GRAPHICS",     "[",    "2x5"   },
+	{ "ROOM L CURVED",      "UNICODE GRAPHICS",     "(",    "2x5"   },
+	{ "ROOM R",             "UNICODE GRAPHICS",     "]",    "2x5"   },
 	{ "ROOM R CURVED",      "UNICODE GRAPHICS",     ")",    "2x5"   },
 
 	{ NULL,			NULL,			NULL,	NULL	}

+ 7 - 7
src/telopt_client.c

@@ -125,7 +125,7 @@ int client_translate_telopts(struct session *ses, unsigned char *src, int cplen)
 
 	if (cplen == 0)
 	{
-		gtd->mud_output_buf[gtd->mud_output_len] = 0;	
+		gtd->mud_output_buf[gtd->mud_output_len] = 0;
 
 		pop_call();
 		return 0;
@@ -251,13 +251,13 @@ int client_translate_telopts(struct session *ses, unsigned char *src, int cplen)
 			{
 				switch(cpsrc[1])
 				{
-					case NOP:   
+					case NOP:
 					case DM:
-					case BREAK: 
-					case IP:    
-					case AO:    
-					case AYT:   
-					case EC:    
+					case BREAK:
+					case IP:
+					case AO:
+					case AYT:
+					case EC:
 					case EL:
 					case IAC:
 					case GA:

+ 1 - 1
src/telopt_server.c

@@ -560,7 +560,7 @@ int process_sb_ttype_is(struct session *ses, struct port_data *buddy, unsigned c
 	{
 		switch (src[i])
 		{
-			default:			
+			default:
 				*pto++ = src[i];
 				break;
 

+ 1 - 1
src/terminal.c

@@ -94,7 +94,7 @@ void reset_terminal(struct session *ses)
 	{
 		return;
 	}
-	
+
 	if (gtd->detach_port == 0)
 	{
 		if (tcsetattr(0, TCSANOW, &gtd->old_terminal))

+ 9 - 6
src/tintin.h

@@ -26,7 +26,7 @@
 *                       modified by Bill Reiss 1993                           *
 *                    recoded by Igor van den Hoven 2004                       *
 ******************************************************************************/
-	
+
 #include <stdio.h>
 #include <zlib.h>
 #include <ctype.h>
@@ -212,7 +212,7 @@
 
 
 #define CLIENT_NAME              "TinTin++"
-#define CLIENT_VERSION           "2.02.50b"
+#define CLIENT_VERSION           "2.02.51 "
 
 
 #define XT_E                            0x27
@@ -253,7 +253,7 @@
 #define COLOR_TEXT          "\e[0m"        // "<088>" // reset
 #define COLOR_TINTIN        "\e[38;5;184m" // "<eea>" // yellow
 #define COLOR_REPEAT        "\e[38;5;33m"  // "<acf>" // azure
-#define COLOR_HELP_DIM      "\e[22;37m" 
+#define COLOR_HELP_DIM      "\e[22;37m"
 #define COLOR_HELP_BOLD     "\e[1;37m"
 #define COLOR_HELP_TITLE    "\e[1;32m"
 #define COLOR_HELP_TABLE    "\e[22;36m"
@@ -603,6 +603,7 @@ enum operators
 #define TAB_FLAG_DICTIONARY           BV05
 #define TAB_FLAG_LIST                 BV06
 #define TAB_FLAG_SCROLLBACK           BV07
+#define TAB_FLAG_INPUT                BV08
 
 #define REGEX_FLAG_NONE                  0
 #define REGEX_FLAG_FIX                BV01
@@ -698,6 +699,7 @@ enum operators
 
 #define NODE_FLAG_COLOR               BV01
 #define NODE_FLAG_MULTI               BV02
+#define NODE_FLAG_DEBUG               BV03
 
 #define LOG_FLAG_NONE                    0
 #define LOG_FLAG_LINEFEED             BV01
@@ -2713,7 +2715,7 @@ extern void dispose_session(struct session *ses);
 
 extern void show_message(struct session *ses, int index, char *format, ...);
 extern void show_error(struct session *ses, int index, char *format, ...);
-extern void show_debug(struct session *ses, int index, char *format, ...);
+extern void show_debug(struct session *ses, int index, struct listnode *node, char *format, ...);
 extern void show_info(struct session *ses, int index, char *format, ...);
 extern void tintin_header(struct session *ses, int width, char *format, ...);
 extern void socket_printf(struct session *ses, size_t length, char *format, ...);
@@ -2924,7 +2926,7 @@ extern void init_local(struct session *ses);
 extern struct scriptroot *push_script_stack(struct session *ses, int list);
 extern void pop_script_stack();
 extern struct listroot *local_list(struct session *ses);
-extern struct session *script_driver(struct session *ses, int list, char *str);
+extern struct session *script_driver(struct session *ses, int list, struct listnode *node, char *str);
 extern char *view_script(struct session *ses, struct scriptroot *root);
 extern char *script_writer(struct session *ses, char *str);
 extern char *script_viewer(struct session *ses, char *str);
@@ -2939,7 +2941,7 @@ extern DO_COMMAND(do_function);
 
 extern void check_all_actions(struct session *ses, char *original, char *line, char *buf);
 extern void check_all_actions_multi(struct session *ses, char *original, char *line, char *buf);
-extern  int check_all_aliases(struct session *ses, char *input);
+extern struct listnode *check_all_aliases(struct session *ses, char *input);
 extern void check_all_buttons(struct session *ses, short row, short col, char *arg1, char *arg2, char *word, char *line);
 extern void check_all_gags(struct session *ses, char *original, char *line);
 extern void check_all_highlights(struct session *ses, char *original, char *line);
@@ -2977,6 +2979,7 @@ extern char *str_time(struct session *ses, char *format, time_t time);
 extern unsigned long long generate_rand(struct session *ses);
 extern void seed_rand(struct session *ses, unsigned long long seed);
 extern char *capitalize(char *str);
+extern char *decapitalize(char *str);
 extern char *ftos(double number);
 extern char *ntos(long long number);
 extern char *indent_one(int len);

+ 29 - 17
src/tokenize.c

@@ -73,65 +73,65 @@ void debugtoken(struct session *ses, struct scriptroot *root, struct scriptnode
 		switch (token->type)
 		{
 			case TOKEN_TYPE_REPEAT:
-				show_debug(ses, root->list, "%s" COLOR_REPEAT "!\e[0m%s", indent(token->lvl + 1), token->str);
+				show_debug(ses, root->list, NULL, "%s" COLOR_REPEAT "!\e[0m%s", indent(token->lvl + 1), token->str);
 				break;
 
 			case TOKEN_TYPE_STRING:
-				show_debug(ses, root->list, "%s%s", indent(token->lvl + 1), token->str);
+				show_debug(ses, root->list, NULL, "%s%s", indent(token->lvl + 1), token->str);
 				break;
 
 			case TOKEN_TYPE_SESSION:
-				show_debug(ses, root->list, "%s" COLOR_TINTIN "%c" COLOR_SESSION "%s", indent(token->lvl + 1), gtd->tintin_char, token->str);
+				show_debug(ses, root->list, NULL, "%s" COLOR_TINTIN "%c" COLOR_SESSION "%s", indent(token->lvl + 1), gtd->tintin_char, token->str);
 				break;
 
 			case TOKEN_TYPE_ELSE:
 			case TOKEN_TYPE_END:
-				show_debug(ses, root->list, "%s" COLOR_TINTIN "%c" COLOR_STATEMENT "%s\e[0m", indent(token->lvl + 1), gtd->tintin_char, token->str);
+				show_debug(ses, root->list, NULL, "%s" COLOR_TINTIN "%c" COLOR_STATEMENT "%s\e[0m", indent(token->lvl + 1), gtd->tintin_char, token->str);
 				break;
 
 			case TOKEN_TYPE_DEFAULT:
-				show_debug(ses, root->list, "%s" COLOR_TINTIN "%c" COLOR_STATEMENT "%s\e[0m", indent(token->lvl + 1), gtd->tintin_char, command_table[token->cmd].name);
+				show_debug(ses, root->list, NULL, "%s" COLOR_TINTIN "%c" COLOR_STATEMENT "%s\e[0m", indent(token->lvl + 1), gtd->tintin_char, command_table[token->cmd].name);
 				break;
 
 			case TOKEN_TYPE_BREAK:
 			case TOKEN_TYPE_CONTINUE:
-				show_debug(ses, root->list, "%s" COLOR_TINTIN "%c" COLOR_STATEMENT "%s\e[0m", indent(token->lvl + 1), gtd->tintin_char, command_table[token->cmd].name);
+				show_debug(ses, root->list, NULL, "%s" COLOR_TINTIN "%c" COLOR_STATEMENT "%s\e[0m", indent(token->lvl + 1), gtd->tintin_char, command_table[token->cmd].name);
 				break;
 
 			case TOKEN_TYPE_COMMAND:
-				show_debug(ses, root->list, "%s" COLOR_TINTIN "%c" COLOR_COMMAND   "%s " COLOR_STRING "%s\e[0m", indent(token->lvl + 1), gtd->tintin_char, command_table[token->cmd].name, token->str);
+				show_debug(ses, root->list, NULL, "%s" COLOR_TINTIN "%c" COLOR_COMMAND   "%s " COLOR_STRING "%s\e[0m", indent(token->lvl + 1), gtd->tintin_char, command_table[token->cmd].name, token->str);
 				break;
 
 			case TOKEN_TYPE_RETURN:
-				show_debug(ses, root->list, "%s" COLOR_TINTIN "%c" COLOR_STATEMENT "%s " COLOR_STRING "%s\e[0m", indent(token->lvl + 1), gtd->tintin_char, command_table[token->cmd].name, token->str);
+				show_debug(ses, root->list, NULL, "%s" COLOR_TINTIN "%c" COLOR_STATEMENT "%s " COLOR_STRING "%s\e[0m", indent(token->lvl + 1), gtd->tintin_char, command_table[token->cmd].name, token->str);
 				break;
 
 			case TOKEN_TYPE_CASE:
 			case TOKEN_TYPE_ELSEIF:
 			case TOKEN_TYPE_IF:
 			case TOKEN_TYPE_WHILE:
-				show_debug(ses, root->list, "%s" COLOR_TINTIN "%c" COLOR_STATEMENT "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\e[0m", indent(token->lvl + 1), gtd->tintin_char, command_table[token->cmd].name, token->str);
+				show_debug(ses, root->list, NULL, "%s" COLOR_TINTIN "%c" COLOR_STATEMENT "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\e[0m", indent(token->lvl + 1), gtd->tintin_char, command_table[token->cmd].name, token->str);
 				break;
 
 			case TOKEN_TYPE_FOREACH:
 			case TOKEN_TYPE_LOOP:
 			case TOKEN_TYPE_PARSE:
 			case TOKEN_TYPE_SWITCH:
-				show_debug(ses, root->list, "%s" COLOR_TINTIN "%c" COLOR_STATEMENT "%s " COLOR_STRING "%s\e[0m", indent(token->lvl + 1), gtd->tintin_char, command_table[token->cmd].name, token->data->hlt);
+				show_debug(ses, root->list, NULL, "%s" COLOR_TINTIN "%c" COLOR_STATEMENT "%s " COLOR_STRING "%s\e[0m", indent(token->lvl + 1), gtd->tintin_char, command_table[token->cmd].name, token->data->hlt);
 				break;
 
 			case TOKEN_TYPE_REGEX:
-				show_debug(ses, root->list, "%s" COLOR_TINTIN "%c" COLOR_STATEMENT "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}\e[0m", indent(token->lvl + 1), gtd->tintin_char, command_table[token->cmd].name, token->str, token->regex->str);
+				show_debug(ses, root->list, NULL, "%s" COLOR_TINTIN "%c" COLOR_STATEMENT "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}\e[0m", indent(token->lvl + 1), gtd->tintin_char, command_table[token->cmd].name, token->str, token->regex->str);
 				break;
 
 			default:
 				if (token == (struct scriptnode *) ses)
 				{
-					show_debug(ses, root->list, "[--] (error) token == ses");
+					show_debug(ses, root->list, NULL, "[--] (error) token == ses");
 				}
 				else
 				{
-					show_debug(ses, root->list, "[%02d] %s\e[1;33m%d {\e[0m%s\e[1;32m}\e[0m", token->type, indent(token->lvl + 1), token->cmd, token->str);
+					show_debug(ses, root->list, NULL, "[%02d] %s\e[1;33m%d {\e[0m%s\e[1;32m}\e[0m", token->type, indent(token->lvl + 1), token->cmd, token->str);
 				}
 				break;
 		}
@@ -297,7 +297,7 @@ void handlereturntoken(struct session *ses, struct scriptnode *token)
 
 		SET_BIT(gtd->flags, TINTIN_FLAG_LOCAL);
 	}
-//	show_debug(ses, LIST_FUNCTION, COLOR_DEBUG "#DEBUG RETURN " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", arg);
+//	show_debug(ses, LIST_FUNCTION, NULL, COLOR_DEBUG "#DEBUG RETURN " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", arg);
 }
 
 void handleswitchtoken(struct session *ses, struct scriptnode *token)
@@ -1052,7 +1052,7 @@ struct scriptnode *parse_script(struct scriptroot *root, int lvl, struct scriptn
 				{
 					substitute(root->ses, token->regex->bod, token->regex->buf, SUB_CMD);
 
-					root->ses = script_driver(root->ses, LIST_COMMAND, token->regex->buf);
+					root->ses = script_driver(root->ses, LIST_COMMAND, NULL, token->regex->buf);
 				}
 				else
 				{
@@ -1269,6 +1269,9 @@ char *view_script(struct session *ses, struct scriptroot *root)
 			case TOKEN_TYPE_LOOP:
 			case TOKEN_TYPE_PARSE:
 			case TOKEN_TYPE_SWITCH:
+			case TOKEN_TYPE_BROKEN_FOREACH:
+			case TOKEN_TYPE_BROKEN_LOOP:
+			case TOKEN_TYPE_BROKEN_PARSE:
 				cat_sprintf(buf, "%s" COLOR_TINTIN "%c" COLOR_STATEMENT "%s " COLOR_STRING "%s\n%s" COLOR_BRACE "{\n", indent(token->lvl), gtd->tintin_char, command_table[token->cmd].name, token->data->hlt, indent(token->lvl));
 				break;
 
@@ -1276,6 +1279,7 @@ char *view_script(struct session *ses, struct scriptroot *root)
 			case TOKEN_TYPE_ELSEIF:
 			case TOKEN_TYPE_IF:
 			case TOKEN_TYPE_WHILE:
+			case TOKEN_TYPE_BROKEN_WHILE:
 				cat_sprintf(buf, "%s" COLOR_TINTIN "%c" COLOR_STATEMENT "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}" COLOR_STRING "\n%s" COLOR_BRACE "{\n", indent(token->lvl), gtd->tintin_char, command_table[token->cmd].name, token->str, indent(token->lvl));
 				break;
 
@@ -1308,9 +1312,10 @@ char *view_script(struct session *ses, struct scriptroot *root)
 	return buf;
 }
 
-struct session *script_driver(struct session *ses, int list, char *str)
+struct session *script_driver(struct session *ses, int list, struct listnode *node, char *str)
 {
 	struct scriptroot *root;
+	int debug;
 
 	push_call("script_driver(%p,%d,%p)",ses,list,str);
 
@@ -1318,14 +1323,21 @@ struct session *script_driver(struct session *ses, int list, char *str)
 
 	gtd->level->input += list != LIST_COMMAND;
 
+	debug = node ? HAS_BIT(node->flags, NODE_FLAG_DEBUG) : 0;
+
+	gtd->level->debug += debug;
+
 	tokenize_script(root, 0, str);
 
 	ses = (struct session *) parse_script(root, 0, root->next, root->prev);
 
 	if (list != LIST_COMMAND)
 	{
-		show_debug(ses, list, COLOR_DEBUG "#END%s", list_table[list].name);
+		show_debug(ses, list, NULL, COLOR_DEBUG "#END%s", list_table[list].name);
 	}
+
+	gtd->level->debug -= debug;
+
 	gtd->level->input -= list != LIST_COMMAND;
 
 	while (root->prev)

+ 19 - 18
src/trigger.c

@@ -83,7 +83,7 @@ void check_all_actions(struct session *ses, char *original, char *line, char *bu
 
 		if (check_one_regexp(ses, node, line, original, 0))
 		{
-			show_debug(ses, LIST_ACTION, COLOR_DEBUG "#DEBUG ACTION " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
+			show_debug(ses, LIST_ACTION, node, COLOR_DEBUG "#DEBUG ACTION " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
 
 			substitute(ses, node->arg2, buf, SUB_ARG|SUB_SEC);
 
@@ -92,7 +92,7 @@ void check_all_actions(struct session *ses, char *original, char *line, char *bu
 				delete_node_list(ses, LIST_ACTION, node);
 			}
 
-			script_driver(ses, LIST_ACTION, buf);
+			script_driver(ses, LIST_ACTION, node, buf);
 
 			return;
 		}
@@ -123,7 +123,7 @@ void check_all_actions_multi(struct session *ses, char *original, char *stripped
 			{
 				break;
 			}
-			show_debug(ses, LIST_ACTION, COLOR_DEBUG "#DEBUG MULTI ACTION " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
+			show_debug(ses, LIST_ACTION, node, COLOR_DEBUG "#DEBUG MULTI ACTION " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
 
 			substitute(ses, node->arg2, buf, SUB_ARG|SUB_SEC);
 
@@ -151,7 +151,7 @@ void check_all_actions_multi(struct session *ses, char *original, char *stripped
 					pto = pts = NULL;
 				}
 			}
-			script_driver(ses, LIST_ACTION, buf);
+			script_driver(ses, LIST_ACTION, node, buf);
 
 			ptm = node->arg1 + (*node->arg1 == '~');
 
@@ -205,7 +205,7 @@ DO_COMMAND(do_unalias)
 	return ses;
 }
 
-int check_all_aliases(struct session *ses, char *input)
+struct listnode *check_all_aliases(struct session *ses, char *input)
 {
 	struct listnode *node;
 	struct listroot *root;
@@ -278,6 +278,8 @@ int check_all_aliases(struct session *ses, char *input)
 
 			if (!strncmp(node->arg1, line, strlen(node->arg1)) && !strcmp(node->arg2, buf) && *gtd->vars[0])
 			{
+				show_error(ses, LIST_ACTION, "#WARNING: #ALIAS {%s} CONTAINS NO %%0-%%99 BUT IS CALLED WITH ARGUMENT {%s}.", node->arg1, gtd->vars[0]);
+
 				sprintf(input, "%s %s", buf, gtd->vars[0]);
 			}
 			else
@@ -285,18 +287,18 @@ int check_all_aliases(struct session *ses, char *input)
 				sprintf(input, "%s", buf);
 			}
 
-			show_debug(ses, LIST_ALIAS, COLOR_DEBUG "#DEBUG ALIAS " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1, gtd->vars[0]);
+			show_debug(ses, LIST_ALIAS, node, COLOR_DEBUG "#DEBUG ALIAS " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1, gtd->vars[0]);
 
 			if (node->shots && --node->shots == 0)
 			{
 				delete_node_list(ses, LIST_ALIAS, node);
 			}
 			pop_call();
-			return TRUE;
+			return node;
 		}
 	}
 	pop_call();
-	return FALSE;
+	return NULL;
 }
 
 
@@ -426,7 +428,7 @@ void check_all_buttons(struct session *ses, short row, short col, char *arg1, ch
 
 		if (!strcmp(arg4, node->arg4))
 		{
-			show_debug(ses, LIST_BUTTON, COLOR_DEBUG "#DEBUG BUTTON " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
+			show_debug(ses, LIST_BUTTON, node, COLOR_DEBUG "#DEBUG BUTTON " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
 
 			RESTRING(gtd->vars[0], ntos(row));
 			RESTRING(gtd->vars[1], ntos(col));
@@ -441,7 +443,7 @@ void check_all_buttons(struct session *ses, short row, short col, char *arg1, ch
 			{
 				delete_node_list(ses, LIST_BUTTON, node);
 			}
-			script_driver(ses, LIST_BUTTON, buf);
+			script_driver(ses, LIST_BUTTON, node, buf);
 
 			break;
 		}
@@ -490,7 +492,6 @@ DO_COMMAND(do_delay)
 			create_node_list(ses->list[LIST_DELAY], time, arg2, arg1, arg3);
 
 			show_message(ses, LIST_DELAY, "#DELAY: IN {%s} SECONDS {%s} IS EXECUTED.", arg1, arg2);
-
 		}
 		else
 		{
@@ -615,7 +616,7 @@ void check_all_gags(struct session *ses, char *original, char *line)
 
 		if (check_one_regexp(ses, node, line, original, 0))
 		{
-//			show_debug(ses, LIST_GAG, "#DEBUG GAG {%s}", node->arg1);
+//			show_debug(ses, LIST_GAG, node, "#DEBUG GAG {%s}", node->arg1);
 
 			if (node->shots && --node->shots == 0)
 			{
@@ -741,7 +742,7 @@ void check_all_highlights(struct session *ses, char *original, char *line)
 
 				pto = ptm + len;
 
-				show_debug(ses, LIST_HIGHLIGHT, COLOR_DEBUG "#DEBUG HIGHLIGHT " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
+				show_debug(ses, LIST_HIGHLIGHT, node, COLOR_DEBUG "#DEBUG HIGHLIGHT " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
 			}
 			while (check_one_regexp(ses, node, ptl, pto, 0));
 
@@ -875,7 +876,7 @@ int check_all_prompts(struct session *ses, char *original, char *line)
 				strip_vt102_codes(original, line);
 			}
 
-			show_debug(ses, LIST_PROMPT, COLOR_DEBUG "#DEBUG PROMPT " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
+			show_debug(ses, LIST_PROMPT, node, COLOR_DEBUG "#DEBUG PROMPT " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
 
 			if (strcmp(node->arg3, "0"))
 			{
@@ -954,7 +955,7 @@ void check_all_substitutions(struct session *ses, char *original, char *line)
 	subst  = str_alloc_stack(0);
 	result = str_alloc_stack(0);
 	temp   = str_alloc_stack(0);
-	
+
 	for (root->update = 0 ; root->update < root->used ; root->update++)
 	{
 		node = root->list[root->update];
@@ -1006,7 +1007,7 @@ void check_all_substitutions(struct session *ses, char *original, char *line)
 
 				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, node, COLOR_DEBUG "#DEBUG SUBSTITUTE " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1, match);
 
 				ptm = node->arg1 + (*node->arg1 == '~');
 
@@ -1097,7 +1098,7 @@ void check_all_substitutions_multi(struct session *ses, char *original, char *li
 
 				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, node, COLOR_DEBUG "#DEBUG SUBSTITUTE " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1, match);
 
 				ptm = node->arg1 + (*node->arg1 == '~');
 
@@ -1194,7 +1195,7 @@ DO_COMMAND(do_tick)
 	}
 	else if (*arg1 && *arg2 == 0)
 	{
-		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, "#TICKER: NO MATCHES FOUND FOR {%s}.", arg1);
 		}

+ 19 - 14
src/update.c

@@ -177,7 +177,7 @@ void mainloop(void)
 			pulse.update_daemon = PULSE_UPDATE_DAEMON;
 
 			update_daemon();
-			
+
 			close_timer(TIMER_UPDATE_DAEMON);
 		}
 
@@ -201,7 +201,7 @@ void mainloop(void)
 			update_port();
 
 			close_timer(TIMER_UPDATE_PORT);
-		}	
+		}
 
 		if (--pulse.update_ticks == 0)
 		{
@@ -560,9 +560,9 @@ void update_daemon(void)
 					if (gtd->detach_sock < 0)
 					{
 						syserr_printf(gtd->ses, "update_daemon: detach_port: accept");
-						
+
 						gtd->detach_sock = close(gtd->detach_sock);
-						
+
 						goto attach;
 					}
 
@@ -571,7 +571,7 @@ void update_daemon(void)
 						syserr_printf(gtd->ses, "update_daemon: detach_port: fcntl O_NDELAY|O_NONBLOCK");
 
 						gtd->detach_sock = close(gtd->detach_sock);
-						
+
 						goto attach;
 					}
 
@@ -698,7 +698,7 @@ void update_daemon(void)
 		if (rv < 0)
 		{
 			gtd->attach_sock = close(gtd->attach_sock);
-	
+
 			show_message(gtd->ses, LIST_COMMAND, "#DAEMON UPDATE: UNATTACHING {%s} DUE TO SELECT ERROR.", gtd->attach_file);
 		}
 		else if (rv > 0)
@@ -876,7 +876,7 @@ void tick_update(void)
 
 	gtd->utime_next_tick = gtd->utime + 1000000000;
 
-	for (ses = gts->next ; ses ; ses = gtd->update)
+	for (ses = gts ; ses ; ses = gtd->update)
 	{
 		gtd->update = ses->next;
 
@@ -891,6 +891,11 @@ void tick_update(void)
 				tintin_printf2(gtd->ses, "error: tick_update: node->val64 == 0");
 			}
 
+			if (ses == gts && node->shots == 0)
+			{
+				continue;
+			}
+
 			if (node->val64 <= gtd->utime)
 			{
 				node->val64 += (long long) (get_number(ses, node->arg3) * 1000000LL);
@@ -904,13 +909,13 @@ void tick_update(void)
 
 				if (!HAS_BIT(root->flags, LIST_FLAG_IGNORE))
 				{
-					show_debug(ses, LIST_TICKER, COLOR_DEBUG "#DEBUG TICKER " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg2);
+					show_debug(ses, LIST_TICKER, node, COLOR_DEBUG "#DEBUG TICKER " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg2);
 
 					if (node->shots && --node->shots == 0)
 					{
 						delete_node_list(ses, LIST_TICKER, node);
 					}
-					script_driver(ses, LIST_TICKER, node->arg2);
+					script_driver(ses, LIST_TICKER, node, node->arg2);
 				}
 			}
 			else
@@ -949,11 +954,11 @@ void delay_update(void)
 
 			if (node->val64 <= gtd->utime)
 			{
-				show_debug(ses, LIST_DELAY, COLOR_DEBUG "#DEBUG DELAY " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg2);
+				show_debug(ses, LIST_DELAY, node, COLOR_DEBUG "#DEBUG DELAY " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg2);
 
 				delete_index_list(root, root->update);
 
-				script_driver(ses, LIST_DELAY, node->arg2);
+				script_driver(ses, LIST_DELAY, node, node->arg2);
 			}
 			else
 			{
@@ -993,9 +998,9 @@ void path_update(void)
 
 				node->val64 = 0;
 
-				show_debug(ses, LIST_PATH, COLOR_DEBUG "#DEBUG PATH " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
+				show_debug(ses, LIST_PATH, node, COLOR_DEBUG "#DEBUG PATH " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", node->arg1);
 
-				script_driver(ses, LIST_PATH, node->arg1);
+				script_driver(ses, LIST_PATH, NULL, node->arg1);
 
 				if (root->update == root->used)
 				{
@@ -1022,7 +1027,7 @@ void packet_update(void)
 		if (HAS_BIT(ses->telopts, TELOPT_FLAG_UPDATENAWS))
 		{
 			client_send_sb_naws(ses, 0, NULL);
-					
+
 			DEL_BIT(ses->telopts, TELOPT_FLAG_UPDATENAWS);
 		}
 	}

Plik diff jest za duży
+ 1 - 1
src/utf8.c


+ 15 - 1
src/utils.c

@@ -338,7 +338,7 @@ char *str_time(struct session *ses, char *format, time_t time)
 
 	return buf[cnt];
 }
-	
+
 void seed_rand(struct session *ses, unsigned long long seed)
 {
 	ses->rand = seed % 4294967291ULL;
@@ -393,6 +393,20 @@ char *capitalize(char *str)
 	return outbuf;
 }
 
+char *decapitalize(char *str)
+{
+	char *outbuf = str_alloc_stack(0);
+	int cnt;
+
+	for (cnt = 0 ; str[cnt] != 0 ; cnt++)
+	{
+		outbuf[cnt] = tolower((int) str[cnt]);
+	}
+	outbuf[cnt] = 0;
+
+	return outbuf;
+}
+
 char *ftos(double number)
 {
 	static char outbuf[10][NUMBER_SIZE];

+ 6 - 6
src/variable.c

@@ -298,7 +298,7 @@ DO_COMMAND(do_replace)
 	}
 	else
 	{
-//		show_debug(ses, LIST_VARIABLE, "#REPLACE {%s} {%s} {%s}", node->arg2, arg2, arg3);
+//		show_debug(ses, LIST_VARIABLE, node, "#REPLACE {%s} {%s} {%s}", node->arg2, arg2, arg3);
 
 		pti = node->arg2;
 		str = str_alloc_stack(0);
@@ -833,7 +833,7 @@ void metricgroupingstring(struct session *ses, char *str)
 		else
 		{
 			snprintf(tmp, NUMBER_SIZE, "%Lf", val);
-		} 
+		}
 		sprintf(str, "%.5s%c", tmp, small[index]);
 	}
 	else if (val <= -1000)
@@ -1027,7 +1027,7 @@ int string_str_raw_len(struct session *ses, char *str, int start, int end)
 		{
 			ret_cnt += (str_cnt >= start) ? 1 : 0;
 			raw_cnt++;
-			
+
 			if (str[raw_cnt] == '\\')
 			{
 				ret_cnt += (str_cnt >= start) ? 1 : 0;
@@ -1107,7 +1107,7 @@ int string_str_str_len(struct session *ses, char *str, int start, int end)
 		if (str[raw_cnt] == '\\')
 		{
 			raw_cnt++;
-			
+
 			if (str[raw_cnt] == '\\')
 			{
 				ret_cnt += (str_cnt >= start) ? 1 : 0;
@@ -1411,7 +1411,7 @@ void format_string(struct session *ses, char *format, char *arg, char *out)
 							{
 								ptt = arg2;
 								ptn = ptn + 1;
-		
+
 								while (*ptn)
 								{
 									*ptt++ = *ptn++;
@@ -1459,7 +1459,7 @@ void format_string(struct session *ses, char *format, char *arg, char *out)
 
 							ptt = argformat;
 							ptn = pts;
-		
+
 							while (*ptt)
 							{
 								*ptn++ = *ptt++;

+ 26 - 26
src/vt102.c

@@ -284,22 +284,22 @@ int skip_vt102_codes_non_graph(char *str)
 	switch (str[skip])
 	{
 		case   7:   // BEL
-//		case   8:   // BS  
-//		case   9:   // HT  
-//		case  10:   // LF  
-		case  11:   // VT  
-		case  12:   // FF  
-		case  13:   // CR  
-		case  14:   // SO  
-		case  15:   // SI  
-		case  17:   // DC1 
-		case  19:   // DC3 
-		case  24:   // CAN 
-		case  26:   // SUB 
-		case 127:   // DEL 
+//		case   8:   // BS
+//		case   9:   // HT
+//		case  10:   // LF
+		case  11:   // VT
+		case  12:   // FF
+		case  13:   // CR
+		case  14:   // SO
+		case  15:   // SI
+		case  17:   // DC1
+		case  19:   // DC3
+		case  24:   // CAN
+		case  26:   // SUB
+		case 127:   // DEL
 			return 1;
 
-		case  27:   // ESC 
+		case  27:   // ESC
 			break;
 
 		default:
@@ -656,7 +656,7 @@ void strip_non_vt102_codes(char *str, char *buf)
 }
 
 char *strip_vt102_strstr(char *str, char *buf, int *len)
-{ 
+{
 	char *pti, *ptm, *pts;
 
 	push_call("strip_vt102_strstr(%p,%p,%p)",str,buf,len);
@@ -804,9 +804,9 @@ void get_color_codes(char *old, char *str, char *buf, int flags)
 					rgb[2] = URANGE(0, atoi(col), 255);
 
 					fgc = rgb[0] * 256 * 256 + rgb[1] * 256 + rgb[2];
-					
+
 					DEL_BIT(vtc, COL_TCF_2|COL_TCF_R);
-					SET_BIT(vtc, COL_TCB);
+					SET_BIT(vtc, COL_TCF);
 				}
 			}
 			else if (HAS_BIT(vtc, COL_TCB_R))
@@ -824,7 +824,7 @@ void get_color_codes(char *old, char *str, char *buf, int flags)
 					rgb[5] = URANGE(0, atoi(col), 255);
 
 					fgc = rgb[3] * 256 * 256 + rgb[4] * 256 + rgb[5];
-					
+
 					DEL_BIT(vtc, COL_TCB_2|COL_TCF_R);
 					SET_BIT(vtc, COL_TCB);
 				}
@@ -916,7 +916,7 @@ void get_color_codes(char *old, char *str, char *buf, int flags)
 								fgc = atoi(col);
 								DEL_BIT(vtc, COL_XTF|COL_TCF);
 								break;
-							
+
 							case 4:
 							case 9:
 								bgc = atoi(col);
@@ -1009,7 +1009,7 @@ int strip_vt102_strlen(struct session *ses, char *str)
 {
 	char *pti;
 	int size, width, str_len;
-	
+
 	str_len = 0;
 
 	pti = str;
@@ -1232,7 +1232,7 @@ int interpret_vt102_codes(struct session *ses, char *str, int real)
 			ses->split->top_row = URANGE(1, ses->split->top_row, gtd->screen->rows);
 
 			ses->split->bot_row = ses->split->bot_row ? URANGE(1, ses->split->bot_row, gtd->screen->rows) : gtd->screen->rows;
-			
+
 			return TRUE;
 		}
 	}
@@ -1255,7 +1255,7 @@ int catch_vt102_codes(struct session *ses, unsigned char *str, int cplen)
 			}
 			pop_call();
 			return 0;
-			
+
 		case ASCII_ESC:
 			break;
 
@@ -1410,9 +1410,9 @@ int catch_vt102_codes(struct session *ses, unsigned char *str, int cplen)
 					if (cplen >= 10)
 					{
 						sprintf(osc, "%.*s", 8, str + 3);
-							
+
 						check_all_events(ses, EVENT_FLAG_VT100, 0, 1, "VT100 OSC COLOR PALETTE", osc);
-							
+
 						if (check_all_events(ses, EVENT_FLAG_CATCH, 0, 1, "CATCH VT100 OSC", osc))
 						{
 							pop_call();
@@ -1448,7 +1448,7 @@ int catch_vt102_codes(struct session *ses, unsigned char *str, int cplen)
 							return 1;
 						}
 					}
-					
+
 					while (cplen >= skip && skip < BUFFER_SIZE)
 					{
 						if (str[skip] == ASCII_BEL)
@@ -1457,7 +1457,7 @@ int catch_vt102_codes(struct session *ses, unsigned char *str, int cplen)
 						}
 						skip++;
 					}
-	
+
 					snprintf(osc, BUFFER_SIZE, "%.*s", skip - 2, str + 2);
 
 					check_all_events(ses, SUB_SEC|EVENT_FLAG_VT100, 0, 1, "VT100 OSC", osc);

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików