Scandum пре 4 година
родитељ
комит
b0fa43339e
41 измењених фајлова са 1530 додато и 974 уклоњено
  1. 4 0
      NEWS
  2. 110 94
      SCRIPTS
  3. 34 30
      TODO
  4. 76 19
      docs/help.html
  5. 58 1
      mods/igr.mods
  6. 11 0
      src/banner.c
  7. 11 11
      src/buffer.c
  8. 13 13
      src/config.c
  9. 246 150
      src/cursor.c
  10. 56 29
      src/data.c
  11. 80 1
      src/dict.c
  12. 5 3
      src/draw.c
  13. 2 2
      src/event.c
  14. 32 32
      src/gui.h
  15. 77 20
      src/help.c
  16. 15 11
      src/input.c
  17. 58 58
      src/line.c
  18. 135 28
      src/log.c
  19. 5 22
      src/main.c
  20. 169 75
      src/mapper.c
  21. 0 4
      src/math.c
  22. 0 81
      src/misc.c
  23. 1 8
      src/nest.c
  24. 1 0
      src/net.c
  25. 11 10
      src/parse.c
  26. 16 62
      src/path.c
  27. 1 1
      src/regex.c
  28. 1 0
      src/scan.c
  29. 18 25
      src/session.c
  30. 48 36
      src/show.c
  31. 4 5
      src/split.c
  32. 2 0
      src/ssl.c
  33. 5 5
      src/string.c
  34. 68 23
      src/substitute.c
  35. 13 15
      src/tables.c
  36. 2 2
      src/telopt_client.c
  37. 75 64
      src/tintin.h
  38. 11 7
      src/tokenize.c
  39. 15 8
      src/utf8.c
  40. 39 17
      src/variable.c
  41. 2 2
      src/vt102.c

+ 4 - 0
NEWS

@@ -1,6 +1,10 @@
 Due to continuous improvements old tintin scripts aren't always compatible
 with new versions. This document tries to list most compatibility conflicts.
 
+TinTin++ 2.02.12
+----------------
+01) The behavior of $variable[] is now identical to $variable[%*].
+
 TinTin++ 2.02.11
 ----------------
 

+ 110 - 94
SCRIPTS

@@ -661,33 +661,33 @@
 
 #event {PROGRAM START}
 {
-    #split 3 1;
-    #config mouse on;
-    #var active gts;
-    session_activated gts;
+	#split 3 1;
+	#config mouse on;
+	#var active gts;
+	session_activated gts;
 }
 
 #event {SESSION CREATED}
 {
-    #gts session_activated %0
+	#gts session_activated %0
 }
 
 #event {SESSION ACTIVATED}
 {
-    #gts session_activated %0
+	#gts session_activated %0
 }
 
 #alias {session_activated}
 {
-    #line sub esc #var sessions[$active] {<138>\e]68;2;TABS;#$active\a\e[4;24m$active\e[24m};
-    #var active {%0};
-    #line sub esc #var sessions[%0] {<128>\e]68;2;TABS;#nop\a\e[4;24m%0\e[24m};
-    #draw foreground Azure table 1 1 3 -1 {$sessions[%*]}
+	#line sub esc #var sessions[$active] {<138>\e]68;2;TABS;#$active\a\e[4;24m$active\e[24m};
+	#var active {%0};
+	#line sub esc #var sessions[%0] {<128>\e]68;2;TABS;#nop\a\e[4;24m%0\e[24m};
+	#draw foreground Azure table 1 1 3 -1 {$sessions[%*]}
 }
 
 #event {PRESSED SECURE LINK TABS MOUSE BUTTON ONE}
 {
-    %4
+	%4
 }
 
 
@@ -699,12 +699,12 @@
 
 #event {IAC DO MXP}
 {
-    #send {\xFF\xFB\x5B\}
+	#send {\xFF\xFB\x5B\}
 }
 
 #function {mxp_link}
 {
-    #line sub esc #var result {\e]68;1;%1;%2\a\e[4m%3\e[24m}
+	#line sub esc #var result {\e]68;1;%1;%2\a\e[4m%3\e[24m}
 }
 
 #act {~\e[1z<VERSION>} {#send {\e[4z<VERSION MXP=1.0 CLIENT=TINTIN++ VERSION=2.02.04>}}
@@ -716,7 +716,7 @@
 
 #event {PRESSED LINK MXP MOUSE BUTTON ONE}
 {
-    #send {%4}
+	#send {%4}
 }
 
 #sub {~\e[4z{<RExits>|</RExits>|<RDesc>|</RDesc>|<PROMPT>|</PROMPT>|<RName>|</RName>}} {}
@@ -742,33 +742,33 @@
 
 	#loop 1 &players[] cnt
 	{
-	    #var out[$cnt] {$cnt;$players[+$cnt][name];$players[+$cnt][age];$players[+$cnt][level]};
+		#var out[$cnt] {$cnt;$players[+$cnt][name];$players[+$cnt][age];$players[+$cnt][level]};
 	};
 	#draw scroll grid table 1 1 2+&players[]*2 80 $out[%*]
 }
 
 #alias {test1}
 {
-    #list players index name;
-    #list players order;
-    display
+	#list players index name;
+	#list players order;
+	display
 }
 
 #alias {test2}
 {
-    #list players index name;
-    #list players order;
-    #list players reverse;
-    display;
+	#list players index name;
+	#list players order;
+	#list players reverse;
+	display;
 }
 
 #alias {test3}
 {
-    #list players index name;
-    #list players order;
-    #list players index level;
-    #list players order;
-    display
+	#list players index name;
+	#list players order;
+	#list players index level;
+	#list players order;
+	display
 }
 
 #nop -------------------------------------------------------------------------
@@ -784,12 +784,12 @@
 
 #alias {inputswitch}
 {
-    #cursor get {input[current]};
-    #cursor clear;
-    #cursor set {$input[buffer2]};
-    #cursor end;
-    #var input[buffer2] {$input[current]};
-    #draw Ebony tile {-1-$input[width]} 1 -2 -1 {$input[buffer2]}
+	#cursor get {input[current]};
+	#cursor clear;
+	#cursor set {$input[buffer2]};
+	#cursor end;
+	#var input[buffer2] {$input[current]};
+	#draw Ebony tile {-1-$input[width]} 1 -2 -1 {$input[buffer2]}
 }
 
 #nop -------------------------------------------------------------------------
@@ -799,79 +799,79 @@
 
 #event {PROGRAM START}
 {
-    #config mouse on;
-    #var SCROLL[MODE] 0;
-    #split 0 1;
-    #screen raise SCREEN RESIZE;
+	#config mouse on;
+	#var SCROLL[MODE] 0;
+	#split 0 1;
+	#screen raise SCREEN RESIZE;
 }
 
 #event {SCREEN RESIZE}
 {
-    #var ROWS %0;
-    #var COLS %1;
-    #screen get SCROLL_TOP_ROW SCROLL[TOP_ROW];
-    #screen get SCROLL_TOP_COL SCROLL[TOP_COL];
-    #screen get SCROLL_BOT_ROW SCROLL[BOT_ROW];
-    #screen get SCROLL_BOT_COL SCROLL[BOT_COL];
+	#var ROWS %0;
+	#var COLS %1;
+	#screen get SCROLL_TOP_ROW SCROLL[TOP_ROW];
+	#screen get SCROLL_TOP_COL SCROLL[TOP_COL];
+	#screen get SCROLL_BOT_ROW SCROLL[BOT_ROW];
+	#screen get SCROLL_BOT_COL SCROLL[BOT_COL];
 }
 
 #EVENT {SCROLLED MOUSE WHEEL UP}
 {
-    #if {$SCROLL[MODE] == 0}
-    {
-	#if {%0 < $ROWS / 2}
+	#if {$SCROLL[MODE] == 0}
 	{
-	    #var SCROLL[MODE] 1;
-	    #var SCROLL[OLD_ROW] $SCROLL[BOT_ROW];
-	    #math SCROLL[BOT_ROW] $SCROLL[OLD_ROW] / 2;
-	    #var BUFFER {};
-	    #screen scroll $SCROLL[TOP_ROW] $SCROLL[TOP_COL] $SCROLL[BOT_ROW] $SCROLL[BOT_COL];
+		#if {%0 < $ROWS / 2}
+		{
+			#var SCROLL[MODE] 1;
+			#var SCROLL[OLD_ROW] $SCROLL[BOT_ROW];
+			#math SCROLL[BOT_ROW] $SCROLL[OLD_ROW] / 2;
+			#var BUFFER {};
+			#screen scroll $SCROLL[TOP_ROW] $SCROLL[TOP_COL] $SCROLL[BOT_ROW] $SCROLL[BOT_COL];
 
-	    #draw red teed line $SCROLL[BOT_ROW]+1 $SCROLL[TOP_COL] $SCROLL[BOT_ROW]+1 $SCROLL[BOT_COL];
+			#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];
+			#screen clear square $SCROLL[BOT_ROW]+2 $SCROLL[TOP_COL] $SCROLL[OLD_ROW] $SCROLL[BOT_COL];
+		};
 	};
-    };
-    #if {$SCROLL[MODE] == 1}
-    {
-	#buffer up 1
-    }
+	#if {$SCROLL[MODE] == 1}
+	{
+		#buffer up 1
+	}
 }
 
 #EVENT {SCROLLED MOUSE WHEEL DOWN}
 {
-    #if {$SCROLL[MODE] == 1}
-    {
-	#if {%0 < $ROWS / 2}
+	#if {$SCROLL[MODE] == 1}
 	{
-	    #buffer down 1;
+		#if {%0 < $ROWS / 2}
+		{
+			#buffer down 1;
 
-	    #buffer info save SCROLL[INFO];
+			#buffer info save SCROLL[INFO];
 
-	    #if {$SCROLL[INFO][LINE] == -1}
-	    {
-		#var SCROLL[MODE] 0;
-		#var SCROLL[BOT_ROW] $SCROLL[OLD_ROW];
+			#if {$SCROLL[INFO][LINE] == -1}
+			{
+				#var SCROLL[MODE] 0;
+				#var SCROLL[BOT_ROW] $SCROLL[OLD_ROW];
 
-		#split 0 1;
-		#buffer end;
-	    }
+				#split 0 1;
+				#buffer end;
+			}
+		}
 	}
-    }
 }
 
 #event {RECEIVED LINE}
 {
-    #if {$SCROLL[MODE] == 1}
-    {
-	#if {&BUFFER[] > $ROWS}
+	#if {$SCROLL[MODE] == 1}
 	{
-	    #list BUFFER del 1
-	};
-	#list BUFFER add {%0};
+		#if {&BUFFER[] > $ROWS}
+		{
+			#list BUFFER del 1
+		};
+		#list BUFFER add {%0};
 
-	#draw tile $SCROLL[BOT_ROW]+2 $SCROLL[TOP_COL] $SCROLL[OLD_ROW] $SCROLL[BOT_COL] $BUFFER[%*];
-    }
+		#draw tile $SCROLL[BOT_ROW]+2 $SCROLL[TOP_COL] $SCROLL[OLD_ROW] $SCROLL[BOT_COL] $BUFFER[%*];
+	}
 }
 
 #nop -------------------------------------------------------------------------
@@ -884,32 +884,48 @@
 
 #alias {gemstone}
 {
-    #var gemstone {};
+	#var gemstone {};
 
-    #line oneshot #action {^GAMEHOST=%*} {#var gemstone[host] %%1};
-    #line oneshot #action {^GAMEPORT=%*} {#var gemstone[port] %%1};
-    #line oneshot #action {^KEY=%*} {#var gemstone[key] %%1};
+	#line oneshot #action {^GAMEHOST=%*} {#var gemstone[host] %%1};
+	#line oneshot #action {^GAMEPORT=%*} {#var gemstone[port] %%1};
+	#line oneshot #action {^KEY=%*} {#var gemstone[key] %%1};
 
-    #scan txt gemstone.sal;
+	#scan txt gemstone.sal;
 
-    #if {&gemstone[] != 3}
-    {
-        #showme Failed to load gemstone.sal file.;
-        #return
-    };
-    #ses gemstone $gemstone[host] $gemstone[port];
-    #send {$gemstone[key]};
-    #send {>/FE:JAVA}
+	#if {&gemstone[] != 3}
+	{
+		#showme Failed to load gemstone.sal file.;
+		#return
+	};
+	#ses gemstone $gemstone[host] $gemstone[port];
+	#send {$gemstone[key]};
+	#send {>/FE:JAVA}
 }
 
 #nop -------------------------------------------------------------------------
-#nop 
+#nop Start a dated log file in the logs directory when a session connects. See
+#nop #help time for the available date options for #format %t.
 #nop -------------------------------------------------------------------------
 
+#event {SESSION CONNECTED}
+{
+	#format date %t %Y-%m-%d-%H-%M;
+
+	#log append logs/%0_$date.log
+}
+
 #nop -------------------------------------------------------------------------
-#nop 
+#nop Sometimes an error doesn't give enough information and it's useful to
+#nop see the calling script.
 #nop -------------------------------------------------------------------------
 
+#event {RECEIVED ERROR}
+{
+	#echo <118>%h { TOKENIZER };
+	#info tokenizer -1;
+	#echo <118>%h
+}
+
 #nop -------------------------------------------------------------------------
 #nop 
 #nop -------------------------------------------------------------------------

+ 34 - 30
TODO

@@ -1,20 +1,34 @@
   - look into large variable handling, foreach, once again
 
-  - tab window, add tab ordering and garbage collection
-
 ----------------
-  - ãã is messing up
+  - GMCP: MG.room.info { "exits": [ ] } gets parsed into {exits} {{1}{}}
 
-  - Add RECEIVED INPUT CHARACTER event / filter mouse input sequences.
+  - #map info save option
+
+  - check: #var bla { x};#draw scroll box 1 1 3 40 $bla
+
+  - set_line_screen stack call triggered on android
+
+  - input spell checking, #cursor display ?
+
+  - cp949toutf8 is missing some characters
 
-  - handle signals in the mainloop.
+  - look into named actions as a 4th argument
+
+  - look into adding #line quiet support to #buffer
+
+  - pruned tile handling
+
+  - Get discworld / aardwolf mxp to work for @sentix
+
+  - look into default input color
+
+  - Add RECEIVED INPUT CHARACTER event / filter mouse input sequences.
 
   - add ctrl-r support for scrollback
 
   - Add #event {SESSION CONNECTED} {5.1} option.
 
-  - Add the option to use + ? . and * as variable exit fields. 
-
   - TT++ HANDBOOK for meticulous organized details.
 
   - vertical bar drawing
@@ -25,6 +39,8 @@
 
   - finish BUFFER_SIZE replacement.
 
+  - WSL sound, double check soundpack scripts for lag/stutter
+
   - WSL faq: #system cmd.exe /c start notepad
 
   - update msdp scripts with #line msdp feature
@@ -35,6 +51,10 @@
 
 * 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
@@ -44,42 +64,26 @@
   - Work on VT2020 protocol (mouse click)
 
   - $var[%*][%*] support.
-  - make list sorting move nests as well
 
   - better #draw font support
 
-  - case insensitive tabbing (partial start with rewrite)
-  - tabbing on directory structure.
-  - tabbing on dictionary
-
-#0  0x00005555555a5418 in tunnel_void (ses=0x555558a97b00, from=8004, room=1931506785, dir=1684955508) at mapper.c:4220
-#1  0x00005555555a599d in searchgrid_find (ses=0x555558a97b00, from=153, search=0x555558d8f850) at mapper.c:4336
-#2  0x00005555555afb44 in map_list (ses=0x555558a97b00, arg=0x5555572e1b95 "{} {} {} {$roomarea} {variable} {area_mapped}",
+  - tab completion on directory structure.
 
+  - pancake mode to display rooms at all levels and annotations
+  - Store the map filename to differentiate between maps.
   - #map list {<exits>} breaks on rooms that have e mapped to eu.
   - finish landmarks
   - map sandbox mode support (flags to disable saving?)
   - add ghosting to fix #map flag nofollow exit cmd issues?
-  ! #map legend support for unicode graphics.
-  - multi-line room symbols
-  - pancake mode to display rooms at all levels and annotations
-  - there might be a terrain density bug
-  - provide the coordinate of the X on the vtmap.
-  - add maze flag for maze handling.
   - Request: aura around the character position. Something similar to terrain dense narrow. Could improve visibility of the character position on big resolutions. Furthermor config to allow modification of the character terrain. 
   - vt map doesn't utilize all available space.
   - Request: 'stop' #map center command, so i could see how the 'user' moves, rather map moves around him? 
   - #map uninsert <vnum>
   - make map spacing easier
-  - add configurable default symbol
-  - exit symbol?
-  - more data to #map list saving, and maybe easier sorting of tables.
   - event for failed #map move.
   - look into #send triggering follow map.
   - add {roomdata} search to #map list
 
-  - truncate prompt longer than split.
-
   - Make actions with a priority of 0. trigger always
 
   - #draw table {1;2;3;4} {a;b;c;d}
@@ -105,8 +109,6 @@
 
   - better color syntax highlighting configuration.
 
-  - Add #log delete/remove option.
-
   - See about adding SESSIONS to the list table.
 
   - Add debugger to syntax highlighter, substitution highlighing, 256 color support, and variable expansion.
@@ -131,14 +133,16 @@
 
   - http://tintin.sourceforge.net/board/viewtopic.php?p=8766#8766 (global verbose toggle?)
 
-  - http://tintin.sourceforge.net/board/viewtopic.php?p=8745#8745 (verbose logging?)
-
   - See about adding ~/ handling for file names.
 
+  - Look into adding basic EUC-KR support.
+
 --------------------------------------------------------------------------------
 
 * LOW PRIORITY
 
+  - ./configure might error on /dev/ptmx
+
   - Add a file handler.
 
   - multi-line buffer searches / captures / deletes

+ 76 - 19
docs/help.html

@@ -616,8 +616,30 @@ Related</span><span style='color:#AAA'>: <a href='#PORT'>port</a>
          with macros. Subsequently many cursor commands only work properly when
          used within a macro or event.
 
-         </span><span style='color:#FFF'>#cursor tab &lt;list;scrollback&gt; &lt;backward|forward&gt;
-         </span><span style='color:#AAA'>  Tab through the given option(s) going forward or backward.
+         </span><span style='color:#FFF'>#cursor flag
+
+         </span><span style='color:#AAA'>EOL         end of line character(s)
+         ECHO        local echo
+         OVERTYPE    overtype mode
+
+         </span><span style='color:#FFF'>#cursor macro
+
+         </span><span style='color:#AAA'>PRESERVE    do not erase the macro from the macro input buffer
+         RESET       erase the macro input buffer
+
+         </span><span style='color:#FFF'>#cursor tab
+
+         </span><span style='color:#AAA'>CASELESS    makes tab completion caseless
+         COMPLETE    makes tab completion work while editing
+
+         DICTIONARY  performs tab completion on the dictionary
+         LIST        performs tab completion on the tab completion list
+         SCROLLBACK  performs tab completion on the scrollback buffer
+
+         BACKWARD    specifies tab completion to go backward
+         FORWARD     specifies tab completion to go forward
+
+         Multiple options can/must be specified at once.
 
 </span><span style='color:#FFF'>Related</span><span style='color:#AAA'>: <a href='#ALIAS'>alias</a>, <a href='#HISTORY'>history</a>, <a href='#KEYPAD'>keypad</a>, <a href='#MACRO'>macro</a>, <a href='#SPEEDWALK'>speedwalk</a> and <a href='#TAB'>tab</a>.
 <a name='DAEMON'></a>
@@ -687,6 +709,8 @@ Related</span><span style='color:#AAA'>: <a href='#PORT'>port</a>
          Nanosecond floating point precision is allowed. Delays will fire in
          0.01 second intervals.
 
+         Named delays are treated as one-shot tickers, see #help tick.
+
 </span><span style='color:#FFF'>Example</span><span style='color:#AAA'>: #delay {1} {#show last};#show first
          This will print 'first', and 'last' around one second later.
 
@@ -1071,6 +1095,9 @@ Related</span><span style='color:#AAA'>: <a href='#PORT'>port</a>
          </span><span style='color:#FFF'>RECEIVED INPUT [NAME]
          </span><span style='color:#AAA'>  %0 raw text
 
+         </span><span style='color:#FFF'>RECEIVED INPUT CHARACTER
+         </span><span style='color:#AAA'>  %0 character  %1 unicode index  %2 size  %3 width
+
          SEND OUTPUT            %0 raw text %1 size
          SENT OUTPUT            %0 raw text %1 size
 
@@ -1343,7 +1370,7 @@ Related</span><span style='color:#AAA'>: <a href='#PORT'>port</a>
 
 </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.11b                    </span><span style='color:#0AA'>#
+      #</span><span style='color:#AAA'>                    T I N T I N + +   2.02.12                     </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'>#
@@ -1523,9 +1550,9 @@ Related</span><span style='color:#AAA'>: <a href='#PORT'>port</a>
 
 </span><span style='color:#5F5'>         INDEX
 
-         On this page you'll find an introduction to using TinTin++. Additional
+</span><span style='color:#AAA'>         On this page you'll find an introduction to using TinTin++. Additional
          information can be found in the individual help sections.
-
+</span><span style='color:#5F5'>
          Starting and Ending
 </span><span style='color:#AAA'>
          The syntax for starting TinTin++ is: ./tt++ [command file]
@@ -1804,6 +1831,7 @@ Command</span><span style='color:#AAA'>: #alias </span><span style='color:#FFF'>
          #info session will show information on the session.
          #info sessions will show information on all sessions.
          #info system will show some system information.
+         #info tokenizer will show information about the script stack.
          #info unicode will show information on the provided character.
 
 </span><span style='color:#FFF'>Related</span><span style='color:#AAA'>: <a href='#CLASS'>class</a>, <a href='#DEBUG'>debug</a>, <a href='#IGNORE'>ignore</a>, <a href='#KILL'>kill</a> and <a href='#MESSAGE'>message</a>.
@@ -1871,19 +1899,19 @@ Terminal -&gt; Window Settings -&gt; Emulation.
 </span><span style='color:#5F5'>         LINE
 
 </span><span style='color:#FFF'>Command</span><span style='color:#AAA'>: #line </span><span style='color:#FFF'>{</span><span style='color:#AAA'>option</span><span style='color:#FFF'>} {</span><span style='color:#AAA'>argument</span><span style='color:#FFF'>}</span><span style='color:#AAA'>
-</span><span style='color:#5F5'>
-         Line sub commands that alter the argument.
-</span><span style='color:#AAA'>
+
+         </span><span style='color:#5F5'>Line options that alter the argument.
+
          </span><span style='color:#FFF'>#line strip &lt;argument&gt;
          </span><span style='color:#AAA'>  Argument is executed with all color codes stripped.
 
          </span><span style='color:#FFF'>#line substitute &lt;options&gt; &lt;argument&gt;
          </span><span style='color:#AAA'>  Argument is executed using the provided substitutions, available
-           options are: arguments, colors, escapes, functions, secure, and
-           variables.
-</span><span style='color:#5F5'>
-         Line sub commands that alter how the line is executed.
-</span><span style='color:#AAA'>
+           options are: arguments, braces, colors, escapes, functions, secure,
+           and variables.
+
+         </span><span style='color:#5F5'>Line options that alter how the line is executed.
+
          </span><span style='color:#FFF'>#line background &lt;argument&gt;
          </span><span style='color:#AAA'>  Prevent new session activation.
 
@@ -2282,12 +2310,36 @@ Terminal -&gt; Window Settings -&gt; Emulation.
 
 </span><span style='color:#5F5'>         LOG
 
-</span><span style='color:#FFF'>Command</span><span style='color:#AAA'>: #log </span><span style='color:#FFF'>{</span><span style='color:#AAA'>append</span><span style='color:#FFF'>|</span><span style='color:#AAA'>overwrite</span><span style='color:#FFF'>|</span><span style='color:#AAA'>off</span><span style='color:#FFF'>} {</span><span style='color:#AAA'>[filename]</span><span style='color:#FFF'>}</span><span style='color:#AAA'>
+</span><span style='color:#FFF'>Command</span><span style='color:#AAA'>: #log </span><span style='color:#FFF'>{</span><span style='color:#AAA'>option</span><span style='color:#FFF'>} {</span><span style='color:#AAA'>argument</span><span style='color:#FFF'>}</span><span style='color:#AAA'>
+
+         The log command allows logging session output to file. You can set the
+         data type to either plain, raw, or html with the config command.
 
-         Logs session output to a file, you can set the data type to either
-         plain, raw, or html with the config command.
+         </span><span style='color:#FFF'>#log append &lt;filename&gt;
+         </span><span style='color:#AAA'>  Start logging to the given file, if the file already exists it won't
+           be overwritten and data will be appended to the end.
 
-</span><span style='color:#FFF'>Related</span><span style='color:#AAA'>: <a href='#READ'>read</a>, <a href='#SCAN'>scan</a>, <a href='#TEXTIN'>textin</a> and <a href='#WRITE'>write</a>.
+         </span><span style='color:#FFF'>#log move &lt;filename_1&gt; &lt;filename_2&gt;
+         </span><span style='color:#AAA'>  Move filename_1 to filename_2. This can be any file and doesn't need
+           to be a log file.
+
+         </span><span style='color:#FFF'>#log overwrite &lt;filename&gt;
+         </span><span style='color:#AAA'>  Start logging to the given file, if the file already exists it will
+           be overwritten.
+
+         </span><span style='color:#FFF'>#log off
+         </span><span style='color:#AAA'>  Stop logging.
+
+         </span><span style='color:#FFF'>#log remove &lt;filename&gt;
+         </span><span style='color:#AAA'>  Remove the file. This can be any file and doesn't need to be a log
+           file.
+
+         </span><span style='color:#FFF'>#log timestamp &lt;format&gt;
+         </span><span style='color:#AAA'>  When set the timestamp will be prepended to each line logged to file.
+           The format will be formatted as a date using the strftime format
+           specifiers as described in #help time.
+
+</span><span style='color:#FFF'>Related</span><span style='color:#AAA'>: <a href='#READ'>read</a>, <a href='#SCAN'>scan</a>, <a href='#TEXTIN'>textin</a>, <a href='#TIME'>time</a> and <a href='#WRITE'>write</a>.
 <a name='LOOP'></a>
 
 </span><span style='color:#5F5'>         LOOP
@@ -2493,9 +2545,11 @@ Terminal -&gt; Window Settings -&gt; Emulation.
          </span><span style='color:#AAA'>  Lists all matching rooms and their distance. The following
            search keywords are supported.
 
+           {distance}    &lt;arg&gt; will list rooms within given distance.
            {roomarea}    &lt;arg&gt; will list rooms with matching area name.
            {roomdesc}    &lt;arg&gt; will list rooms with matching room desc.
            {roomexits}   &lt;arg&gt; will list rooms with identical room exits.
+                               Use * as an exit to ignore non pathdir exits.
            {roomflag}    &lt;arg&gt; will list rooms with matching room flags.
            {roomid}      &lt;arg&gt; will list rooms with identical id name.
            {roomname}    &lt;arg&gt; will list rooms with matching room name.
@@ -3988,8 +4042,11 @@ Related</span><span style='color:#AAA'>: <a href='#ALL'>all</a>, <a href='#PORT'
 
          Adds a word to the tab completion list, alphabetically sorted.
 
-         If no tabs are defined tintin will use the scrollback buffer
-         for auto tab completion.
+         If no tabs are defined tintin will use the scrollback buffer for auto
+         tab completion.
+
+         Tabbing behavior can be modified with the #cursor tab command which
+         by default is bound to the tab key.
 
 </span><span style='color:#FFF'>Comment</span><span style='color:#AAA'>: You can remove a tab with the #untab command.
 

+ 58 - 1
mods/igr.mods

@@ -1,3 +1,60 @@
+May 2022        2.02.12
+------------------------------------------------------------------------------
+input.c         Added RECEIVED INPUT CHARACTER event that triggers on each
+                character added to the input buffer. %0 holds the character,
+                %1 the unicode index, %2 the byte size, %3 the character's
+                display width.
+
+cursor.c        Added #cursor tab caseless option to make tab completion case
+                incensitive.
+
+dict.c          Added #cursor tab dictionary option to tab through the
+                dictionary.
+
+log.c           Added #log timestamp <format>. The format follows strftime as
+                described in #help time. Timestamps will be prepended to each
+                line of log output.
+
+log.c           Added #log move <filename> <filename> to move files.
+
+log.c           Added #log remove <filename> to remove files.
+
+variable.c      #format %r now ignores color and escape codes.
+
+data.c          Added the #info tokenizer option to have a peek at the stack
+                of the scripting engine. Use case example:
+
+                #event {RECEIVED ERROR}
+                {
+                    #echo <118>%h { TOKENIZER };
+                    #info tokenizer -1;
+                    #echo <118>%h
+                }
+
+path.c          #path load now automatically adds reverse directions.
+
+map.c           Added support for #map list {roomflag} {!void} etc.
+
+line.c          Added #line substitute braces which will turn { and } into
+                \x7B and \x7D.
+
+map.c           Added #map list {{distance}{5}} to list all rooms within a
+                weighted distance of 5. Keep in mind this goes by weight,
+                which starts at 1.0 and increases by 2.0 per room by default.
+
+cursor.c        Added #cursor flag eol {cr|lf|crlf|crnul|off} to change the
+                default end of line character between \r \n \r\n and \r\0.
+
+log.c           Changed logging to where it logs data before it's wrapped by
+                the client.
+
+map.c           Added support for roomsymbol lengths up to 5 characters in
+                unicode, and 6 characters in ascii graphics mode.
+
+map.c           Added the option to #map list/find to use * as a roomexit.
+                This will make the search ignore non-pathdir exits without
+                an exit direction.
+
 Mar 2021        2.02.11
 ------------------------------------------------------------------------------
 draw.c          #draw BALIGN will push text to the bottom if there aren't
@@ -37,7 +94,7 @@ math.c          Made #math / #if about 3x faster.
 
 math.c          Updated // to support powers other than 2 and 3.
 
-regex.c         Changed %w to match any letter, number, or undescore instead
+regex.c         Changed %w to match any letter, number, or underscore instead
                 of just letters, to make it match \w. Same for %W.
 
 Nov 2020        2.02.10

+ 11 - 0
src/banner.c

@@ -194,6 +194,17 @@ void banner_init(struct session *ses, char *arg1)
 	banner_website(ses, "Carrion Fields", "http://carrionfields.net", arg1);
 	banner_address(ses, "Carrion Fields", "cf carrionfields.net 4449", arg1);
 	banner_expires(ses, "Carrion Fields", "2026", arg1);
+
+	banner_create(ses, "RetroMUD", arg1);
+
+	banner_desc(ses, "RetroMUD",
+		"RetroMUD features over 100 levels of play, a huge array of character advancement\n"
+		"options, and dozens of quests across six different worlds. It's like six games\n"
+		"in one.", arg1);
+
+	banner_website(ses, "RetroMUD", "http://www.retromud.org", arg1);
+	banner_address(ses, "RetroMUD", "rm 96.126.116.118 3000", arg1);
+	banner_expires(ses, "RetroMUD", "2027", arg1);
 }
 
 int total_banners()

+ 11 - 11
src/buffer.c

@@ -280,6 +280,14 @@ void add_line_buffer(struct session *ses, char *line, int prompt)
 		port_socket_printf(ses, ses->proxy, "%s%s", ses->scroll->input, prompt ? "" : "\n");
 	}
 
+	if (!HAS_BIT(ses->log->mode, LOG_FLAG_LOW))
+	{
+		if (ses->log->file)
+		{
+			logit(ses, ses->scroll->input, ses->log->file, LOG_FLAG_LINEFEED);
+		}
+	}
+
 	ses->scroll->buffer[ses->scroll->used] = calloc(1, sizeof(struct buffer_data));
 
 	buffer = ses->scroll->buffer[ses->scroll->used];
@@ -302,14 +310,6 @@ void add_line_buffer(struct session *ses, char *line, int prompt)
 
 	str_cpy(&ses->scroll->input, "");
 
-	if (!HAS_BIT(ses->logmode, LOG_FLAG_LOW))
-	{
-		if (ses->logfile)
-		{
-			logit(ses, temp, ses->logfile, LOG_FLAG_LINEFEED);
-		}
-	}
-
 	if (gtd->chat)
 	{
 		chat_forward_session(ses, temp);
@@ -1067,15 +1067,15 @@ DO_BUFFER(buffer_write)
 		{
 			show_message(ses, LIST_COMMAND, "#OK: WRITING BUFFER TO '%s'.", arg1);
 
-			loginit(ses, fp, ses->logmode + LOG_FLAG_OVERWRITE);
+			logheader(ses, fp, ses->log->mode + LOG_FLAG_OVERWRITE);
 
 			for (cnt = 0 ; cnt < ses->scroll->used ; cnt++)
 			{
-				if (HAS_BIT(ses->logmode, LOG_FLAG_PLAIN))
+				if (HAS_BIT(ses->log->mode, LOG_FLAG_PLAIN))
 				{
 					strip_vt102_codes(ses->scroll->buffer[cnt]->str, arg2);
 				}
-				else if (HAS_BIT(ses->logmode, LOG_FLAG_HTML))
+				else if (HAS_BIT(ses->log->mode, LOG_FLAG_HTML))
 				{
 					vt102_to_html(ses, ses->scroll->buffer[cnt]->str, arg2);
 				}

+ 13 - 13
src/config.c

@@ -477,11 +477,11 @@ DO_CONFIG(config_loglevel)
 	{
 		if (is_abbrev(arg2, "LOW"))
 		{
-			SET_BIT(ses->logmode, LOG_FLAG_LOW);
+			SET_BIT(ses->log->mode, LOG_FLAG_LOW);
 		}
 		else if (is_abbrev(arg2, "HIGH"))
 		{
-			DEL_BIT(ses->logmode, LOG_FLAG_LOW);
+			DEL_BIT(ses->log->mode, LOG_FLAG_LOW);
 		}
 		else
 		{
@@ -490,7 +490,7 @@ DO_CONFIG(config_loglevel)
 			return NULL;
 		}
 	}
-	strcpy(arg2, HAS_BIT(ses->logmode, LOG_FLAG_LOW) ? "LOW" : "HIGH");
+	strcpy(arg2, HAS_BIT(ses->log->mode, LOG_FLAG_LOW) ? "LOW" : "HIGH");
 
 	return ses;
 }
@@ -502,21 +502,21 @@ DO_CONFIG(config_logmode)
 	{
 		if (is_abbrev(arg2, "HTML"))
 		{
-			SET_BIT(ses->logmode, LOG_FLAG_HTML);
-			DEL_BIT(ses->logmode, LOG_FLAG_PLAIN);
-			DEL_BIT(ses->logmode, LOG_FLAG_RAW);
+			SET_BIT(ses->log->mode, LOG_FLAG_HTML);
+			DEL_BIT(ses->log->mode, LOG_FLAG_PLAIN);
+			DEL_BIT(ses->log->mode, LOG_FLAG_RAW);
 		}
 		else if (is_abbrev(arg2, "PLAIN"))
 		{
-			DEL_BIT(ses->logmode, LOG_FLAG_HTML);
-			SET_BIT(ses->logmode, LOG_FLAG_PLAIN);
-			DEL_BIT(ses->logmode, LOG_FLAG_RAW);
+			DEL_BIT(ses->log->mode, LOG_FLAG_HTML);
+			SET_BIT(ses->log->mode, LOG_FLAG_PLAIN);
+			DEL_BIT(ses->log->mode, LOG_FLAG_RAW);
 		}
 		else if (is_abbrev(arg2, "RAW"))
 		{
-			DEL_BIT(ses->logmode, LOG_FLAG_HTML);
-			DEL_BIT(ses->logmode, LOG_FLAG_PLAIN);
-			SET_BIT(ses->logmode, LOG_FLAG_RAW);
+			DEL_BIT(ses->log->mode, LOG_FLAG_HTML);
+			DEL_BIT(ses->log->mode, LOG_FLAG_PLAIN);
+			SET_BIT(ses->log->mode, LOG_FLAG_RAW);
 		}
 		else
 		{
@@ -525,7 +525,7 @@ DO_CONFIG(config_logmode)
 			return NULL;
 		}
 	}
-	strcpy(arg2, HAS_BIT(ses->logmode, LOG_FLAG_HTML) ? "HTML" : HAS_BIT(ses->logmode, LOG_FLAG_PLAIN) ? "PLAIN" : "RAW");
+	strcpy(arg2, HAS_BIT(ses->log->mode, LOG_FLAG_HTML) ? "HTML" : HAS_BIT(ses->log->mode, LOG_FLAG_PLAIN) ? "PLAIN" : "RAW");
 
 	return ses;
 }

+ 246 - 150
src/cursor.c

@@ -896,7 +896,7 @@ DO_CURSOR(cursor_delete)
 			{
 				break;
 			}
-			size = get_utf8_width(&gtd->ses->input->buf[gtd->ses->input->raw_pos], &width);
+			size = get_utf8_width(&gtd->ses->input->buf[gtd->ses->input->raw_pos], &width, NULL);
 
 			if (width)
 			{
@@ -950,7 +950,7 @@ DO_CURSOR(cursor_delete_word_left)
 
 	while (span_raw < index_raw)
 	{
-		span_raw += get_vt102_width(gtd->ses, &gtd->ses->input->buf[gtd->ses->input->raw_pos], &width);
+		span_raw += get_vt102_width(gtd->ses, &gtd->ses->input->buf[span_raw], &width);
 
 		gtd->ses->input->str_pos -= width;
 	}
@@ -1180,10 +1180,18 @@ DO_CURSOR(cursor_enter_finish)
 	ses->input->raw_pos = 0;
 	ses->input->str_pos = 0;
 
+	ses->input->str_off = 1;
 	ses->input->str_hid = 0;
 
 	DEL_BIT(gtd->ses->input->flags, INPUT_FLAG_EDIT);
 
+	if (ses == gtd->ses && gtd->ses->scroll->line != -1)
+	{
+		cursor_check_line(gtd->ses, "");
+
+		buffer_end(gtd->ses, "", "", "");
+	}
+
 	if (ses == gtd->ses && HAS_BIT(gtd->ses->flags, SES_FLAG_SPLIT))
 	{
 		cursor_redraw_line(gtd->ses, "");
@@ -1197,6 +1205,57 @@ DO_CURSOR(cursor_flag)
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
 
+	if (is_abbrev(arg1, "EOL"))
+	{
+		if (*arg2 == 0)
+		{
+			TOG_BIT(ses->telopts, TELOPT_FLAG_CR|TELOPT_FLAG_LF);
+		}
+		else if (!strcasecmp(arg2, "CR"))
+		{
+			SET_BIT(ses->telopts, TELOPT_FLAG_CR);
+			DEL_BIT(ses->telopts, TELOPT_FLAG_LF);
+			DEL_BIT(ses->telopts, TELOPT_FLAG_NUL);
+		}
+		else if (!strcasecmp(arg2, "LF"))
+		{
+			DEL_BIT(ses->telopts, TELOPT_FLAG_CR);
+			SET_BIT(ses->telopts, TELOPT_FLAG_LF);
+			DEL_BIT(ses->telopts, TELOPT_FLAG_NUL);
+		}
+		else if (!strcasecmp(arg2, "CRLF") || !strcasecmp(arg2, "ON"))
+		{
+			SET_BIT(ses->telopts, TELOPT_FLAG_CR);
+			SET_BIT(ses->telopts, TELOPT_FLAG_LF);
+			DEL_BIT(ses->telopts, TELOPT_FLAG_NUL);
+		}
+		else if (!strcasecmp(arg2, "CRNUL"))
+		{
+			SET_BIT(ses->telopts, TELOPT_FLAG_CR);
+			DEL_BIT(ses->telopts, TELOPT_FLAG_LF);
+			SET_BIT(ses->telopts, TELOPT_FLAG_NUL);
+		}
+		else if (!strcasecmp(arg2, "OFF"))
+		{
+			DEL_BIT(ses->telopts, TELOPT_FLAG_CR);
+			DEL_BIT(ses->telopts, TELOPT_FLAG_LF);
+			DEL_BIT(ses->telopts, TELOPT_FLAG_NUL);
+		}
+		else
+		{
+			show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {FLAG} {EOL} {CR|LF|CRLF|CRNUL|OFF}.");
+			return;
+		}
+
+		show_message(gtd->ses, LIST_COMMAND, "#CURSOR FLAG EOL HAS BEEN SET TO: %s",
+			HAS_BIT(ses->telopts, TELOPT_FLAG_CR|TELOPT_FLAG_LF) == 0 ? "OFF" :
+			HAS_BIT(ses->telopts, TELOPT_FLAG_CR|TELOPT_FLAG_NUL) == (TELOPT_FLAG_CR|TELOPT_FLAG_NUL) ? "CRNUL" :
+			HAS_BIT(ses->telopts, TELOPT_FLAG_CR|TELOPT_FLAG_LF) == TELOPT_FLAG_CR ? "CR" :
+			HAS_BIT(ses->telopts, TELOPT_FLAG_CR|TELOPT_FLAG_LF) == TELOPT_FLAG_LF ? "LF" : "CRLF");
+
+		return;
+	}
+
 	if (is_abbrev(arg1, "ECHO"))
 	{
 		if (*arg2 == 0)
@@ -1218,7 +1277,7 @@ DO_CURSOR(cursor_flag)
 		return;
 	}
 
-	if (is_abbrev(arg1, "INSERT"))
+	if (is_abbrev(arg1, "INSERT") || is_abbrev(arg1, "OVERTYPE"))
 	{
 		if (*arg2 == 0)
 		{
@@ -1239,7 +1298,7 @@ DO_CURSOR(cursor_flag)
 		return;
 	}
 
-	show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {FLAG} {ECHO|INSERT} {ON|OFF}.");
+	show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {FLAG} {ECHO|EOL|INSERT} {ON|OFF}.");
 }
 
 DO_CURSOR(cursor_get)
@@ -1765,7 +1824,7 @@ DO_CURSOR(cursor_move_left_word)
 
 	while (span_raw < index_raw)
 	{
-		span_raw += get_vt102_width(gtd->ses, &gtd->ses->input->buf[gtd->ses->input->raw_pos], &width);
+		span_raw += get_vt102_width(gtd->ses, &gtd->ses->input->buf[span_raw], &width);
 
 		gtd->ses->input->str_pos -= width;
 	}
@@ -1805,7 +1864,7 @@ DO_CURSOR(cursor_move_right)
 				{
 					break;
 				}
-				size = get_utf8_width(&gtd->ses->input->buf[gtd->ses->input->raw_pos], &width);
+				size = get_utf8_width(&gtd->ses->input->buf[gtd->ses->input->raw_pos], &width, NULL);
 
 				if (width)
 				{
@@ -2336,86 +2395,7 @@ DO_CURSOR(cursor_info)
 	original tab cycling by Ben Love
 */
 
-
-DO_CURSOR(cursor_tab)
-{
-	char arg1[BUFFER_SIZE];
-	int flags = 0;
-
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
-
-	while (*arg)
-	{
-		if (is_abbrev(arg1, "LIST"))
-		{
-			SET_BIT(flags, TAB_FLAG_LIST);
-		}
-		else if (is_abbrev(arg1, "SCROLLBACK"))
-		{
-			SET_BIT(flags, TAB_FLAG_SCROLLBACK);
-		}
-		else if (is_abbrev(arg1, "COMPLETE"))
-		{
-			SET_BIT(flags, TAB_FLAG_COMPLETE);
-		}
-
-		arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
-
-		if (*arg == COMMAND_SEPARATOR)
-		{
-			arg++;
-		}
-	}
-
-	if (is_abbrev(arg1, "FORWARD"))
-	{
-		if (!HAS_BIT(flags, TAB_FLAG_COMPLETE) && inputline_editor())
-		{
-			sprintf(arg1, "%*s", gtd->ses->tab_width, "");
-
-			inputline_insert(arg1, -1);
-
-			return cursor_redraw_line(ses, arg);
-		}
-
-		if (!HAS_BIT(flags, TAB_FLAG_LIST|TAB_FLAG_SCROLLBACK))
-		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB {LIST|SCROLLBACK} FORWARD");
-		}
-		else
-		{
-			cursor_tab_forward(ses, ntos(flags));
-		}
-		SET_BIT(flags, TAB_FLAG_FORWARD);
-	}
-	else if (is_abbrev(arg1, "BACKWARD"))
-	{
-		if (!HAS_BIT(flags, TAB_FLAG_COMPLETE) && inputline_editor())
-		{
-			sprintf(arg1, "%*s", gtd->ses->tab_width, "");
-			
-			inputline_insert(arg1, 0);
-
-			return cursor_redraw_line(ses, arg);
-		}
-
-		if (!HAS_BIT(flags, TAB_FLAG_LIST|TAB_FLAG_SCROLLBACK))
-		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB {LIST|SCROLLBACK} BACKWARD");
-		}
-		else
-		{
-			cursor_tab_backward(ses, ntos(flags));
-		}
-		SET_BIT(flags, TAB_FLAG_BACKWARD);
-	}
-	else
-	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB {LIST;SCROLLBACK} <BACKWARD|FORWARD>");
-	}
-}
-
-int cursor_tab_add(int stop_after_first)
+int cursor_tab_add(int flag)
 {
 	struct listroot *tab_root = gtd->ses->list[LIST_TAB];
 	struct listroot *cmd_root = gtd->ses->list[LIST_COMMAND];
@@ -2432,31 +2412,42 @@ int cursor_tab_add(int stop_after_first)
 		{
 			node = tab_root->list[tab_root->update];
 
-			if (*node->arg1 == *tail && !strncmp(node->arg1, tail, tail_len))
+			if (HAS_BIT(flag, TAB_FLAG_CASELESS))
 			{
-				if (search_node_list(cmd_root, node->arg1))
+				if (strncasecmp(node->arg1, tail, tail_len) != 0)
 				{
 					continue;
 				}
-				create_node_list(cmd_root, node->arg1, "", "", "");
-
-				if (node->shots && --node->shots == 0)
+			}
+			else
+			{
+				if (*node->arg1 != *tail || strncmp(node->arg1, tail, tail_len) != 0)
 				{
-					delete_node_list(gtd->ses, LIST_TAB, node);
+					continue;
 				}
+			}
 
-				if (stop_after_first)
-				{
-					return TRUE;
-				}
+			if (search_node_list(cmd_root, node->arg1))
+			{
+				continue;
+			}
+			create_node_list(cmd_root, node->arg1, "", "", "");
+
+			if (node->shots && --node->shots == 0)
+			{
+				delete_node_list(gtd->ses, LIST_TAB, node);
+			}
+
+			if (HAS_BIT(flag, TAB_FLAG_FORWARD))
+			{
+				return TRUE;
 			}
 		}
 	}
 	return FALSE;
 }
 
-
-int cursor_scrollback_tab_add(int stop_after_first)
+int cursor_scrollback_tab_add(int flag)
 {
 	char tab[BUFFER_SIZE], buf[BUFFER_SIZE];
 	struct listroot *root = gtd->ses->list[LIST_COMMAND];
@@ -2494,71 +2485,83 @@ int cursor_scrollback_tab_add(int stop_after_first)
 				ptb++;
 			}
 
-			if (*ptb == *tail && !strncmp(ptb, tail, tail_len))
+			if (HAS_BIT(flag, TAB_FLAG_CASELESS))
 			{
-				ptt = tab;
-
-				for (tab_len = 0 ; tab_len < tail_len ; tab_len++)
+				if (strncasecmp(ptb, tail, tail_len) != 0)
 				{
-					*ptt++ = *ptb++;
+					goto end;
 				}
-
-				while (*ptb && *ptb != ' ')
+			}
+			else
+			{
+				if (*ptb != *tail || strncmp(ptb, tail, tail_len) != 0)
 				{
-					switch (*ptb)
-					{
-						case ';':
-						case '.':
-						case ',':
-						case '!':
-						case '?':
-						case ':':
-						case '"':
-							*ptt++ = 0;
-							ptb++;
-							break;
-
-						default:
-							*ptt++ = *ptb++;
-							break;
-					}
+					goto end;
 				}
-				*ptt = 0;
+			}
+			ptt = tab;
+
+			for (tab_len = 0 ; tab_len < tail_len ; tab_len++)
+			{
+				*ptt++ = *ptb++;
+			}
 
-				if (search_node_list(gtd->ses->list[LIST_COMMAND], tab))
+			while (*ptb && *ptb != ' ')
+			{
+				switch (*ptb)
 				{
-					continue;
+					case ';':
+					case '.':
+					case ',':
+					case '!':
+					case '?':
+					case ':':
+					case '"':
+						*ptt++ = 0;
+						ptb++;
+						break;
+
+					default:
+						*ptt++ = *ptb++;
+						break;
 				}
+			}
+			*ptt = 0;
 
-				node = create_node_list(gtd->ses->list[LIST_COMMAND], tab, "", "", "");
+			if (search_node_list(gtd->ses->list[LIST_COMMAND], tab))
+			{
+				goto end;
+			}
 
-				node->val32[0] = scroll_cnt;
+			node = create_node_list(gtd->ses->list[LIST_COMMAND], tab, "", "", "");
 
-				if (stop_after_first)
-				{
-					return TRUE;
-				}
+			node->val32[0] = scroll_cnt;
 
-				if (root->used > 100)
-				{
-					return FALSE;
-				}
+			if (HAS_BIT(flag, TAB_FLAG_FORWARD))
+			{
+				return TRUE;
 			}
 
+			if (root->used > 100)
+			{
+				return FALSE;
+			}
+
+			end:
+
 			while (*ptb && !is_space(*ptb))
 			{
 				ptb++;
 			}
 		}
 	}
-
 	return FALSE;
 }
 
-DO_CURSOR(cursor_tab_forward)
+void cursor_tab_forward(struct session *ses, int flag)
 {
 	struct listroot *root = gtd->ses->list[LIST_COMMAND];
-	int tab_found, flags;
+	int tab_found;
 
 	if (inputline_tab_valid() == FALSE)
 	{
@@ -2576,16 +2579,19 @@ DO_CURSOR(cursor_tab_forward)
 
 	tab_found = 0;
 
-	flags = atoi(arg);
+	if (tab_found == 0 && HAS_BIT(flag, TAB_FLAG_LIST))
+	{
+		tab_found = cursor_tab_add(flag);
+	}
 
-	if (tab_found == 0 && HAS_BIT(flags, TAB_FLAG_LIST))
+	if (tab_found == 0 && HAS_BIT(flag, TAB_FLAG_SCROLLBACK))
 	{
-		tab_found = cursor_tab_add(TRUE);
+		tab_found = cursor_scrollback_tab_add(flag);
 	}
 
-	if (tab_found == 0 && HAS_BIT(flags, TAB_FLAG_SCROLLBACK))
+	if (tab_found == 0 && HAS_BIT(flag, TAB_FLAG_DICTIONARY))
 	{
-		tab_found = cursor_scrollback_tab_add(TRUE);
+		tab_found = cursor_dictionary_tab_add(flag);
 	}
 
 	if (tab_found == 0)
@@ -2601,10 +2607,9 @@ DO_CURSOR(cursor_tab_forward)
 	cursor_end(ses, "");
 }
 
-DO_CURSOR(cursor_tab_backward)
+void cursor_tab_backward(struct session *ses, int flag)
 {
 	struct listroot *root = ses->list[LIST_COMMAND];
-	int flags;
 
 	if (inputline_tab_valid() == FALSE)
 	{
@@ -2624,16 +2629,19 @@ DO_CURSOR(cursor_tab_backward)
 
 		inputline_cap("");
 
-		flags = atoi(arg);
+		if (HAS_BIT(flag, TAB_FLAG_LIST))
+		{
+			cursor_tab_add(flag);
+		}
 
-		if (HAS_BIT(flags, TAB_FLAG_LIST))
+		if (HAS_BIT(flag, TAB_FLAG_SCROLLBACK))
 		{
-			cursor_tab_add(FALSE);
+			cursor_scrollback_tab_add(flag);
 		}
 
-		if (HAS_BIT(flags, TAB_FLAG_SCROLLBACK))
+		if (HAS_BIT(flag, TAB_FLAG_DICTIONARY))
 		{
-			cursor_scrollback_tab_add(FALSE);
+			cursor_dictionary_tab_add(flag);
 		}
 	}
 	else
@@ -2645,3 +2653,91 @@ DO_CURSOR(cursor_tab_backward)
 
 	cursor_end(ses, "");
 }
+
+DO_CURSOR(cursor_tab)
+{
+	char arg1[BUFFER_SIZE];
+	int flag = 0;
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+
+	while (*arg)
+	{
+		if (is_abbrev(arg1, "CASELESS"))
+		{
+			SET_BIT(flag, TAB_FLAG_CASELESS);
+		}
+		else if (is_abbrev(arg1, "COMPLETE"))
+		{
+			SET_BIT(flag, TAB_FLAG_COMPLETE);
+		}
+		else if (is_abbrev(arg1, "DICTIONARY"))
+		{
+			SET_BIT(flag, TAB_FLAG_DICTIONARY);
+		}
+		else if (is_abbrev(arg1, "LIST"))
+		{
+			SET_BIT(flag, TAB_FLAG_LIST);
+		}
+		else if (is_abbrev(arg1, "SCROLLBACK"))
+		{
+			SET_BIT(flag, TAB_FLAG_SCROLLBACK);
+		}
+
+		arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+
+		if (*arg == COMMAND_SEPARATOR)
+		{
+			arg++;
+		}
+	}
+
+	if (is_abbrev(arg1, "FORWARD"))
+	{
+		SET_BIT(flag, TAB_FLAG_FORWARD);
+
+		if (!HAS_BIT(flag, TAB_FLAG_COMPLETE) && inputline_editor())
+		{
+			sprintf(arg1, "%*s", gtd->ses->tab_width, "");
+
+			inputline_insert(arg1, -1);
+
+			return cursor_redraw_line(ses, arg);
+		}
+
+		if (!HAS_BIT(flag, TAB_FLAG_DICTIONARY|TAB_FLAG_LIST|TAB_FLAG_SCROLLBACK))
+		{
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB {DICTIONARY|LIST|SCROLLBACK} FORWARD");
+		}
+		else
+		{
+			cursor_tab_forward(ses, flag);
+		}
+	}
+	else if (is_abbrev(arg1, "BACKWARD"))
+	{
+		SET_BIT(flag, TAB_FLAG_BACKWARD);
+
+		if (!HAS_BIT(flag, TAB_FLAG_COMPLETE) && inputline_editor())
+		{
+			sprintf(arg1, "%*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))
+		{
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB {DICTIONARY|LIST|SCROLLBACK} BACKWARD");
+		}
+		else
+		{
+			cursor_tab_backward(ses, flag);
+		}
+	}
+	else
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB {DICTIONARY;LIST;SCROLLBACK} <BACKWARD|FORWARD>");
+	}
+}

+ 56 - 29
src/data.c

@@ -27,6 +27,8 @@
 
 #include <limits.h>
 
+extern char **environ;
+
 struct listroot *init_list(struct session *ses, int type, int size)
 {
 	struct listroot *listhead;
@@ -102,23 +104,25 @@ struct listroot *copy_list(struct session *ses, struct listroot *sourcelist, int
 					break;
 
 				case LIST_BUTTON:
-				case LIST_DELAY:
 				case LIST_EVENT:
-				case LIST_TICKER:
+//				case LIST_TICKER:
 				case LIST_PATHDIR:
 					node->val64 = sourcelist->list[i]->val64;
-/*
-					node->val16[0] = sourcelist->list[i]->val16[0];
-					node->val16[1] = sourcelist->list[i]->val16[1];
-					node->val16[2] = sourcelist->list[i]->val16[2];
-					node->val16[3] = sourcelist->list[i]->val16[3];
-*/
 					break;
 
 				case LIST_VARIABLE:
 					copy_nest_node(ses->list[type], node, sourcelist->list[i]);
 					break;
 
+				case LIST_TICKER:
+					node->val64 = gtd->utime + (long long) (tintoi(node->arg3) * 1000000.0);
+
+					if (node->val64 < gtd->utime_next_tick)
+					{
+						gtd->utime_next_tick = node->val64;
+					}
+					break;
+
 				default:
 					if (sourcelist->list[i]->val64)
 					{
@@ -161,26 +165,6 @@ struct listnode *create_node_list(struct listroot *root, char *arg1, char *arg2,
 
 //	printf("debug: %p [%p] (%d) (%s) (%s)\n", root, root->ses, root->type, node->arg1, node->arg3);
 
-	switch (root->type)
-	{
-		case LIST_DELAY:
-			node->val64 = (long long) tintoi(node->arg1);
-
-			if (node->val64 < gtd->utime_next_delay)
-			{
-				gtd->utime_next_delay = node->val64;
-			}
-			break;
-
-		case LIST_TICKER:
-			node->val64 = gtd->utime + (long long) tintoi(arg3) * 1000000.0;
-
-			if (node->val64 < gtd->utime_next_tick)
-			{
-				gtd->utime_next_tick = node->val64;
-			}
-			break;
-	}
 
 	if (gtd->level->shots)
 	{
@@ -202,6 +186,25 @@ struct listnode *create_node_list(struct listroot *root, char *arg1, char *arg2,
 		case LIST_SUBSTITUTE:
 			node->regex = tintin_regexp_compile(root->ses, node, node->arg1, 0);
 			break;
+
+		case LIST_DELAY:
+			node->val64 = (long long) tintoi(node->arg1);
+
+			if (node->val64 < gtd->utime_next_delay)
+			{
+				gtd->utime_next_delay = node->val64;
+			}
+			break;
+
+		case LIST_TICKER:
+			node->val64 = gtd->utime + (long long) (tintoi(arg3) * 1000000.0);
+
+			if (node->val64 < gtd->utime_next_tick)
+			{
+				gtd->utime_next_tick = node->val64;
+			}
+			break;
+
 	}
 
 	return insert_node_list(root, node);
@@ -1327,6 +1330,13 @@ DO_COMMAND(do_info)
 
 		switch (*arg1 % 32)
 		{
+			case CTRL_B:
+				if (is_abbrev(arg1, "BIG5TOUTF8"))
+				{
+					big5toutf8_info(ses);
+				}
+				break;
+
 			case CTRL_C:
 				if (is_abbrev(arg1, "CPU"))
 				{
@@ -1607,13 +1617,26 @@ DO_COMMAND(do_info)
 				}
 				break;
 
+			case CTRL_T:
+				if (is_abbrev(arg1, "TOKENIZER"))
+				{
+					int index = URANGE(0, gtd->script_index + atoi(arg2), gtd->script_index);
+					struct scriptroot *root = gtd->script_stack[index];
+
+					tintin_printf2(ses, "#INFO TOKENIZER: SCRIPT_INDEX = %d", index);
+					tintin_printf2(ses, "#INFO TOKENIZER: SESSION_NAME = %s", root->ses->name);
+					tintin_printf2(ses, "#INFO TOKENIZER: LIST_TYPE    = %s", list_table[root->list].name);
+					tintin_printf2(ses, "#INFO TOKENIZER: LOCAL_VARS   = %d", root->local->used);
+					tintin_printf2(ses, "#INFO TOKENIZER: SCRIPT       =\n%s", view_script(ses, root));
+				}
+				break;
 			case CTRL_U:
 				if (is_abbrev(arg1, "UNICODE"))
 				{
 					int size, width, index;
 
 					size = get_utf8_size(arg2);
-					get_utf8_width(arg2, &width);
+					get_utf8_width(arg2, &width, NULL);
 					get_utf8_index(arg2, &index);
 
 					tintin_printf2(ses, "#INFO UNICODE: %s:  is_utf8_head  = %d (%s)", arg2, is_utf8_head(arg2), is_utf8_head(arg2) ? "true" : "false");
@@ -1622,6 +1645,10 @@ DO_COMMAND(do_info)
 					tintin_printf2(ses, "#INFO UNICODE: %s: get_utf8_index = %d (decimal)", arg2, index);
 					tintin_printf2(ses, "#INFO UNICODE: %s: get_utf8_index = %x (hexadecimal)", arg2, index);
 				}
+				else if (is_abbrev(arg1, "UTF8TOBIG5"))
+				{
+					utf8tobig5_info(ses);
+				}
 				break;
 		}
 		if (*gtd->is_result == 0)

+ 80 - 1
src/dict.c

@@ -176,6 +176,82 @@ int spellcheck_count(struct session *ses, char *in)
 	return cnt;
 }
 
+int cursor_dictionary_tab_add(int flag)
+{
+	struct listroot *cmd_root = gtd->ses->list[LIST_COMMAND];
+	struct listnode *node;
+	char *tail, *word, buf[50];
+	int tail_len, i, hash, val;
+
+	if (dictionary == NULL)
+	{
+		dictionary_init();
+	}
+
+	tail     = cmd_root->list[0]->arg1;
+	tail_len = str_len(tail);
+
+	if (!is_alpha(*tail))
+	{
+		return FALSE;
+	}
+
+	hash = tolower((int) *tail) - 'a';
+
+	i = URANGE(0, cmd_root->list[cmd_root->used - 1]->val32[1], cmd_root->used - 1);
+
+	for ( ; i < dictionary->listsize[hash] ; i++)
+	{
+		word = wordlist[hash] + dictionary->wordindex[hash][i];
+
+		if (HAS_BIT(flag, TAB_FLAG_CASELESS))
+		{
+			val = strncasecmp(word, tail + 1, tail_len - 1);
+		}
+		else
+		{
+			if (*word < tail[1])
+			{
+				continue;
+			}
+			val = strncmp(word, tail + 1, tail_len - 1);
+		}
+
+		if (val < 0)
+		{
+			continue;
+		}
+
+		if (val > 0)
+		{
+			return FALSE;
+		}
+
+		buf[0] = tail[0];
+		strcpy(buf + 1, word);
+
+		if (search_node_list(cmd_root, buf))
+		{
+			continue;
+		}
+
+		node = create_node_list(cmd_root, buf, "", "", "");
+
+		node->val32[1] = i;
+
+		if (HAS_BIT(flag, TAB_FLAG_FORWARD))
+		{
+			return TRUE;
+		}
+
+		if (cmd_root->used > 100)
+		{
+			return FALSE;
+		}
+	}
+	return FALSE;
+}
+
 DO_COMMAND(do_dictionary)
 {
 	int hash, index;
@@ -191,7 +267,10 @@ DO_COMMAND(do_dictionary)
 	{
 		show_message(ses, LIST_COMMAND, "#SYNTAX: #DICTIONARY {WORD}");
 
-		wordlist[0][0] = 0;
+		for (hash = 0 ; hash < 26 ; hash++)
+		{
+			printf("hash %c = %d\n", 'A' + hash, dictionary->listsize[hash]);
+		}
 
 		return ses;
 	}

+ 5 - 3
src/draw.c

@@ -117,7 +117,7 @@ struct draw_type draw_table[] =
 	{       "LINE",      "Draw a line.",                      DRAW_FLAG_NONE, draw_line },
 	{       "MAP",       "Draw the map.",                     DRAW_FLAG_NONE, draw_map },
 	{       "RAIN",      "Draw digital rain.",                DRAW_FLAG_NONE, draw_rain },
-	{       "SIDE",      "Draw a line with corners.",         DRAW_FLAG_BOXED, draw_side },
+	{       "SIDE",      "Draw a line with corners.",         DRAW_FLAG_CORNERED, draw_side },
 	{       "TABLE",     "Draw a table.",                     DRAW_FLAG_BOXED|DRAW_FLAG_LEFT|DRAW_FLAG_RIGHT|DRAW_FLAG_TOP|DRAW_FLAG_BOT, draw_table_grid },
 	{       "TILE",      "Draw a tile.",                      DRAW_FLAG_NONE, draw_square },
 	{       "",          "",                                  DRAW_FLAG_NONE, NULL }
@@ -444,8 +444,10 @@ DO_COMMAND(do_draw)
 	{
 		if (is_abbrev(arg1, draw_table[index].name))
 		{
-			arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
-			arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
+			arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
+			arg = get_arg_in_braces(ses, arg, arg2, GET_ONE);
+//			arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+//			arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
 
 			top_row = get_row_index_arg(ses, arg1);
 			top_col = get_col_index_arg(ses, arg2);

+ 2 - 2
src/event.c

@@ -182,9 +182,9 @@ int check_all_events(struct session *ses, int flags, int args, int vars, char *f
 		return 0;
 	}
 
-	sub = HAS_BIT(flags, SUB_SEC) ? SUB_ARG|SUB_SEC : SUB_ARG;
+	sub = HAS_BIT(flags, SUB_SEC) ? SUB_ARG|SUB_SEC : HAS_BIT(flags, SUB_BRA) ? SUB_ARG|SUB_BRA : SUB_ARG;
 
-	DEL_BIT(flags, SUB_ARG|SUB_SEC);
+	DEL_BIT(flags, SUB_ARG|SUB_SEC|SUB_BRA);
 
 	if (flags == 0)
 	{

+ 32 - 32
src/gui.h

@@ -132,7 +132,7 @@ char *tt_gui = "#line quiet #port init gui 0\n"
 "	#class world_tab kill;\n"
 "	#class profile_tab kill;\n"
 "\n"
-"	#draw tile 4 1 -4 26 {\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n};\n"
+"	#draw tile 4 1 -4 26 { };\n"
 "\n"
 "	#if {&worldlist[] == 0}\n"
 "	{\n"
@@ -160,7 +160,7 @@ char *tt_gui = "#line quiet #port init gui 0\n"
 "	#class world_tab kill;\n"
 "	#class profile_tab kill;\n"
 "\n"
-"	#draw tile 4 1 -4 26 {\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n};\n"
+"	#draw tile 4 1 -4 26 { };\n"
 "\n"
 "	#if {&info[BANNERS][] == 0}\n"
 "	{\n"
@@ -431,6 +431,8 @@ char *tt_gui = "#line quiet #port init gui 0\n"
 "\n"
 "	#line ignore #showme {<acf>Connecting to <ffa>$gui[new][NAME]<acf>..};\n"
 "\n"
+"	#config mouse off;\n"
+"\n"
 "	#buffer refresh;\n"
 "\n"
 "	#if {{$gui[new][SSL]} == {off}}\n"
@@ -563,6 +565,8 @@ char *tt_gui = "#line quiet #port init gui 0\n"
 "#alias {gui_reload}\n"
 "{\n"
 "	#split 1 3 27 27;\n"
+"	#config mouse on;\n"
+"\n"
 "	#screen clear split;\n"
 "	#screen inputregion -2 28 -2 -28 profile_tab_INPUT;\n"
 "\n"
@@ -592,7 +596,6 @@ char *tt_gui = "#line quiet #port init gui 0\n"
 "\n"
 "#alias {gui_init}\n"
 "{\n"
-"	#config mouse on;\n"
 "	#config scroll_lock off;\n"
 "\n"
 "	#class WORLDS assign #variable {worldlist} {};\n"
@@ -613,36 +616,33 @@ char *tt_gui = "#line quiet #port init gui 0\n"
 "\n"
 "	gui_reload;\n"
 "\n"
-"	#line verbose\n"
+"	#if {$gui[cols] > 75}\n"
 "	{\n"
-"		#if {$gui[cols] > 75}\n"
-"		{\n"
-"			#draw Silver huge traced scroll tile 1 1 6 73 { TINTIN++};\n"
-"			#draw Silver calign scroll tile 1 1 2 75 {}{$info[SYSTEM][CLIENT_VERSION]};\n"
-"			#draw Silver calign scroll tile 1 1 3 75 {}{Code by Peter Unold, Bill Reiss, and Igor van den Hoven}\n"
-"		};\n"
-"		#elseif {$gui[cols] > 40}\n"
-"		{\n"
-"			#draw Silver huge traced scroll tile 1 1 6 40 { TT++};\n"
-"			#draw Silver calign scroll tile 1 1 2 40 {}{$info[SYSTEM][CLIENT_VERSION]};\n"
-"			#draw Silver calign scroll tile 1 1 4 40 {}{Code by Peter Unold, Bill Reiss,}{}{and Igor van den Hoven}\n"
-"		};\n"
-"		#elseif {$gui[cols] > 18}\n"
-"		{\n"
-"			#draw Silver calign scroll tile 1 1 14 $gui[cols] {T I N T I N + +}{}{$info[SYSTEM][CLIENT_VERSION]}{}{Code by}{}{Peter Unold}{}{Bill Reiss}{}{and}{}{Igor van den Hoven};\n"
-"		};\n"
-"		#elseif {$gui[cols] > 8}\n"
-"		{\n"
-"			#draw Silver huge traced scroll tile 1 1 6 9 {T};\n"
-"			#draw Silver huge traced scroll tile 1 1 6 9 {T};\n"
-"			#draw Silver huge traced scroll tile 1 1 6 9 {+};\n"
-"			#draw Silver huge traced scroll tile 1 1 6 9 {+};\n"
-"			#draw Silver calign scroll tile 1 1 1 9 {$info[SYSTEM][CLIENT_VERSION]}\n"
-"		};\n"
-"		#elseif {$gui[cols] > 1}\n"
-"		{\n"
-"			#draw Silver calign scroll tile 1 1 8 $gui[cols] {T}{i}{n}{T}{i}{n}{+}{+}\n"
-"		}\n"
+"		#draw Silver huge traced scroll tile 1 1 6 73 { TINTIN++};\n"
+"		#draw Silver calign scroll tile 1 1 2 75 {}{$info[SYSTEM][CLIENT_VERSION]};\n"
+"		#draw Silver calign scroll tile 1 1 3 75 {}{Code by Peter Unold, Bill Reiss, and Igor van den Hoven}\n"
+"	};\n"
+"	#elseif {$gui[cols] > 40}\n"
+"	{\n"
+"		#draw Silver huge traced scroll tile 1 1 6 40 { TT++};\n"
+"		#draw Silver calign scroll tile 1 1 2 40 {}{$info[SYSTEM][CLIENT_VERSION]};\n"
+"		#draw Silver calign scroll tile 1 1 4 40 {}{Code by Peter Unold, Bill Reiss,}{}{and Igor van den Hoven}\n"
+"	};\n"
+"	#elseif {$gui[cols] > 18}\n"
+"	{\n"
+"		#draw Silver calign scroll tile 1 1 14 $gui[cols] {T I N T I N + +}{}{$info[SYSTEM][CLIENT_VERSION]}{}{Code by}{}{Peter Unold}{}{Bill Reiss}{}{and}{}{Igor van den Hoven};\n"
+"	};\n"
+"	#elseif {$gui[cols] > 8}\n"
+"	{\n"
+"		#draw Silver huge traced scroll tile 1 1 6 9 {T};\n"
+"		#draw Silver huge traced scroll tile 1 1 6 9 {T};\n"
+"		#draw Silver huge traced scroll tile 1 1 6 9 {+};\n"
+"		#draw Silver huge traced scroll tile 1 1 6 9 {+};\n"
+"		#draw Silver calign scroll tile 1 1 1 9 {$info[SYSTEM][CLIENT_VERSION]}\n"
+"	};\n"
+"	#elseif {$gui[cols] > 1}\n"
+"	{\n"
+"		#draw Silver calign scroll tile 1 1 8 $gui[cols] {T}{i}{n}{T}{i}{n}{+}{+}\n"
 "	}\n"
 "}\n"
 "\n"

+ 77 - 20
src/help.c

@@ -155,7 +155,7 @@ DO_COMMAND(do_help)
 
 		script_driver(ses, LIST_COMMAND, "#config {log} {html}");
 
-		if (HAS_BIT(ses->logmode, LOG_FLAG_HTML))
+		if (HAS_BIT(ses->log->mode, LOG_FLAG_HTML))
 		{
 			write_html_header(ses, logfile);
 		}
@@ -874,9 +874,31 @@ struct help_type help_table[] =
 		"         with macros. Subsequently many cursor commands only work properly when\n"
 		"         used within a macro or event.\n"
 		"\n"
-		"         <178>#cursor tab <list;scrollback> <backward|forward>\n"
-		"         <278>  Tab through the given option(s) going forward or backward.\n"
-		,
+		"         <178>#cursor flag\n"
+		"\n"
+		"         <278>EOL         end of line character(s)\n"
+		"         <278>ECHO        local echo\n"
+		"         <278>OVERTYPE    overtype mode\n"
+		"\n"
+		"         <178>#cursor macro\n"
+		"\n"
+		"         <278>PRESERVE    do not erase the macro from the macro input buffer\n"
+		"         <278>RESET       erase the macro input buffer\n"
+		"\n"
+		"         <178>#cursor tab\n"
+		"\n"
+		"         <278>CASELESS    makes tab completion caseless\n"
+		"         <278>COMPLETE    makes tab completion work while editing\n"
+		"\n"
+		"         <278>DICTIONARY  performs tab completion on the dictionary\n"
+		"         <278>LIST        performs tab completion on the tab completion list\n"
+		"         <278>SCROLLBACK  performs tab completion on the scrollback buffer\n"
+		"\n"
+		"         <278>BACKWARD    specifies tab completion to go backward\n"
+		"         <278>FORWARD     specifies tab completion to go forward\n"
+		"\n"
+		"         <278>Multiple options can/must be specified at once.\n",
+
 		"alias history keypad macro speedwalk tab"
 	},
 	{
@@ -945,6 +967,8 @@ struct help_type help_table[] =
 		"         Nanosecond floating point precision is allowed. Delays will fire in\n"
 		"         0.01 second intervals.\n"
 		"\n"
+		"         Named delays are treated as one-shot tickers, see #help tick.\n"
+		"\n"
 		"<178>Example<278>: #delay {1} {#show last};#show first\n"
 		"         This will print 'first', and 'last' around one second later.\n"
 		"\n"
@@ -1343,6 +1367,9 @@ struct help_type help_table[] =
 		"         <178>RECEIVED INPUT [NAME]\n"
 		"         <278>  %0 raw text\n"
 		"\n"
+		"         <178>RECEIVED INPUT CHARACTER\n"
+		"         <278>  %0 character  %1 unicode index  %2 size  %3 width\n"
+		"\n"
 		"         SEND OUTPUT            %0 raw text %1 size\n"
 		"         SENT OUTPUT            %0 raw text %1 size\n"
 		"\n"
@@ -1801,7 +1828,7 @@ struct help_type help_table[] =
 	{
 		"INDEX",
 		TOKEN_TYPE_STRING,
-		"         On this page you'll find an introduction to using TinTin++. Additional\n"
+		"<278>         On this page you'll find an introduction to using TinTin++. Additional\n"
 		"         information can be found in the individual help sections.\n"
 		"<128>\n"
 		"         Starting and Ending\n"
@@ -2082,6 +2109,7 @@ struct help_type help_table[] =
 		"         #info session will show information on the session.\n"
 		"         #info sessions will show information on all sessions.\n"
 		"         #info system will show some system information.\n"
+		"         #info tokenizer will show information about the script stack.\n"
 		"         #info unicode will show information on the provided character.\n",
 
 		"class debug ignore kill message"
@@ -2150,19 +2178,19 @@ struct help_type help_table[] =
 		"LINE",
 		TOKEN_TYPE_COMMAND,
 		"<178>Command<278>: #line <178>{<278>option<178>} {<278>argument<178>}<278>\n"
-		"<128>\n"
-		"         Line sub commands that alter the argument.\n"
-		"<278>\n"
+		"\n"
+		"         <128>Line options that alter the argument.\n"
+		"\n"
 		"         <178>#line strip <argument>\n"
 		"         <278>  Argument is executed with all color codes stripped.\n"
 		"\n"
 		"         <178>#line substitute <options> <argument>\n"
 		"         <278>  Argument is executed using the provided substitutions, available\n"
-		"         <278>  options are: arguments, colors, escapes, functions, secure, and\n"
-		"         <278>  variables.\n"
-		"<128>\n"
-		"         Line sub commands that alter how the line is executed.\n"
-		"<278>\n"
+		"         <278>  options are: arguments, braces, colors, escapes, functions, secure,\n"
+		"         <278>  and variables.\n"
+		"\n"
+		"         <128>Line options that alter how the line is executed.\n"
+		"\n"
 		"         <178>#line background <argument>\n"
 		"         <278>  Prevent new session activation.\n"
 		"\n"
@@ -2564,12 +2592,36 @@ struct help_type help_table[] =
 	{
 		"LOG",
 		TOKEN_TYPE_COMMAND,
-		"<178>Command<278>: #log <178>{<278>append<178>|<278>overwrite<178>|<278>off<178>} {<278>[filename]<178>}<278>\n"
+		"<178>Command<278>: #log <178>{<278>option<178>} {<278>argument<178>}<278>\n"
+		"<278>\n"
+		"         The log command allows logging session output to file. You can set the\n"
+		"         data type to either plain, raw, or html with the config command.\n"
 		"\n"
-		"         Logs session output to a file, you can set the data type to either\n"
-		"         plain, raw, or html with the config command.\n",
-		
-		"read scan textin write"
+		"         <178>#log append <filename>\n"
+		"         <278>  Start logging to the given file, if the file already exists it won't\n"
+		"         <278>  be overwritten and data will be appended to the end.\n"
+		"\n"
+		"         <178>#log move <filename_1> <filename_2>\n"
+		"         <278>  Move filename_1 to filename_2. This can be any file and doesn't need\n"
+		"         <278>  to be a log file.\n"
+		"\n"
+		"         <178>#log overwrite <filename>\n"
+		"         <278>  Start logging to the given file, if the file already exists it will\n"
+		"         <278>  be overwritten.\n"
+		"\n"
+		"         <178>#log off\n"
+		"         <278>  Stop logging.\n"
+		"\n"
+		"         <178>#log remove <filename>\n"
+		"         <278>  Remove the file. This can be any file and doesn't need to be a log\n"
+		"         <278>  file.\n"
+		"\n"
+		"         <178>#log timestamp <format>\n"
+		"         <278>  When set the timestamp will be prepended to each line logged to file.\n"
+		"         <278>  The format will be formatted as a date using the strftime format\n"
+		"         <278>  specifiers as described in #help time.\n",
+
+		"read scan textin time write"
 	},
 
 	{
@@ -2776,9 +2828,11 @@ struct help_type help_table[] =
 		"         <278>  Lists all matching rooms and their distance. The following\n"
 		"         <278>  search keywords are supported.\n"
 		"\n"
+		"         <278>  {distance}    <arg> will list rooms within given distance.\n"
 		"         <278>  {roomarea}    <arg> will list rooms with matching area name.\n"
 		"         <278>  {roomdesc}    <arg> will list rooms with matching room desc.\n"
 		"         <278>  {roomexits}   <arg> will list rooms with identical room exits.\n"
+		"         <278>                      Use * as an exit to ignore non pathdir exits.\n"
 		"         <278>  {roomflag}    <arg> will list rooms with matching room flags.\n"
 		"         <278>  {roomid}      <arg> will list rooms with identical id name.\n"
 		"         <278>  {roomname}    <arg> will list rooms with matching room name.\n"
@@ -4303,8 +4357,11 @@ struct help_type help_table[] =
 		"\n"
 		"         Adds a word to the tab completion list, alphabetically sorted.\n"
 		"\n"
-		"         If no tabs are defined tintin will use the scrollback buffer\n"
-		"         for auto tab completion.\n"
+		"         If no tabs are defined tintin will use the scrollback buffer for auto\n"
+		"         tab completion.\n"
+		"\n"
+		"         Tabbing behavior can be modified with the #cursor tab command which\n"
+		"         by default is bound to the tab key.\n"
 		"\n"
 		"<178>Comment<278>: You can remove a tab with the #untab command.\n",
 

+ 15 - 11
src/input.c

@@ -143,11 +143,6 @@ void process_input(void)
 		echo_command(gtd->ses, "");
 	}
 
-	if (gtd->ses->scroll->line != -1)
-	{
-		buffer_end(gtd->ses, "", "", "");
-	}
-
 	input_ses = gtd->ses;
 
 	check_all_events(gtd->ses, SUB_SEC|EVENT_FLAG_INPUT, 0, 1, "RECEIVED INPUT", gtd->ses->input->buf);
@@ -233,11 +228,14 @@ void read_line(char *input, int len)
 
 	if (HAS_BIT(gtd->ses->event_flags, EVENT_FLAG_INPUT))
 	{
-		check_all_events(gtd->ses, EVENT_FLAG_INPUT, 0, 2, "RECEIVED KEYPRESS", input, ntos(index));
+		check_all_events(gtd->ses, SUB_BRA|EVENT_FLAG_INPUT, 0, 2, "RECEIVED KEYPRESS", input, ntos(index));
+	}
 
-		if (check_all_events(gtd->ses, EVENT_FLAG_CATCH, 0, 2, "CATCH RECEIVED KEYPRESS", input, ntos(index)) == 1)
+	if (HAS_BIT(gtd->ses->event_flags, EVENT_FLAG_CATCH))
+	{
+		if (check_all_events(gtd->ses, SUB_BRA|EVENT_FLAG_CATCH, 0, 2, "CATCH RECEIVED KEYPRESS", input, ntos(index)) == 1)
 		{
-			check_all_events(gtd->ses, EVENT_FLAG_INPUT, 0, 4, "PROCESSED KEYPRESS", input, ntos(index), ntos(gtd->ses->input->edit->update + 1), ntos(gtd->ses->input->str_pos + 1));
+			check_all_events(gtd->ses, SUB_BRA|EVENT_FLAG_INPUT, 0, 4, "PROCESSED KEYPRESS", input, ntos(index), ntos(gtd->ses->input->edit->update + 1), ntos(gtd->ses->input->str_pos + 1));
 
 			return;
 		}
@@ -247,7 +245,7 @@ void read_line(char *input, int len)
 	{
 		if (HAS_BIT(gtd->ses->event_flags, EVENT_FLAG_INPUT))
 		{
-			check_all_events(gtd->ses, EVENT_FLAG_INPUT, 0, 4, "PROCESSED KEYPRESS", input, ntos(index), ntos(gtd->ses->input->edit->update + 1), ntos(gtd->ses->input->str_pos + 1));
+			check_all_events(gtd->ses, SUB_BRA|EVENT_FLAG_INPUT, 0, 4, "PROCESSED KEYPRESS", input, ntos(index), ntos(gtd->ses->input->edit->update + 1), ntos(gtd->ses->input->str_pos + 1));
 		}
 		return;
 	}
@@ -282,7 +280,7 @@ void read_line(char *input, int len)
 			default:
 				if (HAS_BIT(gtd->ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(gtd->macro_buf) && gtd->macro_buf[1])
 				{
-					size = get_utf8_width(gtd->macro_buf, &width);
+					size = get_utf8_width(gtd->macro_buf, &width, &index);
 				}
 				else if (HAS_BIT(gtd->ses->charset, CHARSET_FLAG_EUC) && is_euc_head(gtd->ses, gtd->macro_buf) && gtd->macro_buf[1])
 				{
@@ -291,11 +289,17 @@ void read_line(char *input, int len)
 				else
 				{
 					size = get_ascii_width(gtd->macro_buf, &width);
+					index = (int) gtd->macro_buf[0];
 				}
 
 				sprintf(buf, "%.*s", size, gtd->macro_buf);
 
 				inputline_insert(buf, -1);
+
+				if (HAS_BIT(gtd->ses->event_flags, EVENT_FLAG_INPUT))
+				{
+					check_all_events(gtd->ses, SUB_BRA|EVENT_FLAG_INPUT, 0, 4, "RECEIVED INPUT CHARACTER", buf, ntos(index), ntos(size), ntos(width));
+				}
 /*
 				if (width && HAS_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT) && gtd->ses->input->raw_len != gtd->ses->input->raw_pos)
 				{
@@ -337,7 +341,7 @@ void read_line(char *input, int len)
 	}
 	if (HAS_BIT(gtd->ses->event_flags, EVENT_FLAG_INPUT))
 	{
-		check_all_events(gtd->ses, EVENT_FLAG_INPUT, 0, 4, "PROCESSED KEYPRESS", input, ntos(index), ntos(gtd->ses->input->edit->update + 1), ntos(gtd->ses->input->str_pos + 1));
+		check_all_events(gtd->ses, SUB_BRA|EVENT_FLAG_INPUT, 0, 4, "PROCESSED KEYPRESS", input, ntos(index), ntos(gtd->ses->input->edit->update + 1), ntos(gtd->ses->input->str_pos + 1));
 	}
 }
 

+ 58 - 58
src/line.c

@@ -267,31 +267,31 @@ DO_LINE(line_log)
 	{
 		substitute(ses, arg2, arg2, SUB_ESC|SUB_COL|SUB_LNF);
 
-		if (ses->logfile && !strcmp(ses->logname, arg1))
+		if (ses->log->file && !strcmp(ses->log->name, arg1))
 		{
-			logit(ses, arg2, ses->logfile, LOG_FLAG_NONE);
+			logit(ses, arg2, ses->log->file, LOG_FLAG_NONE);
 		}
-		else if (ses->logline_time == gtd->time && !strcmp(ses->logline_name, arg1))
+		else if (ses->log->line_time == gtd->time && !strcmp(ses->log->line_name, arg1))
 		{
-			logit(ses, arg2, ses->logline_file, LOG_FLAG_NONE);
+			logit(ses, arg2, ses->log->line_file, LOG_FLAG_NONE);
 		}
 		else
 		{
 			if ((logfile = fopen(arg1, "a")))
 			{
-				if (ses->logline_file)
+				if (ses->log->line_file)
 				{
-					fclose(ses->logline_file);
+					fclose(ses->log->line_file);
 				}
-				free(ses->logline_name);
+				free(ses->log->line_name);
 
-				ses->logline_name = strdup(arg1);
-				ses->logline_file = logfile;
-				ses->logline_time = gtd->time;
+				ses->log->line_name = strdup(arg1);
+				ses->log->line_file = logfile;
+				ses->log->line_time = gtd->time;
 
-				loginit(ses, ses->logline_file, LOG_FLAG_APPEND | HAS_BIT(ses->logmode, LOG_FLAG_HTML));
+				logheader(ses, ses->log->line_file, LOG_FLAG_APPEND | HAS_BIT(ses->log->mode, LOG_FLAG_HTML));
 
-				logit(ses, arg2, ses->logline_file, LOG_FLAG_NONE);
+				logit(ses, arg2, ses->log->line_file, LOG_FLAG_NONE);
 			}
 			else
 			{
@@ -301,23 +301,23 @@ DO_LINE(line_log)
 	}
 	else
 	{
-		if (ses->lognext_time == gtd->time && !strcmp(ses->lognext_name, arg1))
+		if (ses->log->next_time == gtd->time && !strcmp(ses->log->next_name, arg1))
 		{
-			SET_BIT(ses->logmode, LOG_FLAG_NEXT);
+			SET_BIT(ses->log->mode, LOG_FLAG_NEXT);
 		}
 		else if ((logfile = fopen(arg1, "a")))
 		{
-			if (ses->lognext_file)
+			if (ses->log->next_file)
 			{
-				fclose(ses->lognext_file);
+				fclose(ses->log->next_file);
 			}
-			free(ses->lognext_name);
+			free(ses->log->next_name);
 
-			ses->lognext_name = strdup(arg1);
-			ses->lognext_file = logfile;
-			ses->lognext_time = gtd->time;
+			ses->log->next_name = strdup(arg1);
+			ses->log->next_file = logfile;
+			ses->log->next_time = gtd->time;
 
-			SET_BIT(ses->logmode, LOG_FLAG_NEXT);
+			SET_BIT(ses->log->mode, LOG_FLAG_NEXT);
 		}
 		else
 		{
@@ -333,38 +333,38 @@ DO_LINE(line_logmode)
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 
-	DEL_BIT(ses->logmode, LOG_FLAG_OLD_HTML|LOG_FLAG_OLD_PLAIN|LOG_FLAG_OLD_RAW);
+	DEL_BIT(ses->log->mode, LOG_FLAG_OLD_HTML|LOG_FLAG_OLD_PLAIN|LOG_FLAG_OLD_RAW);
 
-	switch (HAS_BIT(ses->logmode, LOG_FLAG_HTML|LOG_FLAG_PLAIN|LOG_FLAG_RAW))
+	switch (HAS_BIT(ses->log->mode, LOG_FLAG_HTML|LOG_FLAG_PLAIN|LOG_FLAG_RAW))
 	{
 		case LOG_FLAG_HTML:
-			SET_BIT(ses->logmode, LOG_FLAG_OLD_HTML);
+			SET_BIT(ses->log->mode, LOG_FLAG_OLD_HTML);
 			break;
 		case LOG_FLAG_PLAIN:
-			SET_BIT(ses->logmode, LOG_FLAG_OLD_PLAIN);
+			SET_BIT(ses->log->mode, LOG_FLAG_OLD_PLAIN);
 			break;
 		case LOG_FLAG_RAW:
-			SET_BIT(ses->logmode, LOG_FLAG_OLD_RAW);
+			SET_BIT(ses->log->mode, LOG_FLAG_OLD_RAW);
 			break;
 	}
 
 	if (is_abbrev(arg1, "HTML"))
 	{
-		SET_BIT(ses->logmode, LOG_FLAG_HTML);
-		DEL_BIT(ses->logmode, LOG_FLAG_PLAIN);
-		DEL_BIT(ses->logmode, LOG_FLAG_RAW);
+		SET_BIT(ses->log->mode, LOG_FLAG_HTML);
+		DEL_BIT(ses->log->mode, LOG_FLAG_PLAIN);
+		DEL_BIT(ses->log->mode, LOG_FLAG_RAW);
 	}
 	else if (is_abbrev(arg1, "PLAIN"))
 	{
-		SET_BIT(ses->logmode, LOG_FLAG_PLAIN);
-		DEL_BIT(ses->logmode, LOG_FLAG_HTML);
-		DEL_BIT(ses->logmode, LOG_FLAG_RAW);
+		SET_BIT(ses->log->mode, LOG_FLAG_PLAIN);
+		DEL_BIT(ses->log->mode, LOG_FLAG_HTML);
+		DEL_BIT(ses->log->mode, LOG_FLAG_RAW);
 	}
 	else if (is_abbrev(arg1, "RAW"))
 	{
-		SET_BIT(ses->logmode, LOG_FLAG_RAW);
-		DEL_BIT(ses->logmode, LOG_FLAG_HTML);
-		DEL_BIT(ses->logmode, LOG_FLAG_PLAIN);
+		SET_BIT(ses->log->mode, LOG_FLAG_RAW);
+		DEL_BIT(ses->log->mode, LOG_FLAG_HTML);
+		DEL_BIT(ses->log->mode, LOG_FLAG_PLAIN);
 	}
 	else
 	{
@@ -377,18 +377,18 @@ DO_LINE(line_logmode)
 
 	active_ses = script_driver(ses, LIST_COMMAND, arg1);
 
-	DEL_BIT(ses->logmode, LOG_FLAG_HTML|LOG_FLAG_PLAIN|LOG_FLAG_RAW);
+	DEL_BIT(ses->log->mode, LOG_FLAG_HTML|LOG_FLAG_PLAIN|LOG_FLAG_RAW);
 
-	switch (HAS_BIT(ses->logmode, LOG_FLAG_OLD_HTML|LOG_FLAG_OLD_PLAIN|LOG_FLAG_OLD_RAW))
+	switch (HAS_BIT(ses->log->mode, LOG_FLAG_OLD_HTML|LOG_FLAG_OLD_PLAIN|LOG_FLAG_OLD_RAW))
 	{
 		case LOG_FLAG_OLD_HTML:
-			SET_BIT(ses->logmode, LOG_FLAG_HTML);
+			SET_BIT(ses->log->mode, LOG_FLAG_HTML);
 			break;
 		case LOG_FLAG_OLD_PLAIN:
-			SET_BIT(ses->logmode, LOG_FLAG_PLAIN);
+			SET_BIT(ses->log->mode, LOG_FLAG_PLAIN);
 			break;
 		case LOG_FLAG_OLD_RAW:
-			SET_BIT(ses->logmode, LOG_FLAG_RAW);
+			SET_BIT(ses->log->mode, LOG_FLAG_RAW);
 			break;
 	}
 
@@ -404,25 +404,25 @@ DO_LINE(line_logverbatim)
 
 	if (*arg1 && *arg2)
 	{
-		if (!strcmp(ses->logline_name, arg1))
+		if (!strcmp(ses->log->line_name, arg1))
 		{
-			logit(ses, arg2, ses->logline_file, LOG_FLAG_LINEFEED);
+			logit(ses, arg2, ses->log->line_file, LOG_FLAG_LINEFEED);
 		}
 		else
 		{
 			if ((logfile = fopen(arg1, "a")))
 			{
-				if (ses->logline_file)
+				if (ses->log->line_file)
 				{
-					fclose(ses->logline_file);
+					fclose(ses->log->line_file);
 				}
-				free(ses->logline_name);
-				ses->logline_name = strdup(arg1);
-				ses->logline_file = logfile;
+				free(ses->log->line_name);
+				ses->log->line_name = strdup(arg1);
+				ses->log->line_file = logfile;
 
-				loginit(ses, ses->logline_file, LOG_FLAG_APPEND | HAS_BIT(ses->logmode, LOG_FLAG_HTML));
+				logheader(ses, ses->log->line_file, LOG_FLAG_APPEND | HAS_BIT(ses->log->mode, LOG_FLAG_HTML));
 
-				logit(ses, arg2, ses->logline_file, LOG_FLAG_LINEFEED);
+				logit(ses, arg2, ses->log->line_file, LOG_FLAG_LINEFEED);
 			}
 			else
 			{
@@ -432,21 +432,21 @@ DO_LINE(line_logverbatim)
 	}
 	else
 	{
-		if (!strcmp(ses->lognext_name, arg1))
+		if (!strcmp(ses->log->next_name, arg1))
 		{
-			SET_BIT(ses->logmode, LOG_FLAG_NEXT);
+			SET_BIT(ses->log->mode, LOG_FLAG_NEXT);
 		}
 		else if ((logfile = fopen(arg1, "a")))
 		{
-			if (ses->lognext_file)
+			if (ses->log->next_file)
 			{
-				fclose(ses->lognext_file);
+				fclose(ses->log->next_file);
 			}
-			free(ses->lognext_name);
-			ses->lognext_name = strdup(arg1);
-			ses->lognext_file = logfile;
+			free(ses->log->next_name);
+			ses->log->next_name = strdup(arg1);
+			ses->log->next_file = logfile;
 
-			SET_BIT(ses->logmode, LOG_FLAG_NEXT);
+			SET_BIT(ses->log->mode, LOG_FLAG_NEXT);
 		}
 		else
 		{
@@ -478,7 +478,7 @@ DO_LINE(line_multishot)
 {
 	unsigned int shots;
 
-	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
 
 	shots = (unsigned int) get_number(ses, arg1);

+ 135 - 28
src/log.c

@@ -25,6 +25,37 @@
 
 #include "tintin.h"
 
+#define DO_LOG(log) void log (struct session *ses, char *arg, char *arg1, char *arg2)
+
+DO_LOG(log_append);
+DO_LOG(log_info);
+DO_LOG(log_move);
+DO_LOG(log_overwrite);
+DO_LOG(log_off);
+DO_LOG(log_remove);
+DO_LOG(log_timestamp);
+
+typedef void LOG (struct session *ses, char *arg, char *arg1, char *arg2);
+
+struct log_type
+{
+	char                  * name;
+	LOG                   * fun;
+	char                  * desc;
+};
+
+struct log_type log_table[] =
+{
+	{    "APPEND",            log_append,          "Start logging, appending to given file."        },
+	{    "INFO",              log_info,            "Some logging related info."                     },
+	{    "MOVE",              log_move,            "Move the given file."                           },
+	{    "OFF",               log_off,             "Stop logging."                                  },
+	{    "OVERWRITE",         log_overwrite,       "Start logging, overwriting the given file."     },
+	{    "REMOVE",            log_remove,          "Remove the given file."                         },
+	{    "TIMESTAMP",         log_timestamp,       "Timestamp prepended to each log line."          },
+	{    "",                  NULL,                ""                                               }
+};
+
 DO_COMMAND(do_log)
 {
 	int cnt;
@@ -32,7 +63,7 @@ DO_COMMAND(do_log)
 	push_call("do_log(%p,%p)",ses,arg);
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
-	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN|SUB_ESC);
+	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN|SUB_ESC);
 
 	if (*arg1 == 0)
 	{
@@ -75,20 +106,20 @@ DO_COMMAND(do_log)
 
 DO_LOG(log_append)
 {
-	if (ses->logfile)
+	if (ses->log->file)
 	{
-		fclose(ses->logfile);
+		fclose(ses->log->file);
 	}
 
-	if ((ses->logfile = fopen(arg2, "a")))
+	if ((ses->log->file = fopen(arg2, "a")))
 	{
-		SET_BIT(ses->logmode, LOG_FLAG_APPEND);
+		SET_BIT(ses->log->mode, LOG_FLAG_APPEND);
 
-		RESTRING(ses->logname, arg2);
+		RESTRING(ses->log->name, arg2);
 
-		loginit(ses, ses->logfile, ses->logmode);
+		logheader(ses, ses->log->file, ses->log->mode);
 
-		show_message(ses, LIST_COMMAND, "#LOG: LOGGING OUTPUT TO '%s' FILESIZE: %ld", arg2, ftell(ses->logfile));
+		show_message(ses, LIST_COMMAND, "#LOG: LOGGING OUTPUT TO '%s' FILESIZE: %ld", arg2, ftell(ses->log->file));
 	}
 	else
 	{
@@ -98,27 +129,48 @@ DO_LOG(log_append)
 
 DO_LOG(log_info)
 {
-	tintin_printf2(ses, "#LOG INFO: FILE  = %s", ses->logfile ? ses->logname : "");
-	tintin_printf2(ses, "#LOG INFO: LEVEL = %s", HAS_BIT(ses->logmode, LOG_FLAG_LOW) ? "LOW" : "HIGH");
-	tintin_printf2(ses, "#LOG INFO: MODE  = %s", HAS_BIT(ses->logmode, LOG_FLAG_HTML) ? "HTML" : HAS_BIT(ses->logmode, LOG_FLAG_PLAIN) ? "PLAIN" : "RAW");
-	tintin_printf2(ses, "#LOG INFO: LINE  = %s", ses->logline_file ? ses->logline_name : "");
-	tintin_printf2(ses, "#LOG INFO: NEXT  = %s", ses->lognext_file ? ses->lognext_name : "");
+	tintin_printf2(ses, "#LOG INFO: FILE  = %s", ses->log->file ? ses->log->name : "");
+	tintin_printf2(ses, "#LOG INFO: LEVEL = %s", HAS_BIT(ses->log->mode, LOG_FLAG_LOW) ? "LOW" : "HIGH");
+	tintin_printf2(ses, "#LOG INFO: MODE  = %s", HAS_BIT(ses->log->mode, LOG_FLAG_HTML) ? "HTML" : HAS_BIT(ses->log->mode, LOG_FLAG_PLAIN) ? "PLAIN" : "RAW");
+	tintin_printf2(ses, "#LOG INFO: LINE  = %s", ses->log->line_file ? ses->log->line_name : "");
+	tintin_printf2(ses, "#LOG INFO: NEXT  = %s", ses->log->next_file ? ses->log->next_name : "");
+}
+
+DO_LOG(log_move)
+{
+	char *arg3;
+	int result;
+
+	arg3 = str_alloc_stack(0);
+
+	arg = sub_arg_in_braces(ses, arg, arg3, GET_ALL, SUB_VAR|SUB_FUN);
+
+	result = rename(arg2, arg3);
+
+	if (result == 0)
+	{
+		show_message(ses, LIST_COMMAND, "#LOG MOVE: FILE '%s' MOVED TO '%s'.", arg2, arg3);
+	}
+	else
+	{
+		show_error(ses, LIST_COMMAND, "#LOG MOVE: COULDN'T MOVE FILE '%s' TO '%s'.", arg2, arg3);
+	}
 }
 
 DO_LOG(log_overwrite)
 {
-	if (ses->logfile)
+	if (ses->log->file)
 	{
-		fclose(ses->logfile);
+		fclose(ses->log->file);
 	}
 
-	if ((ses->logfile = fopen(arg2, "w")))
+	if ((ses->log->file = fopen(arg2, "w")))
 	{
-		SET_BIT(ses->logmode, LOG_FLAG_OVERWRITE);
+		SET_BIT(ses->log->mode, LOG_FLAG_OVERWRITE);
 
-		RESTRING(ses->logname, arg2);
+		RESTRING(ses->log->name, arg2);
 
-		loginit(ses, ses->logfile, ses->logmode);
+		logheader(ses, ses->log->file, ses->log->mode);
 
 		show_message(ses, LIST_COMMAND, "#LOG: LOGGING OUTPUT TO '%s'", arg2);
 	}
@@ -130,12 +182,12 @@ DO_LOG(log_overwrite)
 
 DO_LOG(log_off)
 {
-	if (ses->logfile)
+	if (ses->log->file)
 	{
-		DEL_BIT(ses->logmode, LOG_FLAG_APPEND|LOG_FLAG_OVERWRITE);
+		DEL_BIT(ses->log->mode, LOG_FLAG_APPEND|LOG_FLAG_OVERWRITE);
 
-		fclose(ses->logfile);
-		ses->logfile = NULL;
+		fclose(ses->log->file);
+		ses->log->file = NULL;
 
 		show_message(ses, LIST_COMMAND, "#LOG {OFF}: LOGGING TURNED OFF.");
 	}
@@ -145,17 +197,72 @@ DO_LOG(log_off)
 	}
 }
 
+DO_LOG(log_remove)
+{
+	int result = remove(arg2);
+
+	if (result == 0)
+	{
+		show_message(ses, LIST_COMMAND, "#LOG REMOVE: FILE '%s' REMOVED.", arg2);
+	}
+	else
+	{
+		show_error(ses, LIST_COMMAND, "#LOG REMOVE: COULDN'T REMOVE FILE '%s'.", arg2);
+	}
+}
+
+DO_LOG(log_timestamp)
+{
+	RESTRING(ses->log->stamp_strf, arg2);
+	ses->log->stamp_time = 0;
+
+	show_message(ses, LIST_COMMAND, "#LOG TIMESTAMP: FORMAT SET TO '%s'.", arg2);
+}
+
+void init_log(struct session *ses)
+{
+	ses->log->name        = strdup("");
+	ses->log->next_name   = strdup("");
+	ses->log->line_name   = strdup("");
+	ses->log->stamp_strf  = strdup("");
+}
+
+void free_log(struct session *ses)
+{
+	free(ses->log->name);
+	free(ses->log->next_name);
+	free(ses->log->line_name);
+	free(ses->log->stamp_strf);
+
+	free(ses->log);
+}
+
 void logit(struct session *ses, char *txt, FILE *file, int flags)
 {
 	char out[BUFFER_SIZE];
 
 	push_call("logit(%p,%p,%p,%d)",ses,txt,file,flags);
 
-	if (HAS_BIT(ses->logmode, LOG_FLAG_PLAIN))
+	if (*ses->log->stamp_strf)
+	{
+		if (ses->log->stamp_time != gtd->time)
+		{
+			struct tm timeval_tm = *localtime(&gtd->time);
+
+			ses->log->stamp_time = gtd->time;
+
+			substitute(ses, ses->log->stamp_strf, out, SUB_COL|SUB_ESC|SUB_VAR|SUB_FUN);
+
+			strftime(ses->log->stamp_text, 99, out, &timeval_tm);
+		}
+		fputs(ses->log->stamp_text, file);
+	}
+			
+	if (HAS_BIT(ses->log->mode, LOG_FLAG_PLAIN))
 	{
 		strip_vt102_codes(txt, out);
 	}
-	else if (HAS_BIT(ses->logmode, LOG_FLAG_HTML))
+	else if (HAS_BIT(ses->log->mode, LOG_FLAG_HTML))
 	{
 		vt102_to_html(ses, txt, out);
 	}
@@ -176,9 +283,9 @@ void logit(struct session *ses, char *txt, FILE *file, int flags)
 	return;
 }
 
-void loginit(struct session *ses, FILE *file, int flags)
+void logheader(struct session *ses, FILE *file, int flags)
 {
-	push_call("loginit(%p,%p,%d)",ses,file,flags);
+	push_call("logheader(%p,%p,%d)",ses,file,flags);
 
 	if (HAS_BIT(flags, LOG_FLAG_APPEND))
 	{
@@ -194,7 +301,7 @@ void loginit(struct session *ses, FILE *file, int flags)
 	}
 	else if (HAS_BIT(flags, LOG_FLAG_OVERWRITE) && HAS_BIT(flags, LOG_FLAG_HTML))
 	{
-		if (HAS_BIT(ses->logmode, LOG_FLAG_HTML))
+		if (HAS_BIT(ses->log->mode, LOG_FLAG_HTML))
 		{
 			write_html_header(ses, file);
 		}

+ 5 - 22
src/main.c

@@ -77,22 +77,6 @@ void winch_handler(int signal)
 	SET_BIT(gtd->flags, TINTIN_FLAG_WINCHUPDATE);
 
 	gtd->time_session = gtd->time;
-/*
-	struct session *ses;
-	init_terminal_size(gts);
-
-	for (ses = gts->next ; ses ; ses = ses->next)
-	{
-		init_terminal_size(ses);
-
-		if (HAS_BIT(ses->telopts, TELOPT_FLAG_NAWS))
-		{
-			SET_BIT(ses->telopts, TELOPT_FLAG_UPDATENAWS);
-		}
-	}
-
-	winch_daemon();
-*/
 }
 
 
@@ -104,9 +88,8 @@ void abort_handler(int signal)
 void child_handler(int signal)
 {
 	return;
-	syserr_printf(gtd->ses, "child_handler");
 
-//	syserr_fatal(signal, "child_handler");
+	syserr_printf(gtd->ses, "child_handler");
 }
 /*
 void interrupt_handler(int signal)
@@ -537,9 +520,6 @@ void init_tintin(int greeting)
 	gts->config_flags   = CONFIG_FLAG_MCCP;
 	gts->socket         = 1;
 	gts->read_max       = 16384;
-	gts->logname        = strdup("");
-	gts->lognext_name   = strdup("");
-	gts->logline_name   = strdup("");
 
 	gts->more_output    = str_dup("");
 
@@ -552,14 +532,17 @@ void init_tintin(int greeting)
 
 	gtd->banner_list    = init_list(gts, LIST_CONFIG, 32);
 
+	gts->log            = calloc(1, sizeof(struct log_data));
+	gts->input          = calloc(1, sizeof(struct input_data));
 	gts->scroll         = calloc(1, sizeof(struct scroll_data));
 	gts->split          = calloc(1, sizeof(struct split_data));
-	gts->input          = calloc(1, sizeof(struct input_data));
 
 	init_local(gts);
 
 	init_terminal_size(gts);
 
+	init_log(gts);
+
 	init_input(gts, 0, 0, 0, 0);
 
 	init_buffer(gts, 10000);

+ 169 - 75
src/mapper.c

@@ -32,7 +32,6 @@
 int                 map_grid_x;
 int                 map_grid_y;
 
-#define             MAP_SEARCH_DIST 1000
 #define             MAP_BF_SIZE 10000
 
 extern  int dir_flags(struct session *ses, int room, int dir);
@@ -2407,13 +2406,14 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 	{
 		// experimental
 
-		substitute(ses, room->symbol, room_symbol, SUB_VAR|SUB_FUN);
+		substitute(ses, room->symbol, room_symbol, SUB_VAR|SUB_FUN|SUB_COL|SUB_ESC);
 
 		symsize = strip_color_strlen(ses, room_symbol);
 
 		if (HAS_BIT(room->flags, ROOM_FLAG_PATH) && room->search_stamp == ses->map->search->stamp)
 		{
 			room_color = ses->map->color[MAP_COLOR_PATH];
+
 			if (symsize > 1)
 			{
 				strcpy(room_symbol, " ");
@@ -2716,32 +2716,40 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 					return buf;
 				}
 
-				switch (exit_w)
+				if (symsize > 5)
 				{
-					case 0:
-						strcat(buf, draw_terrain_symbol(ses, room, line, 1, x, y, TERRAIN_FLAG_DOUBLE));
-						strcat(buf, draw_terrain_symbol(ses, room, line, 2, x, y, TERRAIN_FLAG_DOUBLE));
-						break;
-					case MAP_DIR_E:
-						sprintf(buf, "%s%s%s", get_exit_color(ses, 0, room_w->exit_grid[EXIT_GRID_E]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_E], draw_terrain_symbol(ses, room, line, 2, x, y, flags));
-						break;
-					case MAP_DIR_W:
-						sprintf(buf, "%s%s%s", get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_W]), draw_terrain_symbol(ses, room, line, 1, x, y, flags), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_W]);
-						break;
-					case MAP_DIR_E|MAP_DIR_W:
-						if (room->exit_grid[EXIT_GRID_W]->vnum == room_w->vnum && room_w->exit_grid[EXIT_GRID_E]->vnum == room->vnum)
-						{
-							// ‒‒
-							sprintf(buf, "%s%s%s%s", get_exit_color(ses, 0, room_w->exit_grid[EXIT_GRID_E]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_EW], get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_W]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_EW]);
-						}
-						else
-						{
-							sprintf(buf, "%s%s%s%s", get_exit_color(ses, 0, room_w->exit_grid[EXIT_GRID_E]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_E], get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_W]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_W]);
-						}
-						break;
-					default:
-						strcat(buf, "??");
-						break;
+					room_symbol[raw_len_str(ses, room_symbol, 0, 4)] = 0;
+				}
+
+				if (symsize <= 3 || room->vnum == ses->map->in_room)
+				{
+					switch (exit_w)
+					{
+						case 0:
+							strcat(buf, draw_terrain_symbol(ses, room, line, 1, x, y, TERRAIN_FLAG_DOUBLE));
+							strcat(buf, draw_terrain_symbol(ses, room, line, 2, x, y, TERRAIN_FLAG_DOUBLE));
+							break;
+						case MAP_DIR_E:
+							sprintf(buf, "%s%s%s", get_exit_color(ses, 0, room_w->exit_grid[EXIT_GRID_E]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_E], draw_terrain_symbol(ses, room, line, 2, x, y, flags));
+							break;
+						case MAP_DIR_W:
+							sprintf(buf, "%s%s%s", get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_W]), draw_terrain_symbol(ses, room, line, 1, x, y, flags), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_W]);
+							break;
+						case MAP_DIR_E|MAP_DIR_W:
+							if (room->exit_grid[EXIT_GRID_W]->vnum == room_w->vnum && room_w->exit_grid[EXIT_GRID_E]->vnum == room->vnum)
+							{
+								// ‒‒
+								sprintf(buf, "%s%s%s%s", get_exit_color(ses, 0, room_w->exit_grid[EXIT_GRID_E]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_EW], get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_W]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_EW]);
+							}
+							else
+							{
+								sprintf(buf, "%s%s%s%s", get_exit_color(ses, 0, room_w->exit_grid[EXIT_GRID_E]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_E], get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_W]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_W]);
+							}
+							break;
+						default:
+							strcat(buf, "??");
+							break;
+					}
 				}
 
 				if (room->vnum == ses->map->in_room)
@@ -2750,7 +2758,14 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 				}
 				else if (symsize > 1)
 				{
-					cat_sprintf(buf, "%s%-3s", ses->map->color[MAP_COLOR_SYMBOL], room_symbol);
+					if (symsize > 3)
+					{
+						cat_sprintf(buf, "%s%s%s", ses->map->color[MAP_COLOR_SYMBOL], room_symbol, symsize == 4 ? " " : "");
+					}
+					else
+					{
+						cat_sprintf(buf, "%s%s%s", ses->map->color[MAP_COLOR_SYMBOL], room_symbol, symsize == 2 ? " " : "");
+					}
 				}
 				else
 				{
@@ -3078,9 +3093,9 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 		return buf;
 	}
 
-
 	if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
 	{
+
 		strcpy(buf, "");
 
 		switch (line)
@@ -3121,6 +3136,11 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 				break;
 
 			case 2:
+				if (symsize > 6)
+				{
+					room_symbol[raw_len_str(ses, room_symbol, 0, 5)] = 0;
+				}
+
 				if (HAS_BIT(room->flags, ROOM_FLAG_CURVED))
 				{
 					sprintf(room_left,  "%s%s", room_color, ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_RL_CURVED]);
@@ -3132,7 +3152,7 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 					sprintf(room_right, "%s%s", room_color, ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_RR]);
 				}
 
-				if (!HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS) && symsize <= 3)
+				if (!HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS) && (symsize <= 3 || room->vnum == ses->map->in_room))
 				{
 					cat_sprintf(buf, "%s%s",
 						get_exit_color(ses, room->vnum, room->exit_grid[EXIT_GRID_W]),
@@ -3172,7 +3192,7 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 					}
 					else if (symsize > 3)
 					{
-						cat_sprintf(buf, "%s%-5s", ses->map->color[MAP_COLOR_SYMBOL], room_symbol);
+						cat_sprintf(buf, "%s%s%s", ses->map->color[MAP_COLOR_SYMBOL], room_symbol, symsize > 5 ? "" : " ");
 					}
 					else if (HAS_BIT(room->flags, ROOM_FLAG_VOID))
 					{
@@ -3228,9 +3248,12 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 					}
 				}
 
-				if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS) || symsize > 3)
+				if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIVNUMS) || (symsize > 3 && room->vnum != ses->map->in_room))
 				{
-					cat_sprintf(buf, "%s%s", get_exit_color(ses, room->vnum, room->exit_grid[EXIT_GRID_E]), room->exit_grid[EXIT_GRID_E] ? "-" : draw_terrain_symbol(ses, room, line, 6, x, y, flags));
+					if (symsize < 5)
+					{
+						cat_sprintf(buf, "%s%s", get_exit_color(ses, room->vnum, room->exit_grid[EXIT_GRID_E]), room->exit_grid[EXIT_GRID_E] ? "-" : draw_terrain_symbol(ses, room, line, 6, x, y, flags));
+					}
 				}
 				else
 				{
@@ -3530,6 +3553,10 @@ void search_keywords(struct session *ses, char *arg, char *out, char *var)
 		{
 			arg = sub_arg_in_braces(ses, arg, buf[MAP_SEARCH_FLAG], GET_ALL, SUB_VAR|SUB_FUN);
 		}
+		else if (!strcasecmp(arg1, "distance"))
+		{
+			arg = sub_arg_in_braces(ses, arg, buf[MAP_SEARCH_DISTANCE], GET_ALL, SUB_VAR|SUB_FUN);
+		}
 		else if (!strcasecmp(arg1, "variable"))
 		{
 			arg = sub_arg_in_braces(ses, arg, var, GET_ALL, SUB_VAR|SUB_FUN);
@@ -3778,47 +3805,62 @@ void map_search_compile(struct session *ses, char *arg, char *var)
 		ses->map->search->terrain = NULL;
 	}
 
-	arg = sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN); // flag
+	// flag
+
+	arg = sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN);
 
 	if (*buf)
 	{
-		char flags[BUFFER_SIZE];
+		char flags[BUFFER_SIZE], *ptf;
+		long long *flag;
 
 		ses->map->search->flag = get_number(ses, buf);
+		ses->map->search->galf = 0;
 
 		ptb = buf;
 
 		while (*ptb)
 		{
 			ptb = sub_arg_in_braces(ses, ptb, flags, GET_ONE, SUB_NONE);
+			ptf = flags;
 
-			if (is_abbrev(buf, "avoid"))
+			if (ptf[0] == '!')
 			{
-				SET_BIT(ses->map->search->flag, ROOM_FLAG_AVOID);
+				flag = &ses->map->search->galf;
+				ptf++;
 			}
-			else if (is_abbrev(buf, "curved"))
+			else
 			{
-				SET_BIT(ses->map->search->flag, ROOM_FLAG_CURVED);
+				flag = &ses->map->search->flag;
 			}
-			else if (is_abbrev(buf, "hide"))
+
+			if (is_abbrev(ptf, "avoid"))
 			{
-				SET_BIT(ses->map->search->flag, ROOM_FLAG_HIDE);
+				SET_BIT(*flag, ROOM_FLAG_AVOID);
 			}
-			else if (is_abbrev(buf, "invis"))
+			else if (is_abbrev(ptf, "curved"))
 			{
-				SET_BIT(ses->map->search->flag, ROOM_FLAG_INVIS);
+				SET_BIT(*flag, ROOM_FLAG_CURVED);
 			}
-			else if (is_abbrev(buf, "leave"))
+			else if (is_abbrev(ptf, "hide"))
 			{
-				SET_BIT(ses->map->search->flag, ROOM_FLAG_LEAVE);
+				SET_BIT(*flag, ROOM_FLAG_HIDE);
 			}
-			else if (is_abbrev(buf, "void"))
+			else if (is_abbrev(ptf, "invis"))
 			{
-				SET_BIT(ses->map->search->flag, ROOM_FLAG_VOID);
+				SET_BIT(*flag, ROOM_FLAG_INVIS);
 			}
-			else if (is_abbrev(buf, "static"))
+			else if (is_abbrev(ptf, "leave"))
 			{
-				SET_BIT(ses->map->search->flag, ROOM_FLAG_STATIC);
+				SET_BIT(*flag, ROOM_FLAG_LEAVE);
+			}
+			else if (is_abbrev(ptf, "void"))
+			{
+				SET_BIT(*flag, ROOM_FLAG_VOID);
+			}
+			else if (is_abbrev(ptf, "static"))
+			{
+				SET_BIT(*flag, ROOM_FLAG_STATIC);
 			}
 
 			if (*ptb == COMMAND_SEPARATOR)
@@ -3830,6 +3872,7 @@ void map_search_compile(struct session *ses, char *arg, char *var)
 	else
 	{
 		ses->map->search->flag = 0;
+		ses->map->search->galf = 0;
 	}
 
 	arg = sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN); // id
@@ -3848,6 +3891,17 @@ void map_search_compile(struct session *ses, char *arg, char *var)
 		ses->map->search->id = NULL;
 	}
 
+	arg = sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN); // distance
+
+	if (*buf)
+	{
+		ses->map->search->distance = (float) get_number(ses, buf);
+	}
+	else
+	{
+		ses->map->search->distance = 0;
+	}
+
 	pop_call();
 	return;
 }
@@ -3888,29 +3942,39 @@ int match_room(struct session *ses, int vnum, struct search_data *search)
 	{
 		char *arg, exit[BUFFER_SIZE];
 
-		if (search->exit_dirs != room->exit_dirs)
+		if (!strcmp(search->exit_list, "{*}"))
 		{
-			return 0;
-		}
-		if (search->exit_size != room->exit_size)
-		{
-			return 0;
+			if (search->exit_dirs != (room->exit_dirs | 1))
+			{
+				return 0;
+			}
 		}
-
-		arg = search->exit_list;
-
-		while (*arg)
+		else
 		{
-			arg = get_arg_in_braces(ses, arg, exit, GET_ONE);
-
-			if (!find_exit(ses, vnum, exit))
+			if (search->exit_dirs != room->exit_dirs)
+			{
+				return 0;
+			}
+			if (search->exit_size != room->exit_size)
 			{
 				return 0;
 			}
 
-			if (*arg == COMMAND_SEPARATOR)
+			arg = search->exit_list;
+
+			while (*arg)
 			{
-				arg++;
+				arg = get_arg_in_braces(ses, arg, exit, GET_ONE);
+
+				if (!find_exit(ses, vnum, exit))
+				{
+					return 0;
+				}
+
+				if (*arg == COMMAND_SEPARATOR)
+				{
+					arg++;
+				}
 			}
 		}
 	}
@@ -3954,6 +4018,32 @@ int match_room(struct session *ses, int vnum, struct search_data *search)
 			return 0;
 		}
 	}
+
+	if (search->galf)
+	{
+		if ((room->flags & search->galf) == search->galf)
+		{
+			return 0;
+		}
+	}
+
+	if (search->distance)
+	{
+		if (ses->map->search->stamp != room->search_stamp)
+		{
+			if (search->distance != -1)
+			{
+				return 0;
+			}
+		}
+		else
+		{
+			if (room->length > search->distance)
+			{
+				return 0;
+			}
+		}
+	}
 	return 1;
 }
 
@@ -4648,11 +4738,11 @@ void shortest_path(struct session *ses, int run, char *delay, char *arg)
 		{
 			if (HAS_BIT(ses->map->flags, MAP_FLAG_NOFOLLOW))
 			{
-				check_append_path(ses, exit->cmd, "", exit->delay, 0);
+				check_append_path(ses, exit->cmd, "", exit->delay, 1, 0);
 			}
 			else
 			{
-				check_append_path(ses, exit->name, "", exit->delay, 0);
+				check_append_path(ses, exit->name, "", exit->delay, 1, 0);
 			}
 		}
 
@@ -4660,7 +4750,7 @@ void shortest_path(struct session *ses, int run, char *delay, char *arg)
 
 		if (ses->map->room_list[vnum]->search_stamp != ses->map->search->stamp)
 		{
-			show_error(ses, LIST_COMMAND, "%d bad search stamp %d vs %d", vnum, ses->map->room_list[vnum]->search_stamp, ses->map->search->stamp);
+			show_error(ses, LIST_COMMAND, "#SHORTEST PATH: %d bad search stamp %d vs %d", vnum, ses->map->room_list[vnum]->search_stamp, ses->map->search->stamp);
 		}
 
 		if (vnum == dest)
@@ -4848,11 +4938,11 @@ void explore_path(struct session *ses, int run, char *arg1, char *arg2)
 
 	if (HAS_BIT(ses->map->flags, MAP_FLAG_NOFOLLOW))
 	{
-		check_append_path(ses, exit->cmd, "", exit->delay, 0);
+		check_append_path(ses, exit->cmd, "", exit->delay, 1, 0);
 	}
 	else
 	{
-		check_append_path(ses, exit->name, "", exit->delay, 0);
+		check_append_path(ses, exit->name, "", exit->delay, 1, 0);
 	}
 
 	SET_BIT(ses->map->room_list[room]->flags, ROOM_FLAG_PATH);
@@ -4876,11 +4966,11 @@ void explore_path(struct session *ses, int run, char *arg1, char *arg2)
 		{
 			if (HAS_BIT(ses->map->flags, MAP_FLAG_NOFOLLOW))
 			{
-				check_append_path(ses, exit->cmd, "", exit->delay, 0);
+				check_append_path(ses, exit->cmd, "", exit->delay, 1, 0);
 			}
 			else
 			{
-				check_append_path(ses, exit->name, "", exit->delay, 0);
+				check_append_path(ses, exit->name, "", exit->delay, 1, 0);
 			}
 		}
 
@@ -5419,7 +5509,7 @@ DO_MAP(map_dig)
 		return;
 	}
 
-	room = (int) tintoi(arg1);
+	room = (int) get_number(ses, arg1);
 
 	if (room > 0 && room < ses->map->size)
 	{
@@ -6223,6 +6313,8 @@ DO_MAP(map_goto)
 	}
 	add_undo(ses, "%d %d %d", room, ses->map->in_room, MAP_UNDO_MOVE);
 
+	ses->map->dir = 0;
+
 	goto_room(ses, room);
 
 	show_message(ses, LIST_COMMAND, "#MAP GOTO: MOVED TO ROOM %d {%s}.", room, *ses->map->room_list[room]->name ? ses->map->room_list[room]->name : ses->map->room_list[room]->id);
@@ -6455,6 +6547,8 @@ DO_MAP(map_jump)
 	{
 		add_undo(ses, "%d %d %d", room, ses->map->in_room, MAP_UNDO_MOVE);
 
+		ses->map->dir = 0;
+
 		goto_room(ses, room);
 
 		show_message(ses, LIST_COMMAND, "#MAP JUMP: JUMPED TO ROOM %d {%s}.", room, *ses->map->room_list[room]->name ? ses->map->room_list[room]->name : ses->map->room_list[room]->id);
@@ -6916,7 +7010,7 @@ DO_MAP(map_map)
 
 				if (logfile)
 				{
-					loginit(ses, logfile, LOG_FLAG_APPEND | HAS_BIT(ses->logmode, LOG_FLAG_HTML));
+					logheader(ses, logfile, LOG_FLAG_APPEND | HAS_BIT(ses->log->mode, LOG_FLAG_HTML));
 				}
 				else
 				{
@@ -6947,7 +7041,7 @@ DO_MAP(map_map)
 
 				if (logfile)
 				{
-					loginit(ses, logfile, LOG_FLAG_OVERWRITE | HAS_BIT(ses->logmode, LOG_FLAG_HTML));
+					logheader(ses, logfile, LOG_FLAG_OVERWRITE | HAS_BIT(ses->log->mode, LOG_FLAG_HTML));
 				}
 				else
 				{
@@ -7727,7 +7821,7 @@ DO_MAP(map_roomflag)
 	}
 	if (HAS_BIT(flag, ROOM_FLAG_BLOCK))
 	{
-		show_message(ses, LIST_COMMAND, "#MAP: Block flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_AVOID) ? "ON" : "OFF");
+		show_message(ses, LIST_COMMAND, "#MAP: Block flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_BLOCK) ? "ON" : "OFF");
 	}
 	if (HAS_BIT(flag, ROOM_FLAG_CURVED))
 	{

+ 0 - 4
src/math.c

@@ -139,12 +139,8 @@ long double get_number(struct session *ses, char *str)
 	long double val;
 	char result[BUFFER_SIZE];
 
-	SET_BIT(gtd->flags, TINTIN_FLAG_GETNUMBER);
-
 	val = mathexp(ses, str, result, 0);
 
-	DEL_BIT(gtd->flags, TINTIN_FLAG_GETNUMBER);
-
 	return val;
 }
 

Разлика између датотеке није приказан због своје велике величине
+ 0 - 81
src/misc.c


+ 1 - 8
src/nest.c

@@ -549,7 +549,6 @@ int get_nest_size_val(struct listroot *root, char *variable, char **result)
 {
 	char name[BUFFER_SIZE], *arg;
 	int index, count;
-	static int warning;
 
 	arg = get_arg_to_brackets(root->ses, variable, name);
 
@@ -637,14 +636,9 @@ int get_nest_size_val(struct listroot *root, char *variable, char **result)
 		{
 			if (!strcmp(arg, "[]"))
 			{
-				if (++warning < 100)
-				{
-					tintin_printf2(root->ses, "\n\e[1;5;31mdebug: please use *%s instead of $%s.\n", variable, variable);
-				}
-
 				for (index = 0 ; index < root->used ; index++)
 				{
-					str_cat_printf(result, "{%s}", root->list[index]->arg1);
+					str_cat_printf(result, "{%s}", root->list[index]->arg2);
 				}
 				return root->used + 1;
 			}
@@ -980,7 +974,6 @@ struct listnode *set_nest_node_ses(struct session *ses, char *arg1, char *format
 		arg = get_arg_to_brackets(ses, arg1, name);
 
 		check_all_events(root->ses, EVENT_FLAG_VARIABLE, 1, 3, "VARIABLE UPDATED %s", name, name, arg2, arg1);
-		check_all_events(root->ses, EVENT_FLAG_VARIABLE, 1, 3, "VARIABLE UPDATED %s", arg1, name, arg2, arg1);
 	}
 	free(arg2);
 

+ 1 - 0
src/net.c

@@ -32,6 +32,7 @@
 #include <netinet/in.h>
 #include <netdb.h>
 #include <signal.h>
+#include <sys/socket.h>
 #include <sys/types.h>
 
 /*

+ 11 - 10
src/parse.c

@@ -171,7 +171,7 @@ struct session *parse_input(struct session *ses, char *input)
 	char *line;
 
 	push_call("parse_input(%s,%s)",ses->name,input);
-
+/*
 	if (*input == 0)
 	{
 		write_mud(ses, input, SUB_EOL);
@@ -179,7 +179,7 @@ struct session *parse_input(struct session *ses, char *input)
 		pop_call();
 		return ses;
 	}
-
+*/
 	line = str_alloc_stack(0);
 
 	if (VERBATIM(ses))
@@ -211,7 +211,7 @@ struct session *parse_input(struct session *ses, char *input)
 		return ses;
 	}
 
-	while (*input)
+	do
 	{
 		input = space_out(input);
 
@@ -239,6 +239,7 @@ struct session *parse_input(struct session *ses, char *input)
 			input++;
 		}
 	}
+	while (*input);
 
 	pop_call();
 	return ses;
@@ -664,7 +665,7 @@ char *get_arg_in_braces(struct session *ses, char *string, char *result, int fla
 
 	if (*pti == 0)
 	{
-		tintin_printf2(ses, "#ERROR: GET BRACED ARGUMENT: UNMATCHED BRACE.");
+		show_error(ses, LIST_COMMAND, "#ERROR: GET BRACED ARGUMENT: UNMATCHED BRACE.");
 	}
 	else
 	{
@@ -1025,7 +1026,7 @@ char *get_arg_at_brackets(struct session *ses, char *string, char *result)
 
 	if (nest)
 	{
-		tintin_printf2(NULL, "#ERROR: GET BRACKETED VARIABLE: UNMATCHED BRACKET.");
+		show_error(ses, LIST_COMMAND, "#ERROR: GET BRACKETED VARIABLE: UNMATCHED BRACKET.");
 	}
 	*pto = 0;
 
@@ -1076,7 +1077,7 @@ char *get_arg_in_brackets(struct session *ses, char *string, char *result)
 
 	if (*pti == 0)
 	{
-		tintin_printf2(NULL, "#ERROR: GET BRACKETED ARGUMENT: UNMATCHED BRACKET.");
+		show_error(ses, LIST_COMMAND, "#ERROR: GET BRACKETED ARGUMENT: UNMATCHED BRACKET.");
 	}
 	else
 	{
@@ -1122,7 +1123,7 @@ void write_mud(struct session *ses, char *command, int flags)
 	{
 		if (ses->map == NULL || ses->map->nofollow == 0)
 		{
-			check_append_path(ses, command, NULL, 0.0, 1);
+			check_append_path(ses, command, NULL, 0.0, 0, 1);
 		}
 	}
 
@@ -1195,11 +1196,11 @@ void do_one_line(char *line, struct session *ses)
 		check_all_highlights(ses, line, strip);
 	}
 
-	if (HAS_BIT(ses->logmode, LOG_FLAG_NEXT))
+	if (HAS_BIT(ses->log->mode, LOG_FLAG_NEXT))
 	{
-		logit(ses, line, ses->lognext_file, LOG_FLAG_LINEFEED);
+		logit(ses, line, ses->log->next_file, LOG_FLAG_LINEFEED);
 
-		DEL_BIT(ses->logmode, LOG_FLAG_NEXT);
+		DEL_BIT(ses->log->mode, LOG_FLAG_NEXT);
 	}
 
 	pop_script_stack();

+ 16 - 62
src/path.c

@@ -299,6 +299,10 @@ DO_PATH(path_get)
 			(root->list[root->update]->val64 - gtd->utime) / 1000000.0);
 	}
 	else if (*arg2 == 0)
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH GET <INFO|LENGTH|MAPPING|POSITION|RUNNING> <VARIABLE NAME>");
+	}
+	else if (is_abbrev(arg1, "INFO"))
 	{
 		set_nest_node_ses(ses, arg2, "{length}{%d}", root->used);
 
@@ -350,7 +354,7 @@ DO_PATH(path_get)
 	}
 	else
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH GET <LENGTH|POSITION> <VARIABLE NAME>");
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH GET <INFO|LENGTH|MAPPING|POSITION|RUNNING> <VARIABLE NAME>");
 	}
 }
 
@@ -510,7 +514,6 @@ DO_PATH(path_delete)
 
 DO_PATH(path_insert)
 {
-	struct listroot *root = ses->list[LIST_PATH];
 	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE];
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
@@ -523,14 +526,9 @@ DO_PATH(path_insert)
 	}
 	else
 	{
-		create_node_list(root, arg1, arg2, arg3, "");
-
 		show_message(ses, LIST_COMMAND, "#PATH INSERT: FORWARD {%s} BACKWARD {%s} DELAY {%s}.", arg1, arg2, arg3);
 
-		if (HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING))
-		{
-			root->update = root->used;
-		}
+		check_append_path(ses, arg1, arg2, (float) get_number(ses, arg3), 1, HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING));
 	}
 }
 
@@ -835,59 +833,6 @@ DO_PATH(path_unzip)
 			}
 		}
 	}
-/*
-		arg = get_arg_in_braces(ses, arg, temp, GET_ALL);
-
-		if (is_speedwalk(ses, temp))
-		{
-			char dir[2];
-			int cnt, i;
-
-			str = temp;
-
-			for (dir[1] = 0 ; *str ; str++)
-			{
-				if (is_digit(*str))
-				{
-					sscanf(str, "%d%c", &cnt, dir);
-
-					while (*str != dir[0])
-					{
-						str++;
-					}
-				}
-				else
-				{
-					cnt = 1;
-					dir[0] = *str;
-				}
-
-				for (i = 0 ; i < cnt ; i++)
-				{
-					if ((node = search_node_list(ses->list[LIST_PATHDIR], dir)))
-					{
-						create_node_list(root, node->arg1, node->arg2, "0", "");
-					}
-					else
-					{
-						create_node_list(root, dir, dir, "0", "");
-					}
-				}
-			}
-		}
-		else
-		{
-			if ((node = search_node_list(ses->list[LIST_PATHDIR], temp)))
-			{
-				create_node_list(root, node->arg1, node->arg2, "0", "");
-			}
-			else
-			{
-				create_node_list(root, temp, temp, "0", "");
-			}
-		}
-	}
-*/
 	show_message(ses, LIST_COMMAND, "#PATH UNZIP: PATH WITH %d NODES UNZIPPED.", root->used);
 }
 
@@ -1009,7 +954,7 @@ DO_PATH(path_undo)
 	show_message(ses, LIST_COMMAND, "#PATH MOVE: POSITION SET TO %d.", root->update);
 }
 
-void check_append_path(struct session *ses, char *forward, char *backward, float delay, int follow)
+void check_append_path(struct session *ses, char *forward, char *backward, float delay, int force, int follow)
 {
 	struct listroot *root = ses->list[LIST_PATH];
 	struct listnode *node;
@@ -1024,6 +969,15 @@ void check_append_path(struct session *ses, char *forward, char *backward, float
 
 			root->update = root->used;
 		}
+		else if (force)
+		{
+			show_debug(ses, LIST_PATHDIR, "#DEBUG PATHDIR {%s} {%s}", forward, backward);
+				
+			create_node_list(root, forward, backward, ftos(delay), "");
+
+			root->update = root->used;
+		}
+				
 	}
 	else
 	{

+ 1 - 1
src/regex.c

@@ -1190,7 +1190,7 @@ void tintin_macro_compile(char *input, char *output)
 
 					case 'n':
 						*pto++ = ASCII_LF;
-						*pti += 2;
+						pti  += 2;
 						break;
 
 					case 'r':

+ 1 - 0
src/scan.c

@@ -33,6 +33,7 @@
   #endif
 #endif
 #include <dirent.h>
+#include <limits.h>
 
 #define DO_SCAN(scan) struct session *scan(struct session *ses, FILE *fp, char *arg, char *arg1, char *arg2)
 

+ 18 - 25
src/session.c

@@ -30,15 +30,15 @@
 
 DO_COMMAND(do_all)
 {
-	struct session *sesptr;
+	struct session *sesptr, *sesptr_next;
 
 	if (gts->next)
 	{
 		sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
 
-		for (sesptr = gts->next ; sesptr ; sesptr = gtd->all)
+		for (sesptr = gts->next ; sesptr ; sesptr = sesptr_next)
 		{
-			gtd->all = sesptr->next;
+			sesptr_next = sesptr->next;
 
 			if (!HAS_BIT(sesptr->flags, SES_FLAG_CLOSED))
 			{
@@ -80,7 +80,7 @@ DO_COMMAND(do_session)
 				sesptr->ssl ? "(ssl)" : sesptr->port ? "(port)" : HAS_BIT(sesptr->flags, SES_FLAG_RUN) ? " (run)" : "",
 				sesptr->mccp2 && sesptr->mccp3 ? "(mccp 2+3)" : sesptr->mccp2 ? "(mccp 2)" : sesptr->mccp3 ? "(mccp 3)" : "",
 				HAS_BIT(sesptr->flags, SES_FLAG_SNOOP|SES_FLAG_SNOOPSCROLL) ? "(snoop)" : "",
-				sesptr->logfile ? "(log)" : "");
+				sesptr->log->file ? "(log)" : "");
 		}
 	}
 	else if (*arg1 && *arg == 0)
@@ -404,7 +404,6 @@ struct session *new_session(struct session *ses, char *name, char *arg, int desc
 	newses->flags          = gts->flags;
 	newses->config_flags   = gts->config_flags;
 	newses->color          = gts->color;
-	newses->logmode        = gts->logmode;
 	newses->charset        = gts->charset;
 
 	newses->telopts        = gts->telopts;
@@ -416,9 +415,6 @@ struct session *new_session(struct session *ses, char *name, char *arg, int desc
 	newses->read_max       = gts->read_max;
 	newses->read_buf       = (unsigned char *) calloc(1, gts->read_max);
 
-	newses->logname        = strdup("");
-	newses->lognext_name   = strdup("");
-	newses->logline_name   = strdup("");
 	newses->rand           = ++gtd->utime;
 
 	newses->more_output    = str_dup("");
@@ -458,13 +454,16 @@ struct session *new_session(struct session *ses, char *name, char *arg, int desc
 
 	newses->wrap          = gts->wrap;
 
-	newses->scroll        = calloc(1, sizeof(struct scroll_data));
-	init_buffer(newses, gts->scroll->size);
+	newses->log           = calloc(1, sizeof(struct log_data));
+	init_log(newses);
+	ses->log->mode        = gts->log->mode;
 
 	newses->input         = calloc(1, sizeof(struct input_data));
-
 	init_input(newses, 0, 0, 0, 0);
 
+	newses->scroll        = calloc(1, sizeof(struct scroll_data));
+	init_buffer(newses, gts->scroll->size);
+
 	memcpy(&newses->cur_terminal, &gts->cur_terminal, sizeof(gts->cur_terminal));
 
 	if (desc == 0)
@@ -651,11 +650,6 @@ void cleanup_session(struct session *ses)
 		gtd->update = ses->next;
 	}
 
-	if (ses == gtd->all)
-	{
-		gtd->all = ses->next;
-	}
-
 	UNLINK(ses, gts->next, gts->prev);
 
 	if (ses->socket)
@@ -748,19 +742,19 @@ void dispose_session(struct session *ses)
 
 	UNLINK(ses, gtd->dispose_next, gtd->dispose_prev);
 
-	if (ses->logfile)
+	if (ses->log->file)
 	{
-		fclose(ses->logfile);
+		fclose(ses->log->file);
 	}
 
-	if (ses->lognext_file)
+	if (ses->log->next_file)
 	{
-		fclose(ses->lognext_file);
+		fclose(ses->log->next_file);
 	}
 
-	if (ses->logline_file)
+	if (ses->log->line_file)
 	{
-		fclose(ses->logline_file);
+		fclose(ses->log->line_file);
 	}
 
 	if (ses->map)
@@ -777,6 +771,8 @@ void dispose_session(struct session *ses)
 
 	free_input(ses);
 
+	free_log(ses);
+
 	free(ses->name);
 	free(ses->session_host);
 	free(ses->session_ip);
@@ -784,9 +780,6 @@ void dispose_session(struct session *ses)
 	free(ses->group);
 	free(ses->read_buf);
 	free(ses->cmd_color);
-	free(ses->logname);
-	free(ses->lognext_name);
-	free(ses->logline_name);
 	free(ses->split);
 	free(ses->input);
 

+ 48 - 36
src/show.c

@@ -31,14 +31,14 @@
 DO_COMMAND(do_showme)
 {
 	char *out, *tmp;
-	int lnf;
+	int prompt;
 
 	out = str_alloc_stack(0);
 	tmp = str_alloc_stack(0);
 
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
 
-	lnf = is_suffix(arg1, "\\") && !is_suffix(arg1, "\\\\");
+	prompt = is_suffix(arg1, "\\") && !is_suffix(arg1, "\\\\");
 
 	substitute(ses, arg1, tmp, SUB_VAR|SUB_FUN);
 	substitute(ses, tmp, arg1, SUB_COL|SUB_ESC);
@@ -64,34 +64,46 @@ DO_COMMAND(do_showme)
 		return ses;
 	}
 
-	if (strip_vt102_strlen(ses, ses->more_output) != 0)
-	{
-		str_cpy_printf(&out, "\n%s%s%s", COLOR_TEXT, arg1, COLOR_TEXT);
-	}
-	else
-	{
-		str_cpy_printf(&out, "%s%s%s", COLOR_TEXT, arg1, COLOR_TEXT);
-	}
+	str_cpy_printf(&out, "%s%s%s", COLOR_TEXT, arg1, COLOR_TEXT);
 
-	add_line_buffer(ses, out, lnf);
+	tintin_puts3(ses, out, prompt);
 
-	if (ses == gtd->ses)
-	{
-		if (!HAS_BIT(ses->flags, SES_FLAG_READMUD) && IS_SPLIT(ses))
-		{
-			save_pos(ses);
+	return ses;
+}
 
-			goto_pos(ses, ses->split->bot_row, ses->split->top_col);
-		}
+DO_COMMAND(do_echo)
+{
+	char *result, *out;
+	int prompt;
 
-		print_line(ses, &out, lnf);
+	result = arg2;
 
-		if (!HAS_BIT(ses->flags, SES_FLAG_READMUD) && IS_SPLIT(ses))
-		{
-			restore_pos(ses);
-		}
+	out = str_alloc_stack(0);
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+
+	format_string(ses, arg1, arg, result);
+
+	arg = get_arg_in_braces(ses, result, arg1, GET_ALL);
+
+	prompt = is_suffix(arg1, "\\") && !is_suffix(arg1, "\\\\");
+
+	substitute(ses, arg1, arg1, SUB_COL|SUB_ESC);
+
+	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
+	arg = sub_arg_in_braces(ses, arg, arg3, GET_ONE, SUB_VAR|SUB_FUN);
+
+	if (*arg2)
+	{
+		split_show(ses, arg1, arg2, arg3);
+
+		return ses;
 	}
 
+	str_cpy_printf(&out, "%s%s%s", COLOR_TEXT, arg1, COLOR_TEXT);
+
+	tintin_puts3(ses, out, prompt);
+
 	return ses;
 }
 
@@ -150,7 +162,7 @@ void show_message(struct session *ses, int index, char *format, ...)
 
 	if (HAS_BIT(root->flags, LIST_FLAG_LOG))
 	{
-		if (ses->logfile)
+		if (ses->log->file)
 		{
 			va_start(args, format);
 
@@ -163,7 +175,7 @@ void show_message(struct session *ses, int index, char *format, ...)
 			}
 			va_end(args);
 
-			logit(ses, buffer, ses->logfile, LOG_FLAG_LINEFEED);
+			logit(ses, buffer, ses->log->file, LOG_FLAG_LINEFEED);
 
 			free(buffer);
 		}
@@ -218,9 +230,9 @@ void show_error(struct session *ses, int index, char *format, ...)
 
 	if (HAS_BIT(root->flags, LIST_FLAG_LOG))
 	{
-		if (ses->logfile)
+		if (ses->log->file)
 		{
-			logit(ses, buffer, ses->logfile, LOG_FLAG_LINEFEED);
+			logit(ses, buffer, ses->log->file, LOG_FLAG_LINEFEED);
 		}
 	}
 
@@ -268,9 +280,9 @@ void show_debug(struct session *ses, int index, char *format, ...)
 
 	if (HAS_BIT(root->flags, LIST_FLAG_LOG))
 	{
-		if (ses->logfile)
+		if (ses->log->file)
 		{
-			logit(ses, buf, ses->logfile, LOG_FLAG_LINEFEED);
+			logit(ses, buf, ses->log->file, LOG_FLAG_LINEFEED);
 		}
 	}
 	pop_call();
@@ -363,7 +375,7 @@ void show_lines(struct session *ses, char *str)
 		}
 		*ptf++ = 0;
 
-		tintin_puts3(ses, str);
+		tintin_puts3(ses, str, FALSE);
 
 		str = ptf;
 	}
@@ -503,7 +515,7 @@ void tintin_puts2(struct session *ses, char *string)
 
 	str_cpy_printf(&output, "%s%s%s", COLOR_TEXT, string, COLOR_TEXT);
 
-	tintin_puts3(ses, output);
+	tintin_puts3(ses, output, FALSE);
 
 	pop_call();
 	return;
@@ -515,11 +527,11 @@ void tintin_puts2(struct session *ses, char *string)
 	show string, no triggers, no color reset
 */
 
-void tintin_puts3(struct session *ses, char *string)
+void tintin_puts3(struct session *ses, char *string, int prompt)
 {
 	char *output;
 
-	push_call("tintin_puts3(%p,%p)",ses,string);
+	push_call("tintin_puts3(%p,%p,%d)",ses,string,prompt);
 
 	if (ses == NULL)
 	{
@@ -552,10 +564,10 @@ void tintin_puts3(struct session *ses, char *string)
 	}
 	else
 	{
-		str_cpy_printf(&output, "%s", string);
+		str_cpy(&output, string);
 	}
 
-	add_line_buffer(ses, output, FALSE);
+	add_line_buffer(ses, output, prompt);
 
 	if (ses == gtd->ses)
 	{
@@ -566,7 +578,7 @@ void tintin_puts3(struct session *ses, char *string)
 			goto_pos(ses, ses->split->bot_row, ses->split->top_col);
 		}
 
-		print_line(ses, &output, FALSE);
+		print_line(ses, &output, prompt);
 
 		if (!HAS_BIT(ses->flags, SES_FLAG_READMUD) && IS_SPLIT(ses))
 		{

+ 4 - 5
src/split.c

@@ -258,7 +258,7 @@ void dirty_screen(struct session *ses)
 void split_show(struct session *ses, char *prompt, char *row_str, char *col_str)
 {
 	char buf1[BUFFER_SIZE];
-	int row, col, len, width, clear;
+	int row, col, width, clear;
 
 	row = 0;
 
@@ -315,7 +315,7 @@ void split_show(struct session *ses, char *prompt, char *row_str, char *col_str)
 		return;
 	}
 
-	len = strip_vt102_width(ses, prompt, &width);
+	strip_vt102_width(ses, prompt, &width);
 
 	if (col - 1 + width <= gtd->screen->cols)
 	{
@@ -323,11 +323,10 @@ void split_show(struct session *ses, char *prompt, char *row_str, char *col_str)
 	}
 	else
 	{
-		show_debug(ses, LIST_PROMPT, "#DEBUG PROMPT {%s}", prompt);
+		sprintf(buf1, "%.*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);
-
-		sprintf(buf1, "#PROMPT WIDTH %d WITH OFFSET %d LONGER THAN ROW SIZE %d.", len, col, gtd->screen->cols);
 	}
 
 	save_pos(ses);

+ 2 - 0
src/ssl.c

@@ -363,6 +363,8 @@ nocert:
 		{
 			tintin_printf(ses, "#SSL ERROR: %s", err);
 
+			get_cert_file(ses, filename);
+
 			tintin_printf(ses, "#SSL ALERT: THE SERVER'S SETTINGS WERE CHANGED IN AN UNEXPECTED WAY.");
 			tintin_printf(ses, "#SSL ALERT: YOU MAY BE VULNERABLE TO MAN-IN-THE-MIDDLE ATTACKS.");
 			tintin_printf(ses, "#SSL ALERT: TO CONTINUE, PLEASE DELETE THE FILE:");

+ 5 - 5
src/string.c

@@ -84,7 +84,7 @@ int str_len_str(struct session *ses, char *str, int start, int end)
 		}
 		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(str))
 		{
-			tmp_cnt = get_utf8_width(str, &width);
+			tmp_cnt = get_utf8_width(str, &width, NULL);
 
 			if (str_cnt >= start)
 			{
@@ -133,7 +133,7 @@ int str_len_raw(struct session *ses, char *str, int start, int end)
 		}
 		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&str[raw_cnt]))
 		{
-			raw_cnt += get_utf8_width(&str[raw_cnt], &width);
+			raw_cnt += get_utf8_width(&str[raw_cnt], &width, NULL);
 			ret_cnt += width;
 		}
 		else
@@ -170,7 +170,7 @@ int raw_len_str(struct session *ses, char *str, int start, int end)
 		}
 		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&str[raw_cnt]))
 		{ 
-			tmp_cnt = get_utf8_width(&str[raw_cnt], &width);
+			tmp_cnt = get_utf8_width(&str[raw_cnt], &width, NULL);
 
 			if (str_cnt >= start)
 			{
@@ -229,7 +229,7 @@ int raw_len_str_min(struct session *ses, char *str, int start, int end)
 		}
 		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&str[raw_cnt]))
 		{    
-			tmp_cnt = get_utf8_width(&str[raw_cnt], &width);
+			tmp_cnt = get_utf8_width(&str[raw_cnt], &width, NULL);
 
 			if (str_cnt >= start)
 			{
@@ -288,7 +288,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);
+			tmp_cnt = get_utf8_width(&str[raw_cnt], &width, NULL);
 
 			if (str_cnt >= start)
 			{

+ 68 - 23
src/substitute.c

@@ -329,19 +329,11 @@ int is_variable(struct session *ses, char *str)
 
 	if (root == NULL)
 	{
-		if (str[0] == '&' && HAS_BIT(gtd->flags, TINTIN_FLAG_GETNUMBER))
-		{
-			show_error(ses, LIST_VARIABLE, "\e[1;31m#WARNING: FOUND %c%s. USE %c{%s} INSTEAD?", str[0], temp, str[0], temp);
-		}
 		return FALSE;
 	}
 
 	if (search_node_list(root, temp) == NULL)
 	{
-		if (str[0] == '&' && HAS_BIT(gtd->flags, TINTIN_FLAG_GETNUMBER))
-		{
-			show_error(ses, LIST_VARIABLE, "\e[1;31m#WARNING: FOUND %c%s. USE %c{%s} INSTEAD?", str[0], temp, str[0], temp);
-		}
 		return FALSE;
 	}
 
@@ -1069,7 +1061,22 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 			case '\0':
 				if (HAS_BIT(flags, SUB_EOL))
 				{
-					if (HAS_BIT(ses->flags, SES_FLAG_RUN))
+					if (HAS_BIT(ses->telopts, TELOPT_FLAG_CR|TELOPT_FLAG_LF))
+					{
+						if (HAS_BIT(ses->telopts, TELOPT_FLAG_CR))
+						{
+							*pto++ = '\r';
+						}
+						if (HAS_BIT(ses->telopts, TELOPT_FLAG_LF))
+						{
+							*pto++ = '\n';
+						}
+						if (HAS_BIT(ses->telopts, TELOPT_FLAG_NUL))
+						{
+							*pto++ = '\0';
+						}
+					}
+					else if (HAS_BIT(ses->flags, SES_FLAG_RUN))
 					{
 						*pto++ = '\r';
 					}
@@ -1703,6 +1710,30 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 								}
 								ptt++;
 							}
+							else if (HAS_BIT(flags, SUB_BRA))
+							{
+								switch (*ptt)
+								{
+									case '{':
+										*pto++ = '\\';
+										*pto++ = 'x';
+										*pto++ = '7';
+										*pto++ = 'B';
+										break;
+
+									case '}':
+										*pto++ = '\\';
+										*pto++ = 'x';
+										*pto++ = '7';
+										*pto++ = 'D';
+										break;
+
+									default:
+										*pto++ = *ptt;
+										break;
+								}
+								ptt++;
+							}
 							else
 							{
 								*pto++ = *ptt++;
@@ -2133,6 +2164,34 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 				}
 				break;
 
+			case '{':
+			case '}':
+				if (HAS_BIT(flags, SUB_SEC|SUB_BRA) && !HAS_BIT(flags, SUB_ARG))
+				{
+					switch (*pti)
+					{
+						case '{':
+							*pto++ = '\\';
+							*pto++ = 'x';
+							*pto++ = '7';
+							*pto++ = 'B';
+							break;
+
+						case '}':
+							*pto++ = '\\';
+							*pto++ = 'x';
+							*pto++ = '7';
+							*pto++ = 'D';
+							break;
+					}
+					pti++;
+				}
+				else
+				{
+					*pto++ = *pti++;
+				}
+				break;	
+
 			default:
 				if (HAS_BIT(flags, SUB_SEC) && !HAS_BIT(flags, SUB_ARG))
 				{
@@ -2152,20 +2211,6 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 							}
 							break;
 
-						case '{':
-							*pto++ = '\\';
-							*pto++ = 'x';
-							*pto++ = '7';
-							*pto++ = 'B';
-							break;
-
-						case '}':
-							*pto++ = '\\';
-							*pto++ = 'x';
-							*pto++ = '7';
-							*pto++ = 'D';
-							break;
-
 						case COMMAND_SEPARATOR:
 							*pto++ = '\\';
 							*pto++ = COMMAND_SEPARATOR;

+ 13 - 15
src/tables.c

@@ -57,15 +57,16 @@ struct list_type list_table[LIST_MAX] =
 struct substitution_type substitution_table[] =
 {
 	{    "ARGUMENTS",            SUB_ARG },
-	{    "VARIABLES",            SUB_VAR },
-	{    "FUNCTIONS",            SUB_FUN },
+	{    "BRACES",               SUB_BRA },
 	{    "COLORS",               SUB_COL },
-	{    "ESCAPES",              SUB_ESC },
 //	{    "COMMANDS",             SUB_CMD },
-	{    "SECURE",               SUB_SEC },
 	{    "EOL",                  SUB_EOL },
-	{    "LNF",                  SUB_LNF },
+	{    "ESCAPES",              SUB_ESC },
+	{    "FUNCTIONS",            SUB_FUN },
         {    "LITERAL",              SUB_LIT },
+	{    "LNF",                  SUB_LNF },
+	{    "SECURE",               SUB_SEC },
+	{    "VARIABLES",            SUB_VAR },
 	{    "",                     0       }
 };
 
@@ -927,7 +928,7 @@ struct cursor_type cursor_table[] =
 	{     "",                   "",                                               "\e[1;2a",                        0,    cursor_buffer_up,             ""          },
 	{     "",                   "",                                               "\e[1;2b",                        0,    cursor_buffer_down,           ""          },
 	{     "",                   "",                                               "",                              0,    cursor_buffer_lock,           ""          },
-//	{     "",                   "",                                               "\e[13;2u",                       0,    cursor_enter,                 ""          },
+	{     "",                   "",                                               "\e[13;129u",                     0,    cursor_enter,                 ""          },
 	{     "",                   "",                                               "\eOM",                           0,    cursor_enter,                 ""          },
 	{     "",                   "",                                               "\e[7~",                          0,    cursor_home,                  ""          },
 	{     "",                   "",                                               "\e[1~",                          0,    cursor_home,                  ""          },
@@ -935,15 +936,20 @@ struct cursor_type cursor_table[] =
 	{     "",                   "",                                               "\e[H",                           0,    cursor_home,                  ""          },
 	{     "",                   "",                                               "\eOD",                           0,    cursor_move_left,             ""          },
 	{     "",                   "",                                               "\e[D",                           0,    cursor_move_left,             ""          },
+	{     "",                   "",                                               "\e[1;129D",                      0,    cursor_move_left,             ""          },
 	{     "",                   "",                                               "\e[8~",                          0,    cursor_end,                   ""          },
 	{     "",                   "",                                               "\e[4~",                          0,    cursor_end,                   ""          },
 	{     "",                   "",                                               "\eOF",                           0,    cursor_end,                   ""          },
 	{     "",                   "",                                               "\e[F",                           0,    cursor_end,                   ""          },
 	{     "",                   "",                                               "\eOC",                           0,    cursor_move_right,            ""          },
 	{     "",                   "",                                               "\e[C",                           0,    cursor_move_right,            ""          },
+	{     "",                   "",                                               "\e[1;129C",                      0,    cursor_move_right,            ""          },
 	{     "",                   "",                                               "\x7F",                           0,    cursor_backspace,             ""          },
+	{     "",                   "",                                               "\e[127;129u",                    0,    cursor_backspace,             ""          },
 	{     "",                   "",                                               "\eOB",                           0,    cursor_move_down,             ""          },
+	{     "",                   "",                                               "\e[1;129B",                      0,    cursor_move_down,             ""          },
 	{     "",                   "",                                               "\eOA",                           0,    cursor_move_up,               ""          },
+	{     "",                   "",                                               "\e[1;129A",                      0,    cursor_move_up,               ""          },
 	{     "",                   "",                                               "\e[1;5D",                        0,    cursor_move_left_word,        ""          },
 	{     "",                   "",                                               "\e[1;5C",                        0,    cursor_move_right_word,       ""          },
 	{     "",                   "",                                               "\e[1;5B",                        0,    cursor_move_page_down,        ""          },
@@ -1044,6 +1050,7 @@ struct event_type event_table[] =
 	{    "READ FILE",                              0, EVENT_FLAG_SYSTEM,   "SYSTEM",    "the read command finished"  },
 	{    "RECEIVED ERROR",                         0, EVENT_FLAG_SYSTEM,   "SYSTEM",    "an error is received"       },
 	{    "RECEIVED INPUT",                         0, EVENT_FLAG_INPUT,    "INPUT",     "keyboard input is received" },
+	{    "RECEIVED INPUT CHARACTER",               0, EVENT_FLAG_INPUT,    "INPUT",     "keyboard input character"   },
 	{    "RECEIVED KEYPRESS",                      0, EVENT_FLAG_INPUT,    "INPUT",     "a keypress is received"     },
 	{    "RECEIVED LINE",                          0, EVENT_FLAG_OUTPUT,   "OUTPUT",    "a new line is received"     },
 	{    "RECEIVED OUTPUT",                        0, EVENT_FLAG_OUTPUT,   "OUTPUT",    "bulk output is received"    },
@@ -1157,15 +1164,6 @@ struct line_type line_table[] =
 	{    "",                  NULL,                ""                                               }
 };
 
-struct log_type log_table[] =
-{
-	{    "APPEND",            log_append,          "Start logging, appending to given file."        },
-	{    "INFO",              log_info,            "Some logging related info."                     },
-	{    "OFF",               log_off,             "Stop logging."                                  },
-	{    "OVERWRITE",         log_overwrite,       "Start logging, overwriting the given file."     },
-	{    "",                  NULL,                ""                                               }
-};
-
 struct history_type history_table[] =
 {
 //	{    "CHARACTER",         history_character,   "Set the character used for repeating commands." },

+ 2 - 2
src/telopt_client.c

@@ -216,9 +216,9 @@ int client_translate_telopts(struct session *ses, unsigned char *src, int cplen)
 		cpsrc = src;
 	}
 
-	if (HAS_BIT(ses->logmode, LOG_FLAG_LOW) && ses->logfile)
+	if (HAS_BIT(ses->log->mode, LOG_FLAG_LOW) && ses->log->file)
 	{
-		fwrite(cpsrc, 1, cplen, ses->logfile);
+		fwrite(cpsrc, 1, cplen, ses->log->file);
 	}
 
  	if (ses->read_len + cplen >= ses->read_max)

+ 75 - 64
src/tintin.h

@@ -89,6 +89,9 @@
 #define gnutls_session_t int
 #endif
 
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
 
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
@@ -207,7 +210,7 @@
 #define STRING_SIZE        2 * BUFFER_SIZE
 
 #define CLIENT_NAME              "TinTin++"
-#define CLIENT_VERSION           "2.02.11 "
+#define CLIENT_VERSION           "2.02.12 "
 
 
 #define XT_E                            0x27
@@ -549,45 +552,47 @@ enum operators
 
 #define SUB_ARG                       BV01
 #define SUB_SEC                       BV02
-#define SUB_CMD                       BV03
-#define SUB_VAR                       BV04
-#define SUB_FUN                       BV05
-#define SUB_COL                       BV06
-#define SUB_ESC                       BV07
-#define SUB_EOL                       BV08 // telnet
-#define SUB_LNF                       BV09
-#define SUB_SIL                       BV10 // silent
-#define SUB_LIT                       BV11 // no soft escaping
-
+#define SUB_BRA                       BV03
+#define SUB_CMD                       BV04
+#define SUB_VAR                       BV05
+#define SUB_FUN                       BV06
+#define SUB_COL                       BV07
+#define SUB_ESC                       BV08
+#define SUB_EOL                       BV09 // telnet
+#define SUB_LNF                       BV10
+#define SUB_SIL                       BV11 // silent
+#define SUB_LIT                       BV12 // no soft escaping
 
 /*
 #define SUB_ARG                       BV01
 #define SUB_SEC                       BV02
+#define SUB_BRA                       BV03
 */
-#define EVENT_FLAG_CATCH              BV03
-#define EVENT_FLAG_CLASS              BV04
-#define EVENT_FLAG_GAG                BV05
-#define EVENT_FLAG_INPUT              BV06
-#define EVENT_FLAG_MAP                BV07
-#define EVENT_FLAG_MOUSE              BV08
-#define EVENT_FLAG_OUTPUT             BV09
-#define EVENT_FLAG_PORT               BV10
-#define EVENT_FLAG_SCAN               BV11
-#define EVENT_FLAG_SCREEN             BV12
-#define EVENT_FLAG_SESSION            BV13
-#define EVENT_FLAG_SYSTEM             BV14
-#define EVENT_FLAG_TELNET             BV15
-#define EVENT_FLAG_TIME               BV16
-#define EVENT_FLAG_UPDATE             BV17
-#define EVENT_FLAG_VARIABLE           BV18
-#define EVENT_FLAG_VT100              BV19
-
+#define EVENT_FLAG_CATCH              BV04
+#define EVENT_FLAG_CLASS              BV05
+#define EVENT_FLAG_GAG                BV06
+#define EVENT_FLAG_INPUT              BV07
+#define EVENT_FLAG_MAP                BV08
+#define EVENT_FLAG_MOUSE              BV09
+#define EVENT_FLAG_OUTPUT             BV10
+#define EVENT_FLAG_PORT               BV11
+#define EVENT_FLAG_SCAN               BV12
+#define EVENT_FLAG_SCREEN             BV13
+#define EVENT_FLAG_SESSION            BV14
+#define EVENT_FLAG_SYSTEM             BV15
+#define EVENT_FLAG_TELNET             BV16
+#define EVENT_FLAG_TIME               BV17
+#define EVENT_FLAG_UPDATE             BV18
+#define EVENT_FLAG_VARIABLE           BV19
+#define EVENT_FLAG_VT100              BV20
 
 #define TAB_FLAG_FORWARD              BV01
 #define TAB_FLAG_BACKWARD             BV02
 #define TAB_FLAG_COMPLETE             BV03
-#define TAB_FLAG_LIST                 BV04
-#define TAB_FLAG_SCROLLBACK           BV05
+#define TAB_FLAG_CASELESS             BV04
+#define TAB_FLAG_DICTIONARY           BV05
+#define TAB_FLAG_LIST                 BV06
+#define TAB_FLAG_SCROLLBACK           BV07
 
 #define REGEX_FLAG_NONE                  0
 #define REGEX_FLAG_FIX                BV01
@@ -596,7 +601,7 @@ enum operators
 
 
 
-#define TINTIN_FLAG_GETNUMBER         BV01
+#define TINTIN_FLAG_GETNUMBER         BV01 // UNUSED
 #define TINTIN_FLAG_SESSIONUPDATE     BV02
 #define TINTIN_FLAG_PROCESSINPUT      BV03
 #define TINTIN_FLAG_INHERITANCE       BV04
@@ -657,6 +662,9 @@ enum operators
 #define TELOPT_FLAG_TTYPE             BV08
 #define TELOPT_FLAG_MTTS              BV09
 #define TELOPT_FLAG_UPDATENAWS        BV10
+#define TELOPT_FLAG_CR                BV11
+#define TELOPT_FLAG_LF                BV12
+#define TELOPT_FLAG_NUL               BV13
 
 #define LIST_FLAG_IGNORE              BV01
 #define LIST_FLAG_PRIORITY            BV02
@@ -761,7 +769,8 @@ enum operators
 #define MAP_SEARCH_TERRAIN             5
 #define MAP_SEARCH_FLAG                6
 #define MAP_SEARCH_ID                  7
-#define MAP_SEARCH_MAX                 8
+#define MAP_SEARCH_DISTANCE            8
+#define MAP_SEARCH_MAX                 9
 
 #define MAP_EXIT_N                     1
 #define MAP_EXIT_E                     2
@@ -1084,7 +1093,6 @@ struct tintin_data
 {
 	struct session        * ses;
 	struct session        * update;
-	struct session        * all;
 	struct session        * dispose_next;
 	struct session        * dispose_prev;
 	struct listroot       * dispose_list;
@@ -1148,20 +1156,12 @@ struct session
 	z_stream              * mccp3;
 	gnutls_session_t        ssl;
 	struct termios          cur_terminal;
+	struct log_data       * log;
 	struct scroll_data    * scroll;
 	struct split_data     * split;
 	struct input_data     * input;
 	char                  * name;
 	char                  * group;
-	FILE                  * logfile;
-	char                  * logname;
-	int                     logmode;
-	FILE                  * lognext_file;
-	char                  * lognext_name;
-	time_t                  lognext_time;
-	FILE                  * logline_file;
-	char                  * logline_name;
-	time_t                  logline_time;
 	char                  * line_capturefile;
 	int                     line_captureindex;
 	int                     gagline;
@@ -1278,6 +1278,22 @@ struct level_data
 	unsigned int            verbose;
 };
 
+struct log_data
+{
+	FILE                  * file;
+	char                  * name;
+	int                     mode;
+	FILE                  * next_file;
+	char                  * next_name;
+	time_t                  next_time;
+	FILE                  * line_file;
+	char                  * line_name;
+	time_t                  line_time;
+	char                    stamp_text[100];
+	char                  * stamp_strf;
+	time_t                  stamp_time;
+};
+
 struct split_data
 {
 	int                     sav_top_row;
@@ -1488,7 +1504,9 @@ struct search_data
 	pcre                  * note;
 	pcre                  * terrain;
 	long long               flag;
+	long long               galf;
 	char                  * id;
+	float                   distance;
 };
 
 struct msdp_data
@@ -1601,7 +1619,6 @@ struct window_data
 #define DO_EDIT(edit)          struct session *edit (struct session *ses, char *arg, char *arg1, char *arg2)
 #define DO_HISTORY(history)            void history (struct session *ses, char *arg, char *arg1, char *arg2)
 #define DO_LINE(line)          struct session *line (struct session *ses, char *arg, char *arg1, char *arg2, char *arg3)
-#define DO_LOG(log)                        void log (struct session *ses, char *arg, char *arg1, char *arg2)
 #define DO_MAP(map)                        void map (struct session *ses, char *arg, char *arg1, char *arg2)
 #define DO_PATH(path)                     void path (struct session *ses, char *arg)
 #define DO_PORT(port)          struct session *port (struct session *ses, char *arg, char *arg1, char *arg2)
@@ -1621,7 +1638,6 @@ typedef void            CURSOR  (struct session *ses, char *arg);
 typedef void            DAEMON  (struct session *ses, char *arg, char *arg1, char *arg2);
 typedef struct session *EDIT    (struct session *ses, char *arg, char *arg1, char *arg2);
 typedef void            HISTORY (struct session *ses, char *arg, char *arg1, char *arg2);
-typedef void            LOG     (struct session *ses, char *arg, char *arg1, char *arg2);
 typedef struct session *LINE    (struct session *ses, char *arg, char *arg1, char *arg2, char *arg3);
 typedef void            MAP     (struct session *ses, char *arg, char *arg1, char *arg2);
 typedef void            MSDP    (struct session *ses, struct port_data *buddy, int index);
@@ -1738,13 +1754,6 @@ struct line_type
 	char                  * desc;
 };
 
-struct log_type
-{
-	char                  * name;
-	LOG                   * fun;
-	char                  * desc;
-};
-
 struct map_type
 {
 	char                  * name;
@@ -2027,8 +2036,6 @@ extern DO_CURSOR(cursor_set);
 extern DO_CURSOR(cursor_soft_enter);
 extern DO_CURSOR(cursor_suspend);
 extern DO_CURSOR(cursor_tab);
-extern DO_CURSOR(cursor_tab_backward);
-extern DO_CURSOR(cursor_tab_forward);
 
 #endif
 
@@ -2238,6 +2245,7 @@ extern void dump_stack(void);
 extern DO_COMMAND(do_dictionary);
 
 extern int spellcheck_count(struct session *ses, char *in);
+extern int cursor_dictionary_tab_add(int stop_after_first);
 
 #endif
 
@@ -2363,13 +2371,10 @@ extern DO_LINE(line_verbose);
 #ifndef __LOG_H__
 #define __LOG_H__
 
-DO_LOG(log_append);
-DO_LOG(log_info);
-DO_LOG(log_overwrite);
-DO_LOG(log_off);
-DO_LOG(log_remove);
+extern void logheader(struct session *ses, FILE *file, int newline);
+extern void init_log(struct session *ses);
+extern void free_log(struct session *ses);
 
-extern void loginit(struct session *ses, FILE *file, int newline);
 extern void logit(struct session *ses, char *txt, FILE *file, int newline);
 extern void write_html_header(struct session *ses, FILE *fp);
 extern void vt102_to_html(struct session *ses, char *txt, char *out);
@@ -2570,7 +2575,7 @@ int exit_to_dir(struct session *ses, char *name);
 unsigned char pdir(struct listnode *node);
 char *dir_to_exit(struct session *ses, int dir);
 
-extern void check_append_path(struct session *ses, char *forward, char *backward, float delay, int follow);
+extern void check_append_path(struct session *ses, char *forward, char *backward, float delay, int force, int follow);
 
 extern DO_PATH(path_create);
 extern DO_PATH(path_describe);
@@ -2722,7 +2727,7 @@ extern void telnet_printf(struct session *ses, int length, char *format, ...);
 extern void tintin_printf2(struct session *ses, char *format, ...);
 extern void tintin_printf(struct session *ses, char *format, ...);
 
-extern void tintin_puts3(struct session *ses, char *string);
+extern void tintin_puts3(struct session *ses, char *string, int prompt);
 extern void tintin_puts2(struct session *ses, char *string);
 extern void tintin_puts(struct session *ses, char *string);
 
@@ -2766,6 +2771,9 @@ extern gnutls_session_t ssl_negotiate(struct session *ses);
 extern int get_raw_len_str_range_str_width(struct session *ses, char *str, int start, int end, int *raw_width);
 extern int get_raw_off_str_range_raw_width(struct session *ses, char *str, int start, int end, int *raw_width);
 
+extern int raw_len_str(struct session *ses, char *str, int start, int end);
+extern int str_len_raw(struct session *ses, char *str, int start, int end);
+
 extern char *str_ins_str(struct session *ses, char **str, char *ins, int str_start, int str_end);
 
 extern char *calign(struct session *ses, char *in, char *out, int width);
@@ -2825,7 +2833,6 @@ extern struct event_type event_table[];
 extern struct history_type history_table[];
 extern struct line_type line_table[];
 extern struct list_type list_table[LIST_MAX];
-extern struct log_type log_table[];
 extern struct map_type map_table[];
 extern struct path_type path_table[];
 extern struct port_type port_table[];
@@ -2916,6 +2923,7 @@ 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 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);
 #endif
@@ -2980,12 +2988,15 @@ extern int is_suffix(char *str1, char *str2);
 #ifndef __UTF8_H__
 #define __UTF8_H__
 
+extern void big5toutf8_info(struct session *ses);
+extern void utf8tobig5_info(struct session *ses);
+
 extern int get_ascii_width(char *str, int *width);
 
 extern int is_utf8_head(char *str);
 extern int is_utf8_tail(char *str);
 extern int get_utf8_size(char *str);
-extern int get_utf8_width(char *str, int *width);
+extern int get_utf8_width(char *str, int *width, int *index);
 extern int get_utf8_index(char *str, int *index);
 extern int unicode_to_utf8(int index, char *out);
 extern int utf8_strlen(char *str, int *width);

+ 11 - 7
src/tokenize.c

@@ -1219,12 +1219,6 @@ char *view_script(struct session *ses, struct scriptroot *root)
 		token = token->next;
 	}
 
-	while (root->next)
-	{
-		deltoken(root, root->next);
-	}
-
-	free(root);
 
 	return buf;
 }
@@ -1278,6 +1272,7 @@ char *script_writer(struct session *ses, char *str)
 char *script_viewer(struct session *ses, char *str)
 {
 	struct scriptroot *root;
+	char *pts;
 
 	root = (struct scriptroot *) calloc(1, sizeof(struct scriptroot));
 
@@ -1285,5 +1280,14 @@ char *script_viewer(struct session *ses, char *str)
 
 	tokenize_script(root, 1, str);
 
-	return view_script(ses, root);
+	pts = view_script(ses, root);
+
+	while (root->next)
+	{
+		deltoken(root, root->next);
+	}
+
+	free(root);
+
+	return pts;
 }

Разлика између датотеке није приказан због своје велике величине
+ 15 - 8
src/utf8.c


+ 39 - 17
src/variable.c

@@ -655,27 +655,49 @@ void hexstring(char *str)
 
 void reversestring(char *str)
 {
-	char t;
-	int a = 0, z = strlen(str) - 1;
+	char *pts, *ptz, *dup = str_mim(str);
+	int skip;
 
-	while (z > a)
-	{
-		t = str[z];
-		str[z--] = str[a];
-		str[a++] = t;
-	}
+	pts = str;
+	ptz = dup + strlen(str);
 
-	z = strlen(str) - 1;
+	*ptz-- = 0;
 
-	for (a = 1 ; a < z ; a++)
+	while (*pts)
 	{
-		if (str[a] == '\\' && str[a + 1] != '\\')
+		switch (*pts)
+		{
+			case '\\':
+				skip = pts[1] ? 2 : 0;
+				break;
+
+			case '\e':
+				skip = skip_vt102_codes(pts);
+				break;
+
+			case '<':
+				skip = is_color_code(pts);
+				break;
+
+			default:
+				skip = 0;
+				break;
+		}
+
+		if (skip)
+		{
+			ptz -= skip;
+			memcpy(ptz + 1, pts, skip);
+			pts += skip;
+		}
+		else
 		{
-			str[a] = str[a - 1];
-			str[a - 1] = '\\';
+			*ptz-- = *pts++;
 		}
 	}
+	strcpy(str, dup);
 
+	str_free(dup);
 }
 
 void mathstring(struct session *ses, char *str)
@@ -935,7 +957,7 @@ void wrapstring(struct session *ses, char *str, char *wrap)
 		{
 			*pte++ = 0;
 
-			substitute(ses, pts, arg1, SUB_SEC);
+			substitute(ses, pts, arg1, SUB_BRA);
 
 			cat_sprintf(str, "{%d}{%s}", ++cnt, arg1);
 
@@ -946,7 +968,7 @@ void wrapstring(struct session *ses, char *str, char *wrap)
 			pte++;
 		}
 	}
-	substitute(ses, pts, arg1, SUB_SEC);
+	substitute(ses, pts, arg1, SUB_BRA);
 
 	cat_sprintf(str, "{%d}{%s}", ++cnt, arg1);
 
@@ -1039,7 +1061,7 @@ int string_str_raw_len(struct session *ses, char *str, int start, int end)
 		}
 		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&str[raw_cnt]))
 		{
-			tmp_cnt = get_utf8_width(&str[raw_cnt], &width);
+			tmp_cnt = get_utf8_width(&str[raw_cnt], &width, NULL);
 
 			if (str_cnt >= start)
 			{
@@ -1115,7 +1137,7 @@ int string_raw_str_len(struct session *ses, char *str, int raw_start, int raw_en
 		}
 		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&str[raw_cnt]))
 		{
-			raw_cnt += get_utf8_width(&str[raw_cnt], &width);
+			raw_cnt += get_utf8_width(&str[raw_cnt], &width, NULL);
 
 			ret_cnt += width;
 		}

+ 2 - 2
src/vt102.c

@@ -409,7 +409,7 @@ int get_vt102_width(struct session *ses, char *str, int *str_len)
 
 		if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8))
 		{
-			return get_utf8_width(str, str_len);
+			return get_utf8_width(str, str_len, NULL);
 		}
 
 		return get_ascii_width(str, str_len);
@@ -1015,7 +1015,7 @@ int strip_vt102_strlen(struct session *ses, char *str)
 */
 			if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(pti))
 			{
-				size = get_utf8_width(pti, &width);
+				size = get_utf8_width(pti, &width, NULL);
 			}
 			else
 			{

Неке датотеке нису приказане због велике количине промена