Scandum %!s(int64=5) %!d(string=hai) anos
pai
achega
6d60654726
Modificáronse 68 ficheiros con 12370 adicións e 5252 borrados
  1. 5 4
      FAQ
  2. 17 0
      NEWS
  3. 10 9
      README
  4. 349 1
      SCRIPTS
  5. 35 22
      TODO
  6. 498 143
      docs/help.html
  7. 215 24
      mods/igr.mods
  8. 3 2
      src/Makefile.in
  9. 638 0
      src/banner.c
  10. 17 17
      src/base.c
  11. 240 169
      src/buffer.c
  12. 19 13
      src/chat.c
  13. 41 19
      src/class.c
  14. 263 0
      src/command.c
  15. 78 0
      src/confdefs.h
  16. 165 105
      src/config.c
  17. 632 253
      src/cursor.c
  18. 36 29
      src/daemon.c
  19. 377 109
      src/data.c
  20. 40 19
      src/debug.c
  21. 87 16
      src/dict.c
  22. 0 0
      src/dict.h
  23. 648 223
      src/draw.c
  24. 437 0
      src/edit.c
  25. 266 125
      src/event.c
  26. 91 34
      src/files.c
  27. 730 0
      src/gui.h
  28. 504 134
      src/help.c
  29. 55 40
      src/history.c
  30. 326 132
      src/input.c
  31. 38 47
      src/line.c
  32. 274 105
      src/list.c
  33. 14 1
      src/log.c
  34. 130 125
      src/main.c
  35. 196 139
      src/mapper.c
  36. 92 7
      src/math.c
  37. 344 111
      src/memory.c
  38. 40 80
      src/misc.c
  39. 125 1
      src/msdp.c
  40. 55 16
      src/nest.c
  41. 119 38
      src/net.c
  42. 161 93
      src/parse.c
  43. 118 47
      src/path.c
  44. 138 70
      src/port.c
  45. 26 19
      src/regex.c
  46. 264 143
      src/scan.c
  47. 335 206
      src/screen.c
  48. 87 91
      src/session.c
  49. 76 28
      src/show.c
  50. 11 14
      src/sort.c
  51. 77 55
      src/split.c
  52. 13 26
      src/ssl.c
  53. 309 16
      src/string.c
  54. 153 65
      src/substitute.c
  55. 13 4
      src/system.c
  56. 402 545
      src/tables.c
  57. 105 164
      src/telopt_client.c
  58. 1 1
      src/telopt_server.c
  59. 12 10
      src/terminal.c
  60. 50 25
      src/text.c
  61. 369 297
      src/tintin.h
  62. 129 88
      src/tokenize.c
  63. 75 37
      src/trigger.c
  64. 364 208
      src/update.c
  65. 45 44
      src/utf8.c
  66. 146 38
      src/utils.c
  67. 160 71
      src/variable.c
  68. 482 535
      src/vt102.c

+ 5 - 4
FAQ

@@ -21,11 +21,12 @@ Q01) What machines does tintin work on?
 A01) Pretty much any UNIX machine with a modern compiler as well as Windows,
      Mac OS X, Android, and iOS.
 
-Q02) What version should I use 1.50 or 1.86 or 2.00 ?
+Q02) What causes a part of a line to be missing sometimes?
 
-A02) TinTin++ 2.00 is twice the size of 1.86 with over 90% of the 1.86 code
-     rewritten. TinTin++ 2.00 is not backward compatible with 1.50 or 1.86.
-     The NEWS file contains all known compatibility issues.
+A02) It's most likely caused by packet fragmentation. This problem can be
+     solved by using:
+
+     #config packet_patch 0.5
 
 Q06) I can't get tintin compiled.  Where can I get more help?
 

+ 17 - 0
NEWS

@@ -1,6 +1,23 @@
 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.04
+----------------
+
+01) Variables starting with a number are no longer supported, as per the
+    C standard for naming variables. A warning is generated when trying to
+    do so.
+
+    Keep in mind that #var {8ball} {1} will still work, just that instead of
+    being able to use $8ball you need to use ${8ball} for an explicit
+    variable lookup.
+
+02) Implicit index lookups on undefined variables are no longer supported. If
+    you do something like #if {&target} this needs to be changed to
+    #if {&{target}}.
+
+    The reason for this is that "say I played d&d last night" would evaluate
+    as "say I played d0 last night".
 
 TinTin++ 2.02.00
 ----------------

+ 10 - 9
README

@@ -3,15 +3,16 @@ ABOUT
   TinTin++ is a command line MUD client which features support for TELNET,
   PCRE, UTF-8, SSL, VT100, IPv6, the dynamic TINTIN scripting language,
   a comprensive trigger system, and several other features geared towards
-  mudding, scripting, text processing, interprocess communication,
-  redirection, and VT100 / xterm terminal emulation and multiplexing.
+  mudding, scripting, shell-scripting, text processing, automation,
+  interprocess communication, redirection, xterm terminal emulation, and
+  multiplexing / demultiplexing.
 
 INFO
 
   You'll find answers to common questions in the FAQ and INSTALL documents. A
-  brief introduction to using TinTin++ is available in the docs/tintin19.txt
-  and docs/syntax.txt documents. The SCRIPTS document contains some useful
-  example scripts.
+  brief introduction to using TinTin++ is available in the docs/tintin19.txt,
+  docs/manual.html, and docs/syntax.txt documents. The SCRIPTS document
+  contains a variety of example scripts.
 
   The NEWS document contains important announcements and a list of changes
   that impact backward compatibility with older versions. A more detailed
@@ -19,9 +20,9 @@ INFO
 
 CONTACT
 
-  Easiest is to register on the forum linked from the website if you have
-  questions about using TinTin++. If you need to get in touch with one of
-  the contributors check the CREDITS file. 
+  Easiest is to register on the forum or discord channel linked from the
+  website if you have questions about using TinTin++. If you need to get
+  in touch with one of the contributors check the CREDITS file. 
 
 LICENSE
 
@@ -29,7 +30,7 @@ LICENSE
 
 COPYRIGHT
 
-  Copyright 2004-2019 Igor van den Hoven
+  Copyright 2004-2020 Igor van den Hoven
 
 WEBSITE
 

+ 349 - 1
SCRIPTS

@@ -307,7 +307,7 @@
 	};
 	#else
 	{
-		#var result <118>%1<278>
+		#var result <118>%1<900>
 	}
 }
 
@@ -500,3 +500,351 @@
 	#showme <138>Bubba tells you 'hello';
 	#showme <158>Pamela chats 'bye';
 }
+
+#nop -------------------------------------------------------------------------
+#nop Display two sessions next to each other
+#nop -------------------------------------------------------------------------
+
+#event {SCREEN RESIZE}
+{
+	#var ROWS %0;
+	#var COLS %1;
+	#draw line 1 {$COLS / 2} -3 {$COLS / 2};
+
+	#left #screen scroll 1 1 -3 {$COLS / 2 - 1};
+	#right #screen scroll 1 {$COLS / 2 + 1} -3 -1;
+}
+
+#event {PROGRAM START}
+{
+	#screen raise SCREEN RESIZE;
+	#ses right localhost 4321;
+	#ses left localhost 4321;
+}
+
+#event {SESSION CREATED}
+{
+	#var name %0;
+}
+
+#event {SESSION ACTIVATED}
+{
+	#gts #var active %0;
+}
+
+#event {RECEIVED OUTPUT}
+{
+	#if {"@gts{$active}" == "$name"}
+	{
+		#return;
+	};
+
+	#switch {"$name"}
+	{
+		#case {"left"} {#draw Red boxed foreground buffer 1 1 -3 {$COLS / 2 - 1};};
+		#case {"right"}{#draw Red boxed foreground buffer 1 {$COLS / 2 + 1} -3 -1};
+	};
+}
+
+#nop -------------------------------------------------------------------------
+#nop Follow the group leader on the map.
+#nop -------------------------------------------------------------------------
+
+#var short_dir
+{
+	{north}{n}
+	{northeast}{ne}
+	{east}{e}
+	{southeast}{se}
+	{south}{s}
+	{southwest}{sw}
+	{west}{w}
+	{northwest}{nw}
+}
+
+#action {%1 walks %2.$}
+{
+	#var {follow_targets[%1]} {$short_dir[%2]}
+}
+
+#action {^You follow %1.$}
+{
+	#if {&follow_targets[%1]}
+	{
+		#map move $follow_targets[%1]
+	}
+}
+
+#nop -------------------------------------------------------------------------
+#nop Use mouse click to change the input cursor's position.
+#nop -------------------------------------------------------------------------
+
+#config mouse on
+
+#split
+
+#event {SHORT-CLICKED MOUSE BUTTON ONE -1}
+{
+	#cursor position %1
+}
+
+#nop -------------------------------------------------------------------------
+#nop Move the VT100 map from the top to the right of the screen
+#nop -------------------------------------------------------------------------
+
+#map create
+#map flag vtmap
+#map flag unicode
+#map goto 1
+
+#split 0 1 0 -80;
+#map offset 1 82 -5 -1
+
+#screen resize horizontal 120
+
+#nop -------------------------------------------------------------------------
+#nop Add clickable session tabs at the top of the screen
+#nop -------------------------------------------------------------------------
+
+#event {PROGRAM START}
+{
+    #split 3 1;
+    #config mouse on;
+    #var active gts;
+    session_activated gts;
+}
+
+#event {SESSION CREATED}
+{
+    #gts session_activated %0
+}
+
+#event {SESSION ACTIVATED}
+{
+    #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[%*]}
+}
+
+#event {PRESSED SECURE LINK TABS MOUSE BUTTON ONE}
+{
+    %4
+}
+
+
+#nop -------------------------------------------------------------------------
+#nop Add basic MXP link and color handling
+#nop -------------------------------------------------------------------------
+
+#config mouse on
+
+#event {IAC DO MXP}
+{
+    #send {\xFF\xFB\x5B\}
+}
+
+#function {mxp_link}
+{
+    #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>}}
+#act {~\e[1z<SUPPORT>} {#send {\e[4z<SUPPORTS +SEND +COLOR>}}
+
+#sub {~\e[4z<COLOR #%1>%2\e[4z</COLOR>} {<f%1>%2<900>}
+
+#sub {~\e[4z<SEND HREF="%1">%2\e[4z</SEND>} {@mxp_link{MXP;%1;%2}}
+
+#event {PRESSED LINK MXP MOUSE BUTTON ONE}
+{
+    #send {%4}
+}
+
+#sub {~\e[4z{<RExits>|</RExits>|<RDesc>|</RDesc>|<PROMPT>|</PROMPT>|<RName>|</RName>}} {}
+
+#sub {~\e[4z<RNum %d />} {}
+
+#sub {&lt;} {<}
+#sub {&gt;} {>}
+
+#nop -------------------------------------------------------------------------
+#nop Example script for using #list indexing.
+#nop -------------------------------------------------------------------------
+
+#var players[1] {{name}{bubba}{age}{15}{level}{24}}
+#var players[2] {{name}{pamela}{age}{19}{level}{2}}
+#var players[3] {{name}{ronald}{age}{69}{level}{13}}
+#var players[4] {{name}{bubba}{age}{26}{level}{30}}
+#var players[5] {{name}{ronald}{age}{11}{level}{31}}
+
+#alias {display}
+{
+        #var out {};
+
+        #loop 1 &players[] cnt
+        {
+            #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
+}
+
+#alias {test2}
+{
+    #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
+}
+
+#nop -------------------------------------------------------------------------
+#nop This creates two input lines that can be switched between using the tab
+#nop key.
+#nop -------------------------------------------------------------------------
+
+#line quiet #split
+
+#macro {\t} {inputswitch}
+
+#var input[width] 1
+
+#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]}
+}
+
+#nop -------------------------------------------------------------------------
+#nop This allows for split screen scroll back, just use the mouse wheel in
+#nop the upper half of the screen.
+#nop -------------------------------------------------------------------------
+
+#event {PROGRAM START}
+{
+    #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];
+}
+
+#EVENT {SCROLLED MOUSE WHEEL UP}
+{
+    #if {$SCROLL[MODE] == 0}
+    {
+        #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];
+
+            #screen clear square $SCROLL[BOT_ROW]+2 $SCROLL[TOP_COL] $SCROLL[OLD_ROW] $SCROLL[BOT_COL];
+        };
+    };
+    #if {$SCROLL[MODE] == 1}
+    {
+        #buffer up 1
+    }
+}
+
+#EVENT {SCROLLED MOUSE WHEEL DOWN}
+{
+    #if {$SCROLL[MODE] == 1}
+    {
+        #if {%0 < $ROWS / 2}
+        {
+            #buffer down 1;
+
+            #buffer info save SCROLL[INFO];
+
+            #if {$SCROLL[INFO][LINE] == -1}
+            {
+                #var SCROLL[MODE] 0;
+                #var SCROLL[BOT_ROW] $SCROLL[OLD_ROW];
+
+                #split 0 1;
+                #buffer end;
+            }
+        }
+    }
+}
+
+#event {RECEIVED LINE}
+{
+    #if {$SCROLL[MODE] == 1}
+    {
+        #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[%*];
+    }
+}
+
+#nop -------------------------------------------------------------------------
+#nop 
+#nop -------------------------------------------------------------------------
+
+#nop -------------------------------------------------------------------------
+#nop 
+#nop -------------------------------------------------------------------------
+
+#nop -------------------------------------------------------------------------
+#nop 
+#nop -------------------------------------------------------------------------
+
+#nop -------------------------------------------------------------------------
+#nop 
+#nop -------------------------------------------------------------------------
+
+#nop -------------------------------------------------------------------------
+#nop 
+#nop -------------------------------------------------------------------------
+
+#nop -------------------------------------------------------------------------
+#nop 
+#nop -------------------------------------------------------------------------
+
+#nop -------------------------------------------------------------------------
+#nop 
+#nop -------------------------------------------------------------------------

+ 35 - 22
TODO

@@ -1,24 +1,39 @@
 * BUGS
 
-  - Editor
+  - might be \ handling issues in #format %w
+
+  - finish BUFFER_SIZE replacement.
+
+  - WSL faq: #system cmd.exe /c start notepad
+
+  - str_ify ses->more_output
+
+  - update msdp scripts with #line msdp feature
 
-  - make #line quiet #line capture work.
+  - update the FAQ, and online manual
 
-  - improve screen fill default
+  - refresh input on session switch
 
-  - Add screen and line clear VT events
+  - swap arg1, arg2, arg for do_port
 
-  - Add easy way to check if session is foreground.
+  - https://tintin.sourceforge.io/forum/viewtopic.php?f=5&t=2776
+    Need special casing for non capturing {?!} regex handling.
 
-  - check that desktop dimensions are inherited by sessions
+  - #cursor get word option, maybe get the yank buffer as well.
 
-  - example script for two sessions in one screen.
+  - Look into config option to change the working directory
+
+  - Add a way to set env variables either 1) for the current process, and/or 2) as a parameter to #system (i.e. after fork in the child process).
 
 * STUFF THAT IS PROBABLY GONNA GET DONE
 
-  - if error pcre.h, need export C_INCLUDE_PATH= where it locate
+  - Editor
 
-  - #write table variables a bit nicer.
+  - Finish port proxy support: resizing, input, security
+
+  - look into transparent drawing
+
+  - if error pcre.h, need export C_INCLUDE_PATH= where it locate
 
   - The #else command could follow a #foreach so as to create "for-else" loops
     in case a loop is not broken.
@@ -40,11 +55,12 @@
 
   - Enhance #scan with a scan of the directory structure.
 
+  - #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.
-  - add step count for #map list and rename distance to weight
   - multi-line room symbols
   - pancake mode to display rooms at all levels and annotations
   - there might be a terrain density bug
@@ -60,6 +76,7 @@
   - more data to #map list saving, and maybe easier sorting of tables.
   - event for failed #map move.
   - look into #send triggering follow map.
+
   - truncate prompt longer than split.
 
   - Make actions with a priority of 0. trigger always
@@ -81,14 +98,13 @@
 
   - make #path load bi-directional.
 
-  - class bla assign {stuff} feature?
   - add class specific debug
   - better class event and class size handling ?
 
   - more potent long-click handling including held down ticks.
 
   - look into discord api / arachnos
- 
+
   - better color syntax highlighting configuration.
 
   - Add #log delete/remove option.
@@ -99,15 +115,6 @@
 
   - Add debugger to syntax highlighter, substitution highlighing, 256 color support, and variable expansion.
 
-  - look at scripts/bug.tin
-
-  - Add FILE READ <name> event
-  - #buffer events
-  - add KILLED TYPE ARG event, for example KILLED CLASS bla
-  - CAPTURED INPUT event
-  - http://tintin.sourceforge.net/board/viewtopic.php?p=8735#8735 RECEIVED MESSAGE event?
-? - http://tintin.sourceforge.net/board/viewtopic.php?p=8655#8655 FILE OPENED / CLOSED event?
-
   - fix readmud in net.c to not move the cursor on inactive sessions.
 
   - add packets patched counter
@@ -151,8 +158,12 @@
 
 * LOW PRIORITY
 
+  - Add a file handler.
+
   - multi-line buffer searches / captures / deletes
 
+  - multi-line triggers (use nested actions?)
+
   - add color based auto unwrap routine.
 
   - Start of line anchors aren't working in #replace.
@@ -161,7 +172,7 @@
 
 * ROADMAP
 
-  - dictionary +
+  - dictionary +tabbing
 
   - editor
 
@@ -336,3 +347,5 @@
 - TinTin++ only allows 1 action triggering per line.
 
 - TinTin++ probably should substitute escapes in if checks.
+
+- TinTin++ is not handling #return inside #regex intuitively.

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 498 - 143
docs/help.html


+ 215 - 24
mods/igr.mods

@@ -1,3 +1,196 @@
+May 2020        2.02.04
+------------------------------------------------------------------------------
+
+help.c          Updated the MSLP helpfile.
+
+scan.c          Added #scan forward, does the same as #textin.
+
+substitute.c    Added a warning when using &variable on an undefined variable
+                in math operations.
+
+draw.c          Updated the #draw line mode to behave more distinct from the
+                #draw side mode. When teed a horizontal line can have only
+                the left or right side teed when specified. Similarly a
+                vertical line can have the top or bot side teed.
+
+banner.c        Added the tt++ -g startup option to startup tintin with a gui.
+                So far it only supports a connection manager.
+
+main.c          Added the SYSTEM CRASH event, %0 holds the error message.
+
+screen.c        #screen inputregion now takes a 5th argument to assign a
+                name, can be used with the RECEIVED INPUT [NAME] event.
+
+screen.c        Added #screen swap, swaps the input and scroll region height.
+
+mapper.c        The MAP ENTER ROOM and MAP EXIT ROOM events will store the
+                direction traveled in the %2 argument.
+
+draw.c          #draw CALIGN will prune and center text.
+
+                #draw LALIGN will prune and left align text.
+
+                #draw RALIGN will prune and right align text.
+
+                #draw TALIGN will show the top of the text if it is too long
+                to fit the square, cutting off the bottom. The default is to
+                bottom align and cut off the top.
+
+                #draw UALIGN will unwrap and rewrap text.
+
+math.c          Added very basic ? : ternary operator support in #math. It
+                currently only supports simple assignments like:
+                #math result $variable < 5 ? 0 : $variable
+
+screen.c        Added several #screen get INPUT_ options.
+
+daemon.c        Added DAEMON ATTACHED and DAEMON DETACHED events.
+
+mapper.c        Added #map flag quiet, gets rid of build walk spam.
+
+event.c         With mouse pixel mode enabled the %7 argument of a mouse
+                event will contain nw, n, ne, w, c, e, sw, s, se, depending
+                on where on a character you clicked.
+
+                You can, for example use #if {"%7" == "{nw|w|sw}"} to check
+                if the left side of a character was clicked.
+
+help.c          Added #help edit and #help editing
+
+config.c        Added the #config mouse pixels option for pixel precision.
+                Requires the latext xterm or mintty release to work.
+
+tokenize.z      The default ! repeat character can now be used in scripts.
+                Use with caution. To repeat the last command when you press
+                ctrl-enter use: #macro {\e[13;5u} {!}
+
+tintin.h        Increased BUFFER_SIZE from 30KB to 40KB. 
+
+screen.c        Added #screen scrollbar on/off, currently only works with
+                mintty / wintin++. Allows using the scrollbar with tintin's
+                own scrollback buffer. Works automatically once enabled.
+
+list.c          Changed #list simplify to work in a similar manner as
+                #list sort and #list order. 
+
+draw.c          #draw now takes a second color argument. First color argument
+                sets the box color, the second sets the text color.
+
+split.c         Updated #split to take a 5th argument to set the height of
+                the input region, #split without an argument defaults to
+                #split 0 1 0 0 1.
+
+event.c         Added event group lookups, can use #event mouse to see all
+                mouse events.
+
+edit.c          Added the [CATCH] EDIT FINISHED and EDIT STARTED events.
+
+cursor.c        Added #cursor {page} which has several sub-options that can
+                be used in edit mode.
+
+                ctrl-home is bound by default to #cursor page home
+                ctrl-end  is bound by default to #cursor page end
+
+cursor.c        Added #cursor {soft enter} which allows inserting new lines
+                while in edit mode, it's bound to shift-enter by default. A
+                regular enter will exit edit mode.
+
+edit.c          Added the #edit command, used to enter edit mode and perform
+                various edit buffer operations.
+
+cursor.c        Added #cursor up and #cursor down, moves cursor up/down in
+                multiline input regions.
+
+event.c         Added the INPUT MOUSE event, which triggers when using the
+                mouse in the input region.
+
+cursor.c        Added multiline input support. Use #screen inputregion to
+                enable. For example:
+
+                #screen inputregion -3 1 -1 -1
+                #split 0 3
+
+cursor.c        #cursor preserve macro and reset macro have been moved to
+                #cursor macro {preserve|reset}
+
+                #cursor echo and #cursor insert have been moved to
+                #cursor flag {echo|insert} {on|off}
+
+input.c         Added infinite input support, TinTin++ will still crash
+                somewhere down the line until the rest of the engine has
+                infinite string support as well. When CHILD LOCKED the
+                input buffer is capped.
+
+class.c         Added #event CLASS LOAD <NAME>, triggers after a class is
+                loaded.
+                Added #event CLASS CLEAR <NAME>, triggers before a class is
+                cleared.
+
+scan.c          Added the #scan dir <dir> <variable> option, will scan the
+                given file or directory and store the info in the provided
+                variable.
+
+scan.c          Modernized #scan, includes a warning when the old syntax is
+                used.
+
+variable.c      #return now returns a local result, this should solve issues
+                with function nesting.
+
+list.c          Added #list {<list>} index {nest} which can be used to index
+                a two dimensional table as a one dimensional list. After a
+                table has been indexed, #list find, order, sort, and reverse
+                will work.
+
+triggers.c      Added the <900> color tag which can be used in substitutions
+                to restore the text color to the original text color.
+
+                #sub {\bsmurf\b} {<bdf>smurf<900>}
+                #showme {<afa>A smurf is smurfing here.}
+
+draw.c          Added the SCALED drawing option. When used the size of the
+                square is increased depending on the size of the inputted
+                text.
+
+documentation   Added docs/link.txt file with the initial documentation for
+                link handling.
+
+buffer.c        #buffer find now places the found keyword at the top instead
+                of at the bottom of the page.
+
+path.c          Added #path save {BOTH} <variable> to save both the forward
+                and backward path, as well as any given delays. Keep in mind
+                that delays will only work properly for forward going paths.
+
+path.c          Added a third field to #path insert to specify the delay.
+
+mapper.c        Added a delay field to #map exits, which will be used
+                when using #path run with a delay argument.
+
+data.c          Added #info sessions save which will save the data on all
+                sessions to $info[SESSIONS].
+
+data.c          #info session save now saves the data to $info[SESSION][NAME]
+                rather than to $info[SESSION][SESSION_NAME]
+
+cursor.c        Added #cursor position <column> to move the cursor to the
+                given column.
+
+show.c          Added RECEIVED ERROR event. Example:
+                #event {RECEIVED ERROR} {#info stack}
+
+class.c         Added #class {name} assign {argument} which will execute the
+                argument, assigning all newly created triggers to the given
+                class.
+
+draw.c          Added #draw buffer, which draws the scrollback buffer based
+                on the scrolling state.
+
+draw.c          Added #draw foreground flag, which allows inactive sessions
+                to draw.
+
+update.c        Added END OF RUN event which triggers at the end of #map or
+                #path run.
+
 Mar 2020        2.02.03
 ------------------------------------------------------------------------------
 
@@ -97,7 +290,7 @@ input.c         ctrl-v will now correctly capture ctrl-alt-f and similar
                 combinations. ctrl-v will also allow pasting blocks of text.
                 Example added to the SCRIPTS file.
 
-event.c         Added GAG SESSION CONNECTED, GAG SESSION CREATED, 
+event.c         Added GAG SESSION CONNECTED, GAG SESSION CREATED,
                 GAG SESSION DISCONNECTED, and GAG SESSION TIMED OUT events.
 
 mapper.c        Added #map roomflag fog. Works like #map roomflag hide but
@@ -117,17 +310,15 @@ sort.c          Added sorting routines utilizing quadsort.
 
 list.c          Added #list reverse option.
 
-cursor.c        Added default bindings for ctrl-left, ctrl-right, and 
+cursor.c        Added default bindings for ctrl-left, ctrl-right, and
                 ctrl-backspace
 
 screen.c        Added advanced link support. To create an advanced link
                 surround a keyword with the \e[4m keyword \e24m tags and
-                prefix it with \e]68; code \a. The code must be valid
-                MSDP, which on click will spawn a LINK mouse event holding
-                the MSDP data as a tintin table. Example:
+                prefix it with \e]68; code \a.
 
                 #config mouse on
-                #showme {\e]68;\x01key\x02val\a\e[4mthis is a test\e[24m}
+                #showme {\e]68;;1;test\a\e[4mthis is a test\e[24m}
                 #event {SHORT-CLICKED LINK MOUSE BUTTON ONE} {#showme {[%4]}}
 
 screen.c        Added basic link support. To create a basic link surround a
@@ -200,8 +391,8 @@ draw.c          Added #draw RAIN {<VARIABLE>} {[SPAWN]} {[FADE]} {[LEGEND]}
 class.c         Added #class clear, load, and save. See #help class.
 
 main.c          Configurations and pathdirs are automatically assigned to
-                the CONFIG and PATHDIR class on startup. Somewhat experimental
-                as there may be unforseen complications.
+                the CONFIG and PATHDIR class on startup. Somewhat
+                experimental as there may be unforseen complications.
 
 list.c          Added #list <list> collapse and explode
 
@@ -255,7 +446,7 @@ cursor.c        Added #cursor tab <list|scrollback> <backward|forward>
 
 line.c          Added #line capture <variable> <command> option.
 
-mapper.c        Added the MAP MOUSE LOCATION event to go along with the 
+mapper.c        Added the MAP MOUSE LOCATION event to go along with the
                 SCREEN MOUSE LOCATION event. MAP MOUSE LOCATION is more
                 accurate than regular MAP click events. It needs to be
                 trigged with #screen raise mouse location, which is not
@@ -302,8 +493,8 @@ screen.c        Added #screen raise SCREEN MOUSE LOCATION, the SCREEN MOUSE
                 within the character cell. %8 will report the pixel position
                 as a 3x3 cell using values 1 through 9.
 
-mapper.c        Added the BLOCK exit flag and room flag. Works like AVOID, but
-                also prevents movement into the room.
+mapper.c        Added the BLOCK exit flag and room flag. Works like AVOID,
+                but also prevents movement into the room.
 
 mapper.c        Added #map landmark <name> <vnum> [desc] and #map unlandmark.
                 Landmarks work as fast lookup aliases and to give tintin an
@@ -397,7 +588,7 @@ nest.c          Added a notice for people still using $variable[] instead of
 
 math.c          Added .. ellipsis support to define ranges in tables. It can
                 also be used in #math to join two 32 bit integers into a 64
-                bit integer. 
+                bit integer.
 
 terminal.c      Now initializing a more advanced keyboard mode upon startup,
                 if a macro stops working check if you have to redefine it to
@@ -445,7 +636,7 @@ draw.c          More feature complete, see #help draw.
 vt100.c         Added better cursor save/restore handling.
 
 update.c        Added support for centisecond delays (0.01) and moved ticks to
-                deciseconds (0.1). 
+                deciseconds (0.1).
 
                 Reduced input and session polling lag from 25 ms to 5 ms,
                 which comes at a slight increase in cpu usage.
@@ -787,7 +978,7 @@ main.c          Added better #! hashbang support, with %0 in the PROGRAM START
 
 data.c          Added #INFO SYSTEM option, with #INFO SYSTEM SAVE saving the
                 data to the info[SYSTEM] variable. Current variables
-                supported are CLIENT_NAME and CLIENT_VERSION. 
+                supported are CLIENT_NAME and CLIENT_VERSION.
 
 event.c         Added %4 and %5 arguments to mouse click events which hold the
                 word and line that was clicked. Under construction.
@@ -922,7 +1113,7 @@ telopt.c        Added support for the CHARSET telnet option. Currently
 path.c          Added #path save <length|position> <variable> options.
 
 
-Feb 2019       
+Feb 2019
 ------------------------------------------------------------------------------
                 There was a question regarding copyright and licensing
                 recently so I made some changes and I'm writing this entry to
@@ -976,7 +1167,7 @@ Feb 2019
            2001 Robert Ellsworth, aka Joann Ellsworth, as the copyright holder
                 licensed the tintin15.txt manual under the GPL on 28 Aug 2001.
 
-           2004 Igor van den Hoven received permission from Bill Reiss to 
+           2004 Igor van den Hoven received permission from Bill Reiss to
                 release TinTin++ derived code under the name TinTin++.
 
            2004 Igor van den Hoven released TinTin++ 1.90 on March 13 under
@@ -985,7 +1176,7 @@ Feb 2019
                 file the code could only be legally released under the GPL
                 2 or later.
 
-                Version 1.90 featured a new mathematics engine and regular 
+                Version 1.90 featured a new mathematics engine and regular
                 expression interpreter, telnet negotations, a scroll back
                 buffer, enhanced VT102 interpretation, a more standardized
                 TINTIN scripting language, a nifty string formatter, internal
@@ -1183,7 +1374,7 @@ line.c         #line log {filename} {text} was extremely slow, at least on
                for each log call. Multiple logs to the same file are much
                faster now, with each session having its own dedicated file
                descriptor to speed up consecutive writes to the same log
-               file. 
+               file.
 
 config.c       Added config RANDOM SEED option to set a custom seed for the
                random number generator. Useful for machine learning scripts
@@ -2245,7 +2436,7 @@ alias.c        Variables passed along as an alias argument now go by value
                instead of by reference.
 
 mapper.c       Added the asciivnums flag which displays room vnums in the ascii
-               map. 
+               map.
 
 
 August 2008    1.98.5
@@ -2744,7 +2935,7 @@ input.c        Escaped unmatched sequences are now automagically meta converted.
 cursor.c       history prev and next can now be used in combination with the
                history search function.
 
-mapper.c       Improved map drawing by using virtual coordinates. 
+mapper.c       Improved map drawing by using virtual coordinates.
 
 mapper.c       Added a flag to enable vt graphics mode. A hopefully universal
                legenda is: 250 223 222 200 220 186 201 204 221 188 205 202 187
@@ -2754,7 +2945,7 @@ mapper.c       Added a flag to draw 6x3 ascii graphics which allows displaying
                rooms going ne, nw, se, sw, u, and d.
 
 misc.c         Can no longer use commas in #loop. When using 1 argument with
-               #loop it's assumed 
+               #loop it's assumed
 
 misc.c         Can now use math in delays, as in #delay 1d5 smile.
 
@@ -3163,7 +3354,7 @@ split.c        Fixed various #split bugs when creating or switching sessions.
 
 buffer.c       #buffer {i} will now give some info about the scrollback buffer.
 
-tick.c         #delay now works in the startup session. Tickers are still 
+tick.c         #delay now works in the startup session. Tickers are still
                disabled.
 
 class.c        #class <class> read <file>, now only reads in stuff that belongs
@@ -3307,7 +3498,7 @@ rl.c           No more threading, made tintin crashy as well.
 variable.c     Added %n (name) to #format, which capitalizes the first letter
                of the given string.
 
-buffer.c       No longer resetting the buffer if the new scrollback size 
+buffer.c       No longer resetting the buffer if the new scrollback size
                is the same as the old one.
 
 rl.c           prompts automatically get a newline added in split mode.
@@ -3772,7 +3963,7 @@ action.c       rewrote the %0 - %9 check_one_action regexp routine, it's
 action.c       rewrote substitute_vars, ';' is changed to : per default
 
 variable.c     rewrote subsitute_myvariables, no longer supporting $number
-               variables. ';' is stripped per default. This also easily 
+               variables. ';' is stripped per default. This also easily
                allows a change so variables can contain numbers.
 
 variable.c     #format {variable} {format} {arguments}

+ 3 - 2
src/Makefile.in

@@ -66,10 +66,11 @@ OFILES = \
 files.o help.o trigger.o input.o main.o misc.o net.o parse.o debug.o \
 update.o history.o vt102.o terminal.o text.o memory.o math.o split.o \
 system.o mapper.o tables.o buffer.o event.o tokenize.o chat.o utf8.o \
-advertise.o list.o forkpty.o utils.o line.o data.o variable.o msdp.o \
+banner.o list.o forkpty.o utils.o line.o data.o variable.o msdp.o \
 port.o scan.o telopt_client.o screen.o cursor.o nest.o show.o mccp.o \
 telopt_server.o draw.o log.o path.o session.o class.o config.o ssl.o \
-regex.o substitute.o daemon.o dict.o sort.o base.o string.o
+regex.o substitute.o daemon.o dict.o sort.o base.o string.o edit.o \
+command.o
 
 default: all
 

+ 638 - 0
src/banner.c

@@ -0,0 +1,638 @@
+/******************************************************************************
+*   This file is part of TinTin++                                             *
+*                                                                             *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
+*                                                                             *
+*   TinTin++ is free software; you can redistribute it and/or modify          *
+*   it under the terms of the GNU General Public License as published by      *
+*   the Free Software Foundation; either version 3 of the License, or         *
+*   (at your option) any later version.                                       *
+*                                                                             *
+*   This program is distributed in the hope that it will be useful,           *
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of            *
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
+*   GNU General Public License for more details.                              *
+*                                                                             *
+*   You should have received a copy of the GNU General Public License         *
+*   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
+******************************************************************************/
+
+/******************************************************************************
+*                               T I N T I N + +                               *
+*                                                                             *
+*                      coded by Igor van den Hoven 2009                       *
+******************************************************************************/
+
+#include "tintin.h"
+
+#include "gui.h"
+
+void banner_create(struct session *ses, char *name, char *arg)
+{
+	update_node_list(gtd->banner_list, name, "", "", "");
+}
+
+
+void banner_desc(struct session *ses, char *name, char *arg, char *arg1)
+{
+	struct listnode *node;
+
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
+
+	node = search_node_list(gtd->banner_list, name);
+
+	if (node)
+	{
+		update_node_list(gtd->banner_list, name, arg1, node->arg3, node->arg4);
+	}
+}
+
+void banner_website(struct session *ses, char *name, char *arg, char *arg1)
+{
+	struct listnode *node;
+
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
+
+	node = search_node_list(gtd->banner_list, name);
+
+	if (node)
+	{
+		update_node_list(gtd->banner_list, name, node->arg2, arg1, node->arg4);
+	}
+}
+
+void banner_address(struct session *ses, char *name, char *arg, char *arg1)
+{
+	struct listnode *node;
+
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
+
+	node = search_node_list(gtd->banner_list, name);
+
+	if (node)
+	{
+		update_node_list(gtd->banner_list, name, node->arg2, node->arg3, arg1);
+	}
+}
+
+void banner_expires(struct session *ses, char *name, char *arg, char *arg1)
+{
+	struct listnode *node;
+
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
+
+	node = search_node_list(gtd->banner_list, name);
+
+	if (node)
+	{
+		node->val64 = UMAX(0, (atoi(arg1) - 1970) * 31556926);
+	}
+}
+
+void banner_init(struct session *ses, char *arg1)
+{
+	banner_create(ses, "Lost Souls", arg1);
+
+	banner_desc(ses, "Lost Souls",
+		"\"Lost Souls is not for the faint of heart.\" -- Net Games\n"
+		"\n"
+		"\"The depth of Lost Souls can be amazing.\" -- Playing MUDs On The Internet\n"
+		"\n"
+		"\"Have you ever come upon a place on the Net that's so incredible that you\n"
+		"can't believe such entertainment is free? This MUD will blow your mind with\n"
+		"its marvelous attention to detail and incredible role-playing atmosphere!\"\n"
+		"\n"
+		"  -- Yahoo! Wild Web Rides", arg1);
+
+	banner_website(ses, "Lost Souls", "http://lostsouls.org", arg1);
+	banner_address(ses, "Lost Souls", "ls lostsouls.org 23", arg1);
+	banner_expires(ses, "Lost Souls", "2025", arg1);
+
+
+	banner_create(ses, "Legends of Kallisti", arg1);
+
+	banner_desc(ses, "Legends of Kallisti",
+		"One of the longest running, most feature rich MUDs in the world with decades of\n"
+		"development. Kallisti boasts a massive original world, great atmosphere of long\n"
+		"time players, excellent combat system including group formations, ranged combat,\n"
+		"optional PK and arena PvP, extensive character customization options, player\n"
+		"lineages, clans, customizable player houses, item crafting, extensively\n"
+		"customizable UI, Mud Sound Protocol (MSP), MSDP, and so much more.\n"
+		"\n"
+		"This is an a amazing game that you could literally play for a decade and still\n"
+		"discover more - you won't be disappointed!", arg1);
+
+	banner_website(ses, "Legends of Kallisti", "http://www.KallistiMUD.com", arg1);
+	banner_address(ses, "Legends of Kallisti", "LoK kallistimud.com 4000", arg1);
+	banner_expires(ses, "Legends of Kallisti", "2025", arg1);
+
+
+	banner_create(ses, "3Kingdoms", arg1);
+
+	banner_desc(ses, "3Kingdoms",
+		"{Based around the mighty town of Pinnacle, three main realms beckon the player\n"
+		"to explore.  These kingdoms are: Fantasy, a vast medieval realm of orcs, elves,\n"
+		"dragons, and a myriad of other creatures; Science, a post-apocalyptic, war-torn\n"
+		"world set in the not-so-distant future; and Chaos, a transient realm where the\n"
+		"realities of Fantasy and Science collide to produce unimaginable results.\n"
+		"\n"
+		"3Kingdoms combines all these features, and so much more, to give the player an\n"
+		"experience that will stay with them for the rest of their lives.  Come live the\n"
+		"adventure and find out for yourself why 3K is the best there is!}", arg1);
+
+	banner_website(ses, "3Kingdoms", "http://3k.org", arg1);
+	banner_address(ses, "3Kingdoms", "3K 3k.org 3000", arg1);
+	banner_expires(ses, "3Kingdoms", "2025", arg1);
+
+
+	banner_create(ses, "New World Ateraan", arg1);
+
+	banner_desc(ses, "New World Ateraan",
+		"Ateraan is a world of Intensive Roleplaying offering many unique and powerful\n"
+		"guilds, races, politics, religion, justice, economy, and a storyline that is\n"
+		"dominantly player controlled and based on a novel. The game is based on a\n"
+		"Kingdom with knights, merchants, mages, and thieves, and a fierce southern\n"
+		"state that has warriors, shaman, slaves, and servants. Ships rule the seas and\n"
+		"caravans travel the lands. With 100's of players and features like invasions,\n"
+		"ship creation, house building, clans, theaters, leatherball fields, and massive\n"
+		"events, the game is incredibly robust and diverse.", arg1);
+
+	banner_website(ses, "New World Ateraan", "http://www.ateraan.com", arg1);
+	banner_address(ses, "New World Ateraan", "nwa ateraan.com 4002", arg1);
+	banner_expires(ses, "New World Ateraan", "2025", arg1);
+
+
+	banner_create(ses, "Realm of Utopian Dreams (RUD)", arg1);
+
+	banner_desc(ses, "Realm of Utopian Dreams (RUD)",
+		"RUD is a unique ROM-based high-fantasy MUD with character choices for many play\n"
+		"styles from hack-n-slash to roleplay. Each of the races and classes offer\n"
+		"unique spells and skills, unlocked through a tiered remort system with\n"
+		"customization through religion memberships and epic advancements. RUD started\n"
+		"in 1996, always seeking new adventurers to become the next hero, build a home,\n"
+		"start a shop, and eventually become Nobles of the Realm! New players to RUD can\n"
+		"be just as successful as 20+ year veterans. We run quests, plots, and annual\n"
+		"festivals in an ever evolving world. Come build Lantarea with us!", arg1);
+
+	banner_website(ses, "Realm of Utopian Dreams (RUD)", "http://rudmud.com", arg1);
+	banner_address(ses, "Realm of Utopian Dreams (RUD)", "rud rudmud.com 1701", arg1);
+	banner_expires(ses, "Realm of Utopian Dreams (RUD)", "2025", arg1);
+
+	banner_create(ses, "Carrion Fields", arg1);
+
+	banner_desc(ses, "Carrion Fields",
+		"Carrion Fields blends high-caliber roleplay with complex, hardcore\n"
+		"player-vs-player combat and has been running continuously, 100% free, for \n"
+		"over 25 years.  Choose from among 21 races, 17 highly customizable classes\n"
+		"and several cabals and religions to suit your playstyle and the story you\n"
+		"want to tell.  With a massive, original world and coveted limited objects,\n"
+		"we've been described as \"the 'Dark Souls' of MUDs\".  Come join our vibrant\n"
+		"community for a real challenge and very real rewards: adrenaline-pumping\n"
+		"battles, memorable quests run by our volunteer immortal staff, and stories\n"
+		"that will stick with you for a lifetime.", 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);
+}
+
+int total_banners()
+{
+	int index, count;
+
+	count = 0;
+
+	for (index = 0 ; index < gtd->banner_list->used ; index++)
+	{
+		if (gtd->time < gtd->banner_list->list[index]->val64)
+		{
+			count++;
+		}
+	}
+	return count;
+}
+
+struct listnode *random_pick()
+{
+	struct listnode *node;
+	int index, max;
+
+	max = total_banners();
+
+	for (index = 0 ; index < gtd->banner_list->used ; index++)
+	{
+		node = gtd->banner_list->list[index];
+
+		if (node->val64 < gtd->time)
+		{
+			continue;
+		}
+
+		if (generate_rand(gts) % max == 0)
+		{
+			return node;
+		}
+		max--;
+	}
+	return NULL;
+}
+
+void banner_random(struct session *ses)
+{
+	struct listnode *node;
+
+	node = random_pick();
+
+	if (node)
+	{
+		tintin_printf2(ses, "");
+
+		if (get_scroll_cols(ses) < 80 || HAS_BIT(ses->config_flags, CONFIG_FLAG_SCREENREADER))
+		{
+			command(ses, do_draw, "scroll scaled calign tile 1 1 1 80 <138>%s", node->arg1);
+			command(ses, do_draw, "scroll scaled calign tile 1 1 1 80 <178>%s", node->arg3);
+		}
+		else
+		{
+//			command(ses, do_draw, "scroll scaled calign tile 1 1 1 80 {<138>%s <178>- <138>\e]8;;%s\a\e[58:5:2;4m%s\e[59;24m\e]8;;\a}", node->arg1, node->arg3, node->arg3);
+			command(ses, do_draw, "scroll scaled calign tile 1 1 1 80 {<138>%s <178>- <138>\e]8;;%s\a\e[04m%s\e[24m\e]8;;\a}", node->arg1, node->arg3, node->arg3);
+		}
+		tintin_printf2(ses, "");
+
+		if (get_scroll_cols(ses) < 80 || HAS_BIT(ses->config_flags, CONFIG_FLAG_SCREENREADER))
+		{
+			command(ses, do_draw, "scroll ualign scaled tile 1 1 1 -1 {<278>%s}", node->arg2);
+		}
+		else
+		{
+			command(ses, do_draw, "scroll scaled tile 1 1 1 80 {<278>%s}", node->arg2);
+		}
+
+		tintin_printf2(ses, "");
+
+		command(ses, do_draw, "scroll scaled tile 1 1 1 80 <178>To connect to %s enter: #session %s", node->arg1, node->arg4);
+
+		tintin_printf2(ses, "");
+	}
+//	tintin_printf2(ses, "#NO SESSION ACTIVE. USE: %csession {name} {host} {port} TO START ONE.", gtd->tintin_char);
+}
+
+void banner_list(struct session *ses, char *arg1)
+{
+	int index;
+	struct listnode *node;
+
+	tintin_header(ses, 80, " BANNERS ");
+
+	for (index = 0 ; index < gtd->banner_list->used ; index++)
+	{
+		node = gtd->banner_list->list[index];
+
+		arg1 = strstr(node->arg4, " ");
+
+		tintin_printf2(ses, "[%-30s] %s", node->arg1, arg1);
+	}
+	tintin_header(ses, 80, "");
+
+}
+
+void banner_save(struct session *ses, char *arg1)
+{
+	int index;
+	struct listnode *node;
+	char *name, *arg2;
+	
+	name = str_alloc_stack(0);
+	arg2 = str_alloc_stack(0);
+
+	set_nest_node_ses(ses, "info[BANNERS]", "");
+
+	for (index = 0 ; index < gtd->banner_list->used ; index++)
+	{
+		node = gtd->banner_list->list[index];
+
+		sprintf(name, "info[BANNERS][%s]", node->arg1);
+
+		arg1 = node->arg4;
+
+		arg1 = get_arg_in_braces(ses, arg1, arg2, GET_ONE);
+		add_nest_node_ses(ses, name, "{ALIAS}{%s}", arg2);
+
+		add_nest_node_ses(ses, name, "{DESC}{%s}", node->arg2);
+
+		arg1 = get_arg_in_braces(ses, arg1, arg2, GET_ONE);
+		add_nest_node_ses(ses, name, "{HOST}{%s}", arg2);
+
+		add_nest_node_ses(ses, name, "{NAME}{%s}", node->arg1);
+
+		arg1 = get_arg_in_braces(ses, arg1, arg2, GET_ONE);
+		add_nest_node_ses(ses, name, "{PORT}{%s}", arg2);
+
+		add_nest_node_ses(ses, name, "{WEBSITE}{%s}", node->arg3);
+	}
+
+	show_message(ses, LIST_COMMAND, "#INFO: DATA WRITTEN TO {info[BANNERS]}");
+}
+
+void banner_test(struct session *ses, char *arg1)
+{
+	int cnt, max, index;
+	struct listnode *node;
+
+	max = total_banners() * 100000;
+
+	for (cnt = 0 ; cnt < max ; cnt++)
+	{
+		node = random_pick();
+
+		if (node)
+		{
+			node->shots++;
+		}
+	}
+
+	tintin_header(ses, 80, " BANNER TEST ");
+
+	for (index = 0 ; index < gtd->banner_list->used ; index++)
+	{
+		node = gtd->banner_list->list[index];
+
+		arg1 = strstr(node->arg4, " ");
+
+		tintin_printf2(ses, "[%-30s] [%6d] %s", node->arg1, node->shots, arg1);
+
+		node->shots = 0;
+	}
+	tintin_header(ses, 80, "");
+}
+
+struct session *banner_gui(struct session *ses, char *arg1)
+{
+	char filename[PATH_SIZE];
+	FILE *fp;
+
+	sprintf(filename, "%s/gui.tin", gtd->system->tt_dir);
+
+	if ((fp = fopen(filename, "w")) == NULL)
+	{
+		tintin_printf2(ses, "#BANNER GUI: FAILED TO CREATE {%s}.", filename);
+
+		return ses;
+	}
+
+	fputs(tt_gui, fp);
+
+	fclose(fp);
+
+	return command(ses, do_line, "quiet #read %s", filename);
+}
+
+DO_COMMAND(do_banner)
+{
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
+
+	if (is_abbrev(arg1, "RANDOM"))
+	{
+		banner_random(ses);
+	}
+	else if (is_abbrev(arg1, "INIT"))
+	{
+		banner_init(ses, arg1);
+	}
+	else if (is_abbrev(arg1, "GUI"))
+	{
+		return banner_gui(ses, arg1);
+	}
+	else if (is_abbrev(arg1, "LIST"))
+	{
+		banner_list(ses, arg1);
+	}
+	else if (is_abbrev(arg1, "TEST"))
+	{
+		banner_test(ses, arg1);
+	}
+	else if (is_abbrev(arg1, "SAVE"))
+	{
+		banner_save(ses, arg1);
+	}
+	else
+	{
+		banner_list(ses, arg1);
+//		tintin_printf2(ses, "#SYNTAX: #BANNER {INIT|LIST|RANDOM|TEST}");
+	}
+	return ses;
+}
+
+// archive
+
+/*
+	{
+		1400000000,  // 2014
+		1800000000,  // 2027
+		100,
+
+		"\n"
+		"<138>                 Primal Darkness  -  http://www.primaldarkness.com\n"
+		"\n"
+		"<078>Primal Darkness boasts twenty three start races, three quest races, five start\n"
+		"<078>classes and twenty one subclasses to suit your adventuring needs, and a custom\n"
+		"<078>remort system allowing you to save all your hard work while trying out new\n"
+		"<078>races and/or classes. The world has zoned player killing (pk) supported by a\n"
+		"<078>justice system, player built and ran guilds, a fully sail-able ocean with\n"
+		"<078>customizable ships and ship battle system, a fully flyable sky with mapping\n"
+		"<078>system, mud-wide auction line, a colosseum in which to prove your battle\n"
+		"<078>prowess (harmless/free pk), and 30+ areas on multiple continents to explore.\n"
+		"\n"
+		"<178>To connect to Primal Darkness enter: #session pd mud.primaldarkness.com 5000\n"
+		"\n",
+		
+		"\n"
+		"<138>Primal Darkness\n"
+		"<168>http://www.primaldarkness.com\n"
+		"\n"
+		"<078>Primal Darkness boasts twenty three start races, three quest races, five start classes and twenty one subclasses to suit your adventuring needs, and a custom remort system allowing you to save all your hard work while trying out new races and/or classes. The world has zoned player killing (pk) supported by a justice system, player built and ran guilds, a fully sail-able ocean with customizable ships and ship battle system, a fully flyable sky with mapping system, mud-wide auction line, a colosseum in which to prove your battle prowess (harmless/free pk), and 30+ areas on multiple continents to explore.\n"
+		"\n"
+		"<178>To connect to Primal Darkness enter: #session pd mud.primaldarkness.com 5000\n"
+		"\n"
+	},
+
+	{
+		1400000000,
+ 		1800000000,
+		100,
+
+		"\n"
+		"<138>                The Last Outpost  -  https://www.last-outpost.com\n"
+		"\n"
+		"<078>The Last Outpost has been serving up adventure since 1992.  Along with\n"
+		"<078>exploring and advancing through the game world, the game offers players the\n"
+		"<078>ability to lay claim to the zones that make up the land.  Once claimed, a zone\n"
+		"<078>can be taxed, and the player making the claim gets to decide policy within the\n"
+		"<078>zone.  Whoever claims the whole world is declared the Leader of the Last\n"
+		"<078>Outpost!  Whether you enjoy hack 'n slash, following quests, PvP, NPK, playing\n"
+		"<078>in clans, or soloing, the Last Outpost has it.\n"
+		"\n"
+		"<178>To connect to The Last Outpost enter: #session lo last-outpost.com 4000\n"
+		"\n",
+
+		"\n"
+		"<138>The Last Outpost\n"
+		"<168>https://www.last-outpost.com\n"
+		"\n"
+		"<078>The Last Outpost has been serving up adventure since 1992.  Along with exploring and advancing through the game world, the game offers players the ability to lay claim to the zones that make up the land.  Once claimed, a zone can be taxed, and the player making the claim gets to decide policy within the zone.  Whoever claims the whole world is declared the Leader of the Last Outpost!  Whether you enjoy hack 'n slash, following quests, PvP, NPK, playing in clans, or soloing, the Last Outpost has it.\n"
+		"\n"
+		"<178>To connect to The Last Outpost enter: #session lo last-outpost.com 4000\n"
+		"\n"
+	},
+
+	{
+		1400000000, 
+		1700000000, 
+		100,
+		"\n"
+		"<138>               Carrion Fields  -  http://carrionfields.net\n"
+		"\n"
+		"<078>Adventure, politics and bloody war await you in this life of swords, sorcery,\n"
+		"<078>deception, and honor.  We have 17 customizable classes with which to explore a\n"
+		"<078>massively rich world of over 270 areas.  RP is mandatory, but help is always\n"
+		"<078>available on the newbie channel.  Intuitive game mechanics provide a fun and\n"
+		"<078>fulfilling PK environment.  Carrion Fields is 100% free to play and free of\n"
+		"<078>paid perks as well.  By what name do you wish to be mourned?\n"
+		"\n"
+                "<178>To connect to Carrion Fields enter: #session cf carrionfields.net 4449\n"
+                "\n"
+		                
+	},
+
+	{
+		1400000000, 
+		1700000000, 
+		100,
+		"\n"
+		"<138>                 Alter Aeon  -  http://www.alteraeon.com\n"
+		"\n"
+		"<078>Alter Aeon is a custom multiclass MUD, where each of the character\n"
+		"<078>classes can be combined to make very unique characters.  This huge\n"
+		"<078>fantasy themed game has hundreds of areas and quests, spanning\n"
+		"<078>several continents and outer planar regions.  There are custom spells,\n"
+		"<078>skills, minions, player run shops, boats, PvP, and many other features\n"
+		"<078>for nearly every kind of player.  The game is very friendly to new players\n"
+		"<078>and has extensive support for the blind and visually impaired.\n"
+		"\n"
+		"<178>To connect to Alter Aeon enter: #session aa alteraeon.com 3000\n"
+		"\n"
+	},
+
+	{
+		1260469590, * 10 Dec 2009 *
+		1323541590, * 10 Dec 2011 *
+		"\n"
+		"<138>                                  Lowlands\n"
+		"\n"
+		"<078>Lowlands is an old school severely customized Merc derived Hack and Slash MUD\n"
+		"<078>with an emphasis on exploration and solving challenging and immersive area\n"
+		"<078>based quests.\n"
+		"\n"
+		"<078>A voluntary two faction player killing system is in place for the followers of\n"
+		"<078>the two gods, Chaos and Order, combined with easy corpse retrieval, no corpse\n"
+		"<078>looting, and a large 15,000 room world.\n"
+		"\n"
+		"<178>To connect to Lowlands enter: #session lo slackhalla.org 6969\n"
+		"\n"
+	},
+
+	{
+		1260469590, * 10 Dec 2009 *
+		1323541590, * 10 Dec 2011 *
+		"\n"
+		"<138>                Maiden Desmodus  -  http://maidendesmodus.com\n"
+		"\n"
+		"<078>Maiden Desmodus is an immersive world of high adventure where your actions, or\n"
+		"<078>inaction, will determine the fate of The Isle. Choose to be born unto one of\n"
+		"<078>two opposing factions, join one of the six powerful guilds, and carve your\n"
+		"<078>place in history through your cunning, your strategy, and your skill with magic\n"
+		"<078>or a blade. At every turn are players who may ally themselves to you, or work\n"
+		"<078>to destroy you. Shall you form your own cabal and command your peers, control\n"
+		"<078>the politics of your city, or lead an army against those who oppose you?\n"
+		"<078>Maiden Desmodus features a completely original world and a custom game engine.\n"
+		"\n"
+		"<178>To connect to Maiden Desmodus enter: #session md maidendesmodus.com 4000\n"
+		"\n"
+	},
+
+	{
+		1260469590, * 10 Dec 2009 *
+		1323541590, * 10 Dec 2011 *
+		"\n"
+		"<138>                     Lost Souls  -  http://lostsouls.org\n"
+		"\n"
+		"<078>\"Our world is fallen, boy.  Aedaris is a ruin.  My grandfather, he told me\n"
+		"<078>of days, not so long gone, when everything you see was part of a great empire.\n"
+		"<078>Peaceful, he said.  Full of wonders.  They called it eternal.  Funny, eh, boy?\n"
+		"<078>They thought it'd last forever, and it went crazy and tore itself apart.  But\n"
+		"<078>they left behind a few things for us, didn't they?  Ha!  Yes, lots for us.  Now\n"
+		"<078>give that wizard-stick here before you blow your fool horns off, and get to\n"
+		"<078>work.  Daylight's soon, and these faeries aren't going to skin themselves.\"\n"
+		"<078>Lost Souls: chaos in the wreckage of empire.  Be clever if you want to live.\n"
+		"\n"
+                "<178>To connect to Lost Souls enter: #session ls lostsouls.org 23\n"
+                "\n"
+		                
+	},
+
+	{
+		1291140000, * 30 Nov 2010 *
+		1354280000, * 30 Nov 2012 *
+		100,
+		"\n"
+		"<138>                Threshold RPG  -  http://www.thresholdrpg.com\n"
+		"\n"
+		"<078>Join us as Threshold RPG, one of the oldest RP enforced games on the\n"
+		"<078>internet. Add to thirteen years of player created history and make your own\n"
+		"<078>mark on the world today. Join a hundred other players who are vying for\n"
+		"<078>political and religious power in complex systems that reward skill, effort,\n"
+		"<078>and social interactions. Threshold RPG is a custom code-base written in\n"
+		"<078>LPC and features a completely unique and original world.\n"
+		"\n"
+		"<178>To connect to Threshold RPG enter: #session thresh thresholdrpg.com 23\n"
+		"\n"
+	},
+
+	{
+		1291140000,
+		1354280000,
+		100,
+		"\n"
+		"<138>                   Primordiax - http://www.primordiax.com\n"
+		"\n"
+		"<078>Primordiax is an in-character enforced MUD where roleplaying is heavily\n"
+		"<078>encouraged. The exclusive design of Primordiax makes it extremely\n"
+		"<078>accessible to new players without losing the intrigue and complexity that\n"
+		"<078>continues to attract veterans of the genre. Primordiax offers a classic\n"
+		"<078>gaming experience with a highly unique class system and an open skill tree.\n"
+		"\n"
+		"<178>To connect to Primordiax enter: #session prim primordiax.com 3000\n"
+		"\n"
+	},
+
+	{
+		1291140000, * 30 Nov 2010 *
+		1354280000, * 30 Nov 2012 *
+		100,
+		"\n"
+		"<138>                Northern Crossroads - http://www.ncmud.org\n"
+		"\n"
+		"<078>Northern Crossroads is a diverse world of blade wielders, assassins and magic\n"
+		"<078>users who use their powers together to seek out the darkest dungeons. Decide\n"
+		"<078>between five classes, as allowed by your choice of ten races, and prove your\n"
+		"<078>strength to ascend to an Advanced class. Venture to dangerous zones with other\n"
+		"<078>mortals, claim the rarest of items, join one of several clubs and build your\n"
+		"<078>character to challenge other mortals. NC has enthralled players with hundreds\n"
+		"<078>of detailed areas of various themes since 1993 and is one of the oldest MUDs\n"
+		"<078>in the world.\n"
+		"\n"
+		"<178>To connect to Northern Crossroads enter: #session NC ncmud.org 9000\n"
+		"\n"
+	},
+*/
+

+ 17 - 17
src/base.c

@@ -224,24 +224,24 @@ int str_to_base252(char *in, char *out, size_t size)
 		switch ((unsigned char) in[cnt])
 		{
 			case 0:
-				*pto++ = 0xC0;
-				*pto++ = 0x80 + (unsigned char) in[cnt] % 64;
-				break;
-
-			case 0x10:
-			case 0x11:
 			case '{':
 			case '}':
+				*pto++ = 245;
+				*pto++ = 128 + (unsigned char) in[cnt] % 64;
+				break;
+
 			case '\\':
-				*pto++ = 0xC0 + (unsigned char) in[cnt] / 64;
-				*pto++ = 0x80 + (unsigned char) in[cnt] % 64;
+				*pto++ = 246 + (unsigned char) in[cnt] / 64;
+				*pto++ = 128 + (unsigned char) in[cnt] % 64;
 				break;
 
-			case 0xC0:
-			case 0xC1:
-			case 0xFF:
-				*pto++ = 0x11;
-				*pto++ = 0x80 + (unsigned char) in[cnt] % 64;
+			case 245:
+			case 246:
+			case 247:
+			case 248:
+			case 255:
+				*pto++ = 248;
+				*pto++ = 128 + (unsigned char) in[cnt] % 64;
 				break;
 
 			default:
@@ -267,22 +267,22 @@ int base252_to_str(char *in, char *out, size_t size)
 	{
 		switch ((unsigned char) in[cnt])
 		{
-			case 0xC0:
+			case 245:
 				cnt++;
 				*pto++ =   0 + (unsigned char) in[cnt] % 64;
 				break;
 
-			case 0xC1:
+			case 246:
 				cnt++;
 				*pto++ =  64 + (unsigned char) in[cnt] % 64;
 				break;
 
-			case 0x10:
+			case 247:
 				cnt++;
 				*pto++ = 128 + (unsigned char) in[cnt] % 64;
 				break;
 
-			case 0x11:
+			case 248:
 				cnt++;
 				*pto++ = 192 + (unsigned char) in[cnt] % 64;
 				break;

+ 240 - 169
src/buffer.c

@@ -46,10 +46,7 @@ void init_buffer(struct session *ses, int size)
 			free(ses->scroll->buffer[cnt]);
 		}
 		free(ses->scroll->buffer);
-	}
 
-	if (ses->scroll->input)
-	{
 		str_free(ses->scroll->input);
 	}
 
@@ -81,11 +78,8 @@ void check_buffer(struct session *ses)
 	char temp[STRING_SIZE];
 	int index, wrap;
 
-	push_call("check_buffer(%p)",ses);
-
 	if (!HAS_BIT(ses->scroll->flags, SCROLL_FLAG_RESIZE))
 	{
-		pop_call();
 		return;
 	}
 
@@ -93,6 +87,21 @@ void check_buffer(struct session *ses)
 
 	wrap = get_scroll_cols(ses);
 
+	if (ses->scroll->width)
+	{
+		if (wrap == ses->scroll->wrap)
+		{
+			return;
+		}
+
+		if (ses->scroll->width < ses->scroll->wrap && ses->scroll->width < wrap)
+		{
+			goto end;
+		}
+	}
+
+	ses->scroll->width = 0;
+
 	for (index = ses->scroll->used - 1 ; index >= 0 ; index--)
 	{
 		buffer = ses->scroll->buffer[index];
@@ -105,20 +114,45 @@ void check_buffer(struct session *ses)
 		{
 			buffer->lines = word_wrap_split(ses, buffer->str, temp, wrap, 0, 0, FLAG_NONE, &buffer->height, &buffer->width);
 		}
+
+		if (ses->scroll->width < buffer->width)
+		{
+			ses->scroll->width = buffer->width;
+		}
 	}
 
+	end:
+
 	ses->scroll->wrap = wrap;
 	ses->scroll->time = gtd->time;
 	ses->scroll->base = 0;
 	ses->scroll->line = -1;
 
-	pop_call();
 	return;
 }
 
+void update_scrollbar(struct session *ses)
+{
+	if (HAS_BIT(gtd->screen->flags, SCREEN_FLAG_SCROLLMODE))
+	{
+		if (ses == gtd->ses)
+		{
+			int line = gtd->ses->scroll->line >= 0 ? gtd->ses->scroll->line : gtd->ses->scroll->used + 1;
+
+			line = URANGE(1, line - get_scroll_rows(gtd->ses), gtd->ses->scroll->used);
+
+			print_stdout(0, 0, "\e[%d;%d#t", line, gtd->ses->scroll->used);
+
+			check_all_events(ses, EVENT_FLAG_UPDATE, 0, 2, "SCROLLBAR UPDATE", ntos(line), ntos(gtd->ses->scroll->used));
+
+			DEL_BIT(gtd->screen->flags, SCREEN_FLAG_SCROLLUPDATE);
+		}
+	}
+}
+
 void add_line_buffer(struct session *ses, char *line, int prompt)
 {
-	char temp[STRING_SIZE];
+	char *temp;
 	char *pti, *pto;
 	int cnt, purge;
 	int skip, cur_row, cur_col, top_row, bot_row;
@@ -132,45 +166,12 @@ void add_line_buffer(struct session *ses, char *line, int prompt)
 		return;
 	}
 
-	SET_BIT(ses->flags, SES_FLAG_BUFFERUPDATE);
-
-/*
-	strip_vt102_codes(line, temp);
-
-	check_all_events(ses, SUB_ARG|SUB_SEC|SUB_SIL, 0, 2, "ADD LINE BUFFER", line, temp);
-
-	if (check_all_events(ses, SUB_ARG|SUB_SEC|SUB_SIL, 0, 2, "CATCH ADD LINE BUFFER", line, temp))
-	{
-		pop_call();
-		return;
-	}
-
-	if (prompt)
-	{
-		check_all_events(ses, SUB_ARG|SUB_SEC|SUB_SIL, 0, 2, "ADD PROMPT BUFFER", line, temp);
-		
-		if (check_all_events(ses, SUB_ARG|SUB_SEC|SUB_SIL, 0, 2, "CATCH ADD PROMPT BUFFER", line, temp))
-		{
-			pop_call();
-			return;
-		}
-	}
-*/
-	if (ses->line_capturefile)
-	{
-		sprintf(temp, "{%d}{%s}", ses->line_captureindex++, line);
+	temp = str_alloc_stack(0);
 
-		if (ses->line_captureindex == 1)
-		{
-			set_nest_node_ses(ses, ses->line_capturefile, "%s", temp);
-		}
-		else
-		{
-			add_nest_node_ses(ses, ses->line_capturefile, "%s", temp);
-		}
-	}
+	SET_BIT(gtd->flags, TINTIN_FLAG_SESSIONUPDATE);
+	SET_BIT(ses->flags, SES_FLAG_BUFFERUPDATE);
 
-	if (HAS_BIT(ses->flags, SES_FLAG_CONVERTMETA))
+	if (HAS_BIT(ses->config_flags, CONFIG_FLAG_CONVERTMETA))
 	{
 		convert_meta(line, temp, TRUE);
 
@@ -185,11 +186,28 @@ void add_line_buffer(struct session *ses, char *line, int prompt)
 	if (str_len(ses->scroll->input) + strlen(line) + 100 >= BUFFER_SIZE)
 	{
 		str_cat_printf(&ses->scroll->input, "\n\e[1;31m#BUFFER: LINE LENGTH OF (%d) EXEEDS MAXIMUM SIZE OF (%d)%s\n", str_len(ses->scroll->input) + strlen(line), BUFFER_SIZE, COLOR_TEXT);
+
+		prompt = FALSE;
 	}
 	else
 	{
 		if (prompt == TRUE)
 		{
+			pti = strchr(line, '\n');
+
+			while (pti)
+			{
+				*pti = 0;
+
+				add_line_buffer(ses, line, FALSE);
+
+				*pti++ = '\n';
+
+				line = pti;
+
+				pti = strchr(line, '\n');
+			}
+
 			str_cat(&ses->scroll->input, line);
 
 			pop_call();
@@ -251,6 +269,11 @@ void add_line_buffer(struct session *ses, char *line, int prompt)
 		tintin_printf2(gtd->ses, "%s[%s%s] %s", COLOR_TEXT, ses->name, ses->scroll->input, COLOR_TEXT);
 	}
 
+	if (ses->proxy)
+	{
+		port_socket_printf(ses, ses->proxy, "%s%s", ses->scroll->input, prompt ? "" : "\n");
+	}
+
 	ses->scroll->buffer[ses->scroll->used] = calloc(1, sizeof(struct buffer_data));
 
 	buffer = ses->scroll->buffer[ses->scroll->used];
@@ -259,7 +282,10 @@ void add_line_buffer(struct session *ses, char *line, int prompt)
 	buffer->time  = gtd->time;
 	buffer->str   = strdup(ses->scroll->input);
 
-	add_line_screen(temp);
+	if (ses->scroll->line == -1)
+	{
+		add_line_screen(ses, temp, 0);
+	}
 
 	if (gtd->level->grep || prompt == -1)
 	{
@@ -285,14 +311,7 @@ void add_line_buffer(struct session *ses, char *line, int prompt)
 
 	if (ses->scroll->used == ses->scroll->size)
 	{
-		if (ses->scroll->size < 100000)
-		{
-			purge = ses->scroll->size / 10;
-		}
-		else
-		{
-			purge = 10000;
-		}
+		purge = URANGE(10, ses->scroll->size / 10, 10000);
 
 		for (cnt = 0 ; cnt < purge ; cnt++)
 		{
@@ -305,6 +324,11 @@ void add_line_buffer(struct session *ses, char *line, int prompt)
 		ses->scroll->line = URANGE(-1, ses->scroll->line - purge, ses->scroll->used - 1);
 	}
 
+	if (HAS_BIT(gtd->screen->flags, SCREEN_FLAG_SCROLLMODE))
+	{
+		SET_BIT(gtd->screen->flags, SCREEN_FLAG_SCROLLUPDATE);
+	}
+
 	ses->cur_row = cur_row;
 	ses->cur_col = cur_col;
 	ses->split->top_row = top_row;
@@ -315,38 +339,40 @@ void add_line_buffer(struct session *ses, char *line, int prompt)
 }
 
 
-
 void buffer_print(struct session *ses, int index, int start, int end)
 {
 	struct buffer_data *buffer;
 	char *pti, temp[STRING_SIZE];
-	int col, swap, raw_len, str_len, col_len, height, width;
+	int col, swap, str_len, col_len, height, width;
 
 	push_call("buffer_print(%p,%d,%d,%d)",ses,index,start,end);
 
 	col_len = get_scroll_cols(ses);
 
+	// prompt
+
 	if (start == 0 && end == 0)
 	{
 		if (HAS_BIT(ses->flags, SES_FLAG_PRINTBUFFER) || ses->scroll->line == ses->scroll->used - 1)
 		{
-			pti = ses->scroll->input;
-			raw_len = string_str_raw_len(ses, pti, 0, col_len - 1);
+			word_wrap_split(ses, ses->scroll->input, temp, ses->wrap, 0, 1, WRAP_FLAG_NONE, &height, &width);
 		}
 		else
 		{
-			pti = temp;
-			raw_len = temp[0] = 0;
+			strcpy(temp, "");
 		}
 
 		if (ses->cur_row != ses->split->bot_row)
 		{
-			print_stdout("%02d \e[1;32mmisaligned (%d)", ses->cur_row, ses->scroll->line);
+			print_stdout(0, 0, "%02d \e[1;32mmisaligned (%d)", ses->cur_row, ses->scroll->line);
 		}
 		else
 		{
-//			print_stdout("\e[1;36m%02d\e[0m", ses->cur_row);//
-			print_stdout("\e[%dX%.*s", col_len, raw_len, pti);
+			print_stdout(0, 0, "%s", temp);
+
+			add_line_screen(ses, temp, ses->cur_row);
+
+			erase_cols(col_len - width);
 		}
 	}
 	else
@@ -355,15 +381,15 @@ void buffer_print(struct session *ses, int index, int start, int end)
 
 		if (buffer->height == 1)
 		{
-//			print_stdout("\e[1;37m%02d", ses->cur_row);//
-
 			word_wrap_split(ses, buffer->str, temp, ses->wrap, start, end, 0, &height, &width);
 
-			print_stdout("%s", temp);
+			print_stdout(0, 0, "%s", temp);
+
+			add_line_screen(ses, temp, ses->cur_row);
 
 			erase_cols(col_len - buffer->width);
 
-			goto_pos(ses, ++ses->cur_row, ses->split->top_col);
+			goto_pos(ses, ses->cur_row + 1, ses->split->top_col);
 		}
 		else
 		{
@@ -382,38 +408,16 @@ void buffer_print(struct session *ses, int index, int start, int end)
 
 					str_len = strip_vt102_strlen(ses, pti);
 
-					// debug info
-/*					if (start == 0)
-					{
-						if (end == buffer->height)
-						{
-							print_stdout("\e[1;31m%02d\e[0m(%d)(%d)(%d)", ses->cur_row, buffer->lines, buffer->height, buffer->width);
-						}
-						else
-						{
-							print_stdout("\e[1;33m%02d\e[0m", ses->cur_row);
-						}
-					}
-					else
-					{
-						if (end == buffer->height)
-						{
-							print_stdout("\e[1;32m%02d\e[0m", ses->cur_row);
-						}
-						else
-						{
-							print_stdout("\e[1;34m%02d\e[0m", ses->cur_row);
-						}
-					}
-*/
-					print_stdout("%s", pti);
+					print_stdout(0, 0, "%s", pti);
+
+					add_line_screen(ses, pti, ses->cur_row);
 
 					erase_cols(col_len - str_len);
 
 					pti += col + 1;
 					col = 0;
 
-					goto_pos(ses, ++ses->cur_row, ses->split->top_col);
+					goto_pos(ses, ses->cur_row + 1, ses->split->top_col);
 
 					if (swap == 0)
 					{
@@ -432,7 +436,7 @@ void buffer_print(struct session *ses, int index, int start, int end)
 
 int show_buffer(struct session *ses)
 {
-	int scroll_size, scroll_cnt, scroll_tmp, scroll_add, scroll_cut, start, end;
+	int scroll_size, scroll_cnt, scroll_tmp, scroll_add, scroll_cut, start, end, row;
 
 	if (ses != gtd->ses)
 	{
@@ -488,12 +492,13 @@ int show_buffer(struct session *ses)
 
 	if (scroll_cnt == 0) // home
 	{
-		goto_pos(ses, ses->split->bot_row - scroll_add, ses->split->top_col);
+		row = ses->split->bot_row - scroll_add;
 	}
 	else
 	{
-		goto_pos(ses, ses->split->top_row, ses->split->top_col);
+		row = ses->split->top_row;
 	}
+	goto_pos(ses, row, ses->split->top_col);
 
 	if (IS_SPLIT(ses))
 	{
@@ -514,15 +519,9 @@ int show_buffer(struct session *ses)
 			start = scroll_tmp - scroll_cut;
 			end   = scroll_tmp;
 
-			if (end - start != scroll_size)
-			{
-//				print_stdout("\e[1;32mcnt %d, base: %d, size: %d, add %d, tmp %d, scroll_cut %d start %d end %d\n", scroll_cnt, ses->scroll->base, scroll_size, scroll_add, scroll_tmp, scroll_cut, start, end);
-			}
-			else
-			{
-				buffer_print(ses, scroll_cnt, start, end);
-			}
+			buffer_print(ses, scroll_cnt, start, end);
 		}
+
 		// middle chunk
 
 		else if (scroll_cut > scroll_size)
@@ -530,35 +529,23 @@ int show_buffer(struct session *ses)
 			start = scroll_tmp - scroll_cut;
 			end   = scroll_tmp - scroll_cut + scroll_size;
 
-//			if (end - start > scroll_size)
-			{
-//				print_stdout("\e[1;1H\e[1;33mcnt %d, base: %d, size: %d, add %d, tmp %d, scroll_cut %d start %d end %d\n", scroll_cnt, ses->scroll->base, scroll_size, scroll_add, scroll_tmp, scroll_cut, start, end);
-			}
-//			else
-			{
-				buffer_print(ses, scroll_cnt, start, end);
-			}
+			buffer_print(ses, scroll_cnt, start, end);
 
 			goto eof;
 		}
 
 		// top chunk
+
 		else if (scroll_add == 0)
 		{
 			start = ses->scroll->base;
 			end   = scroll_tmp - scroll_cut;
 
-//			if (end - start > scroll_size)
-			{
-//				print_stdout("\e[1;1H\e[1;34mcnt %d, base: %d, size: %d, add %d, tmp %d, scroll_cut %d start %d end %d\n", scroll_cnt, ses->scroll->base, scroll_size, scroll_add, scroll_tmp, scroll_cut, start, end);
-			}
-//			else
-			{
-				buffer_print(ses, scroll_cnt, start, end);
-			}
+			buffer_print(ses, scroll_cnt, start, end);
 
 			goto eof;
 		}
+
 		// bot chunk
 
 		else
@@ -566,14 +553,7 @@ int show_buffer(struct session *ses)
 			start = scroll_tmp - scroll_cut;
 			end   = scroll_tmp;
 
-//			if (end - start > scroll_size)
-			{
-//				print_stdout("\e[1;1H\e[1;35mcnt %d, base: %d, size: %d, add %d, tmp %d, scroll_cut %d start %d end %d\n", scroll_cnt, ses->scroll->base, scroll_size, scroll_add, scroll_tmp, scroll_cut, start, end);
-			}
-//			else
-			{
-				buffer_print(ses, scroll_cnt, start, end);
-			}
+			buffer_print(ses, scroll_cnt, start, end);
 		}
 		scroll_cnt++;
 		scroll_cut = 0;
@@ -626,6 +606,11 @@ int show_buffer(struct session *ses)
 		DEL_BIT(ses->flags, SES_FLAG_READMUD);
 	}
 
+	if (HAS_BIT(gtd->screen->flags, SCREEN_FLAG_SCROLLMODE))
+	{
+		SET_BIT(gtd->screen->flags, SCREEN_FLAG_SCROLLUPDATE);
+	}
+
 	pop_call();
 	return TRUE;
 }
@@ -637,20 +622,19 @@ DO_COMMAND(do_buffer)
 
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
 
-
 	check_buffer(ses);
 
 	if (*arg1 == 0)
 	{
 		info:
 
-		tintin_header(ses, " BUFFER OPTIONS ");
+		tintin_header(ses, 80, " BUFFER OPTIONS ");
 
 		for (cnt = 0 ; *buffer_table[cnt].name != 0 ; cnt++)
 		{
 			tintin_printf2(ses, "  [%-13s] %s", buffer_table[cnt].name, buffer_table[cnt].desc);
 		}
-		tintin_header(ses, "");
+		tintin_header(ses, 80, "");
 
 		return ses;
 	}
@@ -662,7 +646,7 @@ DO_COMMAND(do_buffer)
 			continue;
 		}
 
-		buffer_table[cnt].fun(ses, arg);
+		buffer_table[cnt].fun(ses, arg, arg1, arg2);
 
 		return ses;
 	}
@@ -688,7 +672,6 @@ DO_BUFFER(buffer_clear)
 
 DO_BUFFER(buffer_up)
 {
-	char arg1[BUFFER_SIZE];
 	int scroll_size;
 
 	check_buffer(ses);
@@ -699,7 +682,10 @@ DO_BUFFER(buffer_up)
 		ses->scroll->base = 0;
 	}
 
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+	if (*arg)
+	{
+		arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+	}
 
 	if (is_math(ses, arg1))
 	{
@@ -736,7 +722,6 @@ DO_BUFFER(buffer_up)
 
 DO_BUFFER(buffer_down)
 {
-	char arg1[BUFFER_SIZE];
 	int scroll_size;
 
 	if (ses->scroll->line == -1)
@@ -746,7 +731,10 @@ DO_BUFFER(buffer_down)
 
 	check_buffer(ses);
 
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+	if (*arg)
+	{
+		arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+	}
 
 	if (is_math(ses, arg1))
 	{
@@ -763,9 +751,9 @@ DO_BUFFER(buffer_down)
 
 		if (ses->scroll->base == 0)
 		{
-			if (++ses->scroll->line == ses->scroll->used)
+			if (++ses->scroll->line >= ses->scroll->used)
 			{
-				buffer_end(ses, "");
+				buffer_end(ses, "", "", "");
 				return;
 			}
 			ses->scroll->base = ses->scroll->buffer[ses->scroll->line]->height;
@@ -782,7 +770,7 @@ DO_BUFFER(buffer_home)
 	ses->scroll->line = 0;
 	ses->scroll->base = 0;
 
-	buffer_down(ses, "");
+	buffer_down(ses, "", "", "");
 }
 
 DO_BUFFER(buffer_end)
@@ -798,10 +786,44 @@ DO_BUFFER(buffer_end)
 	ses->scroll->line = -1;
 }
 
-DO_BUFFER(buffer_lock)
+DO_BUFFER(buffer_jump)
 {
-	char arg1[BUFFER_SIZE];
+	int line;
 
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+
+	line = get_number(ses, arg1);
+
+	if (line >= 0)
+	{
+		line = URANGE(0, line, ses->scroll->used - 1);
+	}
+	else
+	{
+		line = URANGE(0, ses->scroll->used + line, ses->scroll->used - 1);
+	}
+
+	if (line >= ses->scroll->used - 1)
+	{
+		buffer_end(ses, "", "", "");
+
+		return;
+	}
+
+	if (line != ses->scroll->line)
+	{
+		ses->scroll->line = line;
+
+		ses->scroll->base = 0;
+
+		show_buffer(ses);
+
+		update_scrollbar(ses);
+	}
+}
+
+DO_BUFFER(buffer_lock)
+{
 	check_buffer(ses);
 
 	sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
@@ -812,7 +834,7 @@ DO_BUFFER(buffer_lock)
 	}
 	else if (!strcasecmp(arg1, "OFF"))
 	{
-		 buffer_end(ses, "");
+		 buffer_end(ses, "", "", "");
 	}
 	else
 	{
@@ -822,14 +844,13 @@ DO_BUFFER(buffer_lock)
 		}
 		else
 		{
-			buffer_end(ses, "");
+			buffer_end(ses, "", "", "");
 		}
 	}
 }
 
 DO_BUFFER(buffer_find)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 	int scroll_cnt, grep_cnt, grep_max, page;
 
 	check_buffer(ses);
@@ -867,7 +888,7 @@ DO_BUFFER(buffer_find)
 
 	if (page > 0)
 	{
-		for (scroll_cnt = ses->scroll->used - 1; scroll_cnt ; scroll_cnt--)
+		for (scroll_cnt = ses->scroll->used - 1; scroll_cnt >= 0 ; scroll_cnt--)
 		{
 			if (HAS_BIT(ses->scroll->buffer[scroll_cnt]->flags, BUFFER_FLAG_GREP))
 			{
@@ -916,14 +937,13 @@ DO_BUFFER(buffer_find)
 
 	ses->scroll->line = scroll_cnt;
 
-	show_buffer(ses);
+	buffer_down(ses, ntos(get_scroll_rows(ses) - 1), arg1, arg2);
 
 	return;
 }
 
 DO_BUFFER(buffer_get)
 {
-	char arg1[BUFFER_SIZE], arg2[STRING_SIZE], arg3[BUFFER_SIZE];
 	int cnt, min, max;
 
 	check_buffer(ses);
@@ -938,7 +958,6 @@ DO_BUFFER(buffer_get)
 	}
 
 	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);
 
 	min = get_number(ses, arg2);
 
@@ -948,14 +967,16 @@ DO_BUFFER(buffer_get)
 	}
 	min = URANGE(0, min, ses->scroll->used - 1);
 
-	if (*arg3 == 0)
+	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
+
+	if (*arg2 == 0)
 	{
 		set_nest_node_ses(ses, arg1, "%s", ses->scroll->buffer[min]->str);
 
 		return;
 	}
 
-	max = get_number(ses, arg3);
+	max = get_number(ses, arg2);
 
 	if (max < 0)
 	{
@@ -986,10 +1007,41 @@ DO_BUFFER(buffer_get)
 	return;
 }
 
+DO_BUFFER(buffer_refresh)
+{
+	check_buffer(ses);
+
+	if (HAS_BIT(ses->flags, SES_FLAG_PRINTLINE) && ses->check_output == 0)
+	{
+		if (ses == gtd->ses)
+		{
+			DEL_BIT(ses->flags, SES_FLAG_PRINTLINE);
+
+			SET_BIT(ses->flags, SES_FLAG_PRINTBUFFER);
+
+			print_scroll_region(ses);
+
+			DEL_BIT(ses->flags, SES_FLAG_PRINTBUFFER);
+
+			fflush(stdout);
+		}
+		return;
+	}
+
+	if (ses->scroll->line == -1)
+	{
+		buffer_end(ses, "", "", "");
+	}
+	else
+	{
+		show_buffer(ses);
+	}
+	return;
+}
+
 DO_BUFFER(buffer_write)
 {
 	FILE *fp;
-	char arg1[BUFFER_SIZE], out[STRING_SIZE];
 	int cnt;
 
 	check_buffer(ses);
@@ -1012,17 +1064,17 @@ DO_BUFFER(buffer_write)
 			{
 				if (HAS_BIT(ses->logmode, LOG_FLAG_PLAIN))
 				{
-					strip_vt102_codes(ses->scroll->buffer[cnt]->str, out);
+					strip_vt102_codes(ses->scroll->buffer[cnt]->str, arg2);
 				}
 				else if (HAS_BIT(ses->logmode, LOG_FLAG_HTML))
 				{
-					vt102_to_html(ses, ses->scroll->buffer[cnt]->str, out);
+					vt102_to_html(ses, ses->scroll->buffer[cnt]->str, arg2);
 				}
 				else
 				{
-					strcpy(out, ses->scroll->buffer[cnt]->str);
+					strcpy(arg2, ses->scroll->buffer[cnt]->str);
 				}
-				fprintf(fp, "%s\n", out);
+				fprintf(fp, "%s\n", arg2);
 			}
 
 			fclose(fp);
@@ -1041,23 +1093,42 @@ DO_BUFFER(buffer_info)
 
 	check_buffer(ses);
 
-	tintin_printf2(ses, "Scroll row:  %d", ses->scroll->used);
-	tintin_printf2(ses, "Scroll max:  %d", ses->scroll->size);
-	tintin_printf2(ses, "Scroll line: %d", ses->scroll->line);
-	tintin_printf2(ses, "Scroll base: %d", ses->scroll->base);
-	tintin_printf2(ses, "Scroll wrap: %d", ses->scroll->wrap);
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);	
+	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
+
+	if (*arg1 == 0)
+	{
+		tintin_printf2(ses, "#BUFFER INFO: BASE   = %d", ses->scroll->base);
+		tintin_printf2(ses, "#BUFFER INFO: LINE   = %d", ses->scroll->line);
+		tintin_printf2(ses, "#BUFFER INFO: SIZE   = %d", ses->scroll->size);
+		tintin_printf2(ses, "#BUFFER INFO: USED   = %d", ses->scroll->used);
+		tintin_printf2(ses, "#BUFFER INFO: WIDTH  = %d", ses->scroll->width);
+		tintin_printf2(ses, "#BUFFER INFO: WRAP   = %d", ses->scroll->wrap);
 
-	tintin_printf2(ses, "");
+		tintin_printf2(ses, "");
 
-	memory = 0;
+		memory = 0;
 
-	for (index = 0 ; index < ses->scroll->used ; index++)
-	{
-		memory += sizeof(struct buffer_data) + strlen(ses->scroll->buffer[index]->str);
+		for (index = 0 ; index < ses->scroll->used ; index++)
+		{
+			memory += sizeof(struct buffer_data) + strlen(ses->scroll->buffer[index]->str);
+		}
+		tintin_printf2(ses, "#BUFFER INFO: MEMORY = %d", memory);
 	}
+	else if (is_abbrev(arg1, "SAVE") && *arg2)
+	{
+		add_nest_node_ses(ses, arg2, "{BASE}{%d}", ses->scroll->base);
+		add_nest_node_ses(ses, arg2, "{LINE}{%d}", ses->scroll->line);
+		add_nest_node_ses(ses, arg2, "{SIZE}{%d}", ses->scroll->size);
+		add_nest_node_ses(ses, arg2, "{USED}{%d}", ses->scroll->used);
+		add_nest_node_ses(ses, arg2, "{WRAP}{%d}", ses->scroll->wrap);
 
-	tintin_printf2(ses, "Memory use:  %d", memory);
-
+		show_message(ses, LIST_COMMAND, "#BUFFER INFO: SAVED TO {%s}", arg2);
+	}
+	else
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #BUFFER INFO [SAVE] [<VARIABLE>]");
+	}
 }
 
 
@@ -1112,7 +1183,7 @@ DO_COMMAND(do_grep)
 
 	gtd->level->grep++;
 
-	tintin_header(ses, " GREPPING PAGE %d FOR %s ", page, arg2);
+	tintin_header(ses, 80, " GREPPING PAGE %d FOR %s ", page, arg2);
 
 	if (page > 0)
 	{
@@ -1203,7 +1274,7 @@ DO_COMMAND(do_grep)
 			return ses;
 		}
 	}
-	tintin_header(ses, "");
+	tintin_header(ses, 80, "");
 
 	gtd->level->grep--;
 

+ 19 - 13
src/chat.c

@@ -79,13 +79,13 @@ DO_COMMAND(do_chat)
 	{
 		info:
 
-		tintin_header(ses, " CHAT OPTIONS ");
+		tintin_header(ses, 80, " CHAT OPTIONS ");
 
 		for (cnt = 0 ; *chat_table[cnt].name != 0 ; cnt++)
 		{
 			tintin_printf2(ses, "  [%-13s] %s", chat_table[cnt].name, chat_table[cnt].desc);
 		}
-		tintin_header(ses, "");
+		tintin_header(ses, 80, "");
 
 		return ses;
 	}
@@ -737,8 +737,8 @@ void chat_printf(char *format, ...)
 
 	push_call("chat_printf(%p,...)",format);
 
-	buf = str_alloc_stack();
-	tmp = str_alloc_stack();
+	buf = str_alloc_stack(0);
+	tmp = str_alloc_stack(0);
 
 	va_start(args, format);
 	vsnprintf(buf, BUFFER_SIZE / 3, format, args);
@@ -768,11 +768,11 @@ void chat_printf(char *format, ...)
 	}
 	str_cpy_printf(&tmp, "%s%s%s", gtd->chat->color, buf, "\e[0m");
 
-	check_all_events(gtd->ses, SUB_ARG|SUB_SEC, 0, 2, "CHAT MESSAGE", tmp, buf);
+	check_all_events(gtd->ses, SUB_SEC|EVENT_FLAG_PORT, 0, 2, "CHAT MESSAGE", tmp, buf);
 
-	if (!check_all_events(gtd->ses, SUB_ARG|SUB_SEC, 0, 2, "CATCH CHAT MESSAGE", tmp, buf))
+	if (!check_all_events(gtd->ses, SUB_SEC|EVENT_FLAG_CATCH, 0, 2, "CATCH CHAT MESSAGE", tmp, buf))
 	{
-		tintin_puts(NULL, tmp);
+		tintin_printf(gtd->ses, "%s", tmp);
 	}
 	pop_call();
 	return;
@@ -956,7 +956,7 @@ void get_chat_commands(struct chat_data *buddy, char *buf, int len)
 		ptc = *pti++;
 		pto = (unsigned char *) txt;
 
-		while (isspace(*pti))
+		while (is_space(*pti))
 		{
 			pti++;
 		}
@@ -974,7 +974,7 @@ void get_chat_commands(struct chat_data *buddy, char *buf, int len)
 
 		*pto-- = 0;
 
-		while (isspace(*pto))
+		while (is_space(*pto))
 		{
 			*pto-- = 0;
 		}
@@ -1400,7 +1400,7 @@ DO_CHAT(chat_downloaddir)
 {
 	char dir[BUFFER_SIZE];
 
-	sprintf(dir, "%s%s", arg1, !str_suffix(arg1, "/") ? "" : "/");
+	sprintf(dir, "%s%s", arg1, is_suffix(arg1, "/") ? "" : "/");
 
 	RESTRING(gtd->chat->download, dir);
 
@@ -1606,7 +1606,7 @@ DO_CHAT(chat_paste)
 
 		if (IS_SPLIT(gtd->ses))
 		{
-			erase_toeol();
+			command(gtd->ses, do_cursor, "clear");
 		}
 		gtd->chat->paste_time = 0;
 
@@ -2104,7 +2104,11 @@ void send_block(struct chat_data *buddy)
 		}
 		*pto++ = (unsigned char) c;
 	}
-	write(buddy->fd, block, 501);
+
+	if (write(buddy->fd, block, 501) == -1)
+	{
+		syserr_printf(gtd->ses, "send_block: write");
+	}
 
 	buddy->file_block_cnt++;
 
@@ -2212,7 +2216,9 @@ void file_cleanup(struct chat_data *buddy)
 	}
 	if (buddy->file_name)
 	{
-		FREE(buddy->file_name);
+		free(buddy->file_name);
+		
+		buddy->file_name = NULL;
 	}
 }
 

+ 41 - 19
src/class.c

@@ -37,11 +37,11 @@ DO_COMMAND(do_class)
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
-	arg = sub_arg_in_braces(ses, arg, arg3, GET_ONE, SUB_VAR|SUB_FUN);
+	arg = sub_arg_in_braces(ses, arg, arg3, GET_ALL, SUB_VAR|SUB_FUN);
 
 	if (*arg1 == 0)
 	{
-		tintin_header(ses, " CLASSES ");
+		tintin_header(ses, 80, " CLASSES ");
 
 		for (root->update = 0 ; root->update < root->used ; root->update++)
 		{
@@ -76,7 +76,8 @@ DO_COMMAND(do_class)
 			{
 				show_info(ses, LIST_CLASS, "#INFO: CLASS {%s} CREATED", arg1);
 
-				check_all_events(ses, SUB_ARG, 0, 1, "CLASS CREATED", arg1);
+				check_all_events(ses, EVENT_FLAG_CLASS, 0, 1, "CLASS CREATED", arg1);
+				check_all_events(ses, EVENT_FLAG_CLASS, 1, 1, "CLASS CREATED %s", arg1, arg1);
 
 				node = update_node_list(ses->list[LIST_CLASS], arg1, "", arg3, "");
 			}
@@ -109,10 +110,28 @@ int count_class(struct session *ses, struct listnode *group)
 	return cnt;
 }
 
+DO_CLASS(class_assign)
+{
+	char *tmp = ses->group;
+
+	ses->group = strdup(arg1);
+
+	script_driver(ses, LIST_COMMAND, arg2);
+
+	free(ses->group);
+
+	ses->group = tmp;
+
+	return ses;
+}
+
 DO_CLASS(class_clear)
 {
 	int type, index;
 
+	check_all_events(ses, EVENT_FLAG_CLASS, 0, 1, "CLASS CLEAR", ses->group);
+	check_all_events(ses, EVENT_FLAG_CLASS, 1, 1, "CLASS CLEAR %s", ses->group, ses->group);
+
 	for (type = 0 ; type < LIST_MAX ; type++)
 	{
 		if (!HAS_BIT(ses->list[type]->flags, LIST_FLAG_CLASS))
@@ -157,12 +176,12 @@ DO_CLASS(class_close)
 		{
 			show_message(ses, LIST_CLASS, "#CLASS {%s} HAS BEEN CLOSED.", arg1);
 
-			update_node_list(ses->list[LIST_CLASS], arg1, "", "0","");
+			update_node_list(ses->list[LIST_CLASS], arg1, "", "0", node->arg4);
 
 			if (!strcmp(ses->group, arg1))
 			{
-				check_all_events(ses, SUB_ARG, 0, 1, "CLASS DEACTIVATED", ses->group);
-				check_all_events(ses, SUB_ARG, 1, 1, "CLASS DEACTIVATED %s", ses->group, ses->group);
+				check_all_events(ses, EVENT_FLAG_CLASS, 0, 1, "CLASS DEACTIVATED", ses->group);
+				check_all_events(ses, EVENT_FLAG_CLASS, 1, 1, "CLASS DEACTIVATED %s", ses->group, ses->group);
 
 				node = ses->list[LIST_CLASS]->list[0];
 
@@ -172,8 +191,8 @@ DO_CLASS(class_close)
 
 					show_message(ses, LIST_CLASS, "#CLASS {%s} HAS BEEN ACTIVATED.", node->arg1);
 
-					check_all_events(ses, SUB_ARG, 0, 1, "CLASS ACTIVATED", node->arg1);
-					check_all_events(ses, SUB_ARG, 1, 1, "CLASS ACTIVATED %s", arg1, arg1);
+					check_all_events(ses, EVENT_FLAG_CLASS, 0, 1, "CLASS ACTIVATED", node->arg1);
+					check_all_events(ses, EVENT_FLAG_CLASS, 1, 1, "CLASS ACTIVATED %s", arg1, arg1);
 				}
 				else
 				{
@@ -192,7 +211,7 @@ DO_CLASS(class_list)
 
 	if (search_node_list(ses->list[LIST_CLASS], arg1))
 	{
-		tintin_header(ses, " %s ", arg1);
+		tintin_header(ses, 80, " %s ", arg1);
 
 		for (i = 0 ; i < LIST_MAX ; i++)
 		{
@@ -233,8 +252,8 @@ DO_CLASS(class_kill)
 
 	delete_index_list(ses->list[LIST_CLASS], group);
 
-	check_all_events(ses, SUB_ARG, 0, 1, "CLASS DESTROYED", arg1);
-	check_all_events(ses, SUB_ARG, 1, 1, "CLASS DESTROYED %s", arg1, arg1);
+	check_all_events(ses, EVENT_FLAG_CLASS, 0, 1, "CLASS DESTROYED", arg1);
+	check_all_events(ses, EVENT_FLAG_CLASS, 1, 1, "CLASS DESTROYED %s", arg1, arg1);
 
 	show_message(ses, LIST_CLASS, "#CLASS {%s} HAS BEEN KILLED.", arg1);
 
@@ -254,10 +273,13 @@ DO_CLASS(class_load)
 
 	file = fmemopen(node->data, (size_t) atoi(node->arg4), "r");
 
-	show_message(ses, LIST_CLASS, "#CLASS {%s} HAS BEEN LOADED FROM MEMORY.", arg1);
-
 	read_file(ses, file, arg1);
 
+	check_all_events(ses, EVENT_FLAG_CLASS, 0, 1, "CLASS LOAD", arg1);
+	check_all_events(ses, EVENT_FLAG_CLASS, 1, 1, "CLASS LOAD %s", arg1, arg1);
+
+	show_message(ses, LIST_CLASS, "#CLASS {%s} HAS BEEN LOADED FROM MEMORY.", arg1);
+
 	return ses;
 }
 
@@ -273,19 +295,19 @@ DO_CLASS(class_open)
 	{
 		if (*ses->group)
 		{
-			check_all_events(ses, SUB_ARG, 0, 1, "CLASS DEACTIVATED", ses->group);
-			check_all_events(ses, SUB_ARG, 1, 1, "CLASS DEACTIVATED %s", ses->group, ses->group);
+			check_all_events(ses, EVENT_FLAG_CLASS, 0, 1, "CLASS DEACTIVATED", ses->group);
+			check_all_events(ses, EVENT_FLAG_CLASS, 1, 1, "CLASS DEACTIVATED %s", ses->group, ses->group);
 		}
 		RESTRING(ses->group, arg1);
 
 		count = atoi(ses->list[LIST_CLASS]->list[0]->arg3);
 
-		update_node_list(ses->list[LIST_CLASS], arg1, "", ntos(--count), "");
+		update_node_list(ses->list[LIST_CLASS], arg1, "", ntos(--count), node->arg4);
 
 		show_message(ses, LIST_CLASS, "#CLASS {%s} HAS BEEN OPENED AND ACTIVATED.", arg1);
 
-		check_all_events(ses, SUB_ARG, 0, 1, "CLASS ACTIVATED", arg1);
-		check_all_events(ses, SUB_ARG, 1, 1, "CLASS ACTIVATED %s", arg1, arg1);
+		check_all_events(ses, EVENT_FLAG_CLASS, 0, 1, "CLASS ACTIVATED", arg1);
+		check_all_events(ses, EVENT_FLAG_CLASS, 1, 1, "CLASS ACTIVATED %s", arg1, arg1);
 	}
 
 	return ses;
@@ -296,7 +318,7 @@ DO_CLASS(class_read)
 {
 	class_open(ses, node, arg1, arg2);
 
-	execute(ses, "#READ {%s}", arg2);
+	command(ses, do_read, "{%s}", arg2);
 
 	class_close(ses, node, arg1, arg2);
 

+ 263 - 0
src/command.c

@@ -0,0 +1,263 @@
+/******************************************************************************
+*   This file is part of TinTin++                                             *
+*                                                                             *
+*   Copyright 2004-2020 Igor van den Hoven                                    *
+*                                                                             *
+*   TinTin++ is free software; you can redistribute it and/or modify          *
+*   it under the terms of the GNU General Public License as published by      *
+*   the Free Software Foundation; either version 3 of the License, or         *
+*   (at your option) any later version.                                       *
+*                                                                             *
+*   This program is distributed in the hope that it will be useful,           *
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of            *
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
+*   GNU General Public License for more details.                              *
+*                                                                             *
+*   You should have received a copy of the GNU General Public License         *
+*   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
+******************************************************************************/
+
+/******************************************************************************
+*                               T I N T I N + +                               *
+*                                                                             *
+*                      coded by Igor van den Hoven 2004                       *
+******************************************************************************/
+
+#include "tintin.h"
+
+extern struct command_type command_table[];
+
+DO_COMMAND(do_commands)
+{
+	int cmd;
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
+
+	tintin_header(ses, 0, " %s ", "COMMANDS");
+
+	for (cmd = 0 ; *command_table[cmd].name != 0 ; cmd++)
+	{
+		if (*arg1 && !is_abbrev(arg1, command_table[cmd].name))
+		{
+			continue;
+		}
+
+		if (strip_vt102_strlen(ses, arg2) + 20 > get_scroll_cols(ses))
+		{
+			tintin_puts2(ses, arg2);
+			*arg2 = 0;
+		}
+
+		if (command_table[cmd].type == TOKEN_TYPE_COMMAND)
+		{
+			cat_sprintf(arg2, "%s%20s", COLOR_COMMAND, command_table[cmd].name);
+		}
+		else
+		{
+			cat_sprintf(arg2, "%s%20s", COLOR_STATEMENT, command_table[cmd].name);
+		}
+	}
+
+	if (*arg2)
+	{
+		tintin_puts2(ses, arg2);
+	}
+
+	tintin_header(ses, 0, "");
+
+	return ses;
+}
+
+
+void init_commands()
+{
+	int index, ref;
+
+	for (index = 1 ; *command_table[index].name ; index++)
+	{
+		if (strcmp(command_table[index - 1].name, command_table[index].name) > 0)
+		{
+			print_stdout(0, 0, "\e[1;31minit_tintin() unsorted command table %s vs %s.", command_table[index - 1].name, command_table[index].name);
+			exit(1);
+		}
+	}
+
+	for (ref = 0 ; ref < 32 ; ref++)
+	{
+		for (index = 0 ; *command_table[index].name ; index++)
+		{
+			if (*command_table[index].name % 32 == ref)
+			{
+				break;
+			}
+		}
+		gtd->command_ref[ref] = index;
+	}
+}
+
+// unused
+
+struct session *execute(struct session *ses, char *format, ...)
+{
+	char *buffer;
+	va_list args;
+
+	push_call("execute(%p,%p,...)",ses,format);
+
+	va_start(args, format);
+
+	if (vasprintf(&buffer, format, args) == -1)
+	{
+		syserr_printf(ses, "execute: vasprintf:");
+	}
+
+	va_end(args);
+
+	if (*buffer)
+	{
+		if (*buffer != gtd->tintin_char)
+		{
+			*buffer = gtd->tintin_char;
+		}
+		get_arg_all(ses, buffer, buffer, FALSE);
+	}
+
+	ses = script_driver(ses, LIST_COMMAND, buffer);
+
+	free(buffer);
+
+	pop_call();
+	return ses;
+}
+
+struct session *command(struct session *ses, COMMAND *cmd, char *format, ...)
+{
+	char *arg1, *arg2, *arg3, *arg4, *buffer;
+	va_list args;
+
+	push_call("command(%p,%p,%p,...)",ses,cmd,format);
+
+	va_start(args, format);
+
+	if (vasprintf(&buffer, format, args) == -1)
+	{
+		syserr_printf(ses, "command: vasprintf:");
+	}
+
+	va_end(args);
+
+	arg1 = str_alloc_stack(0);
+	arg2 = str_alloc_stack(0);
+	arg3 = str_alloc_stack(0);
+	arg4 = "";
+
+	ses = cmd(ses, buffer, arg1, arg2, arg3, arg4);
+
+	free(buffer);
+
+	pop_call();
+	return ses;
+}
+
+struct command_type command_table[] =
+{
+	{    "action",            do_action,            3, TOKEN_TYPE_COMMAND },
+	{    "alias",             do_alias,             3, TOKEN_TYPE_COMMAND },
+	{    "all",               do_all,               1, TOKEN_TYPE_COMMAND },
+	{    "banner",            do_banner,            1, TOKEN_TYPE_COMMAND },
+	{    "bell",              do_bell,              2, TOKEN_TYPE_COMMAND },
+	{    "break",             do_nop,               0, TOKEN_TYPE_BREAK   },
+	{    "buffer",            do_buffer,            2, TOKEN_TYPE_COMMAND },
+	{    "button",            do_button,            3, TOKEN_TYPE_COMMAND },
+	{    "case",              do_nop,               0, TOKEN_TYPE_CASE    },
+	{    "cat",               do_cat,               1, TOKEN_TYPE_COMMAND },
+	{    "chat",              do_chat,              2, TOKEN_TYPE_COMMAND },
+	{    "class",             do_class,             3, TOKEN_TYPE_COMMAND },
+	{    "commands",          do_commands,          2, TOKEN_TYPE_COMMAND },
+	{    "config",            do_configure,         2, TOKEN_TYPE_COMMAND },
+	{    "continue",          do_nop,               0, TOKEN_TYPE_CONTINUE},
+	{    "cr",                do_cr,                0, TOKEN_TYPE_COMMAND },
+	{    "cursor",            do_cursor,            2, TOKEN_TYPE_COMMAND },
+	{    "daemon",            do_daemon,            2, TOKEN_TYPE_COMMAND },
+	{    "debug",             do_debug,             2, TOKEN_TYPE_COMMAND },
+	{    "default",           do_nop,               0, TOKEN_TYPE_DEFAULT },
+	{    "delay",             do_delay,             3, TOKEN_TYPE_COMMAND },
+	{    "dictionary",        do_dictionary,        3, TOKEN_TYPE_COMMAND },
+	{    "draw",              do_draw,              3, TOKEN_TYPE_COMMAND },
+	{    "echo",              do_echo,              3, TOKEN_TYPE_COMMAND },
+	{    "edit",              do_edit,              2, TOKEN_TYPE_COMMAND },
+	{    "else",              do_nop,               0, TOKEN_TYPE_ELSE    },
+	{    "elseif",            do_nop,               0, TOKEN_TYPE_ELSEIF  },
+	{    "end",               do_end,               1, TOKEN_TYPE_COMMAND },
+	{    "event",             do_event,             2, TOKEN_TYPE_COMMAND },
+	{    "foreach",           do_nop,               3, TOKEN_TYPE_FOREACH },
+	{    "format",            do_format,            3, TOKEN_TYPE_COMMAND },
+	{    "function",          do_function,          2, TOKEN_TYPE_COMMAND },
+	{    "gag",               do_gag,               1, TOKEN_TYPE_COMMAND },
+	{    "grep",              do_grep,              2, TOKEN_TYPE_COMMAND },
+	{    "help",              do_help,              1, TOKEN_TYPE_COMMAND },
+	{    "highlight",         do_highlight,         3, TOKEN_TYPE_COMMAND },
+	{    "history",           do_history,           3, TOKEN_TYPE_COMMAND },
+	{    "if",                do_nop,               0, TOKEN_TYPE_IF      },
+	{    "ignore",            do_ignore,            2, TOKEN_TYPE_COMMAND },
+	{    "info",              do_info,              2, TOKEN_TYPE_COMMAND },
+	{    "kill",              do_kill,              2, TOKEN_TYPE_COMMAND },
+	{    "killall",           do_killall,           2, TOKEN_TYPE_COMMAND },
+	{    "line",              do_line,              3, TOKEN_TYPE_COMMAND },
+	{    "list",              do_list,              3, TOKEN_TYPE_COMMAND },
+	{    "local",             do_local,             1, TOKEN_TYPE_COMMAND },
+	{    "log",               do_log,               2, TOKEN_TYPE_COMMAND },
+	{    "loop",              do_nop,               3, TOKEN_TYPE_LOOP    },
+	{    "macro",             do_macro,             3, TOKEN_TYPE_COMMAND },
+	{    "map",               do_map,               2, TOKEN_TYPE_COMMAND },
+	{    "math",              do_math,              2, TOKEN_TYPE_COMMAND },
+	{    "message",           do_message,           2, TOKEN_TYPE_COMMAND },
+	{    "nop",               do_nop,               0, TOKEN_TYPE_COMMAND },
+	{    "parse",             do_nop,               3, TOKEN_TYPE_PARSE   },
+	{    "path",              do_path,              1, TOKEN_TYPE_COMMAND },
+	{    "pathdir",           do_pathdir,           3, TOKEN_TYPE_COMMAND },
+	{    "port",              do_port,              2, TOKEN_TYPE_COMMAND },
+	{    "prompt",            do_prompt,            2, TOKEN_TYPE_COMMAND },
+	{    "read",              do_read,              1, TOKEN_TYPE_COMMAND },
+	{    "regexp",            do_regexp,            3, TOKEN_TYPE_REGEX   },
+	{    "replace",           do_replace,           3, TOKEN_TYPE_COMMAND },
+	{    "return",            do_nop,               0, TOKEN_TYPE_RETURN  },
+	{    "run",               do_run,               3, TOKEN_TYPE_COMMAND },
+	{    "scan",              do_scan,              2, TOKEN_TYPE_COMMAND },
+	{    "screen",            do_screen,            2, TOKEN_TYPE_COMMAND },
+	{    "script",            do_script,            2, TOKEN_TYPE_COMMAND },
+	{    "send",              do_send,              1, TOKEN_TYPE_COMMAND },
+	{    "session",           do_session,           1, TOKEN_TYPE_COMMAND },
+	{    "showme",            do_showme,            3, TOKEN_TYPE_COMMAND },
+	{    "snoop",             do_snoop,             2, TOKEN_TYPE_COMMAND },
+	{    "split",             do_split,             2, TOKEN_TYPE_COMMAND },
+	{    "ssl",               do_ssl,               3, TOKEN_TYPE_COMMAND },
+	{    "substitute",        do_substitute,        3, TOKEN_TYPE_COMMAND },
+	{    "switch",            do_nop,               0, TOKEN_TYPE_SWITCH  },
+	{    "system",            do_system,            1, TOKEN_TYPE_COMMAND },
+	{    "tab",               do_tab,               1, TOKEN_TYPE_COMMAND },
+	{    "test",              do_test,              3, TOKEN_TYPE_COMMAND },
+	{    "textin",            do_textin,            2, TOKEN_TYPE_COMMAND },
+	{    "ticker",            do_tick,              3, TOKEN_TYPE_COMMAND },
+	{    "unaction",          do_unaction,          0, TOKEN_TYPE_COMMAND },
+	{    "unalias",           do_unalias,           0, TOKEN_TYPE_COMMAND },
+	{    "unbutton",          do_unbutton,          0, TOKEN_TYPE_COMMAND },
+	{    "undelay",           do_undelay,           1, TOKEN_TYPE_COMMAND },
+	{    "unevent",           do_unevent,           0, TOKEN_TYPE_COMMAND },
+	{    "unfunction",        do_unfunction,        0, TOKEN_TYPE_COMMAND },
+	{    "ungag",             do_ungag,             0, TOKEN_TYPE_COMMAND },
+	{    "unhighlight",       do_unhighlight,       0, TOKEN_TYPE_COMMAND },
+	{    "unmacro",           do_unmacro,           0, TOKEN_TYPE_COMMAND },
+	{    "unpathdir",         do_unpathdir,         1, TOKEN_TYPE_COMMAND },
+	{    "unprompt",          do_unprompt,          0, TOKEN_TYPE_COMMAND },
+	{    "unsplit",           do_unsplit,           0, TOKEN_TYPE_COMMAND },
+	{    "unsubstitute",      do_unsubstitute,      0, TOKEN_TYPE_COMMAND },
+	{    "untab",             do_untab,             0, TOKEN_TYPE_COMMAND },
+	{    "unticker",          do_untick,            0, TOKEN_TYPE_COMMAND },
+	{    "unvariable",        do_unvariable,        1, TOKEN_TYPE_COMMAND },
+	{    "variable",          do_variable,          1, TOKEN_TYPE_COMMAND },
+	{    "while",             do_nop,               0, TOKEN_TYPE_WHILE   },
+	{    "write",             do_write,             2, TOKEN_TYPE_COMMAND },
+	{    "zap",               do_zap,               1, TOKEN_TYPE_COMMAND },
+	{    "",                  NULL,                 0, TOKEN_TYPE_COMMAND }
+};

+ 78 - 0
src/confdefs.h

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

+ 165 - 105
src/config.c

@@ -37,7 +37,7 @@ DO_COMMAND(do_configure)
 
 	if (*arg1 == 0)
 	{
-		tintin_header(ses, " CONFIGURATIONS ");
+		tintin_header(ses, 80, " CONFIGURATIONS ");
 
 		for (index = 0 ; *config_table[index].name != 0 ; index++)
 		{
@@ -52,14 +52,21 @@ DO_COMMAND(do_configure)
 				tintin_printf2(ses, "[%-14s] [%12s] %s",
 					node->arg1,
 					arg2,
-					strcmp(node->arg2, "ON") == 0 ? config_table[index].msg_on : config_table[index].msg_off);
+					strcmp(node->arg2, "OFF") ? config_table[index].msg_on : config_table[index].msg_off);
 			}
 		}
 
-		tintin_header(ses, "");
+		tintin_header(ses, 80, "");
 	}
 	else
 	{
+		// fixing silly config name
+
+		if (is_abbrev(arg1, "MOUSE TRACKING"))
+		{
+			str_cpy(&arg1, "MOUSE");
+		}
+
 		for (index = 0 ; *config_table[index].name != 0 ; index++)
 		{
 			if (is_abbrev(arg1, config_table[index].name))
@@ -110,9 +117,9 @@ DO_CONFIG(config_autotab)
 			return NULL;
 		}
 
-		ses->auto_tab = atoi(arg2);
+		ses->scrollback_tab = atoi(arg2);
 	}
-	sprintf(arg2, "%d", ses->auto_tab);
+	sprintf(arg2, "%d", ses->scrollback_tab);
 
 	return ses;
 }
@@ -155,17 +162,17 @@ DO_CONFIG(config_charset)
 	{
 		if (is_abbrev(arg2, "AUTO"))
 		{
-			if (strcasestr(gtd->lang, "UTF-8"))
+			if (strcasestr(gtd->system->lang, "UTF-8"))
 			{
 				DEL_BIT(ses->charset, CHARSET_FLAG_ALL);
 				SET_BIT(ses->charset, CHARSET_FLAG_UTF8);
 			}
-			else if (strcasestr(gtd->lang, "BIG-5"))
+			else if (strcasestr(gtd->system->lang, "BIG-5"))
 			{
 				DEL_BIT(ses->charset, CHARSET_FLAG_ALL);
 				SET_BIT(ses->charset, CHARSET_FLAG_BIG5);
 			}
-			else if (strcasestr(gtd->term, "XTERM"))
+			else if (strcasestr(gtd->system->term, "XTERM"))
 			{
 				DEL_BIT(ses->charset, CHARSET_FLAG_ALL);
 				SET_BIT(ses->charset, CHARSET_FLAG_UTF8);
@@ -231,7 +238,7 @@ DO_CONFIG(config_charset)
 		}
 		else
 		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <AUTO|ASCII|BIG-5|BIG5TOUTF8|CP1251TOUTF8|FANSI|GBK-1|GBK1TOUTF8|KOI8TOUTF8|UTF-8>", config_table[index].name);
+			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <AUTO|ASCII|BIG-5|BIG5TOUTF8|CP1251TOUTF8|FANSI|GBK-1|GBK1TOUTF8|ISO1TOUTF8|ISO2TOUTF8|KOI8TOUTF8|UTF-8>", config_table[index].name);
 
 			return NULL;
 		}
@@ -339,11 +346,11 @@ DO_CONFIG(config_colorpatch)
 	{
 		if (is_abbrev(arg2, "ON"))
 		{
-			SET_BIT(ses->flags, SES_FLAG_COLORPATCH);
+			SET_BIT(ses->config_flags, CONFIG_FLAG_COLORPATCH);
 		}
 		else if (is_abbrev(arg2, "OFF"))
 		{
-			DEL_BIT(ses->flags, SES_FLAG_COLORPATCH);
+			DEL_BIT(ses->config_flags, CONFIG_FLAG_COLORPATCH);
 		}
 		else
 		{
@@ -352,7 +359,7 @@ DO_CONFIG(config_colorpatch)
 			return NULL;
 		}
 	}
-	strcpy(arg2, HAS_BIT(ses->flags, SES_FLAG_COLORPATCH) ? "ON" : "OFF");
+	strcpy(arg2, HAS_BIT(ses->config_flags, CONFIG_FLAG_COLORPATCH) ? "ON" : "OFF");
 
 	return ses;
 }
@@ -376,11 +383,11 @@ DO_CONFIG(config_commandecho)
 	{
 		if (is_abbrev(arg2, "ON"))
 		{
-			SET_BIT(ses->flags, SES_FLAG_ECHOCOMMAND);
+			SET_BIT(ses->config_flags, CONFIG_FLAG_ECHOCOMMAND);
 		}
 		else if (is_abbrev(arg2, "OFF"))
 		{
-			DEL_BIT(ses->flags, SES_FLAG_ECHOCOMMAND);
+			DEL_BIT(ses->config_flags, CONFIG_FLAG_ECHOCOMMAND);
 		}
 		else
 		{
@@ -389,7 +396,7 @@ DO_CONFIG(config_commandecho)
 			return NULL;
 		}
 	}
-	strcpy(arg2, HAS_BIT(ses->flags, SES_FLAG_ECHOCOMMAND) ? "ON" : "OFF");
+	strcpy(arg2, HAS_BIT(ses->config_flags, CONFIG_FLAG_ECHOCOMMAND) ? "ON" : "OFF");
 
 	return ses;
 }
@@ -424,11 +431,11 @@ DO_CONFIG(config_convertmeta)
 	{
 		if (is_abbrev(arg2, "ON"))
 		{
-			SET_BIT(ses->flags, SES_FLAG_CONVERTMETA);
+			SET_BIT(ses->config_flags, CONFIG_FLAG_CONVERTMETA);
 		}
 		else if (is_abbrev(arg2, "OFF"))
 		{
-			DEL_BIT(ses->flags, SES_FLAG_CONVERTMETA);
+			DEL_BIT(ses->config_flags, CONFIG_FLAG_CONVERTMETA);
 		}
 		else
 		{
@@ -437,7 +444,7 @@ DO_CONFIG(config_convertmeta)
 			return NULL;
 		}
 	}
-	strcpy(arg2, HAS_BIT(ses->flags, SES_FLAG_CONVERTMETA) ? "ON" : "OFF");
+	strcpy(arg2, HAS_BIT(ses->config_flags, CONFIG_FLAG_CONVERTMETA) ? "ON" : "OFF");
 
 	return ses;
 }
@@ -582,11 +589,11 @@ DO_CONFIG(config_mccp)
 	{
 		if (is_abbrev(arg2, "ON"))
 		{
-			SET_BIT(ses->flags, SES_FLAG_MCCP);
+			SET_BIT(ses->config_flags, CONFIG_FLAG_MCCP);
 		}
 		else if (is_abbrev(arg2, "OFF"))
 		{
-			DEL_BIT(ses->flags, SES_FLAG_MCCP);
+			DEL_BIT(ses->config_flags, CONFIG_FLAG_MCCP);
 		}
 		else
 		{
@@ -595,7 +602,7 @@ DO_CONFIG(config_mccp)
 			return NULL;
 		}
 	}
-	strcpy(arg2, HAS_BIT(ses->flags, SES_FLAG_MCCP) ? "ON" : "OFF");
+	strcpy(arg2, HAS_BIT(ses->config_flags, CONFIG_FLAG_MCCP) ? "ON" : "OFF");
 
 	return ses;
 }
@@ -604,43 +611,112 @@ DO_CONFIG(config_mousetracking)
 {
 	if (*arg2)
 	{
+		DEL_BIT(ses->config_flags, CONFIG_FLAG_MOUSEDEBUG);
+		DEL_BIT(ses->config_flags, CONFIG_FLAG_MOUSEINFO);
+		DEL_BIT(ses->config_flags, CONFIG_FLAG_MOUSEPIXELS);	
+		DEL_BIT(ses->config_flags, CONFIG_FLAG_MOUSEPIXELS);
+		DEL_BIT(gtd->flags, TINTIN_FLAG_MOUSETRACKING);
+
+		if (is_member(arg2, "INFO"))
+		{
+			SET_BIT(ses->config_flags, CONFIG_FLAG_MOUSEINFO);
+			SET_BIT(gtd->flags, TINTIN_FLAG_MOUSETRACKING);
+		}
+		if (is_member(arg2, "DEBUG"))
+		{
+			SET_BIT(ses->config_flags, CONFIG_FLAG_MOUSEDEBUG);
+			SET_BIT(gtd->flags, TINTIN_FLAG_MOUSETRACKING);
+		}
+		if (is_member(arg2, "ON"))
+		{
+			SET_BIT(gtd->flags, TINTIN_FLAG_MOUSETRACKING);
+		}
+		if (is_member(arg2, "PIXELS"))
+		{
+			SET_BIT(ses->config_flags, CONFIG_FLAG_MOUSEPIXELS);
+			SET_BIT(gtd->flags, TINTIN_FLAG_MOUSETRACKING);
+		}
+
+		if (is_abbrev(arg2, "OFF"))
+		{
+			if (HAS_BIT(gtd->flags, TINTIN_FLAG_MOUSETRACKING))
+			{
+				DEL_BIT(ses->config_flags, CONFIG_FLAG_MOUSEDEBUG);
+				DEL_BIT(ses->config_flags, CONFIG_FLAG_MOUSEINFO);
+				DEL_BIT(ses->config_flags, CONFIG_FLAG_MOUSEPIXELS);
+				DEL_BIT(gtd->flags, TINTIN_FLAG_MOUSETRACKING);
+				print_stdout(0, 0, "\e[?1000l\e[?1002l\e[?1004l\e[?1006l\e[?1016l");
+			}
+		}
+		else
+		{
+			if (HAS_BIT(gtd->flags, TINTIN_FLAG_MOUSETRACKING))
+			{
+				if (HAS_BIT(ses->config_flags, CONFIG_FLAG_MOUSEPIXELS))
+				{
+					print_stdout(0, 0, "\e[?1000h\e[?1002h\e[?1004h\e[?1016h");
+				}
+				else
+				{
+					print_stdout(0, 0, "\e[?1000h\e[?1002h\e[?1004h\e[?1006h");
+				}
+			}
+			else
+			{
+				show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {%s} <ON|OFF|DEBUG|INFO|PIXELS>", config_table[index].name);
+
+				return NULL;
+			}
+		}
+/*
 		if (is_abbrev(arg2, "ON"))
 		{
-			DEL_BIT(ses->flags, SES_FLAG_MOUSEDEBUG);
-			DEL_BIT(ses->flags, SES_FLAG_MOUSEINFO);
+			DEL_BIT(ses->config_flags, CONFIG_FLAG_MOUSEDEBUG);
+			DEL_BIT(ses->config_flags, CONFIG_FLAG_MOUSEINFO);
+			DEL_BIT(ses->config_flags, CONFIG_FLAG_MOUSEPIXELS);
 			SET_BIT(gtd->flags, TINTIN_FLAG_MOUSETRACKING);
-			print_stdout("\e[?1000h\e[?1002h\e[?1004h\e[?1006h");
+			print_stdout(0, 0, "\e[?1000h\e[?1002h\e[?1004h\e[?1006h");
+		}
+		else if (is_abbrev(arg2, "PIXELS"))
+		{
+			DEL_BIT(ses->config_flags, CONFIG_FLAG_MOUSEDEBUG);
+			DEL_BIT(ses->config_flags, CONFIG_FLAG_MOUSEINFO);
+			SET_BIT(ses->config_flags, CONFIG_FLAG_MOUSEPIXELS);
+			SET_BIT(gtd->flags, TINTIN_FLAG_MOUSETRACKING);
+		
+			print_stdout(0, 0, "\e[?1000h\e[?1002h\e[?1004h\e[?1016h");
 		}
 		else if (is_abbrev(arg2, "OFF"))
 		{
 			if (HAS_BIT(gtd->flags, TINTIN_FLAG_MOUSETRACKING))
 			{
-				DEL_BIT(ses->flags, SES_FLAG_MOUSEDEBUG);
-				DEL_BIT(ses->flags, SES_FLAG_MOUSEINFO);
+				DEL_BIT(ses->config_flags, CONFIG_FLAG_MOUSEDEBUG);
+				DEL_BIT(ses->config_flags, CONFIG_FLAG_MOUSEINFO);
+				DEL_BIT(ses->config_flags, CONFIG_FLAG_MOUSEPIXELS);
 				DEL_BIT(gtd->flags, TINTIN_FLAG_MOUSETRACKING);
-				print_stdout("\e[?1000l\e[?1002l\e[?1004l\e[?1006l");
+				print_stdout(0, 0, "\e[?1000l\e[?1002l\e[?1004l\e[?1006l");
 			}
 		}
 		else if (is_abbrev(arg2, "DEBUG"))
 		{
-			DEL_BIT(ses->flags, SES_FLAG_MOUSEINFO);
-			SET_BIT(ses->flags, SES_FLAG_MOUSEDEBUG);
+			DEL_BIT(ses->config_flags, CONFIG_FLAG_MOUSEINFO);
+			SET_BIT(ses->config_flags, CONFIG_FLAG_MOUSEDEBUG);
 			SET_BIT(gtd->flags, TINTIN_FLAG_MOUSETRACKING);
-			print_stdout("\e[?1000h\e[?1002h\e[?1004h\e[?1006h");
+			print_stdout(0, 0, "\e[?1000h\e[?1002h\e[?1004h\e[?1006h");
 		}
 		else if (is_abbrev(arg2, "DEBUG INFO"))
 		{
-			SET_BIT(ses->flags, SES_FLAG_MOUSEDEBUG);
-			SET_BIT(ses->flags, SES_FLAG_MOUSEINFO);
+			SET_BIT(ses->config_flags, CONFIG_FLAG_MOUSEDEBUG);
+			SET_BIT(ses->config_flags, CONFIG_FLAG_MOUSEINFO);
 			SET_BIT(gtd->flags, TINTIN_FLAG_MOUSETRACKING);
-			print_stdout("\e[?1000h\e[?1002h\e[?1004h\e[?1006h");
+			print_stdout(0, 0, "\e[?1000h\e[?1002h\e[?1004h\e[?1006h");
 		}
 		else if (is_abbrev(arg2, "INFO"))
 		{
-			DEL_BIT(ses->flags, SES_FLAG_MOUSEDEBUG);
-			SET_BIT(ses->flags, SES_FLAG_MOUSEINFO);
+			DEL_BIT(ses->config_flags, CONFIG_FLAG_MOUSEDEBUG);
+			SET_BIT(ses->config_flags, CONFIG_FLAG_MOUSEINFO);
 			SET_BIT(gtd->flags, TINTIN_FLAG_MOUSETRACKING);
-			print_stdout("\e[?1000h\e[?1002h\e[?1004h\e[?1006h");
+			print_stdout(0, 0, "\e[?1000h\e[?1002h\e[?1004h\e[?1006h");
 		}
 		else
 		{
@@ -648,23 +724,33 @@ DO_CONFIG(config_mousetracking)
 
 			return NULL;
 		}
+*/
 	}
+
 	if (HAS_BIT(gtd->flags, TINTIN_FLAG_MOUSETRACKING))
 	{
-		switch (HAS_BIT(ses->flags, SES_FLAG_MOUSEDEBUG|SES_FLAG_MOUSEINFO))
+		if (!HAS_BIT(ses->config_flags, CONFIG_FLAG_MOUSEDEBUG|CONFIG_FLAG_MOUSEINFO|CONFIG_FLAG_MOUSEPIXELS))
 		{
-			case 0:
-				strcpy(arg2, "ON");
-				break;
-			case SES_FLAG_MOUSEDEBUG:
-				strcpy(arg2, "DEBUG");
-				break;
-			case SES_FLAG_MOUSEINFO:
-				strcpy(arg2, "INFO");
-				break;
-			default:
-				strcpy(arg2, "DEBUG INFO");
-				break;
+			strcpy(arg2, "ON");
+		}
+		else
+		{
+			strcpy(arg2, "");
+
+			if (HAS_BIT(ses->config_flags, CONFIG_FLAG_MOUSEPIXELS))
+			{
+				strcpy(arg2, "PIXELS");
+			}
+
+			if (HAS_BIT(ses->config_flags, CONFIG_FLAG_MOUSEDEBUG))
+			{
+				strcat(arg2, *arg2 ? " DEBUG" : "DEBUG");
+			}
+
+			if (HAS_BIT(ses->config_flags, CONFIG_FLAG_MOUSEINFO))
+			{
+				strcat(arg2, *arg2 ? " INFO" : "INFO");
+			}
 		}
 	}
 	else
@@ -683,7 +769,7 @@ DO_CONFIG(config_packetpatch)
 		{
 			ses->packet_patch = 0;
 
-			SET_BIT(ses->flags, SES_FLAG_AUTOPATCH);
+			SET_BIT(ses->config_flags, CONFIG_FLAG_AUTOPATCH);
 		}
 		else if (!is_number(arg2))
 		{
@@ -699,19 +785,19 @@ DO_CONFIG(config_packetpatch)
 		}
 		else
 		{
-			DEL_BIT(ses->flags, SES_FLAG_AUTOPATCH);
+			DEL_BIT(ses->config_flags, CONFIG_FLAG_AUTOPATCH);
 
 			ses->packet_patch = (unsigned long long) (tintoi(arg2) * 1000000ULL);
 		}
 	}
 
-	if (HAS_BIT(ses->flags, SES_FLAG_AUTOPATCH))
+	if (HAS_BIT(ses->config_flags, CONFIG_FLAG_AUTOPATCH))
 	{
 		if (ses->list[LIST_PROMPT]->list[0])
 		{
 			strcpy(arg2, "AUTO PROMPT");
 		}
-		else if (HAS_BIT(ses->flags, SES_FLAG_AUTOPROMPT))
+		else if (HAS_BIT(ses->config_flags, CONFIG_FLAG_AUTOPROMPT))
 		{
 			strcpy(arg2, "AUTO TELNET");
 		}
@@ -727,32 +813,6 @@ DO_CONFIG(config_packetpatch)
 	return ses;
 }
 
-DO_CONFIG(config_pid)
-{
-	if (*arg2)
-	{
-		if (!is_number(arg2))
-		{
-			show_error(ses, LIST_CONFIG, "#SYNTAX: #CONFIG {PID} <NUMBER>");
-			
-			return NULL;
-		}
-		else if (atoi(arg2) < 0 || atoi(arg2) > 4194303)
-		{
-			show_error(ses, LIST_CONFIG, "#ERROR: #CONFIG PID: PROVIDE A NUMBER BETWEEN 3 and 4194304");
-
-			return NULL;
-		}
-		else
-		{
-			gtd->detach_pid = atoi(arg2);
-		}
-	}
-	sprintf(arg2, "%d", gtd->detach_pid);
-
-	return ses;
-}
-	
 DO_CONFIG(config_randomseed)
 {
 	if (*arg2)
@@ -804,11 +864,11 @@ DO_CONFIG(config_repeatenter)
 	{
 		if (is_abbrev(arg2, "ON"))
 		{
-			SET_BIT(ses->flags, SES_FLAG_REPEATENTER);
+			SET_BIT(ses->config_flags, CONFIG_FLAG_REPEATENTER);
 		}
 		else if (is_abbrev(arg2, "OFF"))
 		{
-			DEL_BIT(ses->flags, SES_FLAG_REPEATENTER);
+			DEL_BIT(ses->config_flags, CONFIG_FLAG_REPEATENTER);
 		}
 		else
 		{
@@ -817,7 +877,7 @@ DO_CONFIG(config_repeatenter)
 			return NULL;
 		}
 	}
-	strcpy(arg2, HAS_BIT(ses->flags, SES_FLAG_REPEATENTER) ? "ON" : "OFF");
+	strcpy(arg2, HAS_BIT(ses->config_flags, CONFIG_FLAG_REPEATENTER) ? "ON" : "OFF");
 
 	return ses;
 }
@@ -829,11 +889,11 @@ DO_CONFIG(config_screenreader)
 	{
 		if (is_abbrev(arg2, "ON"))
 		{
-			SET_BIT(ses->flags, SES_FLAG_SCREENREADER);
+			SET_BIT(ses->config_flags, CONFIG_FLAG_SCREENREADER);
 		}
 		else if (is_abbrev(arg2, "OFF"))
 		{
-			DEL_BIT(ses->flags, SES_FLAG_SCREENREADER);
+			DEL_BIT(ses->config_flags, CONFIG_FLAG_SCREENREADER);
 		}
 		else
 		{
@@ -842,7 +902,7 @@ DO_CONFIG(config_screenreader)
 			return NULL;
 		}
 	}
-	strcpy(arg2, HAS_BIT(ses->flags, SES_FLAG_SCREENREADER) ? "ON" : "OFF");
+	strcpy(arg2, HAS_BIT(ses->config_flags, CONFIG_FLAG_SCREENREADER) ? "ON" : "OFF");
 
 	return ses;
 }
@@ -856,11 +916,11 @@ DO_CONFIG(config_scrolllock)
 	{	
 		if (is_abbrev(arg2, "ON"))
 		{
-			SET_BIT(ses->flags, SES_FLAG_SCROLLLOCK);
+			SET_BIT(ses->config_flags, CONFIG_FLAG_SCROLLLOCK);
 		}
 		else if (is_abbrev(arg2, "OFF"))
 		{
-			DEL_BIT(ses->flags, SES_FLAG_SCROLLLOCK);
+			DEL_BIT(ses->config_flags, CONFIG_FLAG_SCROLLLOCK);
 		}
 		else
 		{
@@ -869,7 +929,7 @@ DO_CONFIG(config_scrolllock)
 			return NULL;
 		}
 	}
-	strcpy(arg2, HAS_BIT(ses->flags, SES_FLAG_SCROLLLOCK) ? "ON" : "OFF");	
+	strcpy(arg2, HAS_BIT(ses->config_flags, CONFIG_FLAG_SCROLLLOCK) ? "ON" : "OFF");	
 
 	return ses;
 }
@@ -880,11 +940,11 @@ DO_CONFIG(config_speedwalk)
 	{
 		if (is_abbrev(arg2, "ON"))
 		{
-			SET_BIT(ses->flags, SES_FLAG_SPEEDWALK);
+			SET_BIT(ses->config_flags, CONFIG_FLAG_SPEEDWALK);
 		}
 		else if (is_abbrev(arg2, "OFF"))
 		{
-			DEL_BIT(ses->flags, SES_FLAG_SPEEDWALK);
+			DEL_BIT(ses->config_flags, CONFIG_FLAG_SPEEDWALK);
 		}
 		else
 		{
@@ -893,7 +953,7 @@ DO_CONFIG(config_speedwalk)
 			return NULL;
 		}
 	}
-	strcpy(arg2, HAS_BIT(ses->flags, SES_FLAG_SPEEDWALK) ? "ON" : "OFF");
+	strcpy(arg2, HAS_BIT(ses->config_flags, CONFIG_FLAG_SPEEDWALK) ? "ON" : "OFF");
 
 	return ses;
 }
@@ -935,22 +995,22 @@ DO_CONFIG(config_telnet)
 		if (is_abbrev(arg2, "ON"))
 		{
 			DEL_BIT(ses->telopts, TELOPT_FLAG_DEBUG);
-			SET_BIT(ses->flags, SES_FLAG_TELNET);
+			SET_BIT(ses->config_flags, CONFIG_FLAG_TELNET);
 		}
 		else if (is_abbrev(arg2, "OFF"))
 		{
 			DEL_BIT(ses->telopts, TELOPT_FLAG_DEBUG);
-			DEL_BIT(ses->flags, SES_FLAG_TELNET);
+			DEL_BIT(ses->config_flags, CONFIG_FLAG_TELNET);
 		}
 		else if (is_abbrev(arg2, "DEBUG"))
 		{
 			SET_BIT(ses->telopts, TELOPT_FLAG_DEBUG);
-			SET_BIT(ses->flags, SES_FLAG_TELNET);
+			SET_BIT(ses->config_flags, CONFIG_FLAG_TELNET);
 		}
 		else if (is_abbrev(arg2, "INFO"))
 		{
 			SET_BIT(ses->telopts, TELOPT_FLAG_DEBUG);
-			SET_BIT(ses->flags, SES_FLAG_TELNET);
+			SET_BIT(ses->config_flags, CONFIG_FLAG_TELNET);
 		}
 		else
 		{
@@ -959,7 +1019,7 @@ DO_CONFIG(config_telnet)
 			return NULL;
 		}
 	}
-	strcpy(arg2, HAS_BIT(ses->telopts, TELOPT_FLAG_DEBUG) ? "DEBUG" : HAS_BIT(ses->flags, SES_FLAG_TELNET) ? "ON" : "OFF");
+	strcpy(arg2, HAS_BIT(ses->telopts, TELOPT_FLAG_DEBUG) ? "DEBUG" : HAS_BIT(ses->config_flags, CONFIG_FLAG_TELNET) ? "ON" : "OFF");
 
 	return ses;
 }
@@ -989,11 +1049,11 @@ DO_CONFIG(config_verbatim)
 	{
 		if (is_abbrev(arg2, "ON"))
 		{
-			SET_BIT(ses->flags, SES_FLAG_VERBATIM);
+			SET_BIT(ses->config_flags, CONFIG_FLAG_VERBATIM);
 		}
 		else if (is_abbrev(arg2, "OFF"))
 		{
-			DEL_BIT(ses->flags, SES_FLAG_VERBATIM);
+			DEL_BIT(ses->config_flags, CONFIG_FLAG_VERBATIM);
 		}
 		else
 		{
@@ -1002,7 +1062,7 @@ DO_CONFIG(config_verbatim)
 			return NULL;
 		}
 	}
-	strcpy(arg2, HAS_BIT(ses->flags, SES_FLAG_VERBATIM) ? "ON" : "OFF");
+	strcpy(arg2, HAS_BIT(ses->config_flags, CONFIG_FLAG_VERBATIM) ? "ON" : "OFF");
 
 	return ses;
 }
@@ -1031,11 +1091,11 @@ DO_CONFIG(config_verbose)
 	{
 		if (is_abbrev(arg2, "ON"))
 		{
-			SET_BIT(ses->flags, SES_FLAG_VERBOSE);
+			SET_BIT(ses->config_flags, CONFIG_FLAG_VERBOSE);
 		}
 		else if (is_abbrev(arg2, "OFF"))
 		{
-			DEL_BIT(ses->flags, SES_FLAG_VERBOSE);
+			DEL_BIT(ses->config_flags, CONFIG_FLAG_VERBOSE);
 		}
 		else
 		{
@@ -1044,7 +1104,7 @@ DO_CONFIG(config_verbose)
 			return NULL;
 		}
 	}
-	strcpy(arg2, HAS_BIT(ses->flags, SES_FLAG_VERBOSE) ? "ON" : "OFF");
+	strcpy(arg2, HAS_BIT(ses->config_flags, CONFIG_FLAG_VERBOSE) ? "ON" : "OFF");
 
 	return ses;
 }
@@ -1055,11 +1115,11 @@ DO_CONFIG(config_wordwrap)
 	{
 		if (is_abbrev(arg2, "ON"))
 		{
-			SET_BIT(ses->flags, SES_FLAG_WORDWRAP);
+			SET_BIT(ses->config_flags, CONFIG_FLAG_WORDWRAP);
 		}
 		else if (is_abbrev(arg2, "OFF"))
 		{
-			DEL_BIT(ses->flags, SES_FLAG_WORDWRAP);
+			DEL_BIT(ses->config_flags, CONFIG_FLAG_WORDWRAP);
 		}
 		else
 		{
@@ -1068,7 +1128,7 @@ DO_CONFIG(config_wordwrap)
 			return NULL;
 		}
 	}
-	strcpy(arg2, HAS_BIT(ses->flags, SES_FLAG_WORDWRAP) ? "ON" : "OFF");
+	strcpy(arg2, HAS_BIT(ses->config_flags, CONFIG_FLAG_WORDWRAP) ? "ON" : "OFF");
 
 	return ses;
 }

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 632 - 253
src/cursor.c


+ 36 - 29
src/daemon.c

@@ -36,6 +36,8 @@
 #include <dirent.h>
 #include <termios.h>
 #include <sys/un.h>
+#include <sys/socket.h>
+#include <signal.h>
 
 int get_daemon_dir(struct session *ses, char *filename);
 
@@ -49,7 +51,7 @@ DO_COMMAND(do_daemon)
 	{
 		info:
 
-		tintin_header(ses, " DAEMON OPTIONS ");
+		tintin_header(ses, 80, " DAEMON OPTIONS ");
 
 		for (cnt = 0 ; *daemon_table[cnt].fun != NULL ; cnt++)
 		{
@@ -58,7 +60,7 @@ DO_COMMAND(do_daemon)
 				tintin_printf2(ses, "  [%-13s] %s", daemon_table[cnt].name, daemon_table[cnt].desc);
 			}
 		}
-		tintin_header(ses, "");
+		tintin_header(ses, 80, "");
 
 		return ses;
 	}
@@ -78,7 +80,7 @@ DO_COMMAND(do_daemon)
 		}
 		else
 		{
-			daemon_table[cnt].fun(ses, arg);
+			daemon_table[cnt].fun(ses, arg, arg1, arg2);
 		}
 	}
 
@@ -88,15 +90,17 @@ DO_COMMAND(do_daemon)
 
 DO_DAEMON(daemon_attach)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], filename[BUFFER_SIZE], sock_file[BUFFER_SIZE];
+	char filename[PATH_SIZE], sock_file[PATH_SIZE * 2];
 	struct dirent **dirlist;
 	struct sockaddr_un addr_un;
 	int size, index, pid, error, repeat = 0;
 	struct timeval timeout;
 	fd_set wds, rds;
 
-	timeout.tv_sec  = 0;
-	timeout.tv_usec = 100000;
+	gtd->time_daemon = gtd->time;
+
+	timeout.tv_sec   = 0;
+	timeout.tv_usec  = 100000;
 
 	if (gtd->attach_sock)
 	{
@@ -162,7 +166,7 @@ DO_DAEMON(daemon_attach)
 	{
 		if (HAS_BIT(gtd->flags, TINTIN_FLAG_DAEMONIZE))
 		{
-			daemon_detach(ses, arg1);
+			command(ses, do_daemon, "detach {%s}", arg1);
 
 			return;
 		}
@@ -186,7 +190,7 @@ DO_DAEMON(daemon_attach)
 		return;
 	}
 
-	sprintf(sock_file, "%.*s/%.*s.s", PATH_SIZE, filename, PATH_SIZE, arg2);
+	sprintf(sock_file, "%.*s/%.*s.s", PATH_SIZE, filename, NAME_SIZE, arg2);
 
 	if (access(sock_file, F_OK) == -1)
 	{
@@ -317,7 +321,7 @@ DO_DAEMON(daemon_attach)
 
 DO_DAEMON(daemon_detach)
 {
-	char arg1[BUFFER_SIZE], filename[BUFFER_SIZE];
+	char filename[PATH_SIZE];
 	struct sockaddr_un addr_un;
 	pid_t pid, sid;
 	int dev_null;
@@ -328,13 +332,17 @@ DO_DAEMON(daemon_detach)
 	{
 		if (gtd->detach_sock)
 		{
+//			dirty_screen(gtd->ses);
+
 			show_message(gtd->ses, LIST_COMMAND, "#DAEMON DETACH: DETACHING FROM {%s}", gtd->detach_file);
 
 //			kill((pid_t) gtd->detach_sock, SIGTSTP);
 
-//			print_stdout("%c", (char) 255);
+//			print_stdout(0, 0, "%c", (char) 255);
 
 			gtd->detach_sock = close(gtd->detach_sock);
+
+			check_all_events(gtd->ses, EVENT_FLAG_SYSTEM, 0, 2, "DAEMON DETACHED", gtd->detach_file, ntos(gtd->detach_info.pid));
 		}
 		else
 		{
@@ -365,17 +373,17 @@ DO_DAEMON(daemon_detach)
 
 			usleep(2000);
 
-			daemon_attach(ses, *arg1 ? arg1 : "pid");
+			command(ses, do_daemon, "attach {%s}", *arg1 ? arg1 : "pid");
 
 			return;
 		}
-		reset_terminal(gtd->ses);
-
-		print_stdout("\e[r\e[%d;%dH", gtd->screen->rows, 1);
-
-		_exit(0);
+//		check_all_events(gtd->ses, EVENT_FLAG_SYSTEM, 0, 2, "DAEMON DETACHED", gtd->detach_file, ntos(gtd->detach_info.pid));
+		quitmsg(NULL);
 	}
 
+//	reset_terminal(gtd->ses);
+	reset_screen(gtd->ses);
+
 	DEL_BIT(gtd->flags, TINTIN_FLAG_DAEMONIZE);
 
 	sid = setsid();
@@ -455,12 +463,13 @@ DO_DAEMON(daemon_detach)
 
 	gtd->detach_file = restringf(gtd->detach_file, "%s", filename);
 
+	check_all_events(gtd->ses, EVENT_FLAG_SYSTEM, 0, 2, "DAEMON DETACHED", gtd->detach_file, ntos(gtd->detach_info.pid));
+
 	return;
 }
 
 DO_DAEMON(daemon_input)
 {
-	char arg1[BUFFER_SIZE], out[BUFFER_SIZE];
 	int size;
 
 	if (*arg == 0)
@@ -479,9 +488,9 @@ DO_DAEMON(daemon_input)
 
 	get_arg_in_braces(ses, arg, arg1, GET_ALL);
 
-	size = substitute(ses, arg1, out, SUB_VAR|SUB_FUN|SUB_COL|SUB_ESC|SUB_EOL);
+	size = substitute(ses, arg1, arg2, SUB_VAR|SUB_FUN|SUB_COL|SUB_ESC|SUB_EOL);
 
-	if (write(gtd->attach_sock, out, size) < 0)
+	if (write(gtd->attach_sock, arg2, size) < 0)
 	{
 		gtd->attach_sock = close(gtd->attach_sock);
 
@@ -491,7 +500,7 @@ DO_DAEMON(daemon_input)
 
 DO_DAEMON(daemon_kill)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], filename[BUFFER_SIZE], sock_file[BUFFER_SIZE];
+	char filename[PATH_SIZE], sock_file[PATH_SIZE * 2];
 	struct dirent **dirlist;
 	int size, index, pid;
 
@@ -538,7 +547,7 @@ DO_DAEMON(daemon_kill)
 				{
 					pid = atoi(arg + 1);
 
-					sprintf(sock_file, "%.*s/%.*s.s", PATH_SIZE, filename, PATH_SIZE, arg2);
+					sprintf(sock_file, "%.*s/%.*s.s", PATH_SIZE, filename, NAME_SIZE, arg2);
 
 					show_message(ses, LIST_COMMAND, "#DAEMON {%s} KILLED.", sock_file, pid);
 
@@ -561,7 +570,7 @@ DO_DAEMON(daemon_kill)
 
 DO_DAEMON(daemon_list)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], filename[BUFFER_SIZE], sock_file[BUFFER_SIZE];
+	char filename[PATH_SIZE], sock_file[PATH_SIZE * 2];
 	struct dirent **dirlist;
 	int size, index, pid;
 
@@ -608,7 +617,7 @@ DO_DAEMON(daemon_list)
 				{
 					pid = atoi(arg + 1);
 
-					sprintf(sock_file, "%.*s/%.*s.s", PATH_SIZE, filename, PATH_SIZE, arg2);
+					sprintf(sock_file, "%.*s/%.*s.s", PATH_SIZE, filename, NAME_SIZE, arg2);
 
 					tintin_printf2(ses, "%-40s [%6d]", sock_file, pid);
 				}
@@ -626,16 +635,14 @@ DO_DAEMON(daemon_list)
 
 int get_daemon_dir(struct session *ses, char *filename)
 {
-	sprintf(filename, "%s/%s", gtd->home, TINTIN_DIR);
-
-	if (mkdir(filename, 0755) && errno != EEXIST)
+	if (mkdir(gtd->system->tt_dir, 0755) && errno != EEXIST)
 	{
 		show_error(ses, LIST_COMMAND, "#DAEMON CHECK DIR: FAILED TO CREATE TINTIN DIR %s (%s)", filename, strerror(errno));
 
 		return 0;
 	}
 
-	sprintf(filename, "%s/%s/%s", gtd->home, TINTIN_DIR, DAEMON_DIR);
+	sprintf(filename, "%s/%s", gtd->system->tt_dir, DAEMON_DIR);
 
 	if (mkdir(filename, 0755) && errno != EEXIST)
 	{
@@ -650,14 +657,14 @@ void reset_daemon()
 {
 	if (gtd->detach_sock > 0)
 	{
-//		print_stdout("removing(%s)\n", gtd->detach_file);
+//		print_stdout(0, 0, "removing(%s)\n", gtd->detach_file);
 
 		remove(gtd->detach_file);
 	}
 /*
 	if (gtd->attach_sock > 0)
 	{
-		print_stdout("unlinking(%s)\n", gtd->attach_file);
+		print_stdout(0, 0, "unlinking(%s)\n", gtd->attach_file);
 
 		unlink(gtd->attach_file);
 	}

+ 377 - 109
src/data.c

@@ -70,7 +70,7 @@ struct listroot *copy_list(struct session *ses, struct listroot *sourcelist, int
 	int i;
 	struct listnode *node;
 
-	push_call("copy_list(%p,%p,%p)",ses,sourcelist,type);
+	push_call("copy_list(%p,%p,%s)",ses,sourcelist,list_table[type].name);
 
 	ses->list[type] = init_list(ses, type, sourcelist->size);
 
@@ -102,15 +102,29 @@ 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_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;
+
+				default:
+					if (sourcelist->list[i]->val64)
+					{
+						printf("copy_list: unhandled val64 (%d).\n", type);
+					}
+					break;
 			}
 			ses->list[type]->list[i] = node;
 		}
@@ -145,6 +159,29 @@ struct listnode *create_node_list(struct listroot *root, char *arg1, char *arg2,
 	node->arg3 = str_dup(arg3);
 	node->arg4 = str_dup(arg4);
 
+//	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) get_number(root->ses, node->arg3) * 1000000LL;
+
+			if (node->val64 < gtd->utime_next_tick)
+			{
+				gtd->utime_next_tick = node->val64;
+			}
+			break;
+	}
+
 	if (gtd->level->shots)
 	{
 		node->shots = gtd->level->mshot;
@@ -189,11 +226,6 @@ struct listnode *update_node_list(struct listroot *root, char *arg1, char *arg2,
 
 	if (index != -1)
 	{
-		if (list_table[root->type].mode == SORT_DELAY && is_number(arg1))
-		{
-			return create_node_list(root, arg1, arg2, arg3, arg4);
-		}
-
 		node = root->list[index];
 
 		if (gtd->level->shots)
@@ -208,9 +240,13 @@ struct listnode *update_node_list(struct listroot *root, char *arg1, char *arg2,
 
 		switch (root->type)
 		{
-			case LIST_DELAY:
 			case LIST_TICKER:
-				node->val64 = 0;
+				node->val64 = gtd->utime + (long long) get_number(root->ses, node->arg3) * 1000000LL;
+
+				if (node->val64 < gtd->utime_next_tick)
+				{
+					gtd->utime_next_tick = node->val64;
+				}
 				break;
 		}
 
@@ -219,9 +255,12 @@ struct listnode *update_node_list(struct listroot *root, char *arg1, char *arg2,
 			strcpy(arg3, "5");
 		}
 
-		if (strcmp(node->arg3, arg3) != 0)
+		if (list_table[root->type].mode != SORT_PRIORITY)
 		{
-			str_cpy(&node->arg3, arg3);
+			if (strcmp(node->arg3, arg3) != 0)
+			{
+				str_cpy(&node->arg3, arg3);
+			}
 		}
 
 		if (strcmp(node->arg4, arg4) != 0)
@@ -232,9 +271,10 @@ struct listnode *update_node_list(struct listroot *root, char *arg1, char *arg2,
 		switch (list_table[root->type].mode)
 		{
 			case SORT_PRIORITY:
-				if (atof(node->arg3) != atof(arg3))
+				if (strcmp(node->arg3, arg3))
 				{
 					remove_index_list(root, index);
+					str_cpy(&node->arg3, arg3);
 					insert_node_list(root, node);
 				}
 				break;
@@ -245,7 +285,7 @@ struct listnode *update_node_list(struct listroot *root, char *arg1, char *arg2,
 				break;
 
 			case SORT_ALPHA:
-			case SORT_DELAY:
+			case SORT_ALNUM:
 				break;
 
 			default:
@@ -271,7 +311,10 @@ struct listnode *insert_index_list(struct listroot *root, struct listnode *node,
 		root->list = (struct listnode **) realloc(root->list, (root->size) * sizeof(struct listnode *));
 	}
 
-	memmove(&root->list[index + 1], &root->list[index], (root->used - index) * sizeof(struct listnode *));
+	if (index + 1 < root->used)
+	{
+		memmove(&root->list[index + 1], &root->list[index], (root->used - index) * sizeof(struct listnode *));
+	}
 
 	root->list[index] = node;
 
@@ -310,18 +353,6 @@ void delete_index_list(struct listroot *root, int index)
 {
 	struct listnode *node = root->list[index];
 
-	if (node->root)
-	{
-		free_list(node->root);
-	}
-
-	str_free(node->arg1);
-	str_free(node->arg2);
-	str_free(node->arg3);
-	str_free(node->arg4);
-
-	free(node->group);
-
 	if (HAS_BIT(list_table[root->type].flags, LIST_FLAG_REGEX))
 	{
 		if (node->regex)
@@ -343,10 +374,34 @@ void delete_index_list(struct listroot *root, int index)
 				free(node->data);
 			}
 			break;
+
+		case LIST_EVENT:
+			event_table[node->val32[0]].level--;
+			break;
 	}
-	free(node);
 
 	remove_index_list(root, index);
+
+	// dispose in memory update for one shot handling
+
+	insert_index_list(gtd->dispose_list, node, gtd->dispose_list->used);
+}
+
+void dispose_node(struct listnode *node)
+{
+	if (node->root)
+	{
+		free_list(node->root);
+	}
+
+	str_free(node->arg1);
+	str_free(node->arg2);
+	str_free(node->arg3);
+	str_free(node->arg4);
+
+	free(node->group);
+
+	free(node);
 }
 
 struct listnode *search_node_list(struct listroot *root, char *text)
@@ -358,10 +413,17 @@ struct listnode *search_node_list(struct listroot *root, char *text)
 	switch (list_table[root->type].mode)
 	{
 		case SORT_ALPHA:
-		case SORT_DELAY:
 			index = bsearch_alpha_list(root, text, 0);
 			break;
 
+		case SORT_ALNUM:
+			index = bsearch_alnum_list(root, text, 0);
+			break;
+
+		case SORT_DELAY:
+			index = bsearch_priority_list(root, text, text, 0);
+			break;
+
 		default:
 			index = nsearch_list(root, text);
 			break;
@@ -379,14 +441,23 @@ struct listnode *search_node_list(struct listroot *root, char *text)
 
 int search_index_list(struct listroot *root, char *text, char *priority)
 {
-	if (list_table[root->type].mode == SORT_ALPHA || list_table[root->type].mode == SORT_DELAY)
+	switch (list_table[root->type].mode)
 	{
-		return bsearch_alpha_list(root, text, 0);
-	}
+		case SORT_ALPHA:
+			return bsearch_alpha_list(root, text, 0);
+		
+		case SORT_ALNUM:
+			return bsearch_alnum_list(root, text, 0);
 
-	if (list_table[root->type].mode == SORT_PRIORITY && priority)
-	{
-		return bsearch_priority_list(root, text, priority, 0);
+		case SORT_DELAY:
+			return bsearch_priority_list(root, text, text, 0);
+
+		case SORT_PRIORITY:
+			if (priority)
+			{
+				bsearch_priority_list(root, text, priority, 0);
+			}
+			break;
 	}
 
 	return nsearch_list(root, text);
@@ -401,9 +472,14 @@ int locate_index_list(struct listroot *root, char *text, char *priority)
 	switch (list_table[root->type].mode)
 	{
 		case SORT_ALPHA:
-		case SORT_DELAY:
 			return bsearch_alpha_list(root, text, 1);
 
+		case SORT_ALNUM:
+			return bsearch_alnum_list(root, text, 1);
+
+		case SORT_DELAY:
+			return bsearch_priority_list(root, text, text, 1);
+
 		case SORT_PRIORITY:
 			return bsearch_priority_list(root, text, priority, 1);
 
@@ -412,14 +488,48 @@ int locate_index_list(struct listroot *root, char *text, char *priority)
 	}
 }
 
-/*
-	binary search on alphabetically sorted list
-*/
 
 int bsearch_alpha_list(struct listroot *root, char *text, int seek)
 {
-	long long bot, top, val;
-	long double toi, toj, srt;
+	int bot, top, val, srt;
+
+	bot = 0;
+	top = root->used - 1;
+	val = top;
+
+	while (bot <= top)
+	{
+		srt = strcmp(text, root->list[val]->arg1);
+
+		if (srt == 0)
+		{
+			return val;
+		}
+
+		if (srt < 0)
+		{
+			top = val - 1;
+		}
+		else
+		{
+			bot = val + 1;
+		}
+
+		val = bot + (top - bot) / 2;
+	}
+
+	if (seek)
+	{
+		return UMAX(0, val);
+	}
+	return -1;
+}
+
+
+int bsearch_alnum_list(struct listroot *root, char *text, int seek)
+{
+	long double toi, toj;
+	int bot, top, val, noi, noj, srt;
 
 	push_call("bsearch_alpha_list(%p,%p,%d)",root,text,seek);
 
@@ -428,16 +538,30 @@ int bsearch_alpha_list(struct listroot *root, char *text, int seek)
 		switch (*text)
 		{
 			case '+':
-			case '-':
 				toi = get_number(root->ses, text);
 
-				if (toi > 0 && toi <= root->used)
+				if (seek == 0)
 				{
-					pop_call();
-					return toi - 1;
+					if (toi > 0 && toi <= root->used)
+					{
+						pop_call();
+						return toi - 1;
+					}
 				}
+				else
+				{
+					if (toi >= 0 && toi <= root->used)
+					{
+						pop_call();
+						return UMAX(0, toi - 1);
+					}
+				}
+				break;
+
+			case '-':
+				toi = get_number(root->ses, text);
 
-				if (toi < 0 && toi + root->used >= 0)
+				if (toi < 0 && root->used + toi >= 0)
 				{
 					pop_call();
 					return root->used + toi;
@@ -454,17 +578,21 @@ int bsearch_alpha_list(struct listroot *root, char *text, int seek)
 	top = root->used - 1;
 	val = top;
 
-	toi = is_number(text) ? tintoi(text) : 0;
+	noi = is_number(text);
+
+	toi = noi ? tintoi(text) : 0;
 
 	while (bot <= top)
 	{
-		toj = is_number(root->list[val]->arg1) ? tintoi(root->list[val]->arg1) : 0;
+		noj = is_number(root->list[val]->arg1);
+
+		toj = noj ? tintoi(root->list[val]->arg1) : 0;
 
-		if (toi)
+		if (noi)
 		{
-			srt = toi - toj;
+			srt = (toi < toj) ? -1 : (toi > toj) ? 1 : 0;
 		}
-		else if (toj)
+		else if (noj)
 		{
 			srt = -1;
 		}
@@ -507,35 +635,46 @@ int bsearch_alpha_list(struct listroot *root, char *text, int seek)
 int bsearch_priority_list(struct listroot *root, char *text, char *priority, int seek)
 {
 	int bot, top, val;
-	double srt;
+	long double prt, srt;
 
 	bot = 0;
 	top = root->used - 1;
 	val = top;
+	prt = tintoi(priority);
 
 	while (bot <= top)
 	{
-		srt = atof(priority) - atof(root->list[val]->arg3);
+		srt = tintoi(root->list[val]->arg3);
 
-		if (!srt)
+		if (srt == prt)
 		{
 			srt = strcmp(text, root->list[val]->arg1);
-		}
 
-		if (srt == 0)
-		{
-			return val;
-		}
+			if (srt == 0)
+			{
+				return val;
+			}
 
-		if (srt < 0)
-		{
-			top = val - 1;
+			if (srt < 0)
+			{
+				top = val - 1;
+			}
+			else
+			{
+				bot = val + 1;
+			}
 		}
 		else
 		{
-			bot = val + 1;
+			if (prt < srt)
+			{
+				top = val - 1;
+			}
+			else
+			{
+				bot = val + 1;
+			}
 		}
-
 		val = bot + (top - bot) / 2;
 	}
 
@@ -573,7 +712,11 @@ int nsearch_list(struct listroot *root, char *text)
 
 void show_node(struct listroot *root, struct listnode *node, int level)
 {
-	char *str_arg2 = str_dup("");
+	char *str_arg2;
+
+	push_call("show_node(%p,%p,%d)",root,node,level);
+
+	str_arg2 = str_alloc_stack(0);
 
 	show_nest_node(node, &str_arg2, TRUE);
 
@@ -599,7 +742,8 @@ void show_node(struct listroot *root, struct listnode *node, int level)
 			tintin_printf2(root->ses, "%s" COLOR_TINTIN "#" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}", indent(level), list_table[root->type].name, node->arg1);
 			break;
 	}
-	str_free(str_arg2);
+	pop_call();
+	return;
 }
 
 /*
@@ -612,7 +756,7 @@ void show_list(struct listroot *root, int level)
 
 	if (root == root->ses->list[root->type])
 	{
-		tintin_header(root->ses, " %s ", list_table[root->type].name_multi);
+		tintin_header(root->ses, 80, " %s ", list_table[root->type].name_multi);
 	}
 
 	for (i = 0 ; i < root->used ; i++)
@@ -632,10 +776,17 @@ int show_node_with_wild(struct session *ses, char *text, struct listroot *root)
 	switch (list_table[root->type].mode)
 	{
 		case SORT_ALPHA:
-		case SORT_DELAY:
 			index = bsearch_alpha_list(root, text, 0);
 			break;
 
+		case SORT_ALNUM:
+			index = bsearch_alnum_list(root, text, 0);
+			break;
+
+		case SORT_DELAY:
+			index = bsearch_priority_list(root, text, text, 0);
+			break;
+
 		default:
 			index = nsearch_list(root, text);
 			break;
@@ -734,10 +885,17 @@ int delete_node_with_wild(struct session *ses, int type, char *text)
 	switch (list_table[type].mode)
 	{
 		case SORT_ALPHA:
-		case SORT_DELAY:
 			index = bsearch_alpha_list(root, arg1, 0);
 			break;
 
+		case SORT_ALNUM:
+			index = bsearch_alnum_list(root, arg1, 0);
+			break;
+
+		case SORT_DELAY:
+			index = bsearch_priority_list(root, arg1, arg1, 0);
+			break;
+
 		default:
 			index = nsearch_list(root, arg1);
 			break;
@@ -843,7 +1001,7 @@ DO_COMMAND(do_message)
 
 	if (*arg1 == 0)
 	{
-		tintin_header(ses, " MESSAGES ");
+		tintin_header(ses, 80, " MESSAGES ");
 
 		for (index = 0 ; index < LIST_MAX ; index++)
 		{
@@ -853,7 +1011,7 @@ DO_COMMAND(do_message)
 			}
 		}
 
-		tintin_header(ses, "");
+		tintin_header(ses, 80, "");
 	}
 	else
 	{
@@ -910,7 +1068,7 @@ DO_COMMAND(do_ignore)
 
 	if (*arg1 == 0)
 	{
-		tintin_header(ses, " IGNORES ");
+		tintin_header(ses, 80, " IGNORES ");
 
 		for (index = 0 ; index < LIST_MAX ; index++)
 		{
@@ -920,7 +1078,7 @@ DO_COMMAND(do_ignore)
 			}
 		}
 
-		tintin_header(ses, "");
+		tintin_header(ses, 80, "");
 	}
 	else
 	{
@@ -977,7 +1135,7 @@ DO_COMMAND(do_debug)
 
 	if (*arg1 == 0)
 	{
-		tintin_header(ses, " DEBUGS ");
+		tintin_header(ses, 80, " DEBUGS ");
 
 		for (index = 0 ; index < LIST_MAX ; index++)
 		{
@@ -987,7 +1145,7 @@ DO_COMMAND(do_debug)
 			}
 		}
 
-		tintin_header(ses, "");
+		tintin_header(ses, 80, "");
 	}
 	else
 	{
@@ -1050,7 +1208,7 @@ DO_COMMAND(do_info)
 
 	if (*arg1 == 0)
 	{
-		tintin_header(ses, " INFORMATION ");
+		tintin_header(ses, 80, " INFORMATION ");
 
 		for (index = 0 ; index < LIST_MAX ; index++)
 		{
@@ -1066,7 +1224,7 @@ DO_COMMAND(do_info)
 					HAS_BIT(ses->list[index]->flags, LIST_FLAG_LOG)     ? "LOG" : "   ");
 			}
 		}
-		tintin_header(ses, "");
+		tintin_header(ses, 80, "");
 	}
 	else
 	{
@@ -1102,19 +1260,20 @@ DO_COMMAND(do_info)
 				{
 					for (cnt = 0 ; cnt < root->used ; cnt++)
 					{
-						tintin_printf2(ses, "#INFO %s %4d {arg1}{%s} {arg2}{%s} {arg3}{%s} {arg4}{%s} {class}{%s} {shots}{%u}", list_table[index].name, cnt, root->list[cnt]->arg1, root->list[cnt]->arg2, root->list[cnt]->arg3, root->list[cnt]->arg4, root->list[cnt]->group, root->list[cnt]->shots);
+						tintin_printf2(ses, "#INFO %s %4d {arg1}{%s} {arg2}{%s} {arg3}{%s} {arg4}{%s} {class}{%s} {shots}{%u}", list_table[index].name, cnt+1, root->list[cnt]->arg1, root->list[cnt]->arg2, root->list[cnt]->arg3, root->list[cnt]->arg4, root->list[cnt]->group, root->list[cnt]->shots);
 					}
 				}
 				else if (is_abbrev(arg2, "SAVE"))
 				{
 					sprintf(name, "info[%s]", list_table[index].name);
-//					delete_nest_node(ses->list[LIST_VARIABLE], name);
+
+					set_nest_node_ses(ses, name, "");
 
 					for (cnt = 0 ; cnt < root->used ; cnt++)
 					{
-						sprintf(name, "info[%s][%d]", list_table[index].name, cnt);
+						sprintf(name, "info[%s][%d]", list_table[index].name, cnt + 1);
 
-						set_nest_node_ses(ses, name, "{arg1}{%s}{arg2}{%s}{arg3}{%s}{arg4}{%s}{class}{%s}{shots}{%u}", root->list[cnt]->arg1, root->list[cnt]->arg2, root->list[cnt]->arg3, root->list[cnt]->arg4, root->list[cnt]->group, root->list[cnt]->shots);
+						set_nest_node_ses(ses, name, "{arg1}{%s}{arg2}{%s}{arg3}{%s}{arg4}{%s}{class}{%s}{nest}{%d}{shots}{%u}", root->list[cnt]->arg1, root->list[cnt]->arg2, root->list[cnt]->arg3, root->list[cnt]->arg4, root->list[cnt]->group, root->list[cnt]->root ? root->list[cnt]->root->used : 0, root->list[cnt]->shots);
 					}
 					show_message(ses, LIST_COMMAND, "#INFO: DATA WRITTEN TO {info[%s]}", list_table[index].name);
 				}
@@ -1139,35 +1298,104 @@ DO_COMMAND(do_info)
 			{
 				if (ses->mccp2)
 				{
-					tintin_printf2(ses, "#INFO MCCP2: TOTAL IN: %9ull TOTAL OUT: %9ull RATIO: %3d", ses->mccp2->total_in, ses->mccp2->total_out, 100 * ses->mccp2->total_out / ses->mccp2->total_in);
+					tintin_printf2(ses, "#INFO MCCP2: TOTAL IN: %9u TOTAL OUT: %9u PERCENT: %3d", ses->mccp2->total_in, ses->mccp2->total_out, ses->mccp2->total_out ? 100 * ses->mccp2->total_in / ses->mccp2->total_out : 0);
 				}
 				if (ses->mccp3)
 				{
-					tintin_printf2(ses, "#INFO MCCP3: TOTAL IN: %9ull TOTAL OUT: %9ull RATIO: %3d", ses->mccp3->total_in, ses->mccp3->total_out, 100 * ses->mccp3->total_out / ses->mccp3->total_in);
+					tintin_printf2(ses, "#INFO MCCP3: TOTAL IN: %9u TOTAL OUT: %9u PERCENT: %3d", ses->mccp3->total_in, ses->mccp3->total_out, ses->mccp3->total_in ? 100 * ses->mccp3->total_out / ses->mccp3->total_in : 0);
 				}
 			}
 			else if (is_abbrev(arg1, "MEMORY"))
 			{
+				struct str_data *str_ptr;
+
 				long long quan, used, max;
-				struct str_data *str;
 
 				max  = 0;
 				quan = 0;
 				used = 0;
 
-				for (str = gtd->memory->alloc->next ; str ; str = str->next)
+				for (index = 0 ; index < gtd->memory->stack_cap ; index++)
 				{
 					max++;
-					quan += str->max;
-					used += str->len;
+					quan += gtd->memory->stack[index]->max;
+					used += gtd->memory->stack[index]->len;
 				}
 
-				tintin_printf2(ses, "#INFO MEMORY: ALLOC  MAX: %d", max);
-				tintin_printf2(ses, "#INFO MEMORY: ALLOC QUAN: %d", quan);
-				tintin_printf2(ses, "#INFO MEMORY: ALLOC USED: %d", used);
+				tintin_printf2(ses, "#INFO MEMORY: STACK SIZE: %d", quan);
 
 				tintin_printf2(ses, "#INFO MEMORY: STACK  MAX: %d", gtd->memory->stack_max);
+				tintin_printf2(ses, "#INFO MEMORY: STACK  CAP: %d", gtd->memory->stack_cap);
 				tintin_printf2(ses, "#INFO MEMORY: STACK  LEN: %d", gtd->memory->stack_len);
+
+				tintin_printf2(ses, "");
+
+				max  = 0;
+				quan = 0;
+				used = 0;
+
+				for (index = 0 ; index < gtd->memory->list_len ; index++)
+				{
+					str_ptr = gtd->memory->list[index];
+
+					if (str_ptr->max != NAME_SIZE + 1 && strlen(get_str_str(str_ptr)) != str_ptr->len)
+					{
+						tintin_printf2(ses, "#ERROR: index %d len = %d/%d max = %d flags = %d (%s)", index, strlen(get_str_str(str_ptr)), str_ptr->len, str_ptr->max, str_ptr->flags, get_str_str(str_ptr));
+					}
+
+					if (!HAS_BIT(str_ptr->flags, STR_FLAG_FREE))
+					{
+						max++;
+						quan += str_ptr->max;
+						used += str_ptr->len;
+					}
+				}
+
+				tintin_printf2(ses, "#INFO MEMORY: ALLOC SIZE: %d", quan);
+				tintin_printf2(ses, "#INFO MEMORY: ALLOC USED: %d", used);
+
+				tintin_printf2(ses, "#INFO MEMORY: ALLOC  MAX: %d", gtd->memory->list_max);
+				tintin_printf2(ses, "#INFO MEMORY: ALLOC  LEN: %d", gtd->memory->list_len);
+
+				tintin_printf2(ses, "");
+
+				quan = 0;
+				used = 0;
+
+				for (index = 0 ; index < gtd->memory->free_len ; index++)
+				{
+					str_ptr = gtd->memory->list[gtd->memory->free[index]];
+
+					if (HAS_BIT(str_ptr->flags, STR_FLAG_FREE))
+					{
+						quan += str_ptr->max;
+						used += str_ptr->len;
+					}
+					else
+					{
+						tintin_printf2(ses, "error: found freed memory not marked as free.");
+					}
+				}
+
+				tintin_printf2(ses, "#INFO MEMORY: FREED SIZE: %d", quan);
+
+				tintin_printf2(ses, "#INFO MEMORY: FREED  MAX: %d", gtd->memory->free_max);
+				tintin_printf2(ses, "#INFO MEMORY: FREED  LEN: %d", gtd->memory->free_len);
+
+				tintin_printf2(ses, "");
+
+				quan = 0;
+				used = 0;
+
+				for (index = 0 ; index < gtd->memory->debug_len ; index++)
+				{
+					quan += NAME_SIZE;
+				}
+
+				tintin_printf2(ses, "#INFO MEMORY: DEBUG SIZE: %d", quan);
+
+				tintin_printf2(ses, "#INFO MEMORY: DEBUG  MAX: %d", gtd->memory->debug_max);
+				tintin_printf2(ses, "#INFO MEMORY: DEBUG  LEN: %d", gtd->memory->debug_len);
 			}
 			else if (is_abbrev(arg1, "SESSION"))
 			{
@@ -1175,25 +1403,61 @@ DO_COMMAND(do_info)
 				{
 					sprintf(name, "info[SESSION]");
 
-					set_nest_node_ses(ses, name, "{SESSION_NAME}{%s}", ses->name);
-					add_nest_node_ses(ses, name, "{SESSION_ACTIVE}{%d}", gtd->ses == ses);
-					add_nest_node_ses(ses, name, "{SESSION_CLASS}{%s}", ses->group);
-					add_nest_node_ses(ses, name, "{SESSION_CREATED}{%d}", ses->created);
-					add_nest_node_ses(ses, name, "{SESSION_HOST} {%s}", ses->session_host);
-					add_nest_node_ses(ses, name, "{SESSION_IP} {%s}", ses->session_ip);
-					add_nest_node_ses(ses, name, "{SESSION_PORT} {%s}", ses->session_port);
+					set_nest_node_ses(ses, name, "{NAME}{%s}", ses->name);
+					add_nest_node_ses(ses, name, "{ACTIVE}{%d}", gtd->ses == ses);
+					add_nest_node_ses(ses, name, "{CLASS}{%s}", ses->group);
+					add_nest_node_ses(ses, name, "{CREATED}{%d}", ses->created);
+					add_nest_node_ses(ses, name, "{HOST} {%s}", ses->session_host);
+					add_nest_node_ses(ses, name, "{IP} {%s}", ses->session_ip);
+					add_nest_node_ses(ses, name, "{PORT} {%s}", ses->session_port);
 
 					show_message(ses, LIST_COMMAND, "#INFO: DATA WRITTEN TO {info[SESSION]}");
 				}
 				else
 				{
-					tintin_printf2(ses, "{SESSION_NAME}{%s}", ses->name);
-					tintin_printf2(ses, "{SESSION_ACTIVE}{%d}", gtd->ses == ses);
-					tintin_printf2(ses, "{SESSION_CLASS}{%s}", ses->group);
-					tintin_printf2(ses, "{SESSION_CREATED}{%d}", ses->created);
-					tintin_printf2(ses, "{SESSION_HOST} {%s}", ses->session_host);
-					tintin_printf2(ses, "{SESSION_IP} {%s}", ses->session_ip);
-					tintin_printf2(ses, "{SESSION_PORT} {%s}", ses->session_port);
+					tintin_printf2(ses, "{NAME}{%s}", ses->name);
+					tintin_printf2(ses, "{ACTIVE}{%d}", gtd->ses == ses);
+					tintin_printf2(ses, "{CLASS}{%s}", ses->group);
+					tintin_printf2(ses, "{CREATED}{%d}", ses->created);
+					tintin_printf2(ses, "{HOST} {%s}", ses->session_host);
+					tintin_printf2(ses, "{IP} {%s}", ses->session_ip);
+					tintin_printf2(ses, "{PORT} {%s}", ses->session_port);
+				}
+			}
+			else if (is_abbrev(arg1, "SESSIONS"))
+			{
+				struct session *sesptr;
+
+				if (is_abbrev(arg2, "SAVE"))
+				{
+					set_nest_node_ses(ses, "info[SESSIONS]", "");
+
+					for (sesptr = gts ; sesptr ; sesptr = sesptr->next)
+					{
+						sprintf(name, "info[SESSIONS][%s]", sesptr->name);
+
+						add_nest_node_ses(ses, name, "{NAME}{%s}", sesptr->name);
+						add_nest_node_ses(ses, name, "{ACTIVE}{%d}", gtd->ses == sesptr);
+						add_nest_node_ses(ses, name, "{CLASS}{%s}", sesptr->group);
+						add_nest_node_ses(ses, name, "{CREATED}{%d}", sesptr->created);
+						add_nest_node_ses(ses, name, "{HOST} {%s}", sesptr->session_host);
+						add_nest_node_ses(ses, name, "{IP} {%s}", sesptr->session_ip);
+						add_nest_node_ses(ses, name, "{PORT} {%s}", sesptr->session_port);
+					}
+					show_message(ses, LIST_COMMAND, "#INFO: DATA WRITTEN TO {info[SESSION]}");
+				}
+				else
+				{
+					for (sesptr = gts ; sesptr ; sesptr = sesptr->next)
+					{
+						tintin_printf2(ses, "{%s}{NAME}{%s}", sesptr->name, sesptr->name);
+						tintin_printf2(ses, "{%s}{ACTIVE}{%d}", sesptr->name, gtd->ses == sesptr);
+						tintin_printf2(ses, "{%s}{CLASS}{%s}", sesptr->name, sesptr->group);
+						tintin_printf2(ses, "{%s}{CREATED}{%d}", sesptr->name, sesptr->created);
+						tintin_printf2(ses, "{%s}{HOST} {%s}", sesptr->name, sesptr->session_host);
+						tintin_printf2(ses, "{%s}{IP} {%s}", sesptr->name, sesptr->session_ip);
+						tintin_printf2(ses, "{%s}{PORT} {%s}", sesptr->name, sesptr->session_port);
+					}
 				}
 			}
 			else if (is_abbrev(arg1, "STACK"))
@@ -1204,7 +1468,10 @@ DO_COMMAND(do_info)
 			{
 				char cwd[PATH_MAX];
 
-				getcwd(cwd, PATH_MAX);
+				if (getcwd(cwd, PATH_MAX) == NULL)
+				{
+					syserr_printf(ses, "do_info: getcwd:");
+				}
 
 				if (is_abbrev(arg2, "SAVE"))
 				{
@@ -1212,7 +1479,7 @@ DO_COMMAND(do_info)
 
 					set_nest_node_ses(ses, name, "{CLIENT_NAME}{%s}{CLIENT_VERSION}{%s}", CLIENT_NAME, CLIENT_VERSION);
 //					add_nest_node_ses(ses, name, "{CLIENT}{{NAME}{%s}{VERSION}{%s}}", CLIENT_NAME, CLIENT_VERSION);
-					add_nest_node_ses(ses, name, "{CWD}{%s}{EXEC}{%s}{HOME}{%s}{LANG}{%s}{OS}{%s}{TERM}{%s}", cwd, gtd->exec, gtd->home, gtd->lang, gtd->os, gtd->term);
+					add_nest_node_ses(ses, name, "{CWD}{%s}{EXEC}{%s}{HOME}{%s}{LANG}{%s}{OS}{%s}{TERM}{%s}{TINTIN}{%s}", cwd, gtd->system->exec, gtd->system->home, gtd->system->lang, gtd->system->os, gtd->system->term, gtd->system->tt_dir);
 					add_nest_node_ses(ses, name, "{DETACH_FILE}{%s}{ATTACH_FILE}{%s}", gtd->detach_port > 0 ? gtd->detach_file : "", gtd->attach_sock > 0 ? gtd->attach_file : "");
 
 					show_message(ses, LIST_COMMAND, "#INFO: DATA WRITTEN TO {info[SYSTEM]}");
@@ -1222,11 +1489,12 @@ DO_COMMAND(do_info)
 					tintin_printf2(ses, "#INFO SYSTEM: CLIENT_NAME    = %s", CLIENT_NAME);
 					tintin_printf2(ses, "#INFO SYSTEM: CLIENT_VERSION = %s", CLIENT_VERSION);
 					tintin_printf2(ses, "#INFO SYSTEM: CWD            = %s", cwd);
-					tintin_printf2(ses, "#INFO SYSTEM: EXEC           = %s", gtd->exec);
-					tintin_printf2(ses, "#INFO SYSTEM: HOME           = %s", gtd->home);
-					tintin_printf2(ses, "#INFO SYSTEM: LANG           = %s", gtd->lang);
-					tintin_printf2(ses, "#INFO SYSTEM: OS             = %s", gtd->os);
-					tintin_printf2(ses, "#INFO SYSTEM: TERM           = %s", gtd->term);
+					tintin_printf2(ses, "#INFO SYSTEM: EXEC           = %s", gtd->system->exec);
+					tintin_printf2(ses, "#INFO SYSTEM: HOME           = %s", gtd->system->home);
+					tintin_printf2(ses, "#INFO SYSTEM: LANG           = %s", gtd->system->lang);
+					tintin_printf2(ses, "#INFO SYSTEM: OS             = %s", gtd->system->os);
+					tintin_printf2(ses, "#INFO SYSTEM: TERM           = %s", gtd->system->term);
+					tintin_printf2(ses, "#INFO SYSTEM: TINTIN         = %s", gtd->system->tt_dir);
 					tintin_printf2(ses, "#INFO SYSTEM: DETACH_PORT    = %d", gtd->detach_port);
 					tintin_printf2(ses, "#INFO SYSTEM: DETACH_FILE    = %s", gtd->detach_port ? gtd->detach_file : "");
 					tintin_printf2(ses, "#INFO SYSTEM: ATTACH_SOCK    = %d", gtd->attach_sock);

+ 40 - 19
src/debug.c

@@ -26,7 +26,7 @@
 
 #include "tintin.h"
 
-int push_call(char *format, ...)
+int push_call_printf(char *format, ...)
 {
 	int len;
 	va_list ap;
@@ -41,7 +41,7 @@ int push_call(char *format, ...)
 
 		gtd->memory->debug[len] = calloc(1, sizeof(struct stack_data));
 
-		gtd->memory->debug[len]->name = str_alloc(NAME_SIZE);
+		gtd->memory->debug[len]->name = calloc(1, NAME_SIZE);
 	}
 
 	va_start(ap, format);
@@ -52,14 +52,43 @@ int push_call(char *format, ...)
 
 	gtd->memory->debug[len]->index = gtd->memory->stack_len;
 
-	if (gtd->memory->debug_len++ == 1000)
+	if (gtd->memory->debug_len++ == 100)
 	{
-		dump_stack();
+		tintin_printf2(gtd->ses, "\e[1;31merror: push_call_printf: stack size is going past 100.");
+
+		tintin_printf2(gtd->ses, "\e[1;32mDEBUG_STACK[\e[1;31m%03d\e[1;32m] [%03d] = \e[1;31m%s\e[0m", len, gtd->memory->debug[len]->index, gtd->memory->debug[len]->name);
 
-		return 1;
+		return FALSE;
+	}
+	if (gtd->memory->debug_len > 500)
+	{
+		return FALSE;
 	}
+	return TRUE;
+}
+
+void push_call(char *format, ...)
+{
+	int len;
+
+	len = gtd->memory->debug_len;
+
+	if (len == gtd->memory->debug_max)
+	{
+		gtd->memory->debug_max++;
 
-	return 0;
+		gtd->memory->debug = (struct stack_data **) realloc(gtd->memory->debug, sizeof(struct str_data *) * gtd->memory->debug_max);
+
+		gtd->memory->debug[len] = calloc(1, sizeof(struct stack_data));
+
+		gtd->memory->debug[len]->name = calloc(1, NAME_SIZE);
+	}
+
+	strcpy(gtd->memory->debug[len]->name, format);
+
+	gtd->memory->debug[len]->index = gtd->memory->stack_len;
+
+	gtd->memory->debug_len++;
 }
 
 void pop_call(void)
@@ -71,20 +100,13 @@ void pop_call(void)
 	}
 	else
 	{
-		tintin_printf2(gtd->ses, "pop_call: index is zero.");
+		tintin_printf2(gtd->ses, "\e[1;31merror: pop_call: index is zero.");
 
-		unsigned char i;
+		gtd->memory->debug_len = gtd->memory->debug_max;
 
-		tintin_header(gtd->ses, " DEBUG STACK ");
+		dump_stack();
 
-		for (i = 0 ; i < 100 ; i++)
-		{
-			if (i < gtd->memory->debug_max)
-			{
-				tintin_printf2(gtd->ses, "\e[1;31mDEBUG_STACK[%03d] = %s", i, gtd->memory->debug[i]->name);
-			}
-		}
-		tintin_header(gtd->ses, "");
+		gtd->memory->debug_len = 0;
 	}
 }
 
@@ -92,7 +114,7 @@ void dump_stack(void)
 {
 	unsigned int i;
 
-	if (gtd)
+	if (gtd && gtd->ses)
 	{
 		for (i = 0 ; i < gtd->memory->debug_len ; i++)
 		{
@@ -100,4 +122,3 @@ void dump_stack(void)
 		}
 	}
 }
-

+ 87 - 16
src/dict.c

@@ -27,20 +27,83 @@
 
 #include "dict.h"
 
-int dictionary_search(char **array, int array_size, char *key)
+struct dictionary_data
 {
-        // Copyright 2014-2020 Igor van den Hoven
+	unsigned int  * wordindex[26];
+	int             listsize[26];
+};
 
+struct dictionary_data *dictionary;
+
+void dictionary_init()
+{
+	char *pta;
+	int index, hash;
+
+	dictionary = calloc(1, sizeof(struct dictionary_data));
+
+	for (hash = 0 ; hash < 26 ; hash++)
+	{
+		index = 1;
+
+		pta = wordlist[hash];
+
+		do
+		{
+			pta++;
+
+			if (*pta == 0)
+			{
+				index++;
+				pta++;
+			}
+		}
+		while (*pta);
+
+		dictionary->listsize[hash] = index;
+
+		dictionary->wordindex[hash] = calloc(index, sizeof(int));
+	}
+
+	for (hash = 0 ; hash < 26 ; hash++)
+	{
+		index = 1;
+
+		pta = wordlist[hash] + 1;
+
+		do
+		{
+			dictionary->wordindex[hash][index++] = pta - wordlist[hash];
+
+			while (*pta)
+			{
+				pta++;
+			}
+			pta++;
+		}
+		while (*pta);
+	}
+
+//	for (hash = 0 ; hash < 26 ; hash++)
+//	{
+//		printf("hash %2d = %d\n", hash, dictionary->listsize[hash]);
+//	}
+}
+
+int dictionary_search(int hash, char *key)
+{
 	register int mid, i, bot;
 	register char val;
 
 	bot = 0;
-	i = array_size - 1;
+	i = dictionary->listsize[hash] - 1;
 	mid = i / 2;
 
 	while (mid)
 	{
-		val = strcmp(key, array[i - mid]);
+		val = strcmp(key, wordlist[hash] + dictionary->wordindex[hash][i - mid]);
+
+//		printf("debug: %5d '%c' %s\n", i - mid, 'a' + hash, wordlist[hash] + dictionary->wordindex[hash][i - mid]);
 
 		if (val < 0)
 		{
@@ -48,7 +111,7 @@ int dictionary_search(char **array, int array_size, char *key)
 		}
 		else if (val > 0)
 		{
-			bot = i - mid;
+			bot = i - mid + 1;
 		}
 		else
 		{
@@ -59,7 +122,7 @@ int dictionary_search(char **array, int array_size, char *key)
 
 	if (i > bot)
 	{
-		val = strcmp(key, array[i]);
+		val = strcmp(key, wordlist[hash] + dictionary->wordindex[hash][i]);
 
 		if (val > 0)
 		{
@@ -75,7 +138,7 @@ int dictionary_search(char **array, int array_size, char *key)
 		}
 	}
 
-	if (!strcmp(key, array[i]))
+	if (!strcmp(key, wordlist[hash] + dictionary->wordindex[hash][i]))
 	{
 		return i;
 	}
@@ -91,7 +154,7 @@ void dictionary_lowerstring(char *in, char *out)
 
 	while (*pti)
 	{
-		if (isalpha((int) *pti))
+		if (is_alpha(*pti))
 		{
 			*pto++ = tolower(*pti++);
 		}
@@ -108,6 +171,11 @@ int spellcheck_count(struct session *ses, char *in)
 	char *arg, arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 	int cnt, hash, index;
 
+	if (dictionary == NULL)
+	{
+		dictionary_init();
+	}
+
 	cnt = 0;
 	arg = in;
 
@@ -117,11 +185,11 @@ int spellcheck_count(struct session *ses, char *in)
 
 		dictionary_lowerstring(arg1, arg2);
 
-		if (isalpha((int) *arg2))
+		if (is_alpha(*arg2))
 		{
 			hash = *arg2 - 'a';
 
-			index = dictionary_search(wordlist[hash], wordlist_size[hash], arg2 + 1);
+			index = dictionary_search(hash, arg2 + 1);
 
 			if (index == -1)
 			{
@@ -139,11 +207,16 @@ int spellcheck_count(struct session *ses, char *in)
 
 DO_COMMAND(do_dictionary)
 {
-	int hash, size, index;
+	int hash, index;
+
+	if (dictionary == NULL)
+	{
+		dictionary_init();
+	}
 
 	sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
 
-	if (*arg1 == 0 || !isalpha((int) *arg1))
+	if (*arg1 == 0 || !is_alpha(*arg1))
 	{
 		show_message(ses, LIST_COMMAND, "#SYNTAX: #DICTIONARY {WORD}");
 
@@ -158,13 +231,11 @@ DO_COMMAND(do_dictionary)
 
 		dictionary_lowerstring(arg2, arg3);
 
-		if (isalpha((int) *arg3))
+		if (is_alpha(*arg3))
 		{
 			hash = *arg3 - 'a';
 
-			size = wordlist_size[hash];
-
-			index = dictionary_search(wordlist[hash], size, arg3 + 1);
+			index = dictionary_search(hash, arg3 + 1);
 
 			if (index == -1)
 			{

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
src/dict.h


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 648 - 223
src/draw.c


+ 437 - 0
src/edit.c

@@ -0,0 +1,437 @@
+/******************************************************************************
+*   This file is part of TinTin++                                             *
+*                                                                             *
+*   Copyright (C) 2004-2020 Igor van den Hoven                                *
+*                                                                             *
+*   TinTin++ is free software; you can redistribute it and/or modify          *
+*   it under the terms of the GNU General Public License as published by      *
+*   the Free Software Foundation; either version 3 of the License, or         *
+*   (at your option) any later version.                                       *
+*                                                                             *
+*   This program is distributed in the hope that it will be useful,           *
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of            *
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
+*   GNU General Public License for more details.                              *
+*                                                                             *
+*   You should have received a copy of the GNU General Public License         *
+*   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
+******************************************************************************/
+
+/******************************************************************************
+*                               T I N T I N + +                               *
+*                                                                             *
+*                      coded by Igor van den Hoven 2020                       *
+******************************************************************************/
+
+#include "tintin.h"
+
+DO_COMMAND(do_edit)
+{
+	int cnt;
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+
+	if (*arg1 == 0)
+	{
+		tintin_header(ses, 80, " EDIT OPTIONS ");
+
+		for (cnt = 0 ; edit_table[cnt].fun ; cnt++)
+		{
+			if (*edit_table[cnt].desc)
+			{
+				tintin_printf2(ses, "  [%-18s] %s", edit_table[cnt].name, edit_table[cnt].desc);
+			}
+		}
+		tintin_header(ses, 80, "");
+	}
+	else
+	{
+		for (cnt = 0 ; edit_table[cnt].fun ; cnt++)
+		{
+			if (is_abbrev(arg1, edit_table[cnt].name))
+			{
+				edit_table[cnt].fun(ses, arg, arg1, arg2);
+
+				return ses;
+			}
+		}
+		show_error(ses, LIST_COMMAND, "#ERROR: #EDIT {%s} IS NOT A VALID OPTION.", arg1);
+	}
+	return ses;
+}
+
+DO_EDIT(edit_create)
+{
+	struct edit_data *edit = gtd->ses->input->edit;
+	char *pta, *ptn;
+	int index;
+
+	clear_editor(edit);
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+
+	str_cpy(&gtd->ses->input->edit_name, arg1);
+
+	index = 0;
+
+	while (*arg)
+	{
+		arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+
+		pta = arg1;
+		ptn = strchr(pta, '\n');
+
+		while (ptn)
+		{
+			*ptn++ = 0;
+
+			if (*ptn)
+			{
+				insert_line(edit, index++, pta);
+
+				pta = ptn;
+			}
+			ptn = strchr(pta, '\n');
+		}
+		insert_line(edit, index++, pta);
+	}
+
+	show_message(ses, LIST_COMMAND, "#EDIT CREATE: CREATED %d LINES.", edit->used);
+
+	enable_editor(edit);
+
+	return ses;
+}
+
+DO_EDIT(edit_load)
+{
+	struct edit_data *edit = gtd->ses->input->edit;
+	struct listnode *node;
+	int index;
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+
+	if ((node = search_nest_node_ses(ses, arg1)) == NULL)
+	{
+		show_error(ses, LIST_COMMAND, "#EDIT LOAD: VARIABLE {%s} NOT FOUND.", arg1);
+		
+		return ses;
+	}
+
+	if (node->root == NULL)
+	{
+		return edit_create(ses, node->arg1, arg1, arg2);
+	}
+
+	clear_editor(edit);
+
+	for (index = 0 ; index < node->root->used ; index++)
+	{
+		substitute(ses, node->root->list[index]->arg1, arg2, SUB_ESC);
+
+		insert_line(edit, index, arg2);
+	}
+
+	show_message(ses, LIST_COMMAND, "#EDIT LOAD: LOADED %d LINES FROM {%s}.", edit->used, arg1);
+
+	enable_editor(edit);
+
+	return ses;
+}
+
+DO_EDIT(edit_save)
+{
+	struct edit_data *edit = gtd->ses->input->edit;
+	struct listnode *node;
+	int index;
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+
+	if (!valid_variable(ses, arg1))
+	{
+		show_error(ses, LIST_VARIABLE, "#EDIT SAVE: INVALID VARIABLE NAME {%s}.", arg1);
+
+		return ses;
+	}
+
+	node = set_nest_node_ses(ses, arg1, "");
+
+	node->root = init_list(gtd->ses, LIST_VARIABLE, LIST_SIZE);
+
+	for (index = 0 ; index < edit->used ; index++)
+	{
+		substitute(ses, edit->line[index]->str, arg2, SUB_SEC);
+
+		create_node_list(node->root, ntos(index), arg2, "", "");
+	}
+
+	show_message(ses, LIST_COMMAND, "#EDIT SAVE: SAVED %d LINES TO {%s}.", edit->used, arg1);
+
+	return ses;
+}
+
+DO_EDIT(edit_read)
+{
+	struct edit_data *edit = gtd->ses->input->edit;
+	FILE *file;
+	int index, size;
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+
+	if (*arg1 == 0)
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #EDIT READ {<FILENAME>}");
+
+		return ses;
+	}
+
+	if ((file = fopen(arg1, "r")) == NULL)
+	{
+		show_error(ses, LIST_COMMAND, "#ERROR: #EDIT READ: FILE {%s} NOT FOUND.", arg1);
+
+		return ses;
+	}
+
+	clear_editor(edit);
+
+	str_cpy(&gtd->ses->input->edit_name, arg1);
+
+	index = 0;
+	size  = 0;
+
+	while (fread_one_line(&arg2, file))
+	{
+		size += str_len(arg2);
+
+		insert_line(edit, index++, arg2);
+	}
+
+	show_message(ses, LIST_COMMAND, "#EDIT READ: READ %d LINES FROM {%s}.", edit->used, arg1);
+
+	enable_editor(edit);
+
+	fclose(file);
+
+	return ses;
+}
+
+DO_EDIT(edit_write)
+{
+	struct edit_data *edit = gtd->ses->input->edit;
+	FILE *file;
+	int index;
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+
+	if (*arg1 == 0)
+	{
+		str_cpy(&arg1, gtd->ses->input->edit_name);
+	}
+
+	if ((file = fopen(arg1, "w")) == NULL)
+	{
+		show_error(ses, LIST_COMMAND, "#ERROR: #EDIT WRITE: COULDN'T OPEN {%s} TO WRITE.", arg1);
+
+		return ses;
+	}
+
+	for (index = 0 ; index < edit->used ; index++)
+	{
+		fputs(edit->line[index]->str, file);
+
+		putc(ASCII_LF, file);
+	}
+
+	show_message(ses, LIST_COMMAND, "#EDIT WRITE: WROTE %d LINES TO {%s}.", index, arg1);
+
+	return ses;
+}
+
+DO_EDIT(edit_resume)
+{
+	struct edit_data *edit = gtd->ses->input->edit;
+
+	SET_BIT(gtd->ses->input->flags, INPUT_FLAG_EDIT);
+
+	if (edit->size == edit->update)
+	{
+		insert_line(edit, edit->update, "");
+	}
+
+	inputline_set(edit->line[edit->update]->str, 0);
+
+	cursor_redraw_edit(ses, "");
+
+	return ses;
+}
+
+DO_EDIT(edit_suspend)
+{
+	struct edit_data *edit = gtd->ses->input->edit;
+
+	DEL_BIT(gtd->ses->input->flags, INPUT_FLAG_EDIT);
+
+	str_cpy(&edit->line[edit->update]->str, gtd->ses->input->buf);
+
+	cursor_clear_line(ses, "");
+
+	cursor_redraw_edit(ses, "");
+
+	return ses;
+}
+
+struct edit_data *create_editor(void)
+{
+	return calloc(1, sizeof(struct edit_data));
+}
+
+void delete_editor(struct edit_data *edit)
+{
+	if (edit == NULL)
+	{
+		tintin_printf2(gtd->ses, "destroy_edit: NULL");
+
+		return;
+	}
+
+	clear_editor(edit);
+
+	free(edit);
+}
+
+void resize_editor(struct edit_data *edit, int size)
+{
+	if (edit->size < size)
+	{
+		edit->size = size;
+
+		edit->line = (struct row_data **) realloc(edit->line, edit->size * sizeof(struct row_data *));
+	}
+}
+
+void clear_editor(struct edit_data *edit)
+{
+	int index;
+
+	edit->update = 0;
+
+	for (index = edit->used - 1 ; index >= 0 ; index--)
+	{
+		delete_line(edit, index);
+	}
+
+}
+
+void enable_editor(struct edit_data *edit)
+{
+	char *str1;
+	int filesize;
+
+	SET_BIT(gtd->ses->input->flags, INPUT_FLAG_EDIT);
+
+	if (edit->used == 0)
+	{
+		create_line(edit, 0, "");
+	}
+
+	inputline_set(edit->line[edit->update]->str, 0);
+
+	str1 = str_alloc_stack(0);
+
+	filesize = str_save_editor(gtd->ses->input->edit, &str1);
+
+	cursor_redraw_edit(gtd->ses, "");
+
+	check_all_events(gtd->ses, EVENT_FLAG_INPUT, 0, 4, "STARTED EDITING", gtd->ses->input->edit_name, ntos(edit->used), ntos(filesize), str1);
+
+	if (*gtd->ses->input->edit_name)
+	{
+		check_all_events(gtd->ses, EVENT_FLAG_INPUT, 1, 4, "STARTED EDITING %s", gtd->ses->input->edit_name, gtd->ses->input->edit_name, ntos(edit->used), ntos(filesize), str1);
+	}
+}
+
+int str_save_editor(struct edit_data *edit, char **str)
+{
+	int index, size;
+
+	size = 0;
+
+	str_cpy(str, "");
+
+	for (index = 0 ; index < edit->used ; index++)
+	{
+		str_cat_printf(str, "%s\n", edit->line[index]->str);
+
+		size += str_len(edit->line[index]->str);
+	}
+	return size;
+}
+
+int var_save_editor(struct edit_data *edit, char **str)
+{
+	int index, size;
+
+	size = 0;
+
+	for (index = 0 ; index < edit->used ; index++)
+	{
+		str_cat_printf(str, "{%d}{%s}", index + 1, edit->line[index]->str);
+	}
+	return size;
+}
+
+void create_line(struct edit_data *edit, int index, char *str)
+{
+	resize_editor(edit, index + 2);
+
+	edit->line[index]      = (struct row_data *) calloc(1, sizeof(struct row_data));
+	edit->line[index]->str = str_dup(str);
+
+	edit->used++;
+}
+
+void delete_line(struct edit_data *edit, int index)
+{
+	str_free(edit->line[index]->str);
+
+	free(edit->line[index]);
+
+	edit->used--;
+}
+
+void insert_line(struct edit_data *edit, int index, char *str)
+{
+	int cnt;
+
+	if (index >= edit->used)
+	{
+		while (edit->used < index)
+		{
+			create_line(edit, edit->used, "");
+		}
+		create_line(edit, edit->used, str);
+
+		return;
+	}
+
+	resize_editor(edit, edit->used + 2);
+
+	for (cnt = edit->used ; cnt > index ; cnt--)
+	{
+		edit->line[cnt] = edit->line[cnt - 1];
+	}
+
+	create_line(edit, index, str);
+}
+
+void remove_line(struct edit_data *edit, int index)
+{
+	int cnt;
+
+	delete_line(edit, index);
+
+	for (cnt = index ; cnt < edit->used ; cnt++)
+	{
+		edit->line[cnt] = edit->line[cnt + 1];
+	}
+}

+ 266 - 125
src/event.c

@@ -28,42 +28,131 @@
 
 DO_COMMAND(do_event)
 {
+	struct listroot *root = ses->list[LIST_EVENT];
 	struct listnode *node;
-	int cnt;
+	int cnt, found, index;
+	char symbol;
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
 
 	if (*arg1 == 0)
 	{
-		tintin_header(ses, " EVENTS ");
+		tintin_header(ses, 80, " EVENTS ");
 
 		for (cnt = 0 ; *event_table[cnt].name != 0 ; cnt++)
 		{
-			tintin_printf2(ses, "%s [%-27s] %s", search_node_list(ses->list[LIST_EVENT], event_table[cnt].name) ? "+" : " ", event_table[cnt].name, event_table[cnt].desc);
+			symbol = ' ';
+
+			if (event_table[cnt].level)
+			{
+				symbol = '-';
+
+				if (HAS_BIT(ses->event_flags, event_table[cnt].flags))
+				{
+					found = 0;
+
+					for (index = 0 ; index < root->used ; index++)
+					{
+						node = root->list[index];
+
+						if (!strncmp(event_table[cnt].name, node->arg1, strlen(event_table[cnt].name)))
+						{
+							found++;
+						}
+					}
+
+					switch (found)
+					{
+						case 0:
+							break;
+						case 1:
+							symbol = '+';
+							break;
+						default:
+							symbol = '*';
+							break;
+					}
+				}
+			}
+			tintin_printf2(ses, "%c [%-26s] [%-8s] %s", symbol, event_table[cnt].name, event_table[cnt].group, event_table[cnt].desc);
 		}
-		tintin_header(ses, "");
+		tintin_header(ses, 80, "");
 	}
 	else if (*arg2 == 0)
 	{
-		if (show_node_with_wild(ses, arg1, ses->list[LIST_EVENT]) == FALSE)
+		if (show_node_with_wild(ses, arg1, root) == FALSE)
 		{
-			show_message(ses, LIST_ALIAS, "#EVENT: NO MATCH(ES) FOUND FOR {%s}.", arg1);
+			symbol = 0;
+
+			for (cnt = 0 ; *event_table[cnt].name != 0 ; cnt++)
+			{
+				if (!strcasecmp(event_table[cnt].group, arg1))
+				{
+					symbol = ' ';
+
+					if (event_table[cnt].level)
+					{
+						symbol = '-';
+
+						if (HAS_BIT(ses->event_flags, event_table[cnt].flags))
+						{
+							found = 0;
+
+							for (index = 0 ; index < root->used ; index++)
+							{
+								node = root->list[index];
+
+								if (!strncmp(event_table[cnt].name, node->arg1, str_len(node->arg1)))
+								{
+									found++;
+								}
+							}
+
+							switch (found)
+							{
+								case 0:
+									break;
+								case 1:
+									symbol = '+';
+									break;
+								default:
+									symbol = '*';
+									break;
+							}
+						}
+					}
+					tintin_printf2(ses, "%c [%-26s] [%-8s] %s", symbol, event_table[cnt].name, event_table[cnt].group, event_table[cnt].desc);
+				}
+			}
+
+			if (symbol == 0)
+			{
+				show_message(ses, LIST_ALIAS, "#EVENT: NO MATCH(ES) FOUND FOR {%s}.", arg1);
+			}
 		}
 	}
 	else
 	{
-		for (cnt = 0 ; *event_table[cnt].name != 0 ; cnt++)
+		for (index = 0 ; *event_table[index].name != 0 ; index++)
 		{
-			if (!strncmp(event_table[cnt].name, arg1, strlen(event_table[cnt].name)))
+			if (!strncmp(event_table[index].name, arg1, strlen(event_table[index].name)))
 			{
 				show_message(ses, LIST_EVENT, "#EVENT {%s} HAS BEEN SET TO {%s}.", arg1, arg2);
 
-				SET_BIT(ses->event_flags, event_table[cnt].flags);
+				SET_BIT(ses->event_flags, event_table[index].flags);
+				SET_BIT(gtd->event_flags, event_table[index].flags);
 
-				node = update_node_list(ses->list[LIST_EVENT], arg1, arg2, "", "");
+				node = update_node_list(root, arg1, arg2, "", "");
 
-				node->val64 = event_table[cnt].flags;
+				node->val32[0] = index;
+				node->val32[1] = event_table[index].flags;
+
+				if (node->val32[1] == 0)
+				{
+					tintin_printf2(gtd->ses, "\e[1;33mdo_event: event_table[index].flags == 0");
+				}
+				event_table[index].level++;
 
 				return ses;
 			}
@@ -84,20 +173,47 @@ int check_all_events(struct session *ses, int flags, int args, int vars, char *f
 {
 	struct session *ses_ptr;
 	struct listnode *node;
-	char *name, buf[BUFFER_SIZE];
+	char *name, *buf;
 	va_list list;
-	int cnt;
+	int cnt, sub, found;
 
 	if (gtd->level->ignore)
 	{
 		return 0;
 	}
 
+	sub = HAS_BIT(flags, SUB_SEC) ? SUB_ARG|SUB_SEC : SUB_ARG;
+
+	DEL_BIT(flags, SUB_ARG|SUB_SEC);
+
+	if (flags == 0)
+	{
+		tintin_printf2(ses, "\e[1;31merror: check_all_events: flags = %d", flags);
+
+		return 0;
+	}
+
+	if (gtd->level->info == 0 && !HAS_BIT(gtd->ses->list[LIST_EVENT]->flags, LIST_FLAG_INFO))
+	{
+		if (!HAS_BIT(gtd->event_flags, flags))
+		{
+			return 0;
+		}
+
+		if (ses && !HAS_BIT(ses->event_flags, flags))
+		{
+			return 0;
+		}
+	}
+
 	if (args)
 	{
 		va_start(list, fmt);
 
-		vasprintf(&name, fmt, list);
+		if (vasprintf(&name, fmt, list) == -1)
+		{
+			syserr_printf(ses, "check_all_events: vasprintf:");
+		}
 
 		va_end(list); 
 	}
@@ -108,11 +224,15 @@ int check_all_events(struct session *ses, int flags, int args, int vars, char *f
 
 	push_call("check_all_events(%p,%d,%d,%d,%s, ...)",ses,flags,args,vars,name);
 
+	buf = str_alloc_stack(0);
+
+	found = 0;
+
 	for (ses_ptr = ses ? ses : gts ; ses_ptr ; ses_ptr = ses_ptr->next)
 	{
 		if (!HAS_BIT(ses_ptr->list[LIST_EVENT]->flags, LIST_FLAG_IGNORE))
 		{
-			if (!HAS_BIT(flags, SUB_SIL))
+			if (!HAS_BIT(flags, EVENT_FLAG_UPDATE))
 			{
 				show_info(ses_ptr, LIST_EVENT, "#INFO EVENT {%s} ARGUMENTS {%d}", name, vars);
 			}
@@ -121,8 +241,15 @@ int check_all_events(struct session *ses, int flags, int args, int vars, char *f
 
 			if (node)
 			{
-				if (vars)
+				if (node->val32[1] != flags)
+				{
+					tintin_printf2(ses, "\e[1;31merror: check_all_events: %s: flags: %d != %d", name, flags, node->val32[1]);
+				}
+
+				if (vars > 0 && found == 0)
 				{
+					found = 1;
+
 					va_start(list, fmt);
 
 					for (cnt = 0 ; cnt < args ; cnt++)
@@ -137,11 +264,11 @@ int check_all_events(struct session *ses, int flags, int args, int vars, char *f
 					va_end(list);
 				}
 
-				substitute(ses_ptr, node->arg2, buf, flags);
+				substitute(ses_ptr, node->arg2, buf, sub);
 
-				if (!HAS_BIT(flags, SUB_SIL) && HAS_BIT(ses_ptr->list[LIST_EVENT]->flags, LIST_FLAG_DEBUG))
+				if (!HAS_BIT(flags, EVENT_FLAG_UPDATE) && HAS_BIT(ses_ptr->list[LIST_EVENT]->flags, LIST_FLAG_DEBUG))
 				{
-					show_debug(ses_ptr, LIST_EVENT, "#DEBUG EVENT {%s} (%s}", node->arg1, node->arg2);
+					show_debug(ses_ptr, LIST_EVENT, "#DEBUG EVENT {%s} {%s}", node->arg1, node->arg2);
 				}
 
 				if (node->shots && --node->shots == 0)
@@ -149,54 +276,89 @@ int check_all_events(struct session *ses, int flags, int args, int vars, char *f
 					delete_node_list(ses, LIST_EVENT, node);
 				}
 
-				gtd->level->quiet += HAS_BIT(flags, SUB_SIL) ? 1 : 0;
+				gtd->level->quiet += HAS_BIT(flags, EVENT_FLAG_UPDATE) ? 1 : 0;
 
 				script_driver(ses_ptr, LIST_EVENT, buf);
 
-				gtd->level->quiet -= HAS_BIT(flags, SUB_SIL) ? 1 : 0;
+				gtd->level->quiet -= HAS_BIT(flags, EVENT_FLAG_UPDATE) ? 1 : 0;
 
 				if (ses)
 				{
 					free(name);
 
 					pop_call();
-					return 1;
+					return TRUE;
 				}
 			}
 		}
 
 		if (ses)
 		{
-			free(name);
-
-			pop_call();
-			return 0;
+			goto end;
 		}
 	}
+
+	end:
+
 	free(name);
 
 	pop_call();
 	return 0;
 }
 
+void mouse_event_handler(struct session *ses, char *arg1, char *arg2, int row, int col, int rev_row, int rev_col, int pix_row, int pix_col, char *grid, char *word, char *line, char *link, char *name);
+
 void mouse_handler(struct session *ses, int flags, int row, int col)
 {
-	char *arg1, *arg2, line[BUFFER_SIZE];
+	char *arg1, *arg2, *line, *name, link[NUMBER_SIZE];
+	char *grid, *grid_val[] = { "nw", "n", "ne", "w", "c", "e", "sw", "s", "se" };
 	static char word[BUFFER_SIZE];
 	static char last[100], dir[10];
 	static long long click[3];
 	static int swipe[10];
-	int debug, info, rev_row, rev_col, link;
+	int debug, info, rev_row, rev_col, option, pix_row, pix_col, char_row, char_col, grid_pos = 4;
 
 	push_call("mouse_handler(%p,%d,%d,%d,%c)",ses,flags,row,col);
 
-	arg1 = str_alloc_stack();
-	arg2 = str_alloc_stack();
+	arg1 = str_alloc_stack(0);
+	arg2 = str_alloc_stack(0);
+
+	line = str_alloc_stack(0);
+	name = str_alloc_stack(0);
+
+	if (HAS_BIT(ses->config_flags, CONFIG_FLAG_MOUSEPIXELS))
+	{
+		pix_row = row;
+		pix_col = col;
+
+		char_row = (row - 1) % gtd->screen->char_height + 1;
+		char_col = (col - 1) % gtd->screen->char_width  + 1;
+
+//		if (flags == 8) tintin_printf2(NULL, "debug: rpx %4d cpx %4d\n", pix_row, pix_col);
+
+		row = 1 + (row - 1) / gtd->screen->char_height;
+		col = 1 + (col - 1) / gtd->screen->char_width;
+
+//		if (flags == 8) tintin_printf2(NULL, "debug: row %4d col %4d\n", row, col);
+
+//		if (flags == 8) tintin_printf2(NULL, "debug: rpx %4d/%d cpx %4d/%d\n\n\n", char_row, gtd->screen->char_height, char_col, gtd->screen->char_width);
+
+		grid_pos  = char_row * 3 / gtd->screen->char_height * 3;
+		grid_pos += char_col * 3 / gtd->screen->char_width;
+	}
+	else
+	{
+		pix_row = 0;
+		pix_col = 0;
+		char_row = 0;
+		char_col = 0;
+	}
+	grid = grid_val[grid_pos];
 
 /*
 	if (!HAS_BIT(ses->event_flags, EVENT_FLAG_MOUSE))
 	{
-		if (!HAS_BIT(ses->flags, SES_FLAG_MOUSEINFO) && !HAS_BIT(ses->list[LIST_EVENT]->flags, LIST_FLAG_INFO))
+		if (!HAS_BIT(ses->config_flags, CONFIG_FLAG_MOUSEINFO) && !HAS_BIT(ses->list[LIST_EVENT]->flags, LIST_FLAG_INFO))
 		{
 			pop_call();
 			return;
@@ -261,7 +423,36 @@ void mouse_handler(struct session *ses, int flags, int row, int col)
 
 	get_line_screen(line, row - 1);
 
-	link = get_link_screen(ses, word, flags, row, col);
+	option = get_link_screen(ses, name, word, flags, row, col);
+
+	link[0] = 0;
+
+	switch (option)
+	{
+		case 1:
+			strcpy(link, "LINK");
+			break;
+		case 2:
+			strcpy(link, "SECURE LINK");
+			break;
+		case 3:
+			strcpy(link, "URL LINK");
+			break;
+		case 4:
+			strcpy(link, "JUMP MARK");
+			break;
+		case 5:
+			strcpy(link, "JUMP LINK");
+			break;
+		case 6:
+			if (flags == 0)
+			{
+				tintin_printf2(ses, "\e[1;32m         %s\n", capitalize(word));
+
+				command(ses, do_help, "{%s}", word);
+			}
+			break;
+	}
 
 	if (HAS_BIT(flags, MOUSE_FLAG_WHEEL))
 	{
@@ -300,43 +491,22 @@ void mouse_handler(struct session *ses, int flags, int row, int col)
 		}
 	}
 
-	debug = HAS_BIT(ses->flags, SES_FLAG_MOUSEDEBUG) ? 1 : 0;
-	info  = HAS_BIT(ses->flags, SES_FLAG_MOUSEINFO) ? 1 : 0;
+	debug = HAS_BIT(ses->config_flags, CONFIG_FLAG_MOUSEDEBUG) ? 1 : 0;
+	info  = HAS_BIT(ses->config_flags, CONFIG_FLAG_MOUSEINFO) ? 1 : 0;
 
 	gtd->level->debug += debug;
 	gtd->level->info  += info;
-
+/*
 	if (!HAS_BIT(ses->list[LIST_BUTTON]->flags, LIST_FLAG_IGNORE))
 	{
 		check_all_buttons(ses, row, col, arg1, arg2, word, line);
 	}
-
+*/
 	rev_row = -1 - (gtd->screen->rows - row);
 	rev_col = -1 - (gtd->screen->cols - col);
 
-	switch (link)
-	{
-		case 1:
-			check_all_events(ses, SUB_ARG, 2, 6, "%s LINK %s", arg1, arg2, ntos(row), ntos(col), ntos(rev_row), ntos(-1 - (gtd->screen->cols - col)), word, line);
-			break;
-
-		case 2:
-			if (flags == 0)
-			{
-				tintin_printf2(ses, "\e[1;32m         %s\n", capitalize(word));
-
-				execute(ses, "#HELP {%s}", word);
-			}
-			break;
-	}
-
-	check_all_events(ses, SUB_ARG, 2, 6, "%s %s", arg1, arg2, ntos(row), ntos(col), ntos(rev_row), ntos(-1 - (gtd->screen->cols - col)), word, line);
-
-	check_all_events(ses, SUB_ARG, 3, 6, "%s %s %d", arg1, arg2, row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
-
-	check_all_events(ses, SUB_ARG, 3, 6, "%s %s %d", arg1, arg2, rev_row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
 
-	map_mouse_handler(ses, arg1, arg2, row, col, rev_row, rev_col, 0, 0);
+	mouse_event_handler(ses, arg1, arg2, row, col, rev_row, rev_col, pix_row, pix_col, grid, word, line, link, name);
 
 	if (!strcmp(arg1, "PRESSED"))
 	{
@@ -357,45 +527,13 @@ void mouse_handler(struct session *ses, int flags, int row, int col)
 			{
 				if (click[0] - click[2] < 500000)
 				{
-					if (!HAS_BIT(ses->list[LIST_BUTTON]->flags, LIST_FLAG_IGNORE))
-					{
-						check_all_buttons(ses, row, col, "TRIPLE-CLICKED", arg2, word, line);
-					}
-
-					if (link)
-					{
-						check_all_events(ses, SUB_ARG, 1, 6, "TRIPLE-CLICKED LINK %s", arg2, ntos(row), ntos(col), ntos(rev_row), ntos(-1 - (gtd->screen->cols - col)), word, line);
-					}
-
-					check_all_events(ses, SUB_ARG, 1, 6, "TRIPLE-CLICKED %s", arg2, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
-
-					check_all_events(ses, SUB_ARG, 2, 6, "TRIPLE-CLICKED %s %d", arg2, row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
-
-					check_all_events(ses, SUB_ARG, 2, 6, "TRIPLE-CLICKED %s %d", arg2, rev_row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
-
-					map_mouse_handler(ses, "TRIPPLE-CLICKED", arg2, row, col, rev_row, rev_col, 0, 0);
+					mouse_event_handler(ses, "TRIPLE-CLICKED", arg2, row, col, rev_row, rev_col, pix_row, pix_col, grid, word, line, link, name);
 
 					strcpy(last, "");
 				}
 				else
 				{
-					if (!HAS_BIT(ses->list[LIST_BUTTON]->flags, LIST_FLAG_IGNORE))
-					{
-						check_all_buttons(ses, row, col, "DOUBLE-CLICKED", arg2, word, line);
-					}
-
-					if (link)
-					{
-						check_all_events(ses, SUB_ARG, 1, 6, "DOUBLE-CLICKED LINK %s", arg2, ntos(row), ntos(col), ntos(rev_row), ntos(-1 - (gtd->screen->cols - col)), word, line);
-					}
-
-					check_all_events(ses, SUB_ARG, 1, 6, "DOUBLE-CLICKED %s", arg2, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
-
-					check_all_events(ses, SUB_ARG, 2, 6, "DOUBLE-CLICKED %s %d", arg2, row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
-
-					check_all_events(ses, SUB_ARG, 2, 6, "DOUBLE-CLICKED %s %d", arg2, rev_row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
-
-					map_mouse_handler(ses, "DOUBLE-CLICKED", arg2, row, col, rev_row, rev_col, 0, 0);
+					mouse_event_handler(ses, "DOUBLE-CLICKED", arg2, row, col, rev_row, rev_col, pix_row, pix_col, grid, word, line, link, name);
 				}
 			}
 		}
@@ -436,47 +574,19 @@ void mouse_handler(struct session *ses, int flags, int row, int col)
 			{
 				strcpy(dir, swipe[9] > 0 ? "NE" : "NW");
 			}
-			check_all_events(ses, SUB_ARG, 0, 12, "SWIPED", dir, arg2, ntos(swipe[0]), ntos(swipe[1]), ntos(swipe[2]), ntos(swipe[3]), ntos(swipe[4]), ntos(swipe[5]), ntos(swipe[6]), ntos(swipe[7]), ntos(swipe[8]), ntos(swipe[9]));			
-			check_all_events(ses, SUB_ARG, 1, 12, "SWIPED %s", dir, dir, arg2, ntos(swipe[0]), ntos(swipe[1]), ntos(swipe[2]), ntos(swipe[3]), ntos(swipe[4]), ntos(swipe[5]), ntos(swipe[6]), ntos(swipe[7]), ntos(swipe[8]), ntos(swipe[9]));
-			check_all_events(ses, SUB_ARG, 2, 12, "SWIPED %s %s", arg2, dir, dir, arg2, ntos(swipe[0]), ntos(swipe[1]), ntos(swipe[2]), ntos(swipe[3]), ntos(swipe[4]), ntos(swipe[5]), ntos(swipe[6]), ntos(swipe[7]), ntos(swipe[8]), ntos(swipe[9]));
+			check_all_events(ses, EVENT_FLAG_MOUSE, 0, 12, "SWIPED", dir, arg2, ntos(swipe[0]), ntos(swipe[1]), ntos(swipe[2]), ntos(swipe[3]), ntos(swipe[4]), ntos(swipe[5]), ntos(swipe[6]), ntos(swipe[7]), ntos(swipe[8]), ntos(swipe[9]));			
+			check_all_events(ses, EVENT_FLAG_MOUSE, 1, 12, "SWIPED %s", dir, dir, arg2, ntos(swipe[0]), ntos(swipe[1]), ntos(swipe[2]), ntos(swipe[3]), ntos(swipe[4]), ntos(swipe[5]), ntos(swipe[6]), ntos(swipe[7]), ntos(swipe[8]), ntos(swipe[9]));
+			check_all_events(ses, EVENT_FLAG_MOUSE, 2, 12, "SWIPED %s %s", arg2, dir, dir, arg2, ntos(swipe[0]), ntos(swipe[1]), ntos(swipe[2]), ntos(swipe[3]), ntos(swipe[4]), ntos(swipe[5]), ntos(swipe[6]), ntos(swipe[7]), ntos(swipe[8]), ntos(swipe[9]));
 		}
 		else if (utime() - click[0] >= 500000)
 		{
-			
-			check_all_buttons(ses, row, col, "LONG-CLICKED", arg2, word, line);
-
-			if (link)
-			{
-				check_all_events(ses, SUB_ARG, 1, 6, "LONG-CLICKED LINK %s", arg2, ntos(row), ntos(col), ntos(rev_row), ntos(-1 - (gtd->screen->cols - col)), word, line);
-			}
-			check_all_events(ses, SUB_ARG, 1, 6, "LONG-CLICKED %s", arg2, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
-
-			check_all_events(ses, SUB_ARG, 2, 6, "LONG-CLICKED %s %d", arg2, row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
-
-			check_all_events(ses, SUB_ARG, 2, 6, "LONG-CLICKED %s %d", arg2, rev_row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
-
-			map_mouse_handler(ses, "LONG-CLICKED", arg2, row, col, rev_row, rev_col, 0, 0);
+			mouse_event_handler(ses, "LONG-CLICKED", arg2, row, col, rev_row, rev_col, pix_row, pix_col, grid, word, line, link, name);
 		}
 		else if (click[0] - click[1] >= 500000)
 		{
 			if (abs(swipe[0] - swipe[4]) <= 3 && abs(swipe[1] - swipe[5]) <= 3)
 			{
-				if (!HAS_BIT(ses->list[LIST_BUTTON]->flags, LIST_FLAG_IGNORE))
-				{
-					check_all_buttons(ses, row, col, "SHORT-CLICKED", arg2, word, line);
-				}
-
-				if (link)
-				{
-					check_all_events(ses, SUB_ARG, 1, 6, "SHORT-CLICKED LINK %s", arg2, ntos(row), ntos(col), ntos(rev_row), ntos(-1 - (gtd->screen->cols - col)), word, line);
-				}
-				check_all_events(ses, SUB_ARG, 1, 6, "SHORT-CLICKED %s", arg2, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
-
-				check_all_events(ses, SUB_ARG, 2, 6, "SHORT-CLICKED %s %d", arg2, row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
-
-				check_all_events(ses, SUB_ARG, 2, 6, "SHORT-CLICKED %s %d", arg2, rev_row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line);
-
-				map_mouse_handler(ses, "SHORT-CLICKED", arg2, row, col, rev_row, rev_col, 0, 0);
+				mouse_event_handler(ses, "SHORT-CLICKED", arg2, row, col, rev_row, rev_col, pix_row, pix_col, grid, word, line, link, name);
 			}
 		}
 	}
@@ -487,3 +597,34 @@ void mouse_handler(struct session *ses, int flags, int row, int col)
 	pop_call();
 	return;
 }
+
+void mouse_event_handler(struct session *ses, char *arg1, char *arg2, int row, int col, int rev_row, int rev_col, int pix_row, int pix_col, char *grid, char *word, char *line, char *link, char *name)
+{
+	if (!HAS_BIT(ses->list[LIST_BUTTON]->flags, LIST_FLAG_IGNORE))
+	{
+		check_all_buttons(ses, row, col, arg1, arg2, word, line);
+	}
+
+	if (*link)
+	{
+		check_all_events(ses, EVENT_FLAG_MOUSE, 3, 8, "%s %s %s", arg1, link, arg2, ntos(row), ntos(col), ntos(rev_row), ntos(-1 - (gtd->screen->cols - col)), word, line, name, grid);
+
+		if (*name)
+		{
+			check_all_events(ses, EVENT_FLAG_MOUSE, 4, 8, "%s %s %s %s", arg1, link, name, arg2, ntos(row), ntos(col), ntos(rev_row), ntos(-1 - (gtd->screen->cols - col)), word, line, name, grid);
+		}
+	}
+
+	if (row >= ses->input->top_row && row <= ses->input->bot_row && col >= ses->input->top_col && row <= ses->input->bot_col)
+	{
+		check_all_events(ses, EVENT_FLAG_MOUSE, 2, 8, "%s INPUT %s", arg1, arg2, ntos(row), ntos(col - (ses->input->top_col - 1)), ntos(rev_row), ntos(rev_col - (ses->input->top_col - 1)), word, line, name, grid);
+	}
+
+	check_all_events(ses, EVENT_FLAG_MOUSE, 2, 8, "%s %s", arg1, arg2, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line, name, grid);
+
+	check_all_events(ses, EVENT_FLAG_MOUSE, 3, 8, "%s %s %d", arg1, arg2, row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line, name, grid);
+
+	check_all_events(ses, EVENT_FLAG_MOUSE, 3, 8, "%s %s %d", arg1, arg2, rev_row, ntos(row), ntos(col), ntos(rev_row), ntos(rev_col), word, line, name, grid);
+
+	map_mouse_handler(ses, arg1, arg2, row, col, rev_row, rev_col, pix_row, pix_col);
+}

+ 91 - 34
src/files.c

@@ -37,7 +37,7 @@ DO_COMMAND(do_read)
 
 	if ((fp = fopen(arg1, "r")) == NULL)
 	{
-		check_all_events(ses, SUB_ARG, 0, 2, "READ ERROR", arg1, "FILE NOT FOUND.");
+		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "READ ERROR", arg1, "FILE NOT FOUND.");
 
 		tintin_printf(ses, "#READ {%s} - FILE NOT FOUND.", arg1);
 
@@ -57,7 +57,7 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 
 	if (!ispunct((int) temp[0]))
 	{
-		check_all_events(ses, SUB_ARG, 0, 2, "READ ERROR", filename, "INVALID START OF FILE");
+		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "READ ERROR", filename, "INVALID START OF FILE");
 
 		tintin_printf(ses, "#ERROR: #READ {%s} - INVALID START OF FILE '%c'.", filename, temp[0]);
 
@@ -84,7 +84,7 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 
 	if ((bufi = (char *) calloc(1, size + 2)) == NULL || (bufo = (char *) calloc(1, size + 2)) == NULL)
 	{
-		check_all_events(ses, SUB_ARG, 0, 2, "READ ERROR", filename, "FAILED TO ALLOCATE MEMORY");
+		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "READ ERROR", filename, "FAILED TO ALLOCATE MEMORY");
 
 		tintin_printf(ses, "#ERROR: #READ {%s} - FAILED TO ALLOCATE %d BYTES OF MEMORY.", filename, size + 2);
 
@@ -94,7 +94,15 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 	}
 
 
-	fread(bufi, 1, size, fp);
+	if (fread(bufi, 1, size, fp) <= 0)
+	{
+		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "READ ERROR", filename, "FREAD FAILURE");
+		
+		tintin_printf(ses, "#ERROR: #READ {%s} - FREAD FAILURE.", filename);
+
+		fclose(fp);
+		return ses;
+	}
 
 	pti = bufi;
 	pto = bufo;
@@ -161,7 +169,7 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 
 					pto--;
 
-					while (isspace((int) *pto))
+					while (is_space(*pto))
 					{
 						pto--;
 					}
@@ -184,7 +192,7 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 					{
 						pti++;
 
-						while (isspace((int) *pti))
+						while (is_space(*pti))
 						{
 							if (*pti == '\n')
 							{
@@ -196,14 +204,13 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 								}
 							}
 							pti++;
-
 						}
 
-						if (last == 0)
+						if (last != COMMAND_SEPARATOR && last != DEFAULT_OPEN)
 						{
-							if (*pti != DEFAULT_OPEN && *pti != DEFAULT_CLOSE)
+							if (*pti == gtd->tintin_char)
 							{
-								show_error(ses, LIST_COMMAND, "#WARNING: #READ {%s} MISSING SEMICOLON ON LINE %d.", filename, lnc - 1);
+								show_error(ses, LIST_COMMAND, "#WARNING: #READ {%s} MISSING SEMICOLON ON LINE %d.", filename, lnc);
 							}
 						}
 
@@ -223,7 +230,7 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 						if (pti[cnt] == DEFAULT_OPEN)
 						{
 							pti++;
-							while (isspace((int) *pti))
+							while (is_space(*pti))
 							{
 								pti++;
 							}
@@ -231,7 +238,7 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 							break;
 						}
 
-						if (!isspace((int) pti[cnt]))
+						if (!is_space(pti[cnt]))
 						{
 							*pto++ = *pti++;
 							break;
@@ -290,7 +297,7 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 
 	if (lvl)
 	{
-		check_all_events(ses, SUB_ARG, 0, 2, "READ ERROR", filename, "MISSING BRACE OPEN OR CLOSE");
+		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "READ ERROR", filename, "MISSING BRACE OPEN OR CLOSE");
 
 		tintin_printf(ses, "#ERROR: #READ {%s} - MISSING %d '%c' BETWEEN LINE %d AND %d.", filename, abs(lvl), lvl < 0 ? DEFAULT_OPEN : DEFAULT_CLOSE, fix == 0 ? 1 : ok, fix == 0 ? lnc + 1 : fix);
 
@@ -304,7 +311,7 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 
 	if (com)
 	{
-		check_all_events(ses, SUB_ARG, 0, 2, "READ ERROR", filename, "MISSING COMMENT OPEN OR CLOSE");
+		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "READ ERROR", filename, "MISSING COMMENT OPEN OR CLOSE");
 
 		tintin_printf(ses, "#ERROR: #READ {%s} - MISSING %d '%s'", filename, abs(com), com < 0 ? "/*" : "*/");
 
@@ -316,6 +323,8 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 		return ses;
 	}
 
+	check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 1, "READ FILE", filename);
+
 	sprintf(temp, "#CONFIG {TINTIN CHAR} {%c}", bufo[0]);
 
 	if (bufo[0] != gtd->tintin_char)
@@ -335,7 +344,7 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 		gtd->level->quiet--;
 	}
 
-	verbose = HAS_BIT(ses->flags, SES_FLAG_VERBOSE) ? 1 : 0;
+	verbose = HAS_BIT(ses->config_flags, CONFIG_FLAG_VERBOSE) ? 1 : 0;
 
 	gtd->level->input++;
 
@@ -373,7 +382,7 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 
 	gtd->level->input--;
 
-	if (!HAS_BIT(ses->flags, SES_FLAG_VERBOSE))
+	if (!HAS_BIT(ses->config_flags, CONFIG_FLAG_VERBOSE))
 	{
 		for (cnt = 0 ; cnt < LIST_MAX ; cnt++)
 		{
@@ -417,16 +426,16 @@ DO_COMMAND(do_write)
 
 	if (*arg1 == 0)
 	{
-		check_all_events(ses, SUB_ARG, 0, 2, "WRITE ERROR", arg1, "INVALID FILE NAME");
+		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "WRITE ERROR", arg1, "INVALID FILE NAME");
 
 		tintin_printf2(ses, "#SYNTAX: #WRITE {<filename>} {[FORCE]}");
 
 		return ses;
 	}
 	
-	if (!str_suffix(arg1, ".map") && !is_abbrev(arg2, "FORCE"))
+	if (is_suffix(arg1, ".map") && !is_abbrev(arg2, "FORCE"))
 	{
-		check_all_events(ses, SUB_ARG, 0, 2, "WRITE ERROR", arg1, "INVALID FILE EXTENSION");
+		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "WRITE ERROR", arg1, "INVALID FILE EXTENSION");
 		tintin_printf2(ses, "#WRITE {%s}: USE {FORCE} TO OVERWRITE .map FILES.", arg1);
 
 		return ses;
@@ -434,7 +443,7 @@ DO_COMMAND(do_write)
 
 	if ((file = fopen(arg1, "w")) == NULL)
 	{
-		check_all_events(ses, SUB_ARG, 0, 2, "WRITE ERROR", arg1, "FAILED TO OPEN");
+		check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 2, "WRITE ERROR", arg1, "FAILED TO OPEN");
 
 		tintin_printf(ses, "#ERROR: #WRITE: COULDN'T OPEN {%s} TO WRITE.", arg1);
 
@@ -478,6 +487,8 @@ DO_COMMAND(do_write)
 
 	fclose(file);
 
+	check_all_events(ses, EVENT_FLAG_SYSTEM, 0, 1, "WRITE FILE", arg1);
+
 	show_message(ses, LIST_COMMAND, "#WRITE: %d COMMANDS WRITTEN TO {%s}.", cnt, arg1);
 
 	return ses;
@@ -487,7 +498,7 @@ DO_COMMAND(do_write)
 void write_node(struct session *ses, int list, struct listnode *node, FILE *file)
 {
 	char *result, *str;
-
+	int val = 0;
 	int llen = UMAX(20, strlen(node->arg1));
 	int rlen = UMAX(25, strlen(node->arg2));
 
@@ -498,7 +509,7 @@ void write_node(struct session *ses, int list, struct listnode *node, FILE *file
 		case LIST_EVENT:
 		case LIST_FUNCTION:
 		case LIST_MACRO:
-			asprintf(&result, "%c%s {%s}\n{\n%s\n}\n\n", gtd->tintin_char, list_table[list].name, node->arg1, script_writer(ses, node->arg2));
+			val = asprintf(&result, "%c%s {%s}\n{\n%s\n}\n\n", gtd->tintin_char, list_table[list].name, node->arg1, script_writer(ses, node->arg2));
 			break;
 
 		case LIST_ACTION:
@@ -506,22 +517,20 @@ void write_node(struct session *ses, int list, struct listnode *node, FILE *file
 		case LIST_BUTTON:
 			if (!strcmp(node->arg3, "5"))
 			{
-				asprintf(&result, "%c%s {%s}\n{\n%s\n}\n\n", gtd->tintin_char, list_table[list].name, node->arg1, script_writer(ses, node->arg2));
+				val = asprintf(&result, "%c%s {%s}\n{\n%s\n}\n\n", gtd->tintin_char, list_table[list].name, node->arg1, script_writer(ses, node->arg2));
 			}
 			else
 			{
-				asprintf(&result, "%c%s {%s}\n{\n%s\n}\n{%s}\n\n", gtd->tintin_char, list_table[list].name, node->arg1, script_writer(ses, node->arg2), node->arg3);
+				val = asprintf(&result, "%c%s {%s}\n{\n%s\n}\n{%s}\n\n", gtd->tintin_char, list_table[list].name, node->arg1, script_writer(ses, node->arg2), node->arg3);
 			}
 			break;
 
 		case LIST_VARIABLE:
-			str = str_dup("");
+			str = str_alloc_stack(0);
 
 			show_nest_node(node, &str, 1);
 
-			asprintf(&result, "%c%-16s {%s} %*s {%s}\n", gtd->tintin_char, list_table[list].name, node->arg1, 20 - llen, "", str);
-
-			str_free(str);
+			val = asprintf(&result, "%c%-16s {%s} %*s {%s}\n", gtd->tintin_char, list_table[list].name, node->arg1, 20 - llen, "", str);
 
 			break;
 
@@ -532,25 +541,73 @@ void write_node(struct session *ses, int list, struct listnode *node, FILE *file
 					result = strdup("");
 					break;
 				case 1:
-					asprintf(&result, "%c%-16s {%s}\n", gtd->tintin_char, list_table[list].name, node->arg1);
+					val = asprintf(&result, "%c%-16s {%s}\n", gtd->tintin_char, list_table[list].name, node->arg1);
 					break;
 				case 2:
-					asprintf(&result, "%c%-16s {%s} %*s {%s}\n", gtd->tintin_char, list_table[list].name, node->arg1, 20 - llen, "", node->arg2);
+					val = asprintf(&result, "%c%-16s {%s} %*s {%s}\n", gtd->tintin_char, list_table[list].name, node->arg1, 20 - llen, "", node->arg2);
 					break;
 				case 3:
-					asprintf(&result, "%c%-16s {%s} %*s {%s} %*s {%s}\n", gtd->tintin_char, list_table[list].name, node->arg1, 20 - llen, "", node->arg2, 25 - rlen, "", node->arg3);
+					val = asprintf(&result, "%c%-16s {%s} %*s {%s} %*s {%s}\n", gtd->tintin_char, list_table[list].name, node->arg1, 20 - llen, "", node->arg2, 25 - rlen, "", node->arg3);
 					break;
 				case 4:
-					asprintf(&result, "%c%-16s {%s} %*s {%s} %*s {%s} {%s}\n", gtd->tintin_char, list_table[list].name, node->arg1, 20 - llen, "", node->arg2, 25 - rlen, "", node->arg3, node->arg4);
+					val = asprintf(&result, "%c%-16s {%s} %*s {%s} %*s {%s} {%s}\n", gtd->tintin_char, list_table[list].name, node->arg1, 20 - llen, "", node->arg2, 25 - rlen, "", node->arg3, node->arg4);
 					break;
 			}
 			break;
 	}
-	fputs(result, file);
 
-	free(result);
+	if (val != -1)
+	{
+		fputs(result, file);
+
+		free(result);
+	}
+	else
+	{
+		syserr_printf(ses, "write_node: asprintf:");
+	}
 
 	pop_call();
 	return;
 }
 
+char *fread_one_line(char **str, FILE *fp)
+{
+	int byte;
+
+	str_cpy(str, "");
+
+	while (TRUE)
+	{
+		byte = getc(fp);
+
+		switch (byte)
+		{
+			case ASCII_LF:
+				return *str;
+
+			case EOF:
+				if (*(*str))
+				{
+					return *str;
+				}
+				return NULL;
+
+			case ASCII_NUL:
+				tintin_printf2(gtd->ses, "fread_one_line: encountered NULL character.");
+				break;
+
+			case ASCII_CR:
+				break;
+
+			case ASCII_HTAB:
+				str_cat_printf(str, "%*s", gtd->ses->tab_width, "");
+				break;
+
+			default:
+				str_cat_chr(str, byte);
+				break;
+		}
+	}
+	return *str;
+}

+ 730 - 0
src/gui.h

@@ -0,0 +1,730 @@
+char *tt_gui = "#line QUIET #port INIT gui 0\n"
+"\n"
+"#function gui_link\n"
+"{\n"
+"	#format gui[link] {%+11h} {%3};\n"
+"	#replace gui[link] {#} { };\n"
+"	#line sub esc #var gui[link] {\e]68;2;%1;%2\a\e[4;24m$gui[link]\e[24m};\n"
+"	#return $gui[link]\n"
+"}\n"
+"\n"
+"#function gui_profile_link\n"
+"{\n"
+"	#format gui[link] {%-24.24s} {%3};\n"
+"\n"
+"	#line sub esc #var gui[link] {\e]68;2;%1;%2\a\e[4;24m$gui[link]\e[24m};\n"
+"	#return $gui[link]\n"
+"}\n"
+"\n"
+"/*\n"
+"#function input_link\n"
+"{\n"
+"	#line sub esc\n"
+"	{\n"
+"		#var result\n"
+"		{\n"
+"			\e]68;2;INPUT;{{top_row}{%1}{top_col}{%2}{bot_row}{%3}{bot_col}{%4}{name}{%5}{data}{%6}}\a\e[4;24m%7\e[24m\n"
+"		}\n"
+"	}\n"
+"}\n"
+"\n"
+"#event {PRESSED SECURE LINK INPUT MOUSE BUTTON ONE}\n"
+"{\n"
+"	#local link %4;\n"
+"\n"
+"	#screen inputregion {$link[top_row]} {$link[bot_row]} {$link[bot_row]} {$link[bot_col]} {$link[name]};\n"
+"\n"
+"	#cursor clear;\n"
+"\n"
+"	#cursor set {$link[data]}\n"
+"}\n"
+"*/\n"
+"\n"
+"#event {PRESSED SECURE LINK COMMAND MOUSE BUTTON ONE} {%4}\n"
+"\n"
+"#event {PRESSED SECURE LINK COMMAND MOUSE BUTTON THREE}\n"
+"{\n"
+"	#line ignore #showme {<138>Group<178>: %6 <138>Command<178>: %4}\n"
+"}\n"
+"\n"
+"#event {PRESSED SECURE LINK WORLD MOUSE BUTTON ONE}\n"
+"{\n"
+"	world_click {%4}\n"
+"}\n"
+"\n"
+"#event {PRESSED SECURE LINK WORLD MOUSE BUTTON THREE}\n"
+"{\n"
+"	#line ignore #showme {<138>Group<178>: %6 <138>Command<178>: %4}\n"
+"}\n"
+"\n"
+"#event {DOUBLE-CLICKED SECURE LINK WORLD MOUSE BUTTON ONE} {gui_connect}\n"
+"\n"
+"#button {-2 28 -2 -28;PRESSED MOUSE BUTTON ONE}\n"
+"{\n"
+"	profile_tab_update;\n"
+"\n"
+"	#screen inputregion -2 28 -2 -28 profile_tab_INPUT;\n"
+"\n"
+"	profile_tab_set INPUT\n"
+"}\n"
+"\n"
+"#alias {gui_worlds}   {world_tab worlds}\n"
+"#alias {gui_sponsors} {world_tab sponsors}\n"
+"\n"
+"#alias {world_tab}\n"
+"{\n"
+"	#var gui[world_tab] %1;\n"
+"\n"
+"	#class world_tab kill;\n"
+"\n"
+"	#if {{$gui[world_tab]} == {worlds}}\n"
+"	{\n"
+"		#draw jade Azure  rounded calign box 1  1 3 13 {@gui_link{COMMAND;{profile_tab_cancel;world_tab worlds;draw_worlds 0};worlds}};\n"
+"		#draw jade Silver rounded calign box 1 14 3 26 {@gui_link{COMMAND;{profile_tab_cancel;world_tab sponsors;draw_sponsors 0};sponsors}}\n"
+"	};\n"
+"	#else\n"
+"	{\n"
+"		#draw jade Silver rounded calign box 1  1 3 13 {@gui_link{COMMAND;{profile_tab_cancel;world_tab worlds;draw_worlds 0};worlds}};\n"
+"		#draw jade Azure  rounded calign box 1 14 3 26 {@gui_link{COMMAND;{profile_tab_cancel;world_tab sponsors;draw_sponsors 0};sponsors}}\n"
+"	};\n"
+"\n"
+"	#draw jade Green rounded calign box -3  1 -1 13 {@gui_link{COMMAND;gui_new;new}};\n"
+"	#draw jade Green rounded calign box -3 14 -1 26 {@gui_link{COMMAND;#delay 0 #end;exit}}\n"
+"}\n"
+"\n"
+"#alias {draw_world}\n"
+"{\n"
+"	#if {{%2} == {%3}}\n"
+"	{\n"
+"		#draw jade Yellow rounded TALIGN box %1*3+1 1 %1*3+3 26 @gui_profile_link{WORLD;%2;%2};\n"
+"	};\n"
+"	#else\n"
+"	{\n"
+"		#draw jade Azure rounded TALIGN box %1*3+1 1 %1*3+3 26 @gui_profile_link{WORLD;%2;%2}\n"
+"	}\n"
+"}\n"
+"\n"
+"#alias {world_click}\n"
+"{\n"
+"	#var gui[active] {%1};\n"
+"\n"
+"	profile_tab_cancel;\n"
+"\n"
+"	#if {{$gui[world_tab]} == {worlds}}\n"
+"	{\n"
+"		#var gui[new] {$worldlist[%1]};\n"
+"\n"
+"		draw_worlds {%1}\n"
+"	};\n"
+"	#else\n"
+"	{\n"
+"		#var gui[new] {$info[BANNERS][%1]} {{SSL}{off}} {{FILE}{}} {{CHARACTER}{}} {{PASSWORD}{}} {{INPUT}{}};\n"
+"\n"
+"		draw_sponsors {%1}\n"
+"	};\n"
+"	reload_profile_tab;\n"
+"\n"
+"	#buffer end\n"
+"}\n"
+"\n"
+"#function {gui_size_left}\n"
+"{\n"
+"	#if {{$gui[world_tab]} == {worlds}}\n"
+"	{\n"
+"		#return &worldlist[];\n"
+"	};\n"
+"	#else\n"
+"	{\n"
+"		#return &info[BANNERS][];\n"
+"	}\n"
+"}\n"
+"\n"
+"#alias {gui_draw_left}\n"
+"{\n"
+"	#if {{$gui[world_tab]} == {worlds}}\n"
+"	{\n"
+"		draw_worlds\n"
+"	};\n"
+"	#else\n"
+"	{\n"
+"		draw_sponsors\n"
+"	}\n"
+"}\n"
+"\n"
+"#alias {draw_worlds}\n"
+"{\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"
+"\n"
+"	#if {&worldlist[] == 0}\n"
+"	{\n"
+"		#return;\n"
+"	};\n"
+"\n"
+"	#local index 1;\n"
+"	#local offset 1;\n"
+"\n"
+"	#loop $gui[index] &worldlist[] index\n"
+"	{\n"
+"		draw_world {$offset} {$worldlist[+$index][NAME]} {%1};\n"
+"\n"
+"		#math offset $offset + 1;\n"
+"\n"
+"		#if {$offset * 3 > $gui[rows] - 6}\n"
+"		{\n"
+"			#break;\n"
+"		};\n"
+"	}\n"
+"}\n"
+"\n"
+"#alias {draw_sponsors}\n"
+"{\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"
+"\n"
+"	#if {&info[BANNERS][] == 0}\n"
+"	{\n"
+"		#line ignore #showme <faa>Sponsors: No banners found.;\n"
+"		#return;\n"
+"	};\n"
+"\n"
+"	#local index 1;\n"
+"	#local offset 1;\n"
+"\n"
+"	#loop $gui[index] &info[BANNERS][] index\n"
+"	{\n"
+"		draw_world {$offset} {$info[BANNERS][+$index][NAME]} {%1};\n"
+"\n"
+"		#math offset $offset + 1;\n"
+"\n"
+"		#if {$offset * 3 > $gui[rows] - 6}\n"
+"		{\n"
+"			#break;\n"
+"		};\n"
+"	}\n"
+"}\n"
+"\n"
+"#alias {gui_tab_forward}\n"
+"{\n"
+"	#screen get INPUT_NAME input_name;\n"
+"\n"
+"	#switch {{$input_name}}\n"
+"	{\n"
+"		#case {{profile_tab_NAME}}      {profile_tab_cycle ALIAS NAME};\n"
+"		#case {{profile_tab_ALIAS}}     {profile_tab_cycle HOST ALIAS};\n"
+"		#case {{profile_tab_HOST}}      {profile_tab_cycle PORT HOST};\n"
+"		#case {{profile_tab_PORT}}      {profile_tab_cycle FILE PORT};\n"
+"		#case {{profile_tab_FILE}}      {profile_tab_cycle CHARACTER FILE};\n"
+"		#case {{profile_tab_CHARACTER}} {profile_tab_cycle PASSWORD CHARACTER};\n"
+"		#case {{profile_tab_PASSWORD}}  {profile_tab_cycle INPUT PASSWORD};\n"
+"		#case {{profile_tab_INPUT}}     {profile_tab_cycle NAME INPUT};\n"
+"	}\n"
+"}\n"
+"\n"
+"#alias {gui_tab_backward}\n"
+"{\n"
+"	#screen get INPUT_NAME input_name;\n"
+"\n"
+"	#switch {{$input_name}}\n"
+"	{\n"
+"		#case {{profile_tab_NAME}}      {profile_tab_cycle INPUT NAME};\n"
+"		#case {{profile_tab_ALIAS}}     {profile_tab_cycle NAME ALIAS};\n"
+"		#case {{profile_tab_HOST}}      {profile_tab_cycle ALIAS HOST};\n"
+"		#case {{profile_tab_PORT}}      {profile_tab_cycle HOST PORT};\n"
+"		#case {{profile_tab_FILE}}      {profile_tab_cycle PORT FILE};\n"
+"		#case {{profile_tab_CHARACTER}} {profile_tab_cycle FILE CHARACTER};\n"
+"		#case {{profile_tab_PASSWORD}}  {profile_tab_cycle CHARACTER PASSWORD};\n"
+"		#case {{profile_tab_INPUT}}     {profile_tab_cycle PASSWORD INPUT};\n"
+"	}\n"
+"}\n"
+"\n"
+"#alias {profile_tab_cycle}\n"
+"{\n"
+"	profile_tab_pull %2;\n"
+"\n"
+"	#screen inputregion $gui[input][%1][top_row] $gui[input][%1][top_col] $gui[input][%1][bot_row] $gui[input][%1][bot_col] profile_tab_%1;\n"
+"\n"
+"	profile_tab_set %1;\n"
+"}\n"
+"\n"
+"#alias {profile_tab_pull}\n"
+"{\n"
+"	#if {{%1} == {PASSWORD}}\n"
+"	{\n"
+"		#cursor get temp;\n"
+"		#var gui[new][%1] {@b64z{$temp}};\n"
+"		#unvar temp\n"
+"	};\n"
+"	#else\n"
+"	{\n"
+"		#cursor get {gui[new][%1]};\n"
+"	};\n"
+"	#cursor clear;\n"
+"	profile_tab %1\n"
+"}\n"
+"\n"
+"#alias {profile_tab_update}\n"
+"{\n"
+"	#screen get INPUT_NAME input_name;\n"
+"\n"
+"	#regex {$input_name} {profile_tab_{NAME|ALIAS|INPUT|HOST|PORT|FILE|CHARACTER|PASSWORD}}\n"
+"	{\n"
+"		profile_tab_pull &1\n"
+"	}\n"
+"}\n"
+"\n"
+"#function gui_toggle\n"
+"{\n"
+"	#if {{%1} == {%2}}\n"
+"	{\n"
+"		#return %3\n"
+"	};\n"
+"	#return %2\n"
+"}\n"
+"\n"
+"#alias {profile_tab_set}\n"
+"{\n"
+"	#if {{%1} == {PASSWORD}}\n"
+"	{\n"
+"		#local temp {};\n"
+"		#format temp %+64Z {$gui[new][%1]};\n"
+"		#cursor set {$temp}\n"
+"	};\n"
+"	#else\n"
+"	{\n"
+"		#cursor set {$gui[new][%1]};\n"
+"	}\n"
+"}\n"
+"\n"
+"#alias {profile_tab_input}\n"
+"{\n"
+"	#var gui[input][%5] {{top_row}{%1}{top_col}{%2}{bot_row}{%3}{bot_col}{%4}};\n"
+"\n"
+"	#if {{%6} == {toggle}}\n"
+"	{\n"
+"		#button {%1 %2 %3 %4;PRESSED MOUSE BUTTON ONE}\n"
+"		{\n"
+"			#var gui[new][%5] @gui_toggle{$gui[new][%5];on;off};\n"
+"			profile_tab %5\n"
+"		}\n"
+"	};\n"
+"	#else\n"
+"	{\n"
+"		#button {%1 %2 %3 %4;PRESSED MOUSE BUTTON ONE}\n"
+"		{\n"
+"			profile_tab_update;\n"
+"			#screen inputregion %1 %2 %3 %4 profile_tab_%5;\n"
+"			profile_tab_set %5;\n"
+"		};\n"
+"		#event {CATCH RECEIVED INPUT profile_tab_%5}\n"
+"		{\n"
+"			profile_tab_pull %5;\n"
+"			#screen inputregion -2 28 -2 -28 profile_tab_INPUT;\n"
+"		}\n"
+"	}\n"
+"}\n"
+"\n"
+"#function b64z\n"
+"{\n"
+"	#if {{%0} === {}}\n"
+"	{\n"
+"		#return {}\n"
+"	};\n"
+"	#local temp {};\n"
+"	#format temp %+64z %0;\n"
+"	#return $temp\n"
+"}\n"
+"\n"
+"#function b64Z\n"
+"{\n"
+"	#if {{%0} === {}}\n"
+"	{\n"
+"		#return {}\n"
+"	};\n"
+"	#local temp {};\n"
+"	#format temp %+64Z %0;\n"
+"	#return $temp\n"
+"}\n"
+"\n"
+"#function starout\n"
+"{\n"
+"	#local temp {%0};\n"
+"	#replace temp {%.} {*};\n"
+"	#return $temp\n"
+"}\n"
+"\n"
+"#alias {profile_tab_draw}\n"
+"{\n"
+"	#if {{%5} == {PASSWORD}}\n"
+"	{\n"
+"		#var temp @b64Z{$gui[new][%5]};\n"
+"		#draw jade Silver rounded talign box %1 %2 %3 %4 {@starout{$temp}};\n"
+"		#unvar temp\n"
+"	};\n"
+"	#else\n"
+"	{\n"
+"		#draw jade Silver rounded talign box %1 %2 %3 %4 {$gui[new][%5]};\n"
+"	};\n"
+"	#draw jade Azure scaled tile %1 %2+2 %1 %2+3 *gui[new][%5];\n"
+"	#class profile_tab assign\n"
+"	{\n"
+"		profile_tab_input %1+1 %2+1 %1+1 %4-1 %5 %6\n"
+"	};\n"
+"}\n"
+"\n"
+"#alias {profile_tab}\n"
+"{\n"
+"	#switch {{%1}}\n"
+"	{\n"
+"		#case {{NAME}}      {profile_tab_draw 1 -26 3 -1 NAME};\n"
+"		#case {{ALIAS}}     {profile_tab_draw 4 -26 6 -1 ALIAS};\n"
+"		#case {{HOST}}      {profile_tab_draw 7 -26 9 -1 HOST};\n"
+"		#case {{PORT}}      {profile_tab_draw 10 -26 12 -9 PORT};\n"
+"		#case {{SSL}}       {profile_tab_draw 10 -7 12 -1 SSL toggle};\n"
+"		#case {{FILE}}      {profile_tab_draw 13 -26 15 -1 FILE};\n"
+"		#case {{CHARACTER}} {profile_tab_draw 16 -26 18 -1 CHARACTER};\n"
+"		#case {{PASSWORD}}  {profile_tab_draw 19 -26 21 -1 PASSWORD}\n"
+"	};\n"
+"}\n"
+"\n"
+"#alias {profile_tab_cancel}\n"
+"{\n"
+"	#screen get INPUT_NAME input_name;\n"
+"\n"
+"	#regex {$input_name} {profile_tab_{NAME|ALIAS|HOST|PORT|SSL|FILE|CHARACTER|PASSWORD}}\n"
+"	{\n"
+"		profile_tab_cycle INPUT &1\n"
+"	};\n"
+"\n"
+"	#screen clear square 1 -26 -1 -1;\n"
+"	#var gui[profile_tab] 0;\n"
+"	#math gui[index] 1\n"
+"}\n"
+"\n"
+"#alias {profile_tab_save}\n"
+"{\n"
+"	#screen get INPUT_NAME input_name;\n"
+"\n"
+"	#regex {$input_name} {profile_tab_{NAME|ALIAS|INPUT|HOST|PORT|SSL|FILE|CHARACTER|PASSWORD}}\n"
+"	{\n"
+"		profile_tab_pull &1\n"
+"	}\n"
+"}\n"
+"\n"
+"#alias {gui_new}\n"
+"{\n"
+"	#class profile_tab kill;\n"
+"\n"
+"	#var gui[new] {{NAME}{} {ALIAS}{} {HOST}{} {PORT}{} {SSL}{off} {FILE}{} {CHARACTER}{} {PASSWORD}{} {INPUT}{}};\n"
+"\n"
+"	reload_profile_tab\n"
+"}\n"
+"\n"
+"#alias {gui_connect}\n"
+"{\n"
+"	#if {&gui[new] == 0}\n"
+"	{\n"
+"		#line ignore #showme <faa>Connect: No world selected;#return;\n"
+"	};\n"
+"\n"
+"	profile_tab_update;\n"
+"	#screen inputregion -2 28 -2 -28 profile_tab_INPUT;\n"
+"	#cursor clear;\n"
+"\n"
+"	#if {{$gui[new][ALIAS]} == {}}\n"
+"	{\n"
+"		#line ignore #showme <faa>Connect: No alias set;\n"
+"		#return\n"
+"	};\n"
+"\n"
+"	#if {{$gui[new][HOST]} == {}}\n"
+"	{\n"
+"		#line ignore #showme <faa>Connect: No host set;\n"
+"		#return\n"
+"	};\n"
+"\n"
+"	#if {{$gui[new][PORT]} == {}}\n"
+"	{\n"
+"		#line ignore #showme <faa>Connect: No port set;\n"
+"		#return\n"
+"	};\n"
+"\n"
+"	#line ignore #showme {<acf>Connecting to <ffa>$gui[new][NAME]<acf>..};\n"
+"\n"
+"	#buffer refresh;\n"
+"\n"
+"	#if {{$gui[new][SSL]} == {off}}\n"
+"	{\n"
+"		#session $gui[new][ALIAS] $gui[new][HOST] $gui[new][PORT] $gui[new][FILE];\n"
+"	};\n"
+"	#else\n"
+"	{\n"
+"		#ssl $gui[new][ALIAS] $gui[new][HOST] $gui[new][PORT] $gui[new][FILE];\n"
+"	};\n"
+"\n"
+"	#info SESSION save;\n"
+"\n"
+"	#if {{$info[SESSION][NAME]} !== {gui}}\n"
+"	{\n"
+"		#if {{@gui{$gui[new][CHARACTER]}} !== {}}\n"
+"		{\n"
+"			#send {@gui{$gui[new][CHARACTER]}};\n"
+"\n"
+"			#if {{@gui{$gui[new][PASSWORD]}} !== {}}\n"
+"			{\n"
+"				#send {@gui{@b64Z{$gui[new][PASSWORD]}}}\n"
+"			}\n"
+"		}\n"
+"	};\n"
+"	#else\n"
+"	{\n"
+"		#line ignore #showme <faa>Connect: Failed to connect to <ffa>$gui[new][NAME]<faa>.\n"
+"	}\n"
+"}\n"
+"\n"
+"#alias {gui_save}\n"
+"{\n"
+"	#if {&gui[new] == 0}\n"
+"	{\n"
+"		#CLASS WORLDS WRITE $info[SYSTEM][TINTIN]/worlds.tin;\n"
+"		#showme {<acf>Saving worlds.};\n"
+"		#return;\n"
+"	};\n"
+"\n"
+"	profile_tab_update;\n"
+"\n"
+"	#if {{$gui[new][NAME]} === {}}\n"
+"	{\n"
+"		#showme {<faa>Save: No profile name set.};\n"
+"		#return;\n"
+"	};\n"
+"\n"
+"	#screen inputregion -2 28 -2 -28 profile_tab_INPUT;\n"
+"\n"
+"	#var {worldlist[$gui[new][NAME]]} {$gui[new]};\n"
+"\n"
+"	#unvar {worldlist[$gui[new][NAME]][DESC]};\n"
+"\n"
+"	gui_worlds;\n"
+"\n"
+"	draw_worlds {&worldlist[$gui[new][NAME]]};\n"
+"\n"
+"	reload_profile_tab;\n"
+"\n"
+"	#line ignore #showme {<acf>World <ffa>$gui[new][NAME]<acf> saved.};\n"
+"\n"
+"	#CLASS WORLDS WRITE $info[SYSTEM][TINTIN]/worlds.tin;\n"
+"}\n"
+"\n"
+"#alias {gui_remove}\n"
+"{\n"
+"	#if {&gui[new] == 0}\n"
+"	{\n"
+"		#showme {<faa>Remove: No profile loaded.};\n"
+"		#return;\n"
+"	};\n"
+"	#if {{$gui[new][NAME]} === {}}\n"
+"	{\n"
+"		#showme {<faa>Remove: No profile name set.};\n"
+"		#return;\n"
+"	};\n"
+"\n"
+"	profile_tab_save;\n"
+"\n"
+"	#unvar {worldlist[$gui[new][NAME]]};\n"
+"\n"
+"	profile_tab_cancel;\n"
+"\n"
+"	draw_worlds 0;\n"
+"\n"
+"\n"
+"	#line ignore #showme {<acf>World <ffa>$gui[new][NAME]<acf> removed.};\n"
+"\n"
+"	#CLASS WORLDS WRITE $info[SYSTEM][TINTIN]/worlds.tin;\n"
+"}\n"
+"\n"
+"\n"
+"#alias {reload_profile_tab}\n"
+"{\n"
+"	#var gui[profile_tab] 1;\n"
+"\n"
+"	profile_tab NAME;\n"
+"	profile_tab ALIAS;\n"
+"	profile_tab HOST;\n"
+"	profile_tab PORT;\n"
+"	profile_tab SSL;\n"
+"	profile_tab FILE;\n"
+"	profile_tab CHARACTER;\n"
+"	profile_tab PASSWORD;\n"
+"\n"
+"	#if {&gui[new][DESC] && $gui[cols] > 26}\n"
+"	{\n"
+"		#draw jade bumped ualign rounded scaled calign scroll box 1 1 1 $gui[cols] {<ffa>$gui[new][NAME] <fff>- <ffa>$gui[new][WEBSITE]};\n"
+"		#draw jade Silver ualign rounded scaled scroll box 1 1 1 $gui[cols] {$gui[new][DESC]}\n"
+"	};\n"
+"\n"
+"	#draw jade Green rounded calign box -3 14 -1 26 {@gui_link{COMMAND;gui_connect;connect}};\n"
+"\n"
+"	#draw jade Green rounded calign box -3 -26 -1 -14 {@gui_link{COMMAND;gui_save;save}};\n"
+"\n"
+"	#if {{$gui[world_tab]} !== {sponsors}}\n"
+"	{\n"
+"		#draw jade Green rounded calign box -3 -13 -1 -1  {@gui_link{COMMAND;gui_remove;remove}};\n"
+"	};\n"
+"	#macro {\t} {gui_tab_forward};\n"
+"	#macro {\e[Z} {gui_tab_backward};\n"
+"}\n"
+"\n"
+"#event {SESSION ACTIVATED}\n"
+"{\n"
+"	gui_reload\n"
+"}\n"
+"\n"
+"#alias {gui_reload}\n"
+"{\n"
+"	#nop gts #SPLIT 1 3 27 27;\n"
+"	#SPLIT 1 3 27 27;\n"
+"	#screen clear split;\n"
+"	#screen inputregion -2 28 -2 -28 profile_tab_INPUT;\n"
+"\n"
+"	#screen get ROWS gui[rows];\n"
+"	#screen get COLS gui[cols];\n"
+"\n"
+"	#math gui[cols] $gui[cols] - 54;\n"
+"\n"
+"	#var gui[index] 1;\n"
+"\n"
+"	#draw Orange rounded box -3 27 -1 -27;\n"
+"	#draw Orange rounded box 1 27 -4 -27;\n"
+"\n"
+"	world_tab $gui[world_tab];\n"
+"\n"
+"	#switch {{$gui[world_tab]}}\n"
+"	{\n"
+"		#case {{worlds}}   {draw_worlds 0};\n"
+"		#case {{sponsors}} {draw_sponsors 0}\n"
+"	};\n"
+"\n"
+"	#if {$gui[profile_tab] == 1}\n"
+"	{\n"
+"		reload_profile_tab\n"
+"	}\n"
+"}\n"
+"\n"
+"#alias {gui_init}\n"
+"{\n"
+"	#config MOUSE ON;\n"
+"	#config SCROLL_LOCK OFF;\n"
+"\n"
+"	#class WORLDS ASSIGN #VARIABLE {worldlist} {};\n"
+"\n"
+"	#info SYSTEM SAVE;\n"
+"\n"
+"	#banner save;\n"
+"\n"
+"	#line QUIET #read $info[SYSTEM][TINTIN]/worlds.tin;\n"
+"\n"
+"	#var gui[pause] 0;\n"
+"	#var gui[profile_tab] 0;\n"
+"	#var gui[world_tab] worlds;\n"
+"\n"
+"	#screen inputregion -2 28 -2 -28 profile_tab_INPUT;\n"
+"\n"
+"	#var gui[input][INPUT] {{top_row}{-2}{top_col}{28}{bot_row}{-2}{bot_col}{-28}};\n"
+"\n"
+"	gui_reload;\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 {\n\n$info[SYSTEM][CLIENT_VERSION]};\n"
+"		#draw Silver calign scroll tile 1 1 3 75 {\n\nCode by Peter Unold, Bill Reiss, and Igor van den Hoven\n}\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 {\n\n$info[SYSTEM][CLIENT_VERSION]};\n"
+"		#draw Silver calign scroll tile 1 1 3 40 {\n\nCode by Peter Unold, Bill Reiss,\nand Igor van den Hoven\n}\n"
+"	};\n"
+"	#elseif {$gui[cols] > 18}\n"
+"	{\n"
+"		#draw Silver calign scroll tile 1 1 14 $gui[cols] {T I N T I N + +\n\n$info[SYSTEM][CLIENT_VERSION]\n\nCode by\n\nPeter Unold\n\nBill Reiss\n\nand\n\nIgor van den Hoven\n};\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\ni\nn\nT\ni\nn\n+\n+}\n"
+"	}\n"
+"}\n"
+"\n"
+"#EVENT {SCREEN RESIZE}\n"
+"{\n"
+"	#delay {gui_reload} {gui_reload;#buffer end} {0.1}\n"
+"}\n"
+"\n"
+"#EVENT {SESSION DESTROYED} {#gts #delay 0 #end}\n"
+"\n"
+"#event {SCROLLED MOUSE WHEEL UP}\n"
+"{\n"
+"	#if {%1 <= 26}\n"
+"	{\n"
+"		#if {$gui[profile_tab] && $gui[index] > 1}\n"
+"		{\n"
+"			#math gui[index] $gui[index] - 1;\n"
+"			gui_draw_left\n"
+"		}\n"
+"	};\n"
+"	#elseif {$gui[profile_tab] && %3 >= -26}\n"
+"	{\n"
+"		#if {$gui[pause] == 1}\n"
+"		{\n"
+"			#return;\n"
+"		};\n"
+"		gui_tab_backward;\n"
+"		#var gui[pause] 1;\n"
+"		#delay 0.2 #var gui[pause] 0\n"
+"	};\n"
+"	#else\n"
+"	{\n"
+"		#buffer up 1\n"
+"	}\n"
+"}\n"
+"\n"
+"#event {SCROLLED MOUSE WHEEL DOWN}\n"
+"{\n"
+"	#if {%1 <= 26}\n"
+"	{\n"
+"		#if {$gui[profile_tab] && $gui[index] < @gui_size_left{} && @gui_size_left{} > $gui[rows] / 3 - 6}\n"
+"		{\n"
+"			#math gui[index] $gui[index] + 1;\n"
+"			gui_draw_left\n"
+"		}\n"
+"	};\n"
+"	#elseif {$gui[profile_tab] && %3 >= -26}\n"
+"	{\n"
+"		#if {$gui[pause] == 1}\n"
+"		{\n"
+"			#return;\n"
+"		};\n"
+"		gui_tab_forward;\n"
+"		#var gui[pause] 1;\n"
+"		#delay 0.2 #var gui[pause] 0\n"
+"	};\n"
+"	#else\n"
+"	{\n"
+"		#buffer down 1;\n"
+"	}\n"
+"}\n"
+"\n"
+"gui_init\n";

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 504 - 134
src/help.c


+ 55 - 40
src/history.c

@@ -30,21 +30,18 @@ DO_COMMAND(do_history)
 	int cnt;
 
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
-	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
-	arg = sub_arg_in_braces(ses, arg, arg3, GET_ONE, SUB_VAR|SUB_FUN);
-	arg = sub_arg_in_braces(ses, arg, arg4, GET_ALL, SUB_VAR|SUB_FUN);
 
 	if (*arg1 == 0)
 	{
 		info:
 
-		tintin_header(ses, " HISTORY COMMANDS ");
+		tintin_header(ses, 80, " HISTORY COMMANDS ");
 
 		for (cnt = 0 ; *history_table[cnt].name != 0 ; cnt++)
 		{
 			tintin_printf2(ses, "  [%-13s] %s", history_table[cnt].name, history_table[cnt].desc);
 		}
-		tintin_header(ses, "");
+		tintin_header(ses, 80, "");
 
 		return ses;
 	}
@@ -56,7 +53,7 @@ DO_COMMAND(do_history)
 			continue;
 		}
 
-		history_table[cnt].fun(ses, arg2, arg3, arg4);
+		history_table[cnt].fun(ses, arg, arg2, arg3);
 
 		return ses;
 	}
@@ -78,18 +75,11 @@ void add_line_history(struct session *ses, char *line)
 		return;
 	}
 
-	if (*line == 0)
-	{
-		if (root->used && HAS_BIT(ses->flags, SES_FLAG_REPEATENTER))
-		{
-			strcpy(line, root->list[root->used - 1]->arg1);
-		}
-		return;
-	}
+	// avoid infinite loops
 
 	if (*line == gtd->repeat_char)
 	{
-		search_line_history(ses, line);
+		return;
 	}
 
 	update_node_list(ses->list[LIST_HISTORY], line, "", "", "");
@@ -102,27 +92,35 @@ void add_line_history(struct session *ses, char *line)
 	return;
 }
 
-void search_line_history(struct session *ses, char *line)
+struct session *repeat_history(struct session *ses, char *line)
 {
-	struct listroot *root;
+	struct listroot *root = ses->list[LIST_HISTORY];
 	int i;
 
-	root = ses->list[LIST_HISTORY];
-
 	for (i = root->used - 1 ; i >= 0 ; i--)
 	{
-		if (!strncmp(root->list[i]->arg1, &line[1], strlen(&line[1])))
+		if (!strncmp(root->list[i]->arg1, line, strlen(line)))
 		{
-			strcpy(line, root->list[i]->arg1);
-
-			return;
+			add_line_history(gtd->ses, root->list[i]->arg1);
+
+			gtd->level->repeat++;
+			
+			ses = script_driver(ses, LIST_COMMAND, root->list[i]->arg1);
+			
+			gtd->level->repeat--;
+			
+			return ses;
 		}
 	}
-	tintin_printf2(ses, "#REPEAT: NO MATCH FOUND FOR '%s'", line);
+	tintin_printf2(ses, "#REPEAT: NO MATCH FOUND FOR '%s'", line);	
+
+	return ses;
 }
 
 DO_HISTORY(history_character)
 {
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
+
 	gtd->repeat_char = *arg1;
 
 	show_message(ses, LIST_HISTORY, "#HISTORY CHARACTER SET TO {%c}.", gtd->repeat_char);
@@ -140,14 +138,19 @@ DO_HISTORY(history_delete)
 
 DO_HISTORY(history_insert)
 {
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
+
 	add_line_history(ses, arg1);
 }
 
 DO_HISTORY(history_get)
 {
 	struct listroot *root = ses->list[LIST_HISTORY];
+	char *arg3;
 	int cnt, min, max;
 
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
+
 	if (*arg1 == 0)
 	{
 		show_error(ses, LIST_COMMAND, "#SYNTAX: #HISTORY GET <VARIABLE> [LOWER BOUND] [UPPER BOUND]");
@@ -155,6 +158,8 @@ DO_HISTORY(history_get)
 		return;
 	}
 
+	arg = get_arg_in_braces(ses, arg, arg2, GET_ONE);
+
 	min = get_number(ses, arg2);
 
 	if (min < 0)
@@ -164,9 +169,15 @@ DO_HISTORY(history_get)
 
 	min = URANGE(0, min, root->used - 1);
 
+	arg3 = str_alloc_stack(0);
+
+	arg = sub_arg_in_braces(ses, arg, arg3, GET_ONE, SUB_VAR|SUB_FUN);
+
 	if (*arg3 == 0)
 	{
-		set_nest_node_ses(ses, arg1, "%s", root->list[min]->arg1);
+		substitute(ses, root->list[min]->arg1, arg3, SUB_SEC);
+
+		set_nest_node_ses(ses, arg1, "%s", arg3);
 
 		return;
 	}
@@ -194,7 +205,9 @@ DO_HISTORY(history_get)
 	{
 		sprintf(arg2, "%s[%d]", arg1, ++cnt);
 
-		set_nest_node_ses(ses, arg2, "%s", root->list[min++]->arg1);
+		substitute(ses, root->list[min++]->arg1, arg3, SUB_SEC);
+
+		set_nest_node_ses(ses, arg2, "%s", arg3);
 	}
 
 	show_message(ses, LIST_COMMAND, "#HISTORY GET: %d LINES SAVED TO {%s}.", cnt, arg1);
@@ -204,6 +217,8 @@ DO_HISTORY(history_get)
 
 DO_HISTORY(history_list)
 {
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
+
 	if (*arg1 == 0)
 	{
 		show_list(ses->list[LIST_HISTORY], 0);
@@ -217,40 +232,36 @@ DO_HISTORY(history_list)
 
 DO_HISTORY(history_read)
 {
+	struct listroot *root = ses->list[LIST_HISTORY];
 	FILE *file;
-	char *cptr, buffer[BUFFER_SIZE];
+
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
 
 	file = fopen(arg1, "r");
 
 	if (file == NULL)
 	{
 		show_message(ses, LIST_HISTORY, "#HISTORY: COULDN'T OPEN FILE {%s} TO READ.", arg1);
+
 		return;
 	}
 
-	kill_list(ses->list[LIST_HISTORY]);
+	kill_list(root);
 
-	while (fgets(buffer, BUFFER_SIZE-1, file))
+	while (fread_one_line(&arg2, file))
 	{
-		cptr = strchr(buffer, '\n');
-
-		if (cptr)
+		if (*arg2)
 		{
-			*cptr = 0;
-
-			if (*buffer)
-			{
-				create_node_list(ses->list[LIST_HISTORY], buffer, "", "", "");
-			}
+			create_node_list(root, arg2, "", "", "");
 		}
 	}
-	create_node_list(ses->list[LIST_HISTORY], "", "", "", "");
+	create_node_list(root, "", "", "", "");
 
 	fclose(file);
 
 	if (ses->list[LIST_HISTORY]->used > gtd->history_size) 
 	{
-		execute(gts, "#CONFIG {HISTORY SIZE} {%d}", UMIN(ses->list[LIST_HISTORY]->used, 9999));
+		command(gts, do_configure, "{HISTORY SIZE} {%d}", UMIN(ses->list[LIST_HISTORY]->used, 9999));
 	}
 
 	return;
@@ -258,6 +269,8 @@ DO_HISTORY(history_read)
 
 DO_HISTORY(history_size)
 {
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
+
 	if (atoi(arg1) < 1 || atoi(arg1) > 100000)
 	{
 		show_error(ses, LIST_COMMAND, "#ERROR: #HISTORY SIZE: PROVIDE A NUMBER BETWEEN 1 and 100,000");
@@ -275,6 +288,8 @@ DO_HISTORY(history_write)
 	FILE *file;
 	int i;
 
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
+
 	file = fopen(arg1, "w");
 
 	if (file == NULL)

+ 326 - 132
src/input.c

@@ -25,14 +25,17 @@
 
 #include "tintin.h"
 
+int processed_keypress(char *input, int index, int catch);
+
 void process_input(void)
 {
-	char input[STRING_SIZE];
+	char *input;
+	struct session *input_ses;
 	int len, out;
 
 	push_call("process_input(void)");
 
-	gtd->time_input = gtd->time;
+	input = str_alloc_stack(0);
 
 	if (gtd->detach_port)
 	{
@@ -48,17 +51,21 @@ void process_input(void)
 				}
 				else
 				{
-					show_message(gtd->ses, LIST_COMMAND, "#DAEMON UPDATE: DETACHING FROM PID {%d} DUE TO READ FAILURE.", gtd->detach_pid);
+					show_message(gtd->ses, LIST_COMMAND, "#DAEMON UPDATE: DETACHING FROM {%s} DUE TO READ FAILURE.", gtd->detach_file);
 				}
 
 				gtd->detach_sock = close(gtd->detach_sock);
 
+				dirty_screen(gtd->ses);
+
 				pop_call();
 				return;
 			}
 		}
 		else
 		{
+			len = 0;
+
 			printf("process_input: error?\n");
 		}
 	}
@@ -84,7 +91,7 @@ void process_input(void)
 		show_message(gtd->ses, LIST_COMMAND, "#DAEMON ATTACH: WRITE ERROR: UNATTACHING.");
 	}
 
-	if (HAS_BIT(gtd->flags, TINTIN_FLAG_CONVERTMETACHAR))
+	if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_CONVERTMETACHAR))
 	{
 		if (gtd->convert_time == 0)
 		{
@@ -95,7 +102,7 @@ void process_input(void)
 			if (gtd->convert_time < gtd->utime)
 			{
 				gtd->convert_time = 0;
-				DEL_BIT(gtd->flags, TINTIN_FLAG_CONVERTMETACHAR);
+				DEL_BIT(gtd->ses->input->flags, INPUT_FLAG_CONVERTMETACHAR);
 			}
 		}
 	}
@@ -121,15 +128,12 @@ void process_input(void)
 	{
 		chat_paste(gtd->ses->input->buf, NULL);
 
+		cursor_enter_finish(gtd->ses, "");
+
 		pop_call();
 		return;
 	}
 
-	if (HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_ECHO))
-	{
-		add_line_history(gtd->ses, gtd->ses->input->buf);
-	}
-
 	if (HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_ECHO))
 	{
 		echo_command(gtd->ses, gtd->ses->input->buf);
@@ -141,13 +145,30 @@ void process_input(void)
 
 	if (gtd->ses->scroll->line != -1)
 	{
-		buffer_end(gtd->ses, "");
+		buffer_end(gtd->ses, "", "", "");
 	}
 
-	check_all_events(gtd->ses, SUB_ARG|SUB_SEC, 0, 1, "RECEIVED INPUT", gtd->ses->input->buf);
+	input_ses = gtd->ses;
+
+	check_all_events(gtd->ses, SUB_SEC|EVENT_FLAG_INPUT, 0, 1, "RECEIVED INPUT", gtd->ses->input->buf);
+
+	if (*gtd->ses->input->line_name)
+	{
+		check_all_events(gtd->ses, SUB_SEC|EVENT_FLAG_INPUT, 1, 1, "RECEIVED INPUT %s", gtd->ses->input->line_name, gtd->ses->input->buf);
+
+		if (check_all_events(gtd->ses, SUB_SEC|EVENT_FLAG_CATCH, 1, 1, "CATCH RECEIVED INPUT %s", gtd->ses->input->line_name, gtd->ses->input->buf))
+		{
+			cursor_enter_finish(input_ses, "");
+
+			pop_call();
+			return;
+		}
+	}
 
-	if (check_all_events(gtd->ses, SUB_ARG|SUB_SEC, 0, 1, "CATCH RECEIVED INPUT", gtd->ses->input->buf) == 1)
+	if (check_all_events(gtd->ses, SUB_SEC|EVENT_FLAG_CATCH, 0, 1, "CATCH RECEIVED INPUT", gtd->ses->input->buf) == 1)
 	{
+		cursor_enter_finish(input_ses, "");
+
 		pop_call();
 		return;
 	}
@@ -161,12 +182,12 @@ void process_input(void)
 		gtd->ses = script_driver(gtd->ses, LIST_COMMAND, gtd->ses->input->buf);
 	}
 
-	if (IS_SPLIT(gtd->ses))
+	if (HAS_BIT(input_ses->telopts, TELOPT_FLAG_ECHO))
 	{
-		erase_toeol();
+		add_line_history(input_ses, input_ses->input->buf);
 	}
 
-	gtd->ses->input->buf[0] = 0;
+	cursor_enter_finish(input_ses, "");
 
 	fflush(NULL);
 
@@ -176,15 +197,14 @@ void process_input(void)
 
 void read_line(char *input, int len)
 {
+	char buf[BUFFER_SIZE];
 	int size, width, index;
 
-//	gtd->ses->input->buf[gtd->ses->input->len] = 0;
-
-	if (HAS_BIT(gtd->ses->flags, SES_FLAG_CONVERTMETA) || gtd->level->convert)
+	if (HAS_BIT(gtd->ses->config_flags, CONFIG_FLAG_CONVERTMETA) || gtd->level->convert)
 	{
 		convert_meta(input, &gtd->macro_buf[strlen(gtd->macro_buf)], FALSE);
 	}
-	else if (HAS_BIT(gtd->flags, TINTIN_FLAG_CONVERTMETACHAR))
+	else if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_CONVERTMETACHAR))
 	{
 		convert_meta(input, &gtd->macro_buf[strlen(gtd->macro_buf)], TRUE);
 	}
@@ -203,23 +223,41 @@ void read_line(char *input, int len)
 		}
 	}
 
-	check_all_events(gtd->ses, SUB_ARG|SUB_SIL, 0, 2, "RECEIVED KEYPRESS", input, ntos(index));
-
-	if (check_all_events(gtd->ses, SUB_ARG|SUB_SIL, 0, 2, "CATCH RECEIVED KEYPRESS", input, ntos(index)) == 1)
+	if (HAS_BIT(gtd->ses->event_flags, EVENT_FLAG_INPUT))
 	{
-		return;
+		check_all_events(gtd->ses, 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)
+		{
+			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));
+
+			return;
+		}
 	}
 
 	if (check_key(input, 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));
+		}
 		return;
 	}
 
-	if (gtd->macro_buf[0] == ASCII_ESC)
+	if (gtd->macro_buf[0] < 32)
 	{
-		strcpy(input, gtd->macro_buf);
+		switch (gtd->macro_buf[0])
+		{
+			case ASCII_CR:
+			case ASCII_LF:
+				break;
 
-		convert_meta(input, gtd->macro_buf, FALSE);
+			default:
+				strcpy(buf, gtd->macro_buf);
+
+				convert_meta(buf, gtd->macro_buf, FALSE);
+				break;
+		}
 	}
 
 	while (gtd->macro_buf[0])
@@ -237,72 +275,58 @@ void read_line(char *input, int len)
 				if (HAS_BIT(gtd->ses->charset, CHARSET_FLAG_UTF8) && gtd->macro_buf[0] & 128 && gtd->macro_buf[1])
 				{
 					size = get_utf8_width(gtd->macro_buf, &width);
+				}
+				else
+				{
+					size = get_ascii_width(gtd->macro_buf, &width);
+				}
 
-					if (HAS_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT) && gtd->ses->input->len != gtd->ses->input->cur)
-					{
-						if (width)
-						{
-							cursor_delete(gtd->ses, "");
-						}
-					}
+				sprintf(buf, "%.*s", size, gtd->macro_buf);
 
-					ins_sprintf(&gtd->ses->input->buf[gtd->ses->input->cur], "%.*s", size, gtd->macro_buf);
+				inputline_insert(buf, -1);
+/*
+				if (width && HAS_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT) && gtd->ses->input->raw_len != gtd->ses->input->raw_pos)
+				{
+					cursor_delete(gtd->ses, "");
+				}
 
-					gtd->ses->input->pos += width;
-					gtd->ses->input->cur += size;
-					gtd->ses->input->len += size;
+				
+				str_ins_printf(&gtd->ses->input->buf, gtd->ses->input->raw_pos, "%.*s", size, gtd->macro_buf);
 
-					if (width && gtd->ses->input->len != gtd->ses->input->cur)
-					{
-						input_printf("\e[%d@%.*s", width, size, gtd->macro_buf);
-					}
-					else
-					{
-						input_printf("%.*s", size, gtd->macro_buf);
-					}
-					memmove(gtd->macro_buf, &gtd->macro_buf[size], 1 + strlen(&gtd->macro_buf[size]));
+				gtd->ses->input->str_pos += width;
+				gtd->ses->input->str_len += width;
+
+				gtd->ses->input->raw_pos += size;
+				gtd->ses->input->raw_len += size;
+*/
+
+				if (width && gtd->ses->input->raw_len != gtd->ses->input->raw_pos)
+				{
+					cursor_redraw_line(gtd->ses, "");
 				}
 				else
 				{
-					if (HAS_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT) && gtd->ses->input->len != gtd->ses->input->cur)
-					{
-						cursor_delete(gtd->ses, "");
-					}
-
-					ins_sprintf(&gtd->ses->input->buf[gtd->ses->input->cur], "%c", gtd->macro_buf[0]);
-
-					gtd->ses->input->len++;
-					gtd->ses->input->cur++;
-					gtd->ses->input->pos++;
-
-					if (gtd->ses->input->len != gtd->ses->input->cur)
-					{
-						input_printf("\e[1@%c", gtd->macro_buf[0]);
-					}
-					else
-					{
-						input_printf("%c", gtd->macro_buf[0]);
-					}
-					memmove(gtd->macro_buf, &gtd->macro_buf[1], 1 + strlen(&gtd->macro_buf[1]));
+					input_printf("%.*s", size, gtd->macro_buf);
 				}
-
-//				gtd->macro_buf[0] = 0;
-				gtd->ses->input->tmp[0] = 0;
-				gtd->ses->input->buf[gtd->ses->input->len] = 0;
+				memmove(gtd->macro_buf, &gtd->macro_buf[size], 1 + strlen(&gtd->macro_buf[size]));
 
 				cursor_check_line_modified(gtd->ses, "");
 
-				DEL_BIT(gtd->flags, TINTIN_FLAG_HISTORYBROWSE);
+				DEL_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYBROWSE);
 
 				kill_list(gtd->ses->list[LIST_COMMAND]);
 
-				if (HAS_BIT(gtd->flags, TINTIN_FLAG_HISTORYSEARCH))
+				if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
 				{
 					cursor_history_find(gtd->ses, "");
 				}
 				break;
 		}
 	}
+	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));
+	}
 }
 
 void read_key(char *input, int len)
@@ -316,11 +340,11 @@ void read_key(char *input, int len)
 		return;
 	}
 
-	if (HAS_BIT(gtd->ses->flags, SES_FLAG_CONVERTMETA))
+	if (HAS_BIT(gtd->ses->config_flags, CONFIG_FLAG_CONVERTMETA))
 	{
 		convert_meta(input, &gtd->macro_buf[strlen(gtd->macro_buf)], FALSE);
 	}
-	else if (HAS_BIT(gtd->flags, TINTIN_FLAG_CONVERTMETACHAR))
+	else if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_CONVERTMETACHAR))
 	{
 		convert_meta(input, &gtd->macro_buf[strlen(gtd->macro_buf)], TRUE);
 	}
@@ -340,9 +364,13 @@ void read_key(char *input, int len)
 		{
 			case ASCII_CR:
 			case ASCII_LF:
-				gtd->ses->input->buf[0] = 0;
-				gtd->macro_buf[0] = 0;
-				gtd->ses->input->len = 0;
+				str_cpy(&gtd->ses->input->buf, "");
+
+				gtd->ses->input->raw_len = 0;
+				gtd->ses->input->str_len = 0;
+
+				gtd->ses->input->raw_pos = 0;
+				gtd->ses->input->str_pos = 0;
 
 				if (HAS_BIT(gtd->ses->flags, SES_FLAG_RUN))
 				{
@@ -357,30 +385,25 @@ void read_key(char *input, int len)
 			default:
 				if (gtd->macro_buf[cnt] == gtd->tintin_char && gtd->ses->input->buf[0] == 0)
 				{
-					if (gtd->ses->input->len != gtd->ses->input->cur)
-					{
-						print_stdout("\e[1@%c", gtd->macro_buf[cnt]);
-					}
-					else
-					{
-						print_stdout("%c", gtd->macro_buf[cnt]);
-					}
-					gtd->ses->input->buf[0] = gtd->tintin_char;
-					gtd->ses->input->buf[1] = 0;
-					gtd->macro_buf[0] = 0;
-					gtd->ses->input->len = 1;
-					gtd->ses->input->cur = 1;
-					gtd->ses->input->pos = 1;
+					print_stdout(0, 0, "%c", gtd->macro_buf[cnt]);
+
+					str_cpy_printf(&gtd->ses->input->buf, "%c", gtd->tintin_char);
+
+					gtd->ses->input->raw_len = 1;
+					gtd->ses->input->str_len = 1;
+
+					gtd->ses->input->raw_pos = 1;
+					gtd->ses->input->str_pos = 1;
 				}
 				else
 				{
 					socket_printf(gtd->ses, 1, "%c", gtd->macro_buf[cnt]);
-					gtd->ses->input->buf[0] = 127;
-					gtd->macro_buf[0] = 0;
-					gtd->ses->input->len = 0;
+
+					str_cpy(&gtd->ses->input->buf, "\r");
 				}
 				break;
 		}
+		gtd->macro_buf[0] = 0;
 	}
 }
 
@@ -389,13 +412,13 @@ int check_key(char *input, int len)
 	char buf[BUFFER_SIZE];
 	struct listroot *root;
 	struct listnode *node;
-	int cnt, val[5], partial;
+	int cnt, val[6], partial;
 
 	push_call("check_key(%p,%d)",input,len);
 
 //	tintin_printf2(gtd->ses, "check_key(%d,%s)",*gtd->macro_buf, gtd->macro_buf);
 
-	if (!HAS_BIT(gtd->ses->flags, SES_FLAG_CONVERTMETA))
+	if (!HAS_BIT(gtd->ses->config_flags, CONFIG_FLAG_CONVERTMETA))
 	{
 		root = gtd->ses->list[LIST_MACRO];
 
@@ -407,7 +430,7 @@ int check_key(char *input, int len)
 			{
 				node = root->list[root->update];
 
-				if (*node->arg1 == '^' && gtd->ses->input->len)
+				if (*node->arg1 == '^' && gtd->ses->input->raw_len)
 				{
 					continue;
 				}
@@ -439,13 +462,13 @@ int check_key(char *input, int len)
 					partial = TRUE;
 				}
 			}
+			if (partial)
+			{
+				pop_call();
+				return TRUE;
+			}
 		}
 
-		if (partial)
-		{
-			pop_call();
-			return TRUE;
-		}
 
 		if (!HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_SGA) || HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_ECHO) || gtd->ses->input->buf[0] == gtd->tintin_char)
 		{
@@ -455,7 +478,8 @@ int check_key(char *input, int len)
 				{
 					if (!strcmp(gtd->macro_buf, cursor_table[cnt].code))
 					{
-						cursor_table[cnt].fun(gtd->ses, "");
+						cursor_table[cnt].fun(gtd->ses, cursor_table[cnt].arg);
+
 						gtd->macro_buf[0] = 0;
 
 						pop_call();
@@ -474,13 +498,41 @@ int check_key(char *input, int len)
 		{
 			if (gtd->macro_buf[1] == '[')
 			{
+				if (gtd->macro_buf[2] == 'I')
+				{
+					gtd->macro_buf[0] = 0;
+
+					gtd->screen->focus = 1;
+					
+					check_all_events(gtd->ses, EVENT_FLAG_SCREEN, 0, 1, "SCREEN FOCUS", ntos(gtd->screen->focus));
+					
+					msdp_update_all("SCREEN_FOCUS", "%d", gtd->screen->focus);
+					
+					pop_call();
+					return TRUE;
+				}
+
+				if (gtd->macro_buf[2] == 'O')
+				{
+					gtd->macro_buf[0] = 0;
+
+					gtd->screen->focus = 0;
+					
+					check_all_events(gtd->ses, EVENT_FLAG_SCREEN, 0, 1, "SCREEN FOCUS", ntos(gtd->screen->focus));
+					
+					msdp_update_all("SCREEN_FOCUS", "%d", gtd->screen->focus);
+					 
+					pop_call();
+					return TRUE;
+				}
+
 				if (gtd->macro_buf[2] == '<' && HAS_BIT(gtd->flags, TINTIN_FLAG_MOUSETRACKING))
 				{
 					val[0] = val[1] = val[2] = cnt = input[0] = 0;
 
 					for (len = 3 ; gtd->macro_buf[len] ; len++)
 					{
-						if (isdigit((int) gtd->macro_buf[len]))
+						if (is_digit(gtd->macro_buf[len]))
 						{
 							cat_sprintf(input, "%c", gtd->macro_buf[len]);
 						}
@@ -503,7 +555,7 @@ int check_key(char *input, int len)
 									return TRUE;
 
 								default:
-									print_stdout("unknownmouse input error (%s)\n", gtd->macro_buf);
+									print_stdout(0, 0, "unknownmouse input error (%s)\n", str_convert_meta(gtd->macro_buf, TRUE));
 									gtd->macro_buf[0] = 0;
 									pop_call();
 									return TRUE;
@@ -513,13 +565,14 @@ int check_key(char *input, int len)
 					pop_call();
 					return TRUE;
 				}
-				else if (gtd->macro_buf[2] >= '0' && gtd->macro_buf[2] <= '9')
+
+				if (is_digit(gtd->macro_buf[2]))
 				{
 					cnt = input[0] = 0;
 					memset(val, 0, sizeof(val));
 
 //					tintin_printf2(gtd->ses, "debug: %d %d %d %d %d", val[0], val[1], val[2], val[3], val[4], val[5]);
-		
+
 					for (len = 2 ; gtd->macro_buf[len] ; len++)
 					{
 						if (cnt > 5)
@@ -528,7 +581,7 @@ int check_key(char *input, int len)
 							return FALSE;
 						}
 
-						if (isdigit((int) gtd->macro_buf[len]))
+						if (is_digit(gtd->macro_buf[len]))
 						{
 							cat_sprintf(input, "%c", gtd->macro_buf[len]);
 						}
@@ -553,24 +606,77 @@ int check_key(char *input, int len)
 									input[0] = 0;
 									break;
 
-								case 't':
-									val[cnt++] = get_number(gtd->ses, input);
-									csit_handler(val[0], val[1], val[2]);
-									gtd->macro_buf[0] = 0;
-									pop_call();
-									return TRUE;
 
 								case '&':
 									val[cnt++] = get_number(gtd->ses, input);
 									input[0] = 0;
 									break;
 
+								case '#':
+									val[cnt++] = get_number(gtd->ses, input);
+									input[0] = 0;
+									break;
+
 								case 'w':
 									rqlp_handler(val[0], val[1], val[2], val[3]);
 									gtd->macro_buf[0] = 0;
 									pop_call();
 									return TRUE;
 
+								case 't':
+									val[cnt++] = get_number(gtd->ses, input);
+									csit_handler(val[0], val[1], val[2]);
+									gtd->macro_buf[0] = 0;
+									pop_call();
+									return TRUE;
+
+								case 'd':
+									if (gtd->macro_buf[len - 1] == '#')
+									{
+										check_all_events(gtd->ses, EVENT_FLAG_SCREEN, 0, 3, "SCROLLBAR POSITION", ntos(val[0]), ntos(val[1]), ntos(val[2]));
+
+										if (!check_all_events(gtd->ses, EVENT_FLAG_CATCH, 0, 3, "CATCH SCROLLBAR POSITION", ntos(val[0]), ntos(val[1]), ntos(val[2])))
+										{
+											command(gtd->ses, do_buffer, "JUMP %d", URANGE(0, val[0] + get_scroll_rows(gtd->ses), gtd->ses->scroll->used));
+										}
+										gtd->macro_buf[0] = 0;
+										pop_call();
+										return TRUE;
+									}
+									pop_call();
+									return FALSE;
+
+								case 'e':
+									if (gtd->macro_buf[len - 1] == '#')
+									{
+										check_all_events(gtd->ses, EVENT_FLAG_SCREEN, 0, 3, "SCROLLBAR MOVE", ntos(val[0]), ntos(val[1]), ntos(val[2]));
+
+										if (!check_all_events(gtd->ses, EVENT_FLAG_CATCH, 0, 3, "CATCH SCROLLBAR MOVE", ntos(val[0]), ntos(val[1]), ntos(val[2])))
+										{
+											switch (val[0])
+											{
+												case 5:
+													cursor_page(gtd->ses, "up");
+													break;
+												case 6:
+													cursor_page(gtd->ses, "down");
+													break;
+												case 65:
+													cursor_page(gtd->ses, "up 1");
+													break;
+												case 66:
+													cursor_page(gtd->ses, "down 1");
+													break;
+											}
+										}
+										gtd->macro_buf[0] = 0;
+										pop_call();
+										return TRUE;
+									}
+									pop_call();
+									return FALSE;
+										
+									
 								default:
 									pop_call();
 									return FALSE;
@@ -580,7 +686,8 @@ int check_key(char *input, int len)
 					pop_call();
 					return TRUE;
 				}
-				else if (gtd->macro_buf[2] == 0)
+
+				if (gtd->macro_buf[2] == 0)
 				{
 					pop_call();
 					return TRUE;
@@ -610,7 +717,19 @@ int check_key(char *input, int len)
 						break;
 
 					default:
-						print_stdout("\e[1;31merror: unknown osc input (%s)\n", gtd->macro_buf);
+						for (len = 3 ; gtd->macro_buf[len] ; len++)
+						{
+							if (gtd->macro_buf[len] == '\a' || (gtd->macro_buf[len] == '\e' && gtd->macro_buf[len + 1] == '\\'))
+							{
+								break;
+							}
+						}
+						if (gtd->macro_buf[len] == 0 && len < 30)
+						{
+							pop_call();
+							return TRUE;
+						}
+						print_stdout(0, 0, "\e[1;31merror: unknown osc input (%s)\n", str_convert_meta(gtd->macro_buf, TRUE));
 						gtd->macro_buf[0] = 0;
 						pop_call();
 						return TRUE;
@@ -665,13 +784,13 @@ void convert_meta(char *input, char *output, int eol)
 				*pto++ = 'b';
 				pti++;
 				break;
-
+/*
 			case ASCII_FF:
 				*pto++ = '\\';
 				*pto++ = 'f';
 				pti++;
 				break;
-
+*/
 			case ASCII_HTAB:
 				*pto++ = '\\';
 				*pto++ = 't';
@@ -679,7 +798,7 @@ void convert_meta(char *input, char *output, int eol)
 				break;
 
 			case ASCII_CR:
-				if (HAS_BIT(gtd->flags, TINTIN_FLAG_CONVERTMETACHAR))
+				if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_CONVERTMETACHAR))
 				{
 					*pto++ = '\\';
 					*pto++ = 'r';
@@ -696,15 +815,15 @@ void convert_meta(char *input, char *output, int eol)
 					*pto++ = *pti++;
 				}
 				break;
-
+/*
 			case ASCII_VTAB:
 				*pto++ = '\\';
 				*pto++ = 'v';
 				pti++;
 				break;
-
+*/
 			case ASCII_LF:
-				if (HAS_BIT(gtd->flags, TINTIN_FLAG_CONVERTMETACHAR))
+				if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_CONVERTMETACHAR) || gtd->level->convert)
 				{
 					*pto++ = '\\';
 					*pto++ = 'n';
@@ -748,7 +867,7 @@ void convert_meta(char *input, char *output, int eol)
 	}
 	*pto = 0;
 
-	if (HAS_BIT(gtd->flags, TINTIN_FLAG_CONVERTMETACHAR))
+	if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_CONVERTMETACHAR))
 	{
 		gtd->convert_time = 200000LL + gtd->utime;
 	}
@@ -795,7 +914,7 @@ void echo_command(struct session *ses, char *line)
 		return;
 	}
 
-	if (HAS_BIT(ses->flags, SES_FLAG_ECHOCOMMAND))
+	if (HAS_BIT(ses->config_flags, CONFIG_FLAG_ECHOCOMMAND))
 	{
 		sprintf(buffer, "%s%s\e[0m", ses->cmd_color, line);
 	}
@@ -819,12 +938,83 @@ void echo_command(struct session *ses, char *line)
 	add_line_buffer(ses, buffer, -1);
 }
 
+void init_input(struct session *ses, int top_row, int top_col, int bot_row, int bot_col)
+{
+	push_call("init_input(%p,%d,%d,%d,%d)",ses,top_row,top_col,bot_row,bot_col);
+
+	if (ses->input->buf == NULL)
+	{
+		ses->input->str_off = 1;
+
+		ses->input->edit = create_editor();
+		ses->input->line = create_editor(); // unused for now
+
+		ses->input->edit_name = str_dup("");
+		ses->input->line_name = str_dup("");
+
+		ses->input->buf  = str_dup("");
+		ses->input->tmp  = str_dup("");
+		ses->input->cut  = str_dup("");
+	}
+
+	if (top_row && top_col && bot_row && bot_col)
+	{
+		ses->input->sav_top_row = top_row;
+		ses->input->sav_top_col = top_col;
+		ses->input->sav_bot_row = bot_row;
+		ses->input->sav_bot_col = bot_col;
+	}
+	else
+	{
+		if (ses == gts)
+		{
+			ses->input->sav_top_row = -1;
+			ses->input->sav_top_col =  1;
+			ses->input->sav_bot_row = -1;
+			ses->input->sav_bot_col = -1;
+		}
+		else
+		{
+			ses->input->sav_top_row = gts->input->sav_top_row;
+			ses->input->sav_top_col = gts->input->sav_top_col;
+			ses->input->sav_bot_row = gts->input->sav_bot_row;
+			ses->input->sav_bot_col = gts->input->sav_bot_col;
+		}
+	}
+
+	top_row = get_row_index(ses, ses->input->sav_top_row);
+	top_col = get_col_index(ses, ses->input->sav_top_col);
+	bot_row = get_row_index(ses, ses->input->sav_bot_row);
+	bot_col = get_col_index(ses, ses->input->sav_bot_col);
+
+	ses->input->top_row = top_row;
+	ses->input->top_col = top_col;
+	ses->input->bot_row = bot_row;
+	ses->input->bot_col = bot_col;
+
+	ses->input->cur_row = top_row;
+
+	pop_call();
+	return;
+}
+
+void free_input(struct session *ses)
+{
+	delete_editor(ses->input->line);
+	delete_editor(ses->input->edit);
+
+	str_free(ses->input->edit_name);
+	str_free(ses->input->line_name);
+	str_free(ses->input->buf);
+	str_free(ses->input->tmp);
+}
+
 void input_printf(char *format, ...)
 {
-	char buf[STRING_SIZE];
+	char *buf;
 	va_list args;
 
-	if (!HAS_BIT(gtd->flags, TINTIN_FLAG_HISTORYSEARCH))
+	if (!HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
 	{
 		if (!HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_ECHO) && gtd->ses->input->buf[0] != gtd->tintin_char)
 		{
@@ -833,24 +1023,28 @@ void input_printf(char *format, ...)
 	}
 
 	va_start(args, format);
-	vsprintf(buf, format, args);
+	vasprintf(&buf, format, args);
 	va_end(args);
 
-	print_stdout("%s", buf);
+	print_stdout(0, 0, "%s", buf);
+
+	free(buf);
+
+	return;
 }
 
 void modified_input(void)
 {
 	kill_list(gtd->ses->list[LIST_COMMAND]);
 
-	if (HAS_BIT(gtd->flags, TINTIN_FLAG_HISTORYSEARCH))
+	if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
 	{
 		cursor_history_find(gtd->ses, "");
 	}
 
-	if (HAS_BIT(gtd->flags, TINTIN_FLAG_HISTORYBROWSE))
+	if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYBROWSE))
 	{
-		DEL_BIT(gtd->flags, TINTIN_FLAG_HISTORYBROWSE);
+		DEL_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYBROWSE);
 	}
 
 }

+ 38 - 47
src/line.c

@@ -29,15 +29,13 @@ DO_COMMAND(do_line)
 {
 	int cnt;
 
-	push_call("do_line(%p,%p)",ses,arg);
-
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
 
 	if (*arg1 == 0)
 	{
 		info:
 
-		tintin_header(ses, " LINE OPTIONS ");
+		tintin_header(ses, 80, " LINE OPTIONS ");
 
 		for (cnt = 0 ; *line_table[cnt].fun != NULL ; cnt++)
 		{
@@ -46,9 +44,8 @@ DO_COMMAND(do_line)
 				tintin_printf2(ses, "  [%-13s] %s", line_table[cnt].name, line_table[cnt].desc);
 			}
 		}
-		tintin_header(ses, "");
+		tintin_header(ses, 80, "");
 
-		pop_call();
 		return ses;
 	}
 	else
@@ -67,17 +64,14 @@ DO_COMMAND(do_line)
 		}
 		else
 		{
-			ses = line_table[cnt].fun(ses, arg);
+			ses = line_table[cnt].fun(ses, arg, arg1, arg2, arg3);
 		}
 	}
-	pop_call();
 	return ses;
 }
 
 DO_LINE(line_background)
 {
-	char arg1[BUFFER_SIZE];
-
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
 
 	if (*arg1 == 0)
@@ -99,7 +93,6 @@ DO_LINE(line_background)
 DO_LINE(line_benchmark)
 {
 	long long start, end;
-	char arg1[BUFFER_SIZE];
 
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
 
@@ -123,8 +116,6 @@ DO_LINE(line_benchmark)
 
 DO_LINE(line_capture)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
-
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
 
@@ -154,8 +145,6 @@ DO_LINE(line_capture)
 
 DO_LINE(line_convert)
 {
-	char arg1[BUFFER_SIZE];
-
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
 
 	if (*arg1 == 0)
@@ -165,6 +154,8 @@ DO_LINE(line_convert)
 		return ses;
 	}
 
+	// May need a clearer flag here.
+
 	gtd->level->convert++;
 
 	ses = script_driver(ses, LIST_COMMAND, arg1);
@@ -176,8 +167,6 @@ DO_LINE(line_convert)
 
 DO_LINE(line_debug)
 {
-	char arg1[BUFFER_SIZE];
-
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
 
 	if (*arg1 == 0)
@@ -198,8 +187,6 @@ DO_LINE(line_debug)
 
 DO_LINE(line_gag)
 {
-	char arg1[BUFFER_SIZE];
-
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 
 	switch (*arg1)
@@ -227,8 +214,6 @@ DO_LINE(line_gag)
 
 DO_LINE(line_ignore)
 {
-	char arg1[BUFFER_SIZE];
-
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
 
 	if (*arg1 == 0)
@@ -249,8 +234,6 @@ DO_LINE(line_ignore)
 
 DO_LINE(line_local)
 {
-	char arg1[BUFFER_SIZE];
-
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
 
 	if (*arg1 == 0)
@@ -275,7 +258,6 @@ DO_LINE(line_local)
 
 DO_LINE(line_log)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 	FILE *logfile;
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
@@ -285,7 +267,11 @@ DO_LINE(line_log)
 	{
 		substitute(ses, arg2, arg2, SUB_ESC|SUB_COL|SUB_LNF);
 
-		if (ses->logline_time == gtd->time && !strcmp(ses->logline_name, arg1))
+		if (ses->logfile && !strcmp(ses->logname, arg1))
+		{
+			logit(ses, arg2, ses->logfile, LOG_FLAG_NONE);
+		}
+		else if (ses->logline_time == gtd->time && !strcmp(ses->logline_name, arg1))
 		{
 			logit(ses, arg2, ses->logline_file, LOG_FLAG_NONE);
 		}
@@ -345,8 +331,6 @@ DO_LINE(line_logmode)
 {
 	struct session *active_ses;
 
-	char arg1[BUFFER_SIZE];
-
 	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);
@@ -413,7 +397,6 @@ DO_LINE(line_logmode)
 
 DO_LINE(line_logverbatim)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 	FILE *logfile;
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
@@ -473,10 +456,27 @@ DO_LINE(line_logverbatim)
 	return ses;
 }
 
+DO_LINE(line_msdp)
+{
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
+
+	if (*arg1 == 0)
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {STRIP} {command}.");
+
+		return ses;
+	}
+
+	tintin2msdp(arg1, arg2);
+
+	ses = script_driver(ses, LIST_COMMAND, arg2);
+
+	return ses;
+}
+
 DO_LINE(line_multishot)
 {
 	unsigned int shots;
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
 	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
@@ -505,8 +505,6 @@ DO_LINE(line_multishot)
 
 DO_LINE(line_oneshot)
 {
-	char arg1[BUFFER_SIZE];
-
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
 
 	if (*arg1 == 0)
@@ -529,8 +527,6 @@ DO_LINE(line_oneshot)
 
 DO_LINE(line_quiet)
 {
-	char arg1[BUFFER_SIZE];
-
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
 
 	if (*arg1 == 0)
@@ -551,8 +547,6 @@ DO_LINE(line_quiet)
 
 DO_LINE(line_strip)
 {
-	char arg1[BUFFER_SIZE], strip[BUFFER_SIZE];
-
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_ESC|SUB_COL);
 
 	if (*arg1 == 0)
@@ -562,16 +556,15 @@ DO_LINE(line_strip)
 		return ses;
 	}
 
-	strip_vt102_codes(arg1, strip);
+	strip_vt102_codes(arg1, arg2);
 
-	ses = script_driver(ses, LIST_COMMAND, strip);
+	ses = script_driver(ses, LIST_COMMAND, arg2);
 
 	return ses;
 }
 
 DO_LINE(line_substitute)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], subs[BUFFER_SIZE];
 	int i, flags = 0;
 
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
@@ -579,8 +572,10 @@ DO_LINE(line_substitute)
 
 	if (*arg2 == 0)
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {SUBSTITUTE} {argument} {command}.");
-		
+		for (i = 0 ; *substitution_table[i].name ; i++)
+		{
+			tintin_printf2(ses, "#SYNTAX: #LINE {SUBSTITUTE} {%s} {command}.", substitution_table[i].name);
+		}
 		return ses;
 	}
 
@@ -588,11 +583,11 @@ DO_LINE(line_substitute)
 
 	while (*arg)
 	{
-		arg = get_arg_in_braces(ses, arg, subs, GET_ONE);
+		arg = get_arg_in_braces(ses, arg, arg3, GET_ONE);
 
 		for (i = 0 ; *substitution_table[i].name ; i++)
 		{
-			if (is_abbrev(subs, substitution_table[i].name))
+			if (is_abbrev(arg3, substitution_table[i].name))
 			{
 				SET_BIT(flags, substitution_table[i].bitvector);
 			}
@@ -604,17 +599,15 @@ DO_LINE(line_substitute)
 		}
 	}
 
-	substitute(ses, arg2, subs, flags);
+	substitute(ses, arg2, arg3, flags);
 
-	ses = script_driver(ses, LIST_COMMAND, subs);
+	ses = script_driver(ses, LIST_COMMAND, arg3);
 
 	return ses;
 }
 
 DO_LINE(line_verbatim)
 {
-	char arg1[BUFFER_SIZE];
-
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
 
 	if (*arg1 == 0)
@@ -635,8 +628,6 @@ DO_LINE(line_verbatim)
 
 DO_LINE(line_verbose)
 {
-	char arg1[BUFFER_SIZE];
-
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
 
 	if (*arg1 == 0)

+ 274 - 105
src/list.c

@@ -40,7 +40,7 @@ DO_COMMAND(do_list)
 	{
 		info:
 
-		tintin_header(ses, " LIST OPTIONS ");
+		tintin_header(ses, 80, " LIST OPTIONS ");
 
 		for (index = 0 ; *array_table[index].fun ; index++)
 		{
@@ -49,7 +49,7 @@ DO_COMMAND(do_list)
 				tintin_printf2(ses, "  [%-24s] %s", array_table[index].name, array_table[index].desc);
 			}
 		}
-		tintin_header(ses, "");
+		tintin_header(ses, 80, "");
 	}
 	else if (*arg2 == 0)
 	{
@@ -71,11 +71,18 @@ DO_COMMAND(do_list)
 		}
 		else
 		{
+			if (!valid_variable(ses, arg1))
+			{
+				show_error(ses, LIST_VARIABLE, "#LIST: INVALID VARIABLE NAME {%s}.", arg1);
+
+				return ses;
+			}
+
 			if ((node = search_nest_node_ses(ses, arg1)) == NULL)
 			{
 				node = set_nest_node_ses(ses, arg1, "");
 			}
-			array_table[cnt].fun(ses, node, arg, arg1);
+			array_table[cnt].fun(ses, node, arg, arg1, arg2, arg3);
 		}
 	}
 	return ses;
@@ -83,7 +90,7 @@ DO_COMMAND(do_list)
 
 DO_ARRAY(array_add)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], *str;
+	char *str;
 	int index;
 
 	if (!list->root)
@@ -154,10 +161,11 @@ DO_ARRAY(array_collapse)
 
 DO_ARRAY(array_create)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], buf[BUFFER_SIZE], *str;
-
+	char *buf, *str;
 	int index = 1;
 
+	buf = str_alloc_stack(0);
+
 	substitute(ses, arg, buf, SUB_VAR|SUB_FUN);
 
 	arg = buf;
@@ -197,7 +205,6 @@ DO_ARRAY(array_create)
 
 DO_ARRAY(array_delete)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 	int index, cnt, loop;
 
 	if (list->root)
@@ -235,12 +242,12 @@ DO_ARRAY(array_delete)
 
 DO_ARRAY(array_explode)
 {
-	char buf[BUFFER_SIZE], tmp[BUFFER_SIZE], *pti;
+	char *pti;
 	int index = 1;
 
 	if (list->root)
 	{
-		array_collapse(ses, list, "", "");
+		array_collapse(ses, list, arg, var, arg1, arg2);
 	}
 
 	list->root = init_list(ses, LIST_VARIABLE, LIST_SIZE);
@@ -251,76 +258,123 @@ DO_ARRAY(array_explode)
 	{
 		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, pti))
 		{
-			pti += sprintf(tmp, "%.*s", get_euc_size(ses, pti), pti);
+			pti += sprintf(arg2, "%.*s", get_euc_size(ses, pti), pti);
 		}
 		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(pti))
 		{
-			pti += sprintf(tmp, "%.*s", get_utf8_size(pti), pti);
+			pti += sprintf(arg2, "%.*s", get_utf8_size(pti), pti);
 		}
 		else
 		{
-			pti += sprintf(tmp, "%c", *pti);
+			pti += sprintf(arg2, "%c", *pti);
 		}
 
-		set_nest_node(list->root, ntos(index++), "%s", tmp);
+		set_nest_node(list->root, ntos(index++), "%s", arg2);
 	}
-	sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN);
+	sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
 
-	pti = buf;
+	pti = arg1;
 
 	while (*pti)
 	{
 		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, pti))
 		{
-			pti += sprintf(tmp, "%.*s", get_euc_size(ses, pti), pti);
+			pti += sprintf(arg2, "%.*s", get_euc_size(ses, pti), pti);
 		}
 		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(pti))
 		{
-			pti += sprintf(tmp, "%.*s", get_utf8_size(pti), pti);
+			pti += sprintf(arg2, "%.*s", get_utf8_size(pti), pti);
 		}
 		else
 		{
-			pti += sprintf(tmp, "%c", *pti);
+			pti += sprintf(arg2, "%c", *pti);
 		}
 
-		set_nest_node(list->root, ntos(index++), "%s", tmp);
+		set_nest_node(list->root, ntos(index++), "%s", arg2);
 	}
 	return ses;
 }
 
 DO_ARRAY(array_find)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
-	int index;
+	char *arg3;
+	int cnt, index;
+
+	arg3 = str_alloc_stack(0);
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
-	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
+	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
+	arg = sub_arg_in_braces(ses, arg, arg3, GET_ALL, SUB_VAR|SUB_FUN);
 
 	if (*arg2 == 0)
 	{
-		show_error(ses, LIST_VARIABLE, "#SYNTAX: #LIST {variable} FIND {string} {variable}");
-		
+		show_error(ses, LIST_VARIABLE, "#SYNTAX: #LIST {variable} FIND [nest] {string} {variable}");
+
 		return ses;
 	}
 
 	if (list->root)
 	{
-		for (index = 0 ; index < list->root->used ; index++)
+		if (*arg3 == 0)
 		{
-			if (match(ses, list->root->list[index]->arg2, arg1, SUB_NONE))
+			for (index = 0 ; index < list->root->used ; index++)
 			{
-				break;
+				if (match(ses, list->root->list[index]->arg2, arg1, SUB_NONE))
+				{
+					break;
+				}
 			}
-		}
-		if (index < list->root->used)
-		{
-			set_nest_node_ses(ses, arg2, "%d", index + 1);
+			if (index < list->root->used)
+			{
+				set_nest_node_ses(ses, arg2, "%d", index + 1);
+			}
+			else
+			{
+				set_nest_node_ses(ses, arg2, "0");
+			}
+			return ses;
 		}
 		else
 		{
-			set_nest_node_ses(ses, arg2, "0");
+			if (list->root->list[0]->root == NULL)
+			{
+				show_error(ses, LIST_COMMAND, "#ERROR: #LIST {%s} FIND: NOT AN INDEXABLE LIST TABLE.");
+		
+				return ses;
+			}
+		
+			if (list->root->used > 1)
+			{
+				int index = search_index_list(list->root->list[0]->root, arg1, "");
+		
+				if (index == -1)
+				{
+					show_error(ses, LIST_COMMAND, "#ERROR: #LIST {%s} FIND {%s}: FAILED TO FIND NEST.", var, arg1);
+		
+					return ses;
+				}
+		
+				for (cnt = 0 ; cnt < list->root->used ; cnt++)
+				{
+					if (list->root->list[cnt]->root && list->root->list[cnt]->root->used > index)
+					{
+						if (match(ses, list->root->list[cnt]->root->list[index]->arg2, arg2, SUB_NONE))
+						{
+							break;
+						}
+					}
+				}
+
+				if (cnt < list->root->used)
+				{
+					set_nest_node_ses(ses, arg3, "%d", cnt + 1);
+				}
+				else
+				{
+					set_nest_node_ses(ses, arg3, "%d", 0);
+				}
+			}
 		}
-		return ses;
 	}
 	else
 	{
@@ -333,8 +387,6 @@ DO_ARRAY(array_find)
 
 DO_ARRAY(array_get)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
-
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
 
@@ -367,9 +419,48 @@ DO_ARRAY(array_get)
 	return ses;
 }
 
+DO_ARRAY(array_index)
+{
+	int cnt;
+
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
+
+	if (list->root == NULL || list->root->list[0]->root == NULL)
+	{
+		show_error(ses, LIST_COMMAND, "#ERROR: #LIST {%s} INDEX: NOT AN INDEXABLE LIST TABLE.", var);
+
+		return ses;
+	}
+
+	if (list->root->used > 1)
+	{
+		int index = search_index_list(list->root->list[0]->root, arg1, "");
+
+		if (index == -1)
+		{
+			show_error(ses, LIST_COMMAND, "#ERROR: #LIST {%s} INDEX {%s}: FAILED TO FIND NEST.", var, arg1);
+
+			return ses;
+		}
+
+		for (cnt = 0 ; cnt < list->root->used ; cnt++)
+		{
+			if (list->root->list[cnt]->root && list->root->list[cnt]->root->used > index)
+			{
+				str_cpy(&list->root->list[cnt]->arg2, list->root->list[cnt]->root->list[index]->arg2);
+			}
+			else
+			{
+				show_error(ses, LIST_COMMAND, "#ERROR: #LIST {%s} INDEX: FAILED TO POPULATE INDEX {%s}.", var, list->root->list[cnt]->arg1);
+				break;
+			}
+		}
+	}
+	return ses;
+}
+
 DO_ARRAY(array_insert)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 	int cnt, index;
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
@@ -406,36 +497,81 @@ DO_ARRAY(array_insert)
 
 DO_ARRAY(array_order)
 {
-	int cnt;
-	char **buffer;
-
-	array_add(ses, list, arg, var);
+	int cnt, val, len;
+	char **arg2_buffer;
 
-	buffer = malloc(list->root->used * sizeof(char *));
+	array_add(ses, list, arg, var, arg1, arg2);
 
-	for (cnt = 0 ; cnt < list->root->used ; cnt++)
+	if (list->root->used > 1)
 	{
-		buffer[cnt] = list->root->list[cnt]->arg2;
-	}
+		if (*list->root->list[0]->arg2 == 0)
+		{
+			show_error(ses, LIST_COMMAND, "#ERROR: #LIST {%s} ORDER: LIST IS NOT INDEXED.", var);
 
-	quadsort(buffer, list->root->used, sizeof(char *), cmp_num);
+			return ses;
+		}
 
-	for (cnt = 0 ; cnt < list->root->used ; cnt++)
-	{
-		list->root->list[cnt]->arg2 = buffer[cnt];
-	}
+		if (list->root->list[0]->root)
+		{
+			struct listroot **root_buffer;
+
+			root_buffer = malloc(list->root->used * sizeof(struct listroot *));
+			arg2_buffer = malloc(list->root->used * sizeof(char *));
+
+			for (cnt = 0 ; cnt < list->root->used ; cnt++)
+			{
+				len = str_len(list->root->list[cnt]->arg2);
+
+				root_buffer[cnt] = list->root->list[cnt]->root;
+				arg2_buffer[cnt] = list->root->list[cnt]->arg2;
+
+				str_resize(&arg2_buffer[cnt], 10);
+
+				sprintf(arg2_buffer[cnt] + len + 1, "%x", cnt);
+			}
+
+			quadsort(arg2_buffer, list->root->used, sizeof(char *), cmp_num);
+
+			for (cnt = 0 ; cnt < list->root->used ; cnt++)
+			{
+				val = hex_number_32bit(arg2_buffer[cnt] + str_len(arg2_buffer[cnt]) + 1);
+
+				list->root->list[cnt]->root = root_buffer[val];
+				list->root->list[cnt]->arg2 = arg2_buffer[cnt];
+			}
 
-	free(buffer);
+			free(arg2_buffer);
+			free(root_buffer);
+		}
+		else
+		{
+			arg2_buffer = malloc(list->root->used * sizeof(char *));
+
+			for (cnt = 0 ; cnt < list->root->used ; cnt++)
+			{
+				arg2_buffer[cnt] = list->root->list[cnt]->arg2;
+			}
+
+			quadsort(arg2_buffer, list->root->used, sizeof(char *), cmp_num);
+
+			for (cnt = 0 ; cnt < list->root->used ; cnt++)
+			{
+				list->root->list[cnt]->arg2 = arg2_buffer[cnt];
+			}
 
+			free(arg2_buffer);
+		}
+	}
 	return ses;
 }
 
 DO_ARRAY(array_reverse)
 {
+	struct listroot *toor;
 	char *swap;
 	int cnt, rev;
 
-	array_add(ses, list, arg, var);
+	array_add(ses, list, arg, var, arg1, arg2);
 
 	for (cnt = 0 ; cnt < list->root->used / 2 ; cnt++)
 	{
@@ -444,47 +580,36 @@ DO_ARRAY(array_reverse)
 		swap = list->root->list[cnt]->arg2;
 		list->root->list[cnt]->arg2 = list->root->list[rev]->arg2;
 		list->root->list[rev]->arg2 = swap;
+
+		toor = list->root->list[cnt]->root;
+		list->root->list[cnt]->root = list->root->list[rev]->root;
+		list->root->list[rev]->root = toor;
 	}
 	return ses;
 }
 
 DO_ARRAY(array_simplify)
 {
-	char arg1[BUFFER_SIZE], *str;
+	char *str;
 	int index;
 
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
-/*
-	if (*arg1 == 0)
-	{
-		show_error(ses, LIST_VARIABLE, "#SYNTAX: #LIST {variable} SIMPLIFY {variable}");
-		
-		return ses;
-	}
-*/
+	array_add(ses, list, arg, var, arg1, arg2);
+
+	str = str_alloc_stack(0);
+
 	if (list->root)
 	{
-		for (index = 0 ; index < list->root->used ; index++)
-		{
-			if (index == 0)
-			{
-				str = str_dup(list->root->list[index]->arg2);
-			}
-			else
-			{
-				str_cat_printf(&str, ";%s", list->root->list[index]->arg2);
-			}
-		}
-		if (*arg1 == 0)
+		if (list->root->used)
 		{
-			set_nest_node_ses(ses, list->arg1, "%s", str);
+			str_cpy(&str, list->root->list[0]->arg2);
 		}
-		else
+
+		for (index = 1 ; index < list->root->used ; index++)
 		{
-			set_nest_node_ses(ses, arg1, "%s", str);
+			str_cat_printf(&str, ";%s", list->root->list[index]->arg2);
 		}
 
-		str_free(str);
+		set_nest_node_ses(ses, var, "%s", str);
 
 		return ses;
 	}
@@ -498,8 +623,6 @@ DO_ARRAY(array_simplify)
 
 DO_ARRAY(array_size)
 {
-	char arg1[BUFFER_SIZE];
-
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
 
 	if (*arg1 == 0)
@@ -522,8 +645,6 @@ DO_ARRAY(array_size)
 
 DO_ARRAY(array_set)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
-
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
 
@@ -552,10 +673,11 @@ DO_ARRAY(array_set)
 
 DO_ARRAY(array_shuffle)
 {
+	struct listroot *toor;
 	char *swap;
 	int cnt, rnd;
 
-	array_add(ses, list, arg, var);
+	array_add(ses, list, arg, var, arg1, arg2);
 
 	for (cnt = 0 ; cnt < list->root->used ; cnt++)
 	{
@@ -564,42 +686,89 @@ DO_ARRAY(array_shuffle)
 		swap = list->root->list[cnt]->arg2;
 		list->root->list[cnt]->arg2 = list->root->list[rnd]->arg2;
 		list->root->list[rnd]->arg2 = swap;
+
+		toor = list->root->list[cnt]->root;
+		list->root->list[cnt]->root = list->root->list[rnd]->root;
+		list->root->list[rnd]->root = toor;
 	}
 	return ses;
 }
 
 DO_ARRAY(array_sort)
 {
-	int cnt;
-	char **buffer;
+	int cnt, val, len;
+	char **arg2_buffer;
 
-	array_add(ses, list, arg, var);
+	array_add(ses, list, arg, var, arg1, arg2);
 
-	buffer = malloc(list->root->used * sizeof(char *));
-
-	for (cnt = 0 ; cnt < list->root->used ; cnt++)
+	if (list->root->used > 1)
 	{
-		buffer[cnt] = list->root->list[cnt]->arg2;
-	}
+		if (*list->root->list[0]->arg2 == 0)
+		{
+			show_error(ses, LIST_COMMAND, "#ERROR: #LIST {%s} ORDER: LIST IS NOT INDEXED.", var);
+
+			return ses;
+		}
 
-	quadsort(buffer, list->root->used, sizeof(char *), cmp_str);
+		if (list->root->list[0]->root)
+		{
+			struct listroot **root_buffer;
 
-	for (cnt = 0 ; cnt < list->root->used ; cnt++)
-	{
-		list->root->list[cnt]->arg2 = buffer[cnt];
-	}
+			root_buffer = malloc(list->root->used * sizeof(struct listroot *));
+			arg2_buffer = malloc(list->root->used * sizeof(char *));
+
+			for (cnt = 0 ; cnt < list->root->used ; cnt++)
+			{
+				len = str_len(list->root->list[cnt]->arg2);
 
-	free(buffer);
+				root_buffer[cnt] = list->root->list[cnt]->root;
+				arg2_buffer[cnt] = list->root->list[cnt]->arg2;
 
+				str_resize(&arg2_buffer[cnt], 10);
+
+				sprintf(arg2_buffer[cnt] + len + 1, "%x", cnt);
+			}
+
+			quadsort(arg2_buffer, list->root->used, sizeof(char *), cmp_str);
+
+			for (cnt = 0 ; cnt < list->root->used ; cnt++)
+			{
+				val = hex_number_32bit(arg2_buffer[cnt] + str_len(arg2_buffer[cnt]) + 1);
+
+				list->root->list[cnt]->root = root_buffer[val];
+				list->root->list[cnt]->arg2 = arg2_buffer[cnt];
+			}
+
+			free(arg2_buffer);
+			free(root_buffer);
+		}
+		else
+		{
+			arg2_buffer = malloc(list->root->used * sizeof(char *));
+
+			for (cnt = 0 ; cnt < list->root->used ; cnt++)
+			{
+				arg2_buffer[cnt] = list->root->list[cnt]->arg2;
+			}
+
+			quadsort(arg2_buffer, list->root->used, sizeof(char *), cmp_str);
+
+			for (cnt = 0 ; cnt < list->root->used ; cnt++)
+			{
+				list->root->list[cnt]->arg2 = arg2_buffer[cnt];
+			}
+
+			free(arg2_buffer);
+		}
+	}
 	return ses;
 }
 
 DO_ARRAY(array_tokenize)
 {
-	char buf[BUFFER_SIZE], tmp[BUFFER_SIZE];
 	int index = 1, i;
 
-	sub_arg_in_braces(ses, arg, buf, GET_ALL, SUB_VAR|SUB_FUN);
+	sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
 
 	if (list->root)
 	{
@@ -610,22 +779,22 @@ DO_ARRAY(array_tokenize)
 
 	i = 0;
 
-	while (buf[i] != 0)
+	while (arg1[i] != 0)
 	{
-		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, &buf[i]))
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, &arg1[i]))
 		{
-			i += sprintf(tmp, "%.*s", get_euc_size(ses, &buf[i]), &buf[i]);
+			i += sprintf(arg2, "%.*s", get_euc_size(ses, &arg1[i]), &arg1[i]);
 		}
-		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&buf[i]))
+		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&arg1[i]))
 		{
-			i += sprintf(tmp, "%.*s", get_utf8_size(&buf[i]), &buf[i]);
+			i += sprintf(arg2, "%.*s", get_utf8_size(&arg1[i]), &arg1[i]);
 		}
 		else
 		{
-			i += sprintf(tmp, "%c", buf[i]);
+			i += sprintf(arg2, "%c", arg1[i]);
 		}
 
-		set_nest_node(list->root, ntos(index++), "%s", tmp);
+		set_nest_node(list->root, ntos(index++), "%s", arg2);
 	}
 	return ses;
 }

+ 14 - 1
src/log.c

@@ -38,7 +38,7 @@ DO_COMMAND(do_log)
 	{
 		info:
 
-		tintin_header(ses, " LOG OPTIONS ");
+		tintin_header(ses, 80, " LOG OPTIONS ");
 
 		for (cnt = 0 ; *log_table[cnt].fun != NULL ; cnt++)
 		{
@@ -84,6 +84,8 @@ DO_LOG(log_append)
 	{
 		SET_BIT(ses->logmode, LOG_FLAG_APPEND);
 
+		RESTRING(ses->logname, arg2);
+
 		loginit(ses, ses->logfile, ses->logmode);
 
 		show_message(ses, LIST_COMMAND, "#LOG: LOGGING OUTPUT TO '%s' FILESIZE: %ld", arg2, ftell(ses->logfile));
@@ -94,6 +96,15 @@ 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 : "");
+}
+
 DO_LOG(log_overwrite)
 {
 	if (ses->logfile)
@@ -105,6 +116,8 @@ DO_LOG(log_overwrite)
 	{
 		SET_BIT(ses->logmode, LOG_FLAG_OVERWRITE);
 
+		RESTRING(ses->logname, arg2);
+
 		loginit(ses, ses->logfile, ses->logmode);
 
 		show_message(ses, LIST_COMMAND, "#LOG: LOGGING OUTPUT TO '%s'", arg2);

+ 130 - 125
src/main.c

@@ -29,6 +29,10 @@
 
 #include <signal.h>
 
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
 /*************** globals ******************/
 
 struct session *gts;
@@ -75,7 +79,7 @@ void winch_handler(int signal)
 
 		if (HAS_BIT(ses->telopts, TELOPT_FLAG_NAWS))
 		{
-			client_send_sb_naws(ses, 0, NULL);
+			SET_BIT(ses->telopts, TELOPT_FLAG_UPDATENAWS);
 		}
 	}
 
@@ -146,7 +150,7 @@ void trap_handler(int signal)
 int main(int argc, char **argv)
 {
 	int c, i = 0, greeting = 0;
-	char filename[256];
+	char filename[PATH_SIZE];
 	char arg[BUFFER_SIZE];
 
 	#ifdef SOCKS
@@ -235,7 +239,7 @@ int main(int argc, char **argv)
 
 	if (argc > 1)
 	{
-		while ((c = getopt(argc, argv, "a: e: G h M:: r: R:: s t: T v V")) != EOF)
+		while ((c = getopt(argc, argv, "a: e: g G h M:: r: R:: s t: T v V")) != EOF)
 		{
 			switch (c)
 			{
@@ -244,10 +248,12 @@ int main(int argc, char **argv)
 					printf("\n");
 					printf("  -a  Set argument for PROGRAM START event.\n");
 					printf("  -e  Execute given command.\n");
+					printf("  -g  Enable the startup user interface.\n");
 					printf("  -G  Don't show the greeting screen.\n");
 					printf("  -h  This help section.\n");
 					printf("  -M  Matrix Digital Rain.\n");
 					printf("  -r  Read given file.\n");
+					printf("  -R  Reattach to daemonized process.\n");
 					printf("  -s  Enable screen reader mode.\n");
 					printf("  -t  Set given title.\n");
 					printf("  -T  Don't set the default title.\n");
@@ -280,16 +286,11 @@ int main(int argc, char **argv)
 
 	init_tintin(greeting);
 
-	sprintf(filename, "%s/%s", gtd->home, TINTIN_DIR);
+	sprintf(filename, "%s/%s", gtd->system->tt_dir, HISTORY_FILE);
 
-	if (mkdir(filename, 0777) || errno == EEXIST)
+	if (access(filename, F_OK ) != -1)
 	{
-		sprintf(filename, "%s/%s/%s", gtd->home, TINTIN_DIR, HISTORY_FILE);
-
-		if (access(filename, F_OK ) != -1)
-		{
-			history_read(gts, filename, "", "");
-		}
+		command(gts, do_history, "read %s", filename);
 	}
 
 	RESTRING(gtd->vars[1], argv[0]);
@@ -300,7 +301,7 @@ int main(int argc, char **argv)
 
 		RESTRING(gtd->vars[2], argv[1]);
 
-		while ((c = getopt(argc, argv, "a: e: G h M:: r: R:: s t: T v")) != EOF)
+		while ((c = getopt(argc, argv, "a: e: g G h M:: r: R:: s t: T v")) != EOF)
 		{
 			switch (c)
 			{
@@ -315,22 +316,26 @@ int main(int argc, char **argv)
 					gtd->level->input--;
 					break;
 
+				case 'g':
+					gtd->ses = command(gtd->ses, do_banner, "gui");
+					break;
+
 				case 'G':
 					break;
 
 				case 'M':
-					execute(gts, "#TEST %s", optarg ? optarg : "");
+					command(gts, do_test, "rain %s", optarg ? optarg : "");
 					break;
 
 				case 'r':
 //					gtd->level->input++;
-					gtd->ses = execute(gtd->ses, "#READ %s", optarg);
+					gtd->ses = command(gtd->ses, do_read, "%s", optarg);
 //					gtd->level->input--;
 					break;
 
 				case 'R':
 					SET_BIT(gtd->flags, TINTIN_FLAG_DAEMONIZE);
-					daemon_attach(gtd->ses, optarg ? optarg : "");
+					command(gtd->ses, do_daemon, "attach {%s}", optarg ? optarg : "");
 					break;
 
 				case 's':
@@ -338,7 +343,7 @@ int main(int argc, char **argv)
 
 				case 't':
 					SET_BIT(greeting, STARTUP_FLAG_NOTITLE);
-					print_stdout("\e]0;%s\007", optarg);
+					print_stdout(0, 0, "\e]0;%s\007", optarg);
 					break;
 
 				case 'T':
@@ -358,12 +363,12 @@ int main(int argc, char **argv)
 
 	if (!HAS_BIT(greeting, STARTUP_FLAG_NOTITLE))
 	{
-		execute(gts, "#SCREEN LOAD BOTH");
-		execute(gts, "#SCREEN SAVE BOTH");
-		execute(gts, "#SCREEN SET BOTH TinTin++");
+		command(gts, do_screen, "LOAD BOTH");
+		command(gts, do_screen, "SAVE BOTH");
+		command(gts, do_screen, "SET BOTH TinTin++");
 	}
 
-	gtd->exec = strdup(argv[0]);
+	gtd->system->exec = strdup(argv[0]);
 
 	if (argc > 2)
 	{
@@ -400,19 +405,19 @@ int main(int argc, char **argv)
 	{
 		if (!strncasecmp(argv[optind], "telnet://", 9))
 		{
-			gtd->ses = execute(gts, "#SESSION %s", argv[optind]);
+			gtd->ses = command(gtd->ses, do_session, "%s", argv[optind]);
 		}
 		else
 		{
 			gtd->level->input++;
 
-			gtd->ses = execute(gtd->ses, "#READ %s", argv[optind]);
+			gtd->ses = command(gtd->ses, do_read, "%s", argv[optind]);
 
 			gtd->level->input--;
 		}
 	}
 
-	check_all_events(gts, SUB_ARG, 0, 0, "PROGRAM START");
+	check_all_events(gts, EVENT_FLAG_SYSTEM, 0, 0, "PROGRAM START");
 
 	mainloop();
 
@@ -421,21 +426,18 @@ int main(int argc, char **argv)
 
 void init_tintin(int greeting)
 {
-	int ref, index;
+	int index;
 
-	gtd                    = (struct tintin_data *) calloc(1, sizeof(struct tintin_data));
+	gtd                 = (struct tintin_data *) calloc(1, sizeof(struct tintin_data));
 
-	gtd->memory            = calloc(1, sizeof(struct memory_data));
-	gtd->memory->debug     = calloc(1, sizeof(struct stack_data *));
-	gtd->memory->stack     = calloc(1, sizeof(struct str_data *));
-	gtd->memory->alloc     = calloc(1, sizeof(struct str_data));
+	init_memory();
 
 	push_call("init_tintin(%d)",greeting);
 
-	gtd->level             = (struct level_data *) calloc(1, sizeof(struct level_data));
+	gtd->level          = (struct level_data *) calloc(1, sizeof(struct level_data));
 
-	gtd->buf               = str_alloc(STRING_SIZE);
-	gtd->out               = str_alloc(STRING_SIZE);
+	gtd->buf            = str_alloc(BUFFER_SIZE);
+	gtd->out            = str_alloc(BUFFER_SIZE);
 
 	gtd->flags          = TINTIN_FLAG_INHERITANCE;
 
@@ -445,10 +447,23 @@ void init_tintin(int greeting)
 	gtd->mud_output_max = 16384;
 	gtd->mud_output_buf = (char *) calloc(1, gtd->mud_output_max);
 
-	gtd->os             = strdup(getenv("OS")   ? getenv("OS")   : "UNKNOWN");
-	gtd->home           = strdup(getenv("HOME") ? getenv("HOME") : "~/");
-	gtd->lang           = strdup(getenv("LANG") ? getenv("LANG") : "UNKNOWN");
-	gtd->term           = strdup(getenv("TERM") ? getenv("TERM") : "UNKNOWN");
+	// WSL: /proc/sys/kernel/osrelease
+
+	gtd->system         = (struct system_data *) calloc(1, sizeof(struct system_data));
+
+	gtd->system->os     = strdup(getenv("OS")   ? getenv("OS")   : "UNKNOWN");
+	gtd->system->home   = strdup(getenv("HOME") ? getenv("HOME") : "~/");
+	gtd->system->lang   = strdup(getenv("LANG") ? getenv("LANG") : "UNKNOWN");
+	gtd->system->term   = strdup(getenv("TERM") ? getenv("TERM") : "UNKNOWN");
+
+	gtd->system->tt_dir = restringf(gtd->system->tt_dir, "%s/%s", gtd->system->home, TINTIN_DIR);
+
+	if (mkdir(gtd->system->tt_dir, 0755) && errno != EEXIST)
+	{
+		gtd->system->tt_dir = restringf(gtd->system->tt_dir, "%s", TINTIN_DIR);
+
+		mkdir(gtd->system->tt_dir, 0755);
+	}
 
 	gtd->detach_file    = strdup("");
 	gtd->attach_file    = strdup("");
@@ -456,7 +471,6 @@ void init_tintin(int greeting)
 	gtd->tintin_char    = '#';
 
 	gtd->time           = time(NULL);
-	gtd->calendar       = *localtime(&gtd->time);
 
 	for (index = 0 ; index < 100 ; index++)
 	{
@@ -464,23 +478,6 @@ void init_tintin(int greeting)
 		gtd->cmds[index] = strdup("");
 	}
 
-	for (ref = 0 ; ref < 26 ; ref++)
-	{
-		for (index = 0 ; *command_table[index].name != 0 ; index++)
-		{
-			if (index && strcmp(command_table[index - 1].name, command_table[index].name) > 0)
-			{
-				print_stdout("\e[1;31minit_tintin() unsorted command table %s vs %s.", command_table[index - 1].name, command_table[index].name);
-			}
-
-			if (*command_table[index].name == 'a' + ref)
-			{
-				gtd->command_ref[ref] = index;
-				break;
-			}
-		}
-	}
-
 	for (index = 1 ; index ; index++)
 	{
 		if (*event_table[index].name == 0)
@@ -490,12 +487,14 @@ void init_tintin(int greeting)
 
 		if (strcmp(event_table[index - 1].name, event_table[index].name) > 0)
 		{
-			print_stdout("\e[1;31minit_tintin() unsorted event table %s vs %s.", event_table[index - 1].name, event_table[index].name);
+			print_stdout(0, 0, "\e[1;31minit_tintin() unsorted event table %s vs %s.", event_table[index - 1].name, event_table[index].name);
 
 			break;
 		}
 	}
 
+	init_commands();
+
 	gtd->screen = calloc(1, sizeof(struct screen_data));
 
 	gtd->screen->rows   = SCREEN_HEIGHT;
@@ -504,9 +503,9 @@ void init_tintin(int greeting)
 	gtd->screen->width  = SCREEN_WIDTH * 10;
 	gtd->screen->focus  = 1;
 
-	init_msdp_table();
-
+	gtd->dispose_list   = init_list(NULL, 0, 32);
 
+	init_msdp_table();
 
 	// global tintin session
 
@@ -520,9 +519,10 @@ void init_tintin(int greeting)
 	gts->session_port   = strdup("");
 	gts->cmd_color      = strdup("");
 	gts->telopts        = TELOPT_FLAG_ECHO;
-	gts->flags          = SES_FLAG_MCCP;
+	gts->config_flags   = CONFIG_FLAG_MCCP;
 	gts->socket         = 1;
 	gts->read_max       = 16384;
+	gts->logname        = strdup("");
 	gts->lognext_name   = strdup("");
 	gts->logline_name   = strdup("");
 
@@ -533,17 +533,18 @@ void init_tintin(int greeting)
 		gts->list[index] = init_list(gts, index, 32);
 	}
 
+	gtd->banner_list    = init_list(gts, LIST_CONFIG, 32);
+
 	gts->split          = calloc(1, sizeof(struct split_data));
 	gts->scroll         = calloc(1, sizeof(struct scroll_data));
 	gts->input          = calloc(1, sizeof(struct input_data));
-	gts->input->buf     = str_alloc(BUFFER_SIZE);
-	gts->input->tmp     = str_alloc(BUFFER_SIZE);
-	gts->input->off     = 1;
 
 	init_local(gts);
 
 	init_terminal_size(gts);
 
+	init_input(gts, 0, 0, 0, 0);
+
 	init_buffer(gts, 10000);
 
 	if (HAS_BIT(greeting,  STARTUP_FLAG_VERBOSE))
@@ -553,42 +554,42 @@ void init_tintin(int greeting)
 
 	gtd->level->input++;
 
-	execute(gts, "#CONFIG {AUTO TAB}         {5000}");
-	execute(gts, "#CONFIG {BUFFER SIZE}     {10000}");
-	execute(gts, "#CONFIG {COLOR MODE}         {ON}");
-	execute(gts, "#CONFIG {COLOR PATCH}       {OFF}");
-	execute(gts, "#CONFIG {COMMAND COLOR}   {<078>}");
-	execute(gts, "#CONFIG {COMMAND ECHO}       {ON}");
-	execute(gts, "#CONFIG {CONNECT RETRY}       {0}");
-	execute(gts, "#CONFIG {CHARSET}          {AUTO}");
-	execute(gts, "#CONFIG {HISTORY SIZE}     {1000}");
-	execute(gts, "#CONFIG {LOG MODE}          {RAW}");
-	execute(gts, "#CONFIG {MOUSE TRACKING}    {OFF}");
-	execute(gts, "#CONFIG {PACKET PATCH}     {AUTO}");
-	execute(gts, "#CONFIG {RANDOM SEED}      {AUTO}");
-	execute(gts, "#CONFIG {REPEAT CHAR}         {!}");
-	execute(gts, "#CONFIG {REPEAT ENTER}      {OFF}");
-	execute(gts, "#CONFIG {SCREEN READER}      {%s}", HAS_BIT(greeting, STARTUP_FLAG_SCREENREADER) ? "ON" : "OFF");
-	execute(gts, "#CONFIG {SCROLL LOCK}        {ON}");
-	execute(gts, "#CONFIG {SPEEDWALK}         {OFF}");
-	execute(gts, "#CONFIG {TAB WIDTH}        {AUTO}");
-	execute(gts, "#CONFIG {TELNET}             {ON}");
-	execute(gts, "#CONFIG {TINTIN CHAR}         {#}");
-	execute(gts, "#CONFIG {VERBATIM}          {OFF}");
-	execute(gts, "#CONFIG {VERBATIM CHAR}      {\\}");
-	execute(gts, "#CONFIG {VERBOSE}            {%s}", HAS_BIT(greeting, STARTUP_FLAG_VERBOSE) ? "ON" : "OFF");
-	execute(gts, "#CONFIG {WORDWRAP}           {ON}");
-
-	execute(gts, "#PATHDIR  n  s  1");
-	execute(gts, "#PATHDIR  e  w  2");
-	execute(gts, "#PATHDIR  s  n  4");
-	execute(gts, "#PATHDIR  w  e  8");
-	execute(gts, "#PATHDIR  u  d 16");
-	execute(gts, "#PATHDIR  d  u 32");
-	execute(gts, "#PATHDIR ne sw  3");
-	execute(gts, "#PATHDIR nw se  9");
-	execute(gts, "#PATHDIR se nw  6");
-	execute(gts, "#PATHDIR sw ne 12");
+	command(gts, do_configure, "{AUTO TAB}         {5000}");
+	command(gts, do_configure, "{BUFFER SIZE}     {10000}");
+	command(gts, do_configure, "{COLOR MODE}         {ON}");
+	command(gts, do_configure, "{COLOR PATCH}       {OFF}");
+	command(gts, do_configure, "{COMMAND COLOR}   {<078>}");
+	command(gts, do_configure, "{COMMAND ECHO}       {ON}");
+	command(gts, do_configure, "{CONNECT RETRY}       {0}");
+	command(gts, do_configure, "{CHARSET}          {AUTO}");
+	command(gts, do_configure, "{HISTORY SIZE}     {1000}");
+	command(gts, do_configure, "{LOG MODE}          {RAW}");
+	command(gts, do_configure, "{MOUSE}             {OFF}");
+	command(gts, do_configure, "{PACKET PATCH}     {AUTO}");
+	command(gts, do_configure, "{RANDOM SEED}      {AUTO}");
+	command(gts, do_configure, "{REPEAT CHAR}         {!}");
+	command(gts, do_configure, "{REPEAT ENTER}      {OFF}");
+	command(gts, do_configure, "{SCREEN READER}      {%s}", HAS_BIT(greeting, STARTUP_FLAG_SCREENREADER) ? "ON" : "OFF");
+	command(gts, do_configure, "{SCROLL LOCK}        {ON}");
+	command(gts, do_configure, "{SPEEDWALK}         {OFF}");
+	command(gts, do_configure, "{TAB WIDTH}        {AUTO}");
+	command(gts, do_configure, "{TELNET}             {ON}");
+	command(gts, do_configure, "{TINTIN CHAR}         {#}");
+	command(gts, do_configure, "{VERBATIM}          {OFF}");
+	command(gts, do_configure, "{VERBATIM CHAR}      {\\}");
+	command(gts, do_configure, "{VERBOSE}            {%s}", HAS_BIT(greeting, STARTUP_FLAG_VERBOSE) ? "ON" : "OFF");
+	command(gts, do_configure, "{WORDWRAP}           {ON}");
+
+	command(gts, do_pathdir, " n  s  1");
+	command(gts, do_pathdir, " e  w  2");
+	command(gts, do_pathdir, " s  n  4");
+	command(gts, do_pathdir, " w  e  8");
+	command(gts, do_pathdir, " u  d 16");
+	command(gts, do_pathdir, " d  u 32");
+	command(gts, do_pathdir, "ne sw  3");
+	command(gts, do_pathdir, "nw se  9");
+	command(gts, do_pathdir, "se nw  6");
+	command(gts, do_pathdir, "sw ne 12");
 
 	gtd->level->input--;
 
@@ -601,33 +602,39 @@ void init_tintin(int greeting)
 
 	reset_screen(gts);
 
+	command(gts, do_banner, "INIT");
+
 	if (!HAS_BIT(greeting, STARTUP_FLAG_NOGREETING))
 	{
 		if (HAS_BIT(greeting, STARTUP_FLAG_SCREENREADER))
 		{
 			tintin_printf2(gts, "Welcome to TinTin Plus Plus. Don't know which MUD to play? How about the following MUD.");
 
-			execute(gts, "ADVERTISE");
+			command(gts, do_banner, "RANDOM");
+
+			tintin_printf2(gts, "You're using TinTin Plus Plus version %s written by Peter Unold, Bill Reis, and Igor van den Hoven.", CLIENT_VERSION);
 
-			tintin_printf2(gts, "You're using TinTin Plus Plus written by Peter Unold, Bill Reis, and Igor van den Hoven.", CLIENT_VERSION);
+			tintin_printf2(gts, "");
 
-			tintin_printf2(gts, "For help and requests visit tintin.sourceforge.io/forum the captcha answer is 3671.");
+			tintin_printf2(gts, "For help and requests visit the Discord channel at https://discord.gg/gv7a37n");
 		}
 		else
 		{
-			execute(gts, "#ADVERTISE");
+			command(gts, do_banner, "RANDOM");
 
 			if (gtd->screen->cols >= 80)
 			{
-				execute(gts, "#HELP GREETING");
+				command(gts, do_help, "GREETING");
 			}
 			else
 			{
-				tintin_printf2(gts,
-					"\e[0;37mT I N T I N + +   %s"
-					"\n\n\e[0;36mT\e[0;37mhe K\e[0;36mi\e[0;37mcki\e[0;36mn\e[0;37m \e[0;36mT\e[0;37mickin D\e[0;36mi\e[0;37mkuMUD Clie\e[0;36mn\e[0;37mt\n\n"
-					"Code by Peter Unold, Bill Reis, and Igor van den Hoven\n",
-					CLIENT_VERSION);
+				tintin_printf2(gts, "\e[0;37mT I N T I N + +   %s", CLIENT_VERSION);
+
+				tintin_printf2(gts, "");
+
+//				tintin_printf2(gts, "\e[0;36mT\e[0;37mhe K\e[0;36mi\e[0;37mcki\e[0;36mn\e[0;37m \e[0;36mT\e[0;37mickin D\e[0;36mi\e[0;37mkuMUD Clie\e[0;36mn\e[0;37mt");
+
+				tintin_printf2(gts, "Code by Peter Unold, Bill Reis, and Igor van den Hoven");
 			}
 		}
 	}
@@ -643,7 +650,7 @@ void quitmsg(char *message)
 
 	if (crashed++)
 	{
-		print_stdout("quitmsg(crashed)\n");
+		print_stdout(0, 0, "quitmsg(crashed)\n");
 
 		fflush(NULL);
 
@@ -652,7 +659,7 @@ void quitmsg(char *message)
 
 	SET_BIT(gtd->flags, TINTIN_FLAG_TERMINATE);
 
-	while ((ses = gts->next) != NULL)
+	for (ses = gts->next ; ses ; ses = gts->next)
 	{
 		cleanup_session(ses);
 	}
@@ -662,15 +669,11 @@ void quitmsg(char *message)
 		chat_uninitialize("", "");
 	}
 
-	check_all_events(gts, SUB_ARG, 0, 1, "PROGRAM TERMINATION", message ? message : "");
+	check_all_events(gts, EVENT_FLAG_SYSTEM, 0, 1, "PROGRAM TERMINATION", message ? message : "");
 
 	if (gtd->history_size)
 	{
-		char filename[BUFFER_SIZE];
-
-		sprintf(filename, "%s/%s/%s", gtd->home, TINTIN_DIR, HISTORY_FILE);
-
-		history_write(gts, filename, "", "");
+		command(gts, do_history, "write %s/%s", gtd->system->tt_dir, HISTORY_FILE);
 	}
 
 	reset_daemon();
@@ -683,11 +686,11 @@ void quitmsg(char *message)
 	{
 		if (message)
 		{
-			print_stdout("\n\e[0m%s", message);
+			print_stdout(0, 0, "\n\e[0m%s", message);
 		}
-		print_stdout("\nGoodbye from TinTin++\n\n");
+		print_stdout(0, 0, "\nGoodbye from TinTin++\n\n");
 	}
-	fflush(NULL);
+	fflush(stdout);
 
 	exit(0);
 }
@@ -713,9 +716,9 @@ void syserr_printf(struct session *ses, char *fmt, ...)
 		sprintf(name, "(null)");
 	}
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "SYSTEM ERROR", name, buf, ntos(errno), errstr);
+	check_all_events(ses, SUB_SEC|EVENT_FLAG_SYSTEM, 0, 4, "SYSTEM ERROR", name, buf, ntos(errno), errstr);
 
-	if (!check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "CATCH SYSTEM ERROR", name, buf, ntos(errno), errstr))
+	if (!check_all_events(ses, SUB_SEC|EVENT_FLAG_SYSTEM, 0, 4, "CATCH SYSTEM ERROR", name, buf, ntos(errno), errstr))
 	{
 		if (gts)
 		{
@@ -741,7 +744,7 @@ void syserr_signal(int signal, char *msg)
 
 	if (crashed++)
 	{
-		print_stdout("syserr_signal(crashed)\n");
+		print_stdout(0, 0, "syserr_signal(crashed)\n");
 
 		fflush(NULL);
 
@@ -758,7 +761,7 @@ void syserr_signal(int signal, char *msg)
 
 	sprintf(buf, "\e[1;31mFATAL SIGNAL FROM (%s): %s\e[0m\n", msg, strsignal(signal));
 
-	print_stdout("%s", buf);
+	print_stdout(0, 0, "%s", buf);
 
 	fflush(NULL);
 
@@ -772,7 +775,7 @@ void syserr_fatal(int signal, char *msg)
 
 	if (crashed++)
 	{
-		print_stdout("syserr_fatal(crashed)");
+		print_stdout(0, 0, "syserr_fatal(crashed)");
 
 		fflush(NULL);
 
@@ -788,6 +791,8 @@ void syserr_fatal(int signal, char *msg)
 		sprintf(errstr, "(signal %d: %s)", signal, strsignal(signal));
 	}
 
+	check_all_events(NULL, SUB_SEC|EVENT_FLAG_SYSTEM, 0, 1, "SYSTEM CRASH", errstr);
+
 	if (gtd->level->quiet)
 	{
 		gtd->level->quiet = 0;
@@ -797,13 +802,13 @@ void syserr_fatal(int signal, char *msg)
 
 	reset_screen(gts);
 
-	print_stdout("\e[r");
+	print_stdout(0, 0, "\e[?1049l\e[r");
 
 	dump_stack();
 
 	sprintf(buf, "\n\e[1;31mFATAL ERROR \e[1;32m%s %s\e[0m\n", msg, errstr);
 
-	print_stdout("%s", buf);
+	print_stdout(0, 0, "%s", buf);
 
 	reset_daemon();
 

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 196 - 139
src/mapper.c


+ 92 - 7
src/math.c

@@ -42,8 +42,9 @@
 #define EXP_PR_LOGAND        9
 #define EXP_PR_LOGXOR       10
 #define EXP_PR_LOGOR        11
-#define EXP_PR_VAR          12
-#define EXP_PR_LVL          13
+#define EXP_PR_TERNARY      12
+#define EXP_PR_VAR          13
+#define EXP_PR_LVL          14
 
 struct link_data *math_head;
 struct link_data *math_tail;
@@ -87,14 +88,18 @@ long double get_number(struct session *ses, char *str)
 	long double val;
 	char result[BUFFER_SIZE];
 
+	SET_BIT(gtd->flags, TINTIN_FLAG_GETNUMBER);
+
 	mathexp(ses, str, result, 0);
 
+	DEL_BIT(gtd->flags, TINTIN_FLAG_GETNUMBER);
+
 	val = tintoi(result);
 
 	return val;
 }
 
-unsigned long long get_integer(struct session *ses, char *str)
+unsigned long long get_ulong(struct session *ses, char *str)
 {
 	unsigned long long val;
 	char result[BUFFER_SIZE];
@@ -108,10 +113,19 @@ unsigned long long get_integer(struct session *ses, char *str)
 
 int get_ellipsis(struct listroot *root, char *name, int *min, int *max)
 {
-	unsigned long long range = get_integer(root->ses, name);
+	size_t len;
+	unsigned long long range;
 
 	push_call("get_ellipsis(%p,%p,%p,%p)",root,name,min,max);
 
+	len = strlen(name);
+
+	if (name[len - 1] == '.')
+	{
+		strcpy(name + len, "-1");
+	}
+
+	range = get_ulong(root->ses, name);
 
 	*min = (int) (HAS_BIT(range, 0x00000000FFFFFFFFLL));
 	*max = (int) (HAS_BIT(range, 0xFFFFFFFF00000000ULL) >> 32ULL);
@@ -194,6 +208,7 @@ void mathexp(struct session *ses, char *str, char *result, int seed)
 {                                                               \
 	if (buffercheck && pta == buf3)                         \
 	{                                                       \
+		pop_call( );                                    \
 		return FALSE;                                   \
 	}                                                       \
 	if (badnumber && debug)                                 \
@@ -238,9 +253,15 @@ void del_math_node(struct link_data *node)
 
 int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 {
-	char buf1[BUFFER_SIZE], buf2[BUFFER_SIZE], buf3[STRING_SIZE], *pti, *pta;
+	char *buf1, *buf2, *buf3, *pti, *pta;
 	int level, status, point, badnumber, metric, nest;
 
+	push_call("mathexp_tokenize(%p,%s,%d,%d)",ses,str,seed,debug);
+
+	buf1 = str_alloc_stack(0);
+	buf2 = str_alloc_stack(0);
+	buf3 = str_alloc_stack(0);
+
 	nest      = 0;
 	level     = 0;
 	metric    = 0;
@@ -282,6 +303,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 
 							if (debug == 0)
 							{
+								pop_call();
 								return FALSE;
 							}
 						}
@@ -368,6 +390,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 							{
 								show_debug(ses, LIST_VARIABLE, "MATH EXP: { FOUND INSIDE A NUMBER");
 							}
+							pop_call();
 							return FALSE;
 						}
 						*pta++ = *pti++;
@@ -382,6 +405,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 							{
 								show_debug(ses, LIST_VARIABLE, "MATH EXP: \" FOUND INSIDE A NUMBER");
 							}
+							pop_call();
 							return FALSE;
 						}
 						*pta++ = *pti++;
@@ -396,6 +420,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 							{
 								show_debug(ses, LIST_VARIABLE, "#MATH EXP: PARANTESES FOUND INSIDE A NUMBER");
 							}
+							pop_call();
 							return FALSE;
 						}
 						else
@@ -415,9 +440,25 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 						break;
 						
 					case '.':
-						if (pta != buf3 && pti[1] == '.')
+						if (pti[1] == '.')
 						{
+							if (pta == buf3)
+							{
+								*pta++ = '1';
+							}
+
 							MATH_NODE(FALSE, EXP_PR_VAR, EXP_OPERATOR);
+
+							if (pti[2] == 0)
+							{
+								*pta++ = *pti++;
+								*pta++ = *pti++;
+
+								MATH_NODE(FALSE, EXP_PR_LOGCOMP, EXP_VARIABLE);
+								
+								*pta++ = '-';
+								*pta++ = '1';
+							}
 						}
 						else
 						{
@@ -429,6 +470,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 									show_debug(ses, LIST_VARIABLE, "#MATH EXP: MORE THAN ONE POINT FOUND INSIDE A NUMBER");
 								}
 								precision = 0;
+								pop_call();
 								return FALSE;
 							}
 							point++;
@@ -451,12 +493,14 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 					case '^':
 					case '|':
 					case '=':
+					case '?':
 						if (pti == str)
 						{
 							if (debug)
 							{
 								show_debug(ses, LIST_VARIABLE, "#MATH EXP: EXPRESSION STARTED WITH AN OPERATOR.");
 							}
+							pop_call();
 							return FALSE;
 						}
 
@@ -484,6 +528,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 
 							if (debug == 0)
 							{
+								pop_call();
 								return FALSE;
 							}
 							*pta++ = *pti++;
@@ -529,6 +574,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 
 							if (debug == 0)
 							{
+								pop_call();
 								return FALSE;
 							}
 							*pta++ = *pti++;
@@ -570,6 +616,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 
 						if (debug == 0)
 						{
+							pop_call();
 							return FALSE;
 						}
 						break;
@@ -639,6 +686,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 							{
 								show_debug(ses, LIST_VARIABLE, "#MATH EXP: UNKNOWN OPERATOR: %c%c", pti[0], pti[1]);
 							}
+							pop_call();
 							return FALSE;
 						}
 						break;
@@ -649,6 +697,11 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 						MATH_NODE(FALSE, EXP_PR_LVL, EXP_OPERATOR);
 						break;
 
+					case '?':
+						*pta++ = *pti++;
+						MATH_NODE(FALSE, EXP_PR_TERNARY, EXP_VARIABLE);
+						break;
+
 					case 'd':
 						*pta++ = *pti++;
 						MATH_NODE(FALSE, EXP_PR_DICE, EXP_VARIABLE);
@@ -806,6 +859,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 								{
 									show_debug(ses, LIST_VARIABLE, "#MATH EXP: UNKNOWN OPERATOR: %c%c", pti[-1], pti[0]);
 								}
+								pop_call();
 								return FALSE;
 						}
 						break;
@@ -815,6 +869,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 						{
 							show_debug(ses, LIST_VARIABLE, "#MATH EXP: UNKNOWN OPERATOR: %c", *pti);
 						}
+						pop_call();
 						return FALSE;
 				}
 				break;
@@ -827,6 +882,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 		{
 			show_debug(ses, LIST_VARIABLE, "#MATH EXP: UNMATCHED PARENTHESES, LEVEL: %d", level);
 		}
+		pop_call();
 		return FALSE;
 	}
 
@@ -835,6 +891,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 		MATH_NODE(TRUE, EXP_PR_VAR, EXP_OPERATOR);
 	}
 
+	pop_call();
 	return TRUE;
 }
 
@@ -921,6 +978,11 @@ void mathexp_compute(struct session *ses, struct link_data *node)
 				value = tindice(ses, node->prev->str3, node->next->str3);
 			}
 			break;
+
+		case '?':
+			value = tinternary(node->prev->str3, node->next->str3);
+			break;
+
 		case '*':
 			switch (node->str3[1])
 			{
@@ -1107,12 +1169,33 @@ void mathexp_compute(struct session *ses, struct link_data *node)
 	}
 	else
 	{
-		sprintf(temp, "%.*Lf", precision, value);
+//		sprintf(temp, "%.*Lf", precision, value);
+		sprintf(temp, "%Lf", value);
 	}
 	free(node->str3);
 	node->str3 = strdup(temp);
 }
 
+long double tinternary(char *arg1, char *arg2)
+{
+	char *arg3 = strchr(arg2, ':');
+
+	if (arg3 == NULL)
+	{
+		return 0;
+	}
+	*arg3++ = 0;
+
+	if (tintoi(arg1))
+	{
+		return tintoi(arg2);
+	}
+	else
+	{
+		return tintoi(arg3);
+	}
+}
+
 /*
 	Keep synced with is_number()
 */
@@ -1173,6 +1256,8 @@ long double tintoi(char *str)
 				break;
 
 			case ':':
+//				show_error(gtd->ses, LIST_COMMAND, "\e[1;31m#WARNING: THE : TIME OPERATOR IN #MATH WILL BE REMOVED IN FUTURE RELEASES.");
+
 				switch (i)
 				{
 					case 2:

+ 344 - 111
src/memory.c

@@ -25,6 +25,8 @@
 
 #include "tintin.h"
 
+struct str_data *str_alloc_list(int size);
+
 char *restring(char *point, char *string)
 {
 	if (point)
@@ -57,75 +59,84 @@ char *restringf(char *point, char *fmt, ...)
 	str_ functions
 */
 
-struct str_data *str_calloc(int size)
+void init_memory(void)
 {
-	struct str_data *str_ptr = (struct str_data *) calloc(1, sizeof(struct str_data) + size + 1);
+	gtd->memory            = calloc(1, sizeof(struct memory_data));
 
-	LINK(str_ptr, gtd->memory->alloc->next, gtd->memory->alloc->prev);
+	gtd->memory->debug     = calloc(1, sizeof(struct stack_data *));
 
-	str_ptr->max = size + 1;
-	str_ptr->len = 0;
+	gtd->memory->stack     = calloc(1, sizeof(struct str_data *));
+	gtd->memory->stack_max = 1;
 
-	return str_ptr;
+	gtd->memory->list      = calloc(1, sizeof(struct str_data *));
+	gtd->memory->list_max  = 1;
+
+	gtd->memory->free      = calloc(1, sizeof(int));
+	gtd->memory->free_max  = 1;
 }
 
-char *str_alloc(int size)
-{
-	struct str_data *str_ptr;
-	char *str;
 
-	str_ptr = str_calloc(size);
+struct str_data *str_ptr_alloc(int size)
+{
+	return str_alloc_list(size);
+/*
+	struct str_data *str_ptr = (struct str_data *) calloc(1, sizeof(struct str_data) + size + 1);
 
-	str = (char *) str_ptr + sizeof(struct str_data);
+	str_ptr->max = size + 1;
 
-	return str;
+	return str_ptr;
+*/
 }
 
-struct str_data *str_realloc(struct str_data *str_ptr, int size)
+struct str_data *get_str_ptr(char *str)
 {
-	struct str_data *new_ptr;
-
-	push_call("str_realloc(%p,%d) (%d,%d,%p,%p)",str_ptr,size, str_ptr->len, str_ptr->max, str_ptr->next, str_ptr->prev);
+	return (struct str_data *) (str - sizeof(struct str_data));
+}
 
-	if (str_ptr->max <= str_ptr->len)
-	{
-		tintin_printf2(gtd->ses, "\e[1;35mstr_realloc: we got problem\n");
-	}
+char *get_str_str(struct str_data *str_ptr)
+{
+	return (char *) str_ptr + sizeof(struct str_data);
+}
 
+struct str_data *str_ptr_realloc(struct str_data *str_ptr, int size)
+{
 	if (str_ptr->max <= size)
 	{
-//		int len = str_ptr->len;
+		str_ptr = (struct str_data *) realloc(str_ptr, sizeof(struct str_data) + size + 1);
 
-		UNLINK(str_ptr, gtd->memory->alloc->next, gtd->memory->alloc->prev);
+		switch (str_ptr->flags)
+		{
+			case STR_FLAG_STACK:
+				gtd->memory->stack[str_ptr->index] = str_ptr;
+				break;
 
-		new_ptr = (struct str_data *) realloc(str_ptr, sizeof(struct str_data) + size + 1);
+			case STR_FLAG_LIST:
+				gtd->memory->list[str_ptr->index] = str_ptr;
+				break;
 
-		if (new_ptr == NULL)
-		{
-			printf("str_realloc: failed to realloc mem.\n");
-		}
-		else
-		{
-			str_ptr = new_ptr;
+			default:
+				printf("\e[1;35mstr_ptr_realloc: unknown memory type (%d)", str_ptr->flags);
+				break;
 		}
 
-		LINK(str_ptr, gtd->memory->alloc->next, gtd->memory->alloc->prev);
-
 		str_ptr->max = size + 1;
-//		str_ptr->len = len;
 	}
-	pop_call();
+	else
+	{
+		printf("\e[1;35mstr_ptr_realloc: shrink error max=%d len=%d\n", str_ptr->max, str_ptr->len);
+	}
+
 	return str_ptr;
 }
 
-struct str_data *get_str_ptr(char *str)
-{
-	return (struct str_data *) (str - sizeof(struct str_data));
-}
 
-char *get_str_str(struct str_data *str_ptr)
+char *str_alloc(int size)
 {
-	return (char *) str_ptr + sizeof(struct str_data);
+	struct str_data *str_ptr;
+
+	str_ptr = str_ptr_alloc(size);
+
+	return get_str_str(str_ptr);
 }
 
 struct str_data *str_ptr_resize(struct str_data *str_ptr, int add)
@@ -134,7 +145,7 @@ struct str_data *str_ptr_resize(struct str_data *str_ptr, int add)
 
 	if (str_ptr->max <= len + add)
 	{
-		str_ptr = str_realloc(str_ptr, len * 2 + add);
+		str_ptr = str_ptr_realloc(str_ptr, len + add + 1);
 	}
 	return str_ptr;
 }
@@ -150,6 +161,27 @@ char *str_resize(char **str, int add)
 	return *str;
 }
 
+// call after a non str_ function alters *str to set the correct length.
+
+int str_fix(char *original)
+{
+	struct str_data *str_ptr = get_str_ptr(original);
+
+	str_ptr->len = strlen(original);
+
+	return str_ptr->len;
+}
+
+int str_len(char *str)
+{
+	return get_str_ptr(str)->len;
+}
+
+int str_max(char *str)
+{
+	return get_str_ptr(str)->max;
+}
+
 
 // like str_dup but return an empty string
 
@@ -172,7 +204,7 @@ void str_clone(char **clone, char *original)
 
 	if (clo_ptr->max < len)
 	{
-		clo_ptr = str_realloc(clo_ptr, len * 2);
+		clo_ptr = str_ptr_realloc(clo_ptr, len * 2);
 
 		*clone = get_str_str(clo_ptr);
 	}
@@ -184,37 +216,26 @@ char *str_dup_clone(char *original)
 	int len;
 
 	len = str_len(original);
+
 	dup = str_alloc(len);
 
 	memcpy(dup, original, len + 1);
 
-	return dup;
-}
-
-// call after a non str_ function alters *str to set the correct length.
-
-int str_fix(char *original)
-{
-	struct str_data *str_ptr = get_str_ptr(original);
-
-	str_ptr->len = strlen(original);
-
-	return str_ptr->len;
-}
+	get_str_ptr(dup)->len = len;
 
-int str_len(char *str)
-{
-	return get_str_ptr(str)->len;
+	return dup;
 }
 
-int str_max(char *str)
-{
-	return get_str_ptr(str)->max;
-}
 
 char *str_dup(char *original)
 {
-	char *dup = str_alloc(strlen(original));
+	char *dup;
+
+	if (*original == 0)
+	{
+		return str_alloc(0);
+	}
+	dup = str_alloc(strlen(original));
 
 	str_cpy(&dup, original);
 
@@ -223,21 +244,23 @@ char *str_dup(char *original)
 
 char *str_dup_printf(char *fmt, ...)
 {
-	char *str, *ptr;
+	char *str, *ptv;
+	int len;
 	va_list args;
 
-	push_call("str_dup_printf(%s)", fmt);
-
 	va_start(args, fmt);
-	vasprintf(&str, fmt, args);
+
+	len = vasprintf(&ptv, fmt, args);
+
 	va_end(args);
 
-	ptr = str_dup(str);
+	str = str_alloc(len);
+
+	memcpy(str, ptv, len + 1);
 
-	free(str);
+	free(ptv);
 
-	pop_call();
-	return ptr;
+	return str;
 }
 
 char *str_cpy(char **str, char *buf)
@@ -251,7 +274,7 @@ char *str_cpy(char **str, char *buf)
 
 	if (str_ptr->max <= buf_len)
 	{
-		str_ptr = str_realloc(str_ptr, buf_len);
+		str_ptr = str_ptr_realloc(str_ptr, buf_len);
 
 		*str = get_str_str(str_ptr);
 	}
@@ -264,16 +287,35 @@ char *str_cpy(char **str, char *buf)
 
 char *str_cpy_printf(char **str, char *fmt, ...)
 {
-	char *arg;
+	struct str_data *str_ptr;
+	char *ptv;
 	va_list args;
+	int len;
 
 	va_start(args, fmt);
-	vasprintf(&arg, fmt, args);
+
+	len = vasprintf(&ptv, fmt, args);
+
 	va_end(args);
+/*
+	str_cpy(str, ptv);
 
-	str_cpy(str, arg);
+	return *str;
+*/
+	str_ptr = get_str_ptr(*str);
 
-	free(arg);
+	if (str_ptr->max <= len)
+	{
+		str_ptr = str_ptr_realloc(str_ptr, len);
+
+		*str = get_str_str(str_ptr);
+	}
+
+	memcpy(*str, ptv, len + 1);
+
+	str_ptr->len = len;
+
+	free(ptv);
 
 	return *str;
 }
@@ -302,7 +344,7 @@ char *str_ncpy(char **str, char *buf, int len)
 
 	if (str_ptr->max <= buf_len)
 	{
-		str_ptr = str_realloc(str_ptr, len);
+		str_ptr = str_ptr_realloc(str_ptr, len);
 
 		*str = get_str_str(str_ptr);
 	}
@@ -316,67 +358,73 @@ char *str_ncpy(char **str, char *buf, int len)
 	return *str;
 }
 
-char *str_cat(char **str, char *arg)
+
+char *str_cat_len(char **str, char *arg, int len)
 {
-	int arg_len;
 	struct str_data *str_ptr;
 
-	arg_len = strlen(arg);
-
 	str_ptr = get_str_ptr(*str);
 
-	if (str_ptr->max <= str_ptr->len + arg_len)
+	if (str_ptr->max <= str_ptr->len + len)
 	{
-		str_ptr = str_ptr_resize(str_ptr, arg_len);
+		str_ptr = str_ptr_resize(str_ptr, len);
 
 		*str = get_str_str(str_ptr);
 	}
 
 	strcpy(&(*str)[str_ptr->len], arg);
 
-	str_ptr->len += arg_len;
+	str_ptr->len += len;
 
 	return *str;
 }
 
-char *str_cat_chr(char **ptr, char chr)
+char *str_cat(char **str, char *arg)
+{
+	return str_cat_len(str, arg, strlen(arg));
+}
+
+char *str_cat_chr(char **str, char chr)
 {
 	struct str_data *str_ptr;
 
-	str_ptr = get_str_ptr(*ptr);
+	str_ptr = get_str_ptr(*str);
 
 	if (str_ptr->max <= str_ptr->len + 1)
 	{
-		str_ptr = str_ptr_resize(str_ptr, 1);
+		str_ptr = str_ptr_realloc(str_ptr, str_ptr->max + 10);
 
-		*ptr = get_str_str(str_ptr);
+		*str = get_str_str(str_ptr);
 	}
 
-	(*ptr)[str_ptr->len++] = chr;
+	(*str)[str_ptr->len++] = chr;
 
-	(*ptr)[str_ptr->len] = 0;
+	(*str)[str_ptr->len] = 0;
 
-	return *ptr;
+	return *str;
 }
-	
 
 char *str_cat_printf(char **str, char *fmt, ...)
 {
 	char *arg;
 	va_list args;
+	int len;
 
 	va_start(args, fmt);
-	vasprintf(&arg, fmt, args);
+	
+	len = vasprintf(&arg, fmt, args);
+
 	va_end(args);
 
-	str_cat(str, arg);
+	str_cat_len(str, arg, len);
 
 	free(arg);
 
 	return *str;
 }
 
-char *str_ins(char **str, int index, char *buf)
+
+char *str_cap(char **str, int index, char *buf)
 {
 	int buf_len;
 	struct str_data *str_ptr;
@@ -385,6 +433,34 @@ char *str_ins(char **str, int index, char *buf)
 
 	str_ptr = get_str_ptr(*str);
 
+	if (str_ptr->max <= index + buf_len)
+	{
+		str_ptr = str_ptr_resize(str_ptr, buf_len);
+
+		*str = get_str_str(str_ptr);
+	}
+
+	if (index <= str_ptr->len)
+	{
+		strcpy(&(*str)[index], buf);
+	}
+	else
+	{
+		tintin_printf2(gtd->ses, "debug: str_cap: index=%d str_len=%d cap=%s", index, str_ptr->len, buf);
+	}
+
+	str_ptr->len = index + buf_len;
+
+	return *str;
+}
+
+
+char *str_ins_len(char **str, int index, char *buf, int buf_len)
+{
+	struct str_data *str_ptr;
+
+	str_ptr = get_str_ptr(*str);
+
 	if (str_ptr->max <= str_ptr->len + buf_len)
 	{
 		str_ptr = str_ptr_resize(str_ptr, buf_len);
@@ -401,10 +477,10 @@ char *str_ins(char **str, int index, char *buf)
 		int cnt;
 		char *pta, *ptz;
 
-		pta = &(*str)[str_ptr->len + 1];
-		ptz = &(*str)[str_ptr->len + 1 + buf_len];
+		pta = &(*str)[str_ptr->len];
+		ptz = &(*str)[str_ptr->len + buf_len];
 
-		for (cnt = 0 ; cnt < buf_len + 1 ; cnt++)
+		for (cnt = 0 ; cnt <= str_ptr->len - index ; cnt++)
 		{
 			*ptz-- = *pta--;
 		}
@@ -412,7 +488,7 @@ char *str_ins(char **str, int index, char *buf)
 		pta = &(*str)[index];
 		ptz = buf;
 
-		for (cnt = 0 ; cnt < buf_len ; cnt++)
+		while (*ptz)
 		{
 			*pta++ = *ptz++;
 		}
@@ -423,32 +499,189 @@ char *str_ins(char **str, int index, char *buf)
 	return *str;
 }
 
-void str_free(char *ptr)
+char *str_ins(char **str, int index, char *buf)
+{
+	return str_ins_len(str, index, buf, strlen(buf));
+}
+
+char *str_ins_printf(char **str, int index, char *fmt, ...)
 {
-	struct str_data *str_ptr = get_str_ptr(ptr);
+	int len;
+	char *arg;
+	va_list args;
+
+	va_start(args, fmt);
+
+	len = vasprintf(&arg, fmt, args);
+
+	va_end(args);
+
+	str_ins_len(str, index, arg, len);
 
-	UNLINK(str_ptr, gtd->memory->alloc->next, gtd->memory->alloc->prev);
+	free(arg);
 
-	free(str_ptr);
+	return *str;
+}
+
+char *str_mov(char **str, int dst, int src)
+{
+	struct str_data *str_ptr;
+	char *ptm;
+
+	if (dst >= src)
+	{
+		show_error(gtd->ses, LIST_COMMAND, "str_mov: dst (%d) >= src (%d)", dst, src);
+
+		return *str;
+	}
+
+	str_ptr = get_str_ptr(*str);
+
+	if (src > str_ptr->len)
+	{
+		show_error(gtd->ses, LIST_COMMAND, "str_mov: src (%d) >= len (%d)", src, str_ptr->len);
+
+		return *str;
+	}
+
+	ptm = &(*str)[src];
+
+	str_ptr->len -= (src - dst);
+
+	while (*ptm)
+	{
+		(*str)[dst++] = *ptm++;
+	}
+	(*str)[dst++] = 0;
+
+	return *str;
+}
+
+
+void str_alloc_free(struct str_data *str_ptr)
+{
+	if (HAS_BIT(str_ptr->flags, STR_FLAG_STACK|STR_FLAG_FREE))
+	{
+		tintin_printf2(gtd->ses, "\e[1;31mstr_alloc_free: trying to free invalid memory: %d", str_ptr->flags);
+		dump_stack();
+		return;
+	}
+
+	if (gtd->memory->free_len == gtd->memory->free_max)
+	{
+		gtd->memory->free_max *= 2;
+
+		gtd->memory->free = (int *) realloc(gtd->memory->free, sizeof(int) * gtd->memory->free_max);
+	}
+	SET_BIT(str_ptr->flags, STR_FLAG_FREE);
+
+	gtd->memory->free[gtd->memory->free_len++] = str_ptr->index;
+}
+
+void str_free(char *str)
+{
+//	free(get_str_ptr(str));
+
+	str_alloc_free(get_str_ptr(str));
 }
 
 // stack handling
 
-char *str_alloc_stack()
+char *str_alloc_stack(int size)
 {
 	struct str_data *str_ptr;
+	char *str;
+
+	if (size < BUFFER_SIZE)
+	{
+		size = BUFFER_SIZE;
+	}
 
-	if (gtd->memory->stack_len == gtd->memory->stack_max)
+	if (gtd->memory->stack_len == gtd->memory->stack_cap)
 	{
-		gtd->memory->stack_max++;
+		gtd->memory->stack_cap++;
+
+		if (gtd->memory->stack_cap == gtd->memory->stack_max)
+		{
+			gtd->memory->stack_max *= 2;
+
+			gtd->memory->stack = (struct str_data **) realloc(gtd->memory->stack, sizeof(struct str_data *) * gtd->memory->stack_max);
+		}
+		str_ptr = (struct str_data *) calloc(1, sizeof(struct str_data) + size + 1);
 
-		gtd->memory->stack = (struct str_data **) realloc(gtd->memory->stack, sizeof(struct str_data *) * gtd->memory->stack_max);
+		str_ptr->max   = size + 1;
+		str_ptr->flags = STR_FLAG_STACK;
+		str_ptr->index = gtd->memory->stack_len++;
 
-		gtd->memory->stack[gtd->memory->stack_len] = str_calloc(BUFFER_SIZE);
+		gtd->memory->stack[str_ptr->index] = str_ptr;
+	}
+	else
+	{
+		str_ptr = gtd->memory->stack[gtd->memory->stack_len++];
+	}
+
+	if (str_ptr->max < size)
+	{
+		str_ptr = str_ptr_realloc(str_ptr, size);
 	}
-	str_ptr = gtd->memory->stack[gtd->memory->stack_len++];
 
 	str_ptr->len = 0;
 
-	return get_str_str(str_ptr);
+	str = get_str_str(str_ptr);
+
+	*str = 0;
+
+	return str;
+}
+
+struct str_data *str_alloc_list(int size)
+{
+	struct str_data *str_ptr;
+	char *str;
+
+	if (size < 0)
+	{
+		tintin_printf2(gtd->ses, "str_alloc_list: negative size: %d", size);
+		dump_stack();
+		size = BUFFER_SIZE;
+	}
+
+	if (gtd->memory->free_len)
+	{
+		int index;
+
+		index = gtd->memory->free[--gtd->memory->free_len];
+
+		str_ptr = gtd->memory->list[index];
+
+		DEL_BIT(str_ptr->flags, STR_FLAG_FREE);
+
+		if (size >= str_ptr->max)
+		{
+			str_ptr = str_ptr_realloc(str_ptr, size);
+		}
+		str_ptr->len = 0;
+	}
+	else
+	{
+		if (gtd->memory->list_len + 1 >= gtd->memory->list_max)
+		{
+			gtd->memory->list_max *= 2;
+
+			gtd->memory->list = (struct str_data **) realloc(gtd->memory->list, sizeof(struct str_data *) * gtd->memory->list_max);
+		}
+		str_ptr = (struct str_data *) calloc(1, sizeof(struct str_data) + size + 1);
+
+		str_ptr->max   = size + 1;
+		str_ptr->flags = STR_FLAG_LIST;
+		str_ptr->index = gtd->memory->list_len++;
+
+		gtd->memory->list[str_ptr->index] = str_ptr;
+	}
+
+	str = get_str_str(str_ptr);
+
+	*str = 0;
+
+	return str_ptr;
 }

+ 40 - 80
src/misc.c

@@ -34,17 +34,17 @@ DO_COMMAND(do_bell)
 
 	if (*arg1 == 0)
 	{
-		print_stdout("\007");
+		print_stdout(0, 0, "\007");
 	}
 	else if (is_abbrev(arg1, "FLASH"))
 	{
 		if (is_abbrev(arg2, "ON"))
 		{
-			print_stdout("\e[?1042h");
+			print_stdout(0, 0, "\e[?1042h");
 		}
 		else if (is_abbrev(arg2, "OFF"))
 		{
-			print_stdout("\e[?1042l");
+			print_stdout(0, 0, "\e[?1042l");
 		}
 		else
 		{
@@ -55,11 +55,11 @@ DO_COMMAND(do_bell)
 	{
 		if (is_abbrev(arg2, "ON"))
 		{
-			print_stdout("\e[?1043h");
+			print_stdout(0, 0, "\e[?1043h");
 		}
 		else if (is_abbrev(arg2, "OFF"))
 		{
-			print_stdout("\e[?1043l");
+			print_stdout(0, 0, "\e[?1043l");
 		}
 		else
 		{
@@ -70,11 +70,11 @@ DO_COMMAND(do_bell)
 	{
 		if (is_abbrev(arg2, "ON"))
 		{
-			print_stdout("\e[?44h");
+			print_stdout(0, 0, "\e[?44h");
 		}
 		else if (is_abbrev(arg2, "OFF"))
 		{
-			print_stdout("\e[?44l");
+			print_stdout(0, 0, "\e[?44l");
 		}
 		else
 		{
@@ -83,13 +83,13 @@ DO_COMMAND(do_bell)
 	}
 	else if (is_abbrev(arg1, "RING"))
 	{
-		print_stdout("\007");
+		print_stdout(0, 0, "\007");
 	}
 	else if (is_abbrev(arg1, "VOLUME"))
 	{
 		if (is_math(ses, arg2))
 		{
-			print_stdout("\e[ %dt", (int) get_number(ses, arg2));
+			print_stdout(0, 0, "\e[ %dt", (int) get_number(ses, arg2));
 		}
 		else
 		{
@@ -105,42 +105,6 @@ DO_COMMAND(do_bell)
 }
 
 
-DO_COMMAND(do_commands)
-{
-	char buf[BUFFER_SIZE] = { 0 };
-	int cmd;
-
-	tintin_header(ses, " %s ", "COMMANDS");
-
-	for (cmd = 0 ; *command_table[cmd].name != 0 ; cmd++)
-	{
-		if (*arg && !is_abbrev(arg, command_table[cmd].name))
-		{
-			continue;
-		}
-
-		if (strip_vt102_strlen(ses, buf) + 20 > gtd->screen->cols)
-		{
-			tintin_puts2(ses, buf);
-			buf[0] = 0;
-		}
-		if (command_table[cmd].type == TOKEN_TYPE_COMMAND)
-		{
-			cat_sprintf(buf, "%s%20s", COLOR_COMMAND, command_table[cmd].name);
-		}
-		else
-		{
-			cat_sprintf(buf, "%s%20s", COLOR_STATEMENT, command_table[cmd].name);
-		}
-	}
-	if (buf[0])
-	{
-		tintin_puts2(ses, buf);
-	}
-	return ses;
-}
-
-
 DO_COMMAND(do_cr)
 {
 	write_mud(ses, "", SUB_EOL);
@@ -151,9 +115,15 @@ DO_COMMAND(do_cr)
 
 DO_COMMAND(do_echo)
 {
-	char format[BUFFER_SIZE], result[BUFFER_SIZE], temp[BUFFER_SIZE], *output, left[BUFFER_SIZE];
+	char *format, *result, *temp, *output, *left;
 	int lnf;
 
+	format = arg1;
+	result = arg2;
+
+	temp = str_alloc_stack(0);
+	left = str_alloc_stack(0);
+
 	arg = sub_arg_in_braces(ses, arg, format, GET_ONE, SUB_VAR|SUB_FUN);
 
 	format_string(ses, format, arg, result);
@@ -167,27 +137,29 @@ DO_COMMAND(do_echo)
 
 		if (*temp)
 		{
-			int row = (int) get_number(ses, temp);
+//			int row = (int) get_number(ses, temp);
 
-			substitute(ses, left, temp, SUB_COL|SUB_ESC);
+			substitute(ses, left, format, SUB_COL|SUB_ESC);
 
-			split_show(ses, temp, row, 0);
+			split_show(ses, format, temp, "");
 
 			return ses;
 		}
 	}
 
-	lnf = !str_suffix(arg, "\\");
+	lnf = is_suffix(arg, "\\") && !is_suffix(arg, "\\\\");
 
 	substitute(ses, arg, temp, SUB_COL|SUB_ESC);
 
+	output = str_alloc_stack(0);
+
 	if (strip_vt102_strlen(ses, ses->more_output) != 0)
 	{
-		output = str_dup_printf("\n\e[0m%s\e[0m", temp);
+		str_cpy_printf(&output, "\n\e[0m%s\e[0m", temp);
 	}
 	else
 	{
-		output = str_dup_printf("\e[0m%s\e[0m", temp);
+		str_cpy_printf(&output, "\e[0m%s\e[0m", temp);
 	}
 
 	add_line_buffer(ses, output, lnf);
@@ -209,7 +181,6 @@ DO_COMMAND(do_echo)
 			print_line(ses, &output, lnf);
 		}
 	}
-	str_free(output);
 
 	return ses;
 }
@@ -253,43 +224,32 @@ DO_COMMAND(do_send)
 
 DO_COMMAND(do_test)
 {
-	if (!strcmp(arg, "string"))
-	{
-		char *test = str_dup("\e[32m0 2 4 6 8 A C E");
-
-		test = str_ins_str(ses, &test, "\e[33mbli bli", 4, 11);
-
-		printf("test: [%s]\n", test);
-
-		str_free(test);
-		
-		return ses;
-	}
-
-	strcpy(arg2, "9");
-	strcpy(arg3, "<f0b8>");
-	strcpy(arg4, "1 9");
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 
-	if (isdigit((int) arg[0]))
+	if (!strcmp(arg1, "rain"))
 	{
-		sprintf(arg2, "%d", (arg[0] - '0') * (arg[0] - '0'));
+		strcpy(arg2, "9");
+		strcpy(arg3, "<f3c3>");
+		strcpy(arg1, "1 9");
 
-		if ((isxdigit((int) arg[1]) && isxdigit((int) arg[2]) && isxdigit((int) arg[3])) || (arg[1] == '?' && arg[2] == '?' && arg[3] == '?'))
+		if (is_digit(arg[0]))
 		{
-			sprintf(arg3, "<f%c%c%c>", arg[1], arg[2], arg[3]);
+			sprintf(arg2, "%d", (arg[0] - '0') * (arg[0] - '0'));
 
-			if (isdigit((int) arg[4]) && isdigit((int) arg[5]))
+			if ((is_hex(arg[1]) && is_hex(arg[2]) && is_hex(arg[3])) || (arg[1] == '?' && arg[2] == '?' && arg[3] == '?'))
 			{
-				sprintf(arg4, "%f %d %s", (arg[4] - '0') * (arg[4] - '0') / 10.0, (arg[5] - '0') * (arg[5] - '0'), &arg[6]);
+				sprintf(arg3, "<f%c%c%c>", arg[1], arg[2], arg[3]);
 
-				tintin_printf2(ses, "do_test debug: %s", arg4);
+				if (is_digit(arg[4]) && is_digit(arg[5]))
+				{
+					sprintf(arg1, "%f %d %s", (arg[4] - '0') * (arg[4] - '0') / 10.0, (arg[5] - '0') * (arg[5] - '0'), &arg[6]);
+				}
 			}
 		}
-	}
-	sprintf(arg1, "#line quiet {#event {RECEIVED KEYPRESS} {#end \\};#screen cursor hide;#screen clear all;#event {SECOND} #loop 0 %s cnt #delay {$cnt / (1.0+%s)} #draw %s rain 1 1 -1 -1 rain %s}", arg2, arg2, arg3, arg4);
-
-	script_driver(gtd->ses, LIST_COMMAND, arg1);
+		command(gtd->ses, do_line, "quiet {#event {RECEIVED KEYPRESS} {#end \\};#screen cursor hide;#screen clear all;#event {SECOND} #loop 0 %s cnt #delay {$cnt / (1.0+%s)} #draw %s rain 1 1 -1 -1 rain %s}", arg2, arg2, arg3, arg1);
 
+		return ses;
+	}
 	return ses;
 }
 

+ 125 - 1
src/msdp.c

@@ -38,7 +38,7 @@ void init_msdp_table(void)
 		{
 			if (*msdp_table[index+1].name)
 			{
-				print_stdout("\e[31minit_msdp_table: Improperly sorted variable: %s.\e0m", msdp_table[index+1].name);
+				print_stdout(0, 0, "\e[31minit_msdp_table: Improperly sorted variable: %s.\e0m", msdp_table[index+1].name);
 			}
 		}
 	}
@@ -974,3 +974,127 @@ int json2msdp(unsigned char *src, int srclen, char *out)
 	return pto - out;
 }
 
+int tintin2msdp(char *str, char *out)
+{
+	char *pto, *ptv, var[BUFFER_SIZE], val[BUFFER_SIZE];
+	int nest, last, type, level, state[100];
+
+	nest = last = level = 0;
+
+	pto = out;
+	ptv = var;
+
+	while (*str && *str != '{')
+	{
+		*pto++ = *str++;
+	}
+
+	pto += sprintf(pto, "%c%c%c", IAC, SB, TELOPT_MSDP);
+
+	state[0] = nest = type = 0;
+
+	while (*str && nest < 99)
+	{
+		switch (*str)
+		{
+			case '{':
+				level++;
+
+				if (state[nest] == 0)
+				{
+					ptv = var;
+
+					state[nest] = *pto++ = MSDP_VAR;
+				}
+				else if (state[nest] == MSDP_VAR)
+				{
+					ptv = val;
+
+					state[nest] = *pto++ = MSDP_VAL;
+				}
+				str++;
+
+				break;
+
+			case '}':
+				level--;
+
+				if (level == 0)
+				{
+					if (state[nest] == MSDP_VAR)
+					{
+						*ptv = 0;
+
+						pto += sprintf(pto, "%s", var);
+					}
+					else if (state[nest] == MSDP_VAL)
+					{
+						*ptv = 0;
+
+						pto += sprintf(pto, "%s", val);
+
+						state[nest] = 0;
+					}
+				}
+				str++;
+
+				if (nest < 0)
+				{
+					pto += sprintf(pto, "%c%c", IAC, SE);
+					return pto - out;
+				}
+				break;
+
+			case ';':
+				if (level)
+				{
+					if (state[nest] == MSDP_VAL)
+					{
+						*ptv = 0;
+
+						pto += sprintf(pto, "%s%c", val, MSDP_VAL);
+
+						ptv = val;
+					}
+				}
+				else
+				{
+					goto end;
+				}
+				str++;
+
+				break;
+
+			default:
+				if (level)
+				{
+					if (state[nest] == MSDP_VAR)
+					{
+						*ptv++ = *str++;
+					}
+					else if (state[nest] == MSDP_VAL)
+					{
+						*ptv++ = *str++;
+					}
+				}
+				else
+				{
+					goto end;
+				}
+
+				break;
+		}
+	}
+
+	end:
+
+	pto += sprintf(pto, "%c%c", IAC, SE);
+
+	while (*str)
+	{
+		*pto++ = *str++;
+	}
+	*pto = 0;
+
+	return pto - out;
+}

+ 55 - 16
src/nest.c

@@ -47,7 +47,7 @@ struct listroot *search_nest_base_ses(struct session *ses, char *arg)
 
 	if (HAS_BIT(gtd->flags, TINTIN_FLAG_LOCAL))
 	{
-		for (index = gtd->script_index ; index ; index--)
+		for (index = gtd->script_index ; index >= 0 ; index--)
 		{
 			root = gtd->script_stack[index]->local;
 
@@ -90,7 +90,7 @@ struct listnode *search_nest_node_ses(struct session *ses, char *variable)
 
 	if (HAS_BIT(gtd->flags, TINTIN_FLAG_LOCAL))
 	{
-		for (index = gtd->script_index ; index ; index--)
+		for (index = gtd->script_index ; index >= 0 ; index--)
 		{
 			root = gtd->script_stack[index]->local;
 
@@ -871,12 +871,20 @@ struct listnode *set_nest_node_ses(struct session *ses, char *arg1, char *format
 	push_call("set_nest_node_ses(%p,%s,%p,...)",ses,arg1,format);
 
 	va_start(args, format);
-	vasprintf(&arg2, format, args);
+
+	if (vasprintf(&arg2, format, args) == -1)
+	{
+		syserr_printf(ses, "set_nest_node_ses: vasprintf");
+	}
+
 	va_end(args);
 
 	arg = get_arg_to_brackets(ses, arg1, name);
 
-	check_all_events(ses, SUB_ARG, 1, 2, "VARIABLE UPDATE %s", name, name, arg2);
+	if (HAS_BIT(ses->event_flags, EVENT_FLAG_VARIABLE))
+	{
+		check_all_events(ses, EVENT_FLAG_VARIABLE, 1, 2, "VARIABLE UPDATE %s", name, name, arg2);
+	}
 
 	root = search_nest_base_ses(ses, name);
 
@@ -936,8 +944,10 @@ struct listnode *set_nest_node_ses(struct session *ses, char *arg1, char *format
 		node->shots = gtd->level->mshot;
 	}
 
-	check_all_events(root->ses, SUB_ARG, 1, 1, "VARIABLE UPDATED %s", name, name, arg2);
-
+	if (HAS_BIT(root->ses->event_flags, EVENT_FLAG_VARIABLE))
+	{
+		check_all_events(root->ses, EVENT_FLAG_VARIABLE, 1, 1, "VARIABLE UPDATED %s", name, name, arg2);
+	}
 	free(arg2);
 
 	pop_call();
@@ -956,12 +966,19 @@ struct listnode *add_nest_node_ses(struct session *ses, char *arg1, char *format
 	push_call("add_nest_node_ses(%p,%s,%p,...)",ses,arg1,format);
 
 	va_start(args, format);
-	vasprintf(&arg2, format, args);
+	if (vasprintf(&arg2, format, args) == -1)
+	{
+		syserr_printf(ses, "add_nest_node_ses: vasprintf");
+	}
+
 	va_end(args);
 
 	arg = get_arg_to_brackets(ses, arg1, name);
 
-	check_all_events(ses, SUB_ARG, 1, 2, "VARIABLE UPDATE %s", name, name, arg2);
+	if (HAS_BIT(ses->event_flags, EVENT_FLAG_VARIABLE))
+	{
+		check_all_events(ses, EVENT_FLAG_VARIABLE, 1, 2, "VARIABLE UPDATE %s", name, name, arg2);
+	}
 
 	root = search_nest_base_ses(ses, name);
 
@@ -1016,8 +1033,10 @@ struct listnode *add_nest_node_ses(struct session *ses, char *arg1, char *format
 		node->shots = gtd->level->mshot;
 	}
 
-	check_all_events(root->ses, SUB_ARG, 1, 1, "VARIABLE UPDATED %s", name, name, arg2);
-
+	if (HAS_BIT(root->ses->event_flags, EVENT_FLAG_VARIABLE))
+	{
+		check_all_events(root->ses, EVENT_FLAG_VARIABLE, 1, 1, "VARIABLE UPDATED %s", name, name, arg2);
+	}
 	free(arg2);
 
 	pop_call();
@@ -1035,12 +1054,19 @@ struct listnode *set_nest_node(struct listroot *root, char *arg1, char *format,
 	push_call("set_nest_node(%p,%s,%p,...)",root,arg1,format);
 
 	va_start(args, format);
-	vasprintf(&arg2, format, args);
+	if (vasprintf(&arg2, format, args) == -1)
+	{
+		syserr_printf(root->ses, "set_nest_node: vasprintf");
+	}
+
 	va_end(args);
 
 	arg = get_arg_to_brackets(root->ses, arg1, name);
 
-	check_all_events(root->ses, SUB_ARG, 1, 2, "VARIABLE UPDATE %s", name, name, arg2);
+	if (HAS_BIT(root->ses->event_flags, EVENT_FLAG_VARIABLE))
+	{
+		check_all_events(root->ses, EVENT_FLAG_VARIABLE, 1, 2, "VARIABLE UPDATE %s", name, name, arg2);
+	}
 
 	if (HAS_BIT(gtd->flags, TINTIN_FLAG_LOCAL))
 	{
@@ -1091,7 +1117,10 @@ struct listnode *set_nest_node(struct listroot *root, char *arg1, char *format,
 		node->shots = gtd->level->mshot;
 	}
 
-	check_all_events(root->ses, SUB_ARG, 1, 1, "VARIABLE UPDATED %s", name, name, arg2);
+	if (HAS_BIT(root->ses->event_flags, EVENT_FLAG_VARIABLE))
+	{
+		check_all_events(root->ses, EVENT_FLAG_VARIABLE, 1, 1, "VARIABLE UPDATED %s", name, name, arg2);
+	}
 
 	free(arg2);
 
@@ -1111,12 +1140,19 @@ struct listnode *add_nest_node(struct listroot *root, char *arg1, char *format,
 	push_call("add_nest_node(%p,%s,%p,...)",root,arg1,format);
 
 	va_start(args, format);
-	vasprintf(&arg2, format, args);
+	if (vasprintf(&arg2, format, args) == -1)
+	{
+		syserr_printf(root->ses, "add_nest_node: vasprintf");
+	}
+
 	va_end(args);
 
 	arg = get_arg_to_brackets(root->ses, arg1, name);
 
-	check_all_events(root->ses, SUB_ARG, 1, 2, "VARIABLE UPDATE %s", name, name, arg2);
+	if (HAS_BIT(root->ses->event_flags, EVENT_FLAG_VARIABLE))
+	{
+		check_all_events(root->ses, EVENT_FLAG_VARIABLE, 1, 2, "VARIABLE UPDATE %s", name, name, arg2);
+	}
 
 	if (HAS_BIT(gtd->flags, TINTIN_FLAG_LOCAL))
 	{
@@ -1170,7 +1206,10 @@ struct listnode *add_nest_node(struct listroot *root, char *arg1, char *format,
 		node->shots = gtd->level->mshot;
 	}
 
-	check_all_events(root->ses, SUB_ARG, 1, 1, "VARIABLE UPDATED %s", name, name, arg2);
+	if (HAS_BIT(root->ses->event_flags, EVENT_FLAG_VARIABLE))
+	{
+		check_all_events(root->ses, EVENT_FLAG_VARIABLE, 1, 1, "VARIABLE UPDATED %s", name, name, arg2);
+	}
 
 	free(arg2);
 

+ 119 - 38
src/net.c

@@ -38,6 +38,65 @@
 	IPv6 compatible connect code.
 */
 
+int wait_on_connect(struct session *ses, int sock, int connect_error)
+{
+	static struct timeval timeout;
+	static fd_set rfd;
+	static fd_set wfd;
+	socklen_t len, val;
+
+	FD_SET(sock, &rfd);
+	FD_SET(sock, &wfd);
+
+	timeout.tv_sec = 4;
+
+	if (connect_error)
+	{
+		switch (select(FD_SETSIZE, &rfd, &wfd, NULL, &timeout))
+		{
+			case 0:
+				syserr_printf(ses, "wait_on_connect:");
+				return -1;
+
+			case -1:
+				syserr_printf(ses, "wait_on_connect: select");
+				return -1;
+		}
+	}
+	else
+	{
+		switch (select(sock+1, NULL, &wfd, NULL, &timeout))
+		{
+			case 0:
+				syserr_printf(ses, "wait_on_connect2:");
+				return -1;
+
+			case -1:
+				syserr_printf(ses, "wait_on_connect2: select");
+				return -1;
+		}
+	}
+
+	len = sizeof(val);
+
+	if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &val, &len) == -1)
+	{
+		syserr_printf(ses, "wait_on_connect: getsockopt:");
+
+		return -1;
+	}
+
+	if (val)
+	{
+		errno = val;
+
+		syserr_printf(ses, "wait_on_connect: getsockopt:");
+
+		return -1;
+	}
+	return 0;
+}
+
 #ifdef HAVE_GETADDRINFO
 
 int connect_mud(struct session *ses, char *host, char *port)
@@ -49,7 +108,7 @@ int connect_mud(struct session *ses, char *host, char *port)
 
 	if (!is_number(port))
 	{
-		tintin_puts(ses, "#THE PORT SHOULD BE A NUMBER.");
+		show_error(ses, LIST_COMMAND, "#CONNECT: THE PORT {%s} SHOULD BE A NUMBER.", port);
 		return -1;
 	}
 
@@ -85,20 +144,7 @@ int connect_mud(struct session *ses, char *host, char *port)
 		return -1;
 	}
 
-//	fcntl(sock, F_SETFL, O_NDELAY);
-
-        ses->connect_error = connect(sock, address->ai_addr, address->ai_addrlen);
-
-        if (ses->connect_error)
-        {
-                syserr_printf(ses, "connect_mud: connect");
-
-                close(sock);
-
-                freeaddrinfo(address);
-
-                return -1;
-        }
+	ses->connect_error = connect(sock, address->ai_addr, address->ai_addrlen);
 
 	if (fcntl(sock, F_SETFL, O_NDELAY|O_NONBLOCK) == -1)
 	{
@@ -111,6 +157,22 @@ int connect_mud(struct session *ses, char *host, char *port)
 		return -1;
 	}
 
+	if (ses->connect_error)
+	{
+//		ses->connect_error = wait_on_connect(ses, sock, ses->connect_error);
+
+		if (ses->connect_error)
+		{
+			syserr_printf(ses, "connect_mud: connect");
+
+			close(sock);
+
+			freeaddrinfo(address);
+
+			return 0;
+		}
+	}
+
 	error = getnameinfo(address->ai_addr, address->ai_addrlen, ip, 100, NULL, 0, NI_NUMERICHOST);
 
 	if (error)
@@ -134,8 +196,6 @@ int connect_mud(struct session *ses, char *host, char *port)
 	int sock, d;
 	struct sockaddr_in sockaddr;
 
-	print_stdout("debug: NO ADDRESS INFO?\n");
-
 	if (sscanf(host, "%d.%d.%d.%d", &d, &d, &d, &d) == 4)
 	{
 		sockaddr.sin_addr.s_addr = inet_addr(host);
@@ -159,7 +219,7 @@ int connect_mud(struct session *ses, char *host, char *port)
 	}
 	else
 	{
-		tintin_puts(ses, "#THE PORT SHOULD BE A NUMBER.");
+		show_error(ses, "#CONNECT: THE PORT {%s} SHOULD BE A NUMBER.", port);
 		return -1;
 	}
 
@@ -201,9 +261,9 @@ void write_line_mud(struct session *ses, char *line, int size)
 
 	push_call("write_line_mud(%p,%p)",line,ses);
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "SEND OUTPUT", line, ntos(size));
+	check_all_events(ses, SUB_SEC|EVENT_FLAG_INPUT, 0, 2, "SEND OUTPUT", line, ntos(size));
 
-	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "CATCH SEND OUTPUT", line, ntos(size)))
+	if (check_all_events(ses, SUB_SEC|EVENT_FLAG_CATCH, 0, 2, "CATCH SEND OUTPUT", line, ntos(size)))
 	{
 		pop_call();
 		return;
@@ -213,7 +273,7 @@ void write_line_mud(struct session *ses, char *line, int size)
 	{
 		if (HAS_BIT(gtd->flags, TINTIN_FLAG_CHILDLOCK))
 		{
-			tintin_printf2(ses, "#THIS SESSION IS CHILD LOCKED, PRESS CTRL-D TO EXIT.");
+			tintin_printf2(ses, "#NO SESSION ACTIVE. TINTIN IS CHILD LOCKED, PRESS CTRL-D TO EXIT.");
 		}
 		else
 		{
@@ -278,7 +338,7 @@ void write_line_mud(struct session *ses, char *line, int size)
 		}
 	}
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "SENT OUTPUT", line, ntos(size));
+	check_all_events(ses, SUB_SEC|EVENT_FLAG_INPUT, 0, 2, "SENT OUTPUT", line, ntos(size));
 
 	pop_call();
 	return;
@@ -310,12 +370,14 @@ int read_buffer_mud(struct session *ses)
 	else
 #endif
 	size = read(ses->socket, buffer, BUFFER_SIZE - 1);
-	
+
 	if (size <= 0)
 	{
 		pop_call();
 		return FALSE;
 	}
+	buffer[size] = 0;
+
 	ses->read_len = client_translate_telopts(ses, buffer, size);
 
 	pop_call();
@@ -362,9 +424,9 @@ void readmud(struct session *ses)
 
 	if (gtd->mud_output_len < BUFFER_SIZE)
 	{
-		check_all_events(ses, SUB_ARG|SUB_SEC, 0, 1, "RECEIVED OUTPUT", gtd->mud_output_buf);
+		check_all_events(ses, SUB_SEC|EVENT_FLAG_OUTPUT, 0, 1, "RECEIVED OUTPUT", gtd->mud_output_buf);
 
-		if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 1, "CATCH RECEIVED OUTPUT", gtd->mud_output_buf))
+		if (check_all_events(ses, SUB_SEC|EVENT_FLAG_CATCH, 0, 1, "CATCH RECEIVED OUTPUT", gtd->mud_output_buf))
 		{
 			pop_call();
 			return;
@@ -429,7 +491,7 @@ void readmud(struct session *ses)
 
 						break;
 					}
-					else if (HAS_BIT(ses->flags, SES_FLAG_AUTOPATCH))
+					else if (HAS_BIT(ses->config_flags, CONFIG_FLAG_AUTOPATCH))
 					{
 						if (ses->list[LIST_PROMPT]->list[0])
 						{
@@ -440,7 +502,7 @@ void readmud(struct session *ses)
 								break;
 							}
 						}
-						else if (HAS_BIT(ses->flags, SES_FLAG_AUTOPROMPT))
+						else if (HAS_BIT(ses->config_flags, CONFIG_FLAG_AUTOPROMPT))
 						{
 							strcat(ses->more_output, line);
 							ses->check_output = utime() + 500000ULL;
@@ -507,9 +569,9 @@ void process_mud_output(struct session *ses, char *linebuf, int prompt)
 	raw_len = strlen(linebuf);
 	str_len = strip_vt102_codes(linebuf, line);
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "RECEIVED LINE", linebuf, line);
+	check_all_events(ses, SUB_SEC|EVENT_FLAG_OUTPUT, 0, 2, "RECEIVED LINE", linebuf, line);
 
-	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "CATCH RECEIVED LINE", linebuf, line))
+	if (check_all_events(ses, SUB_SEC|EVENT_FLAG_CATCH, 0, 2, "CATCH RECEIVED LINE", linebuf, line))
 	{
 		pop_call();
 		return;
@@ -517,16 +579,16 @@ void process_mud_output(struct session *ses, char *linebuf, int prompt)
 
 	if (str_len && prompt)
 	{
-		check_all_events(ses, SUB_ARG|SUB_SEC, 0, 4, "RECEIVED PROMPT", linebuf, line, ntos(raw_len), ntos(str_len));
+		check_all_events(ses, SUB_SEC|EVENT_FLAG_OUTPUT, 0, 4, "RECEIVED PROMPT", linebuf, line, ntos(raw_len), ntos(str_len));
 
-		if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 4, "CATCH RECEIVED PROMPT", linebuf, line, ntos(raw_len), ntos(str_len)))
+		if (check_all_events(ses, SUB_SEC|EVENT_FLAG_CATCH, 0, 4, "CATCH RECEIVED PROMPT", linebuf, line, ntos(raw_len), ntos(str_len)))
 		{
 			pop_call();
 			return;
 		}
 	}
 
-	if (HAS_BIT(ses->flags, SES_FLAG_COLORPATCH))
+	if (HAS_BIT(ses->config_flags, CONFIG_FLAG_COLORPATCH))
 	{
 		sprintf(line, "%s%s%s", ses->color_patch, linebuf, "\e[0m");
 
@@ -547,7 +609,7 @@ void process_mud_output(struct session *ses, char *linebuf, int prompt)
 
 		strip_non_vt102_codes(linebuf, line);
 
-		print_stdout("%s", line);
+		print_stdout(0, 0, "%s", line);
 
 		strip_vt102_codes(linebuf, line);
 
@@ -561,17 +623,36 @@ void process_mud_output(struct session *ses, char *linebuf, int prompt)
 
 	if (ses == gtd->ses)
 	{
-		char *output = str_dup(linebuf);
+		char *output = str_alloc_stack(0);
+		
+		str_cpy(&output, linebuf);
 
 		print_line(ses, &output, prompt);
 
-		str_free(output);
+		if (!IS_SPLIT(ses))
+		{
+			if (prompt)
+			{
+				int height, width;
+
+				word_wrap_split(ses, linebuf, line, ses->wrap, 0, 0, FLAG_NONE, &height, &width);
 
-		if (prompt)
+				if (height > 1)
+				{
+					word_wrap_split(ses, linebuf, line, ses->wrap, height, height, WRAP_FLAG_SPLIT, &height, &width);
+				}
+				ses->input->str_off = 1 + width;
+			}
+			else
+			{
+				ses->input->str_off = 1;
+			}
+		}
+		else
 		{
-			if (!IS_SPLIT(ses))
+			if (!HAS_BIT(ses->flags, SES_FLAG_SPLIT))
 			{
-				ses->input->off = 1 + strip_vt102_strlen(ses, linebuf);
+				ses->input->str_off = 1;
 			}
 		}
 	}

+ 161 - 93
src/parse.c

@@ -53,11 +53,13 @@ int case_table[256] =
 
 int is_abbrev(char *str1, char *str2)
 {
-	char *str3 = gtd->is_result;
+	char buf[NUMBER_SIZE], *str3;
+
+	str3 = buf;
 
 	if (*str1 == 0)
 	{
-		return false;
+		return FALSE;
 	}
 
 	if (*str2 == 0)
@@ -66,53 +68,89 @@ int is_abbrev(char *str1, char *str2)
 
 		dump_stack();
 
-		return false;
+		return FALSE;
 	}
 
-	while (true)
+	while (TRUE)
 	{
 		if (*str1 == 0)
 		{
-			strcpy(str3, str2);
+			*str3 = 0;
+
+			strcpy(gtd->is_result, buf);
 
-			return true;
+			return TRUE;
 		}
 
 		if (case_table[(int) *str1] != case_table[(int) *str2])
 		{
-			return false;
+			return FALSE;
 		}
 		str1++;
+
 		*str3++ = *str2++;
 	}
 }
 
-void filename_string(char *input, char *output)
+int is_member(char *str1, char *str2)
 {
-	while (*input)
+	char *pt1, *pt2;
+
+	if (*str1 == 0)
 	{
-		*output++ = (char) case_table[(int) *input++];
+		return FALSE;
 	}
-	*output = 0;
-}
 
-int is_suffix(char *str1, char *str2)
-{
-	int len1, len2;
+	if (*str2 == 0)
+	{
+		tintin_printf2(gtd->ses, "\e[1;31mis_member(%s,%s)", str1, str2);
 
-	len1 = strlen(str1);
-	len2 = strlen(str2);
+		dump_stack();
 
-	if (len1 >= len2)
+		return FALSE;
+	}
+
+	while (*str1)
 	{
-		if (is_abbrev(str1 + len1 - len2, str2))
+		if (case_table[(int) *str1] == case_table[(int) *str2])
 		{
-			return TRUE;
+			pt1 = str1;
+			pt2 = str2;
+
+			while (case_table[(int) *pt1] == case_table[(int) *pt2])
+			{
+				pt1++;
+				pt2++;
+
+				if (*pt1 == ' ' || *pt1 == 0)
+				{
+					return TRUE;
+				}
+			}
+		}
+
+		while (*str1 && *str1 != ' ')
+		{
+			str1++;
+		}
+
+		if (*str1)
+		{
+			str1++;
 		}
 	}
 	return FALSE;
 }
 
+void filename_string(char *input, char *output)
+{
+	while (*input)
+	{
+		*output++ = (char) case_table[(int) *input++];
+	}
+	*output = 0;
+}
+
 int is_vowel(char *str)
 {
 	switch (case_table[(int) *str])
@@ -127,31 +165,6 @@ int is_vowel(char *str)
 	return FALSE;
 }
 
-struct session *execute(struct session *ses, char *format, ...)
-{
-	char *buffer;
-	va_list args;
-
-	va_start(args, format);
-	vasprintf(&buffer, format, args);
-	va_end(args);
-
-	if (*buffer)
-	{
-		if (*buffer != gtd->tintin_char)
-		{
-			*buffer = gtd->tintin_char;
-		}
-		get_arg_all(ses, buffer, buffer, FALSE);
-	}
-
-	ses = script_driver(ses, LIST_COMMAND, buffer);
-
-	free(buffer);
-
-	return ses;
-}
-
 
 struct session *parse_input(struct session *ses, char *input)
 {
@@ -167,27 +180,25 @@ struct session *parse_input(struct session *ses, char *input)
 		return ses;
 	}
 
+	line = str_alloc_stack(0);
+
 	if (VERBATIM(ses))
 	{
-		line = (char *) malloc(BUFFER_SIZE);
-
 		sub_arg_all(ses, input, line, 1, SUB_SEC);
 
 		if (check_all_aliases(ses, line))
 		{
 			ses = script_driver(ses, LIST_ALIAS, line);
 		}
-		else if (HAS_BIT(ses->flags, SES_FLAG_SPEEDWALK) && is_speedwalk(ses, line))
+		else if (HAS_BIT(ses->config_flags, CONFIG_FLAG_SPEEDWALK) && is_speedwalk(ses, line))
 		{
 			process_speedwalk(ses, line);
 		}
 		else
 		{
-			write_mud(ses, line, SUB_EOL);
+			write_mud(ses, line, SUB_EOL|SUB_ESC);
 		}
 
-		free(line);
-
 		pop_call();
 		return ses;
 	}
@@ -200,8 +211,6 @@ struct session *parse_input(struct session *ses, char *input)
 		return ses;
 	}
 
-	line = (char *) malloc(BUFFER_SIZE);
-
 	while (*input)
 	{
 		input = space_out(input);
@@ -216,7 +225,7 @@ struct session *parse_input(struct session *ses, char *input)
 		{
 			ses = script_driver(ses, LIST_ALIAS, line);
 		}
-		else if (HAS_BIT(ses->flags, SES_FLAG_SPEEDWALK) && is_speedwalk(ses, line))
+		else if (HAS_BIT(ses->config_flags, CONFIG_FLAG_SPEEDWALK) && is_speedwalk(ses, line))
 		{
 			process_speedwalk(ses, line);
 		}
@@ -229,11 +238,8 @@ struct session *parse_input(struct session *ses, char *input)
 		{
 			input++;
 		}
-
 	}
 
-	free(line);
-
 	pop_call();
 	return ses;
 }
@@ -244,23 +250,25 @@ struct session *parse_input(struct session *ses, char *input)
 
 struct session *parse_command(struct session *ses, char *input)
 {
-	char *arg, line[BUFFER_SIZE], cmd1[BUFFER_SIZE], cmd2[BUFFER_SIZE];
+	char *arg, *arg1;
 
 	push_call("parse_command(%p,%p)",ses,input);
 
-	arg = get_arg_stop_spaces(ses, input, cmd1, GET_ONE);
+	arg1 = str_alloc_stack(0);
 
-	substitute(ses, cmd1, cmd2, SUB_VAR|SUB_FUN);
+	arg = sub_arg_stop_spaces(ses, input, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 
-	if (!strcmp(cmd1, cmd2))
+	if (!strncmp(input, arg1, strlen(arg1)))
 	{
 		pop_call();
 		return NULL;
 	}
 
-	sprintf(line, "%s%s%s", cmd2, *arg ? " " : "", arg);
-
-	strcpy(input, line);
+	if (*arg)
+	{
+		cat_sprintf(arg1, " %s", arg);
+	}
+	strcpy(input, arg1);
 
 	pop_call();
 	return ses;
@@ -276,16 +284,16 @@ char *substitute_speedwalk(struct session *ses, char *input, char *output)
 
 	while (*pti && pto - output < INPUT_SIZE)
 	{
-		while (isspace((int) *pti))
+		if (is_space(*pti))
 		{
-			pti++;
+			return input;
 		}
 
-		if (isdigit((int) *pti))
+		if (is_digit(*pti))
 		{
 			ptn = num;
 
-			while (isdigit((int) *pti))
+			while (is_digit(*pti))
 			{
 				if (ptn - num < 4)
 				{
@@ -299,6 +307,11 @@ char *substitute_speedwalk(struct session *ses, char *input, char *output)
 			*ptn = 0;
 
 			max = atoi(num);
+
+			if (*pti == 0)
+			{
+				return input;
+			}
 		}
 		else
 		{
@@ -307,9 +320,9 @@ char *substitute_speedwalk(struct session *ses, char *input, char *output)
 
 		pti = get_arg_stop_digits(ses, pti, name, GET_ONE);
 
-		if (*name == 0)
+		if (*name == 0 || !is_pathdir(ses, name))
 		{
-			break;
+			return input;
 		}
 
 		for (cnt = 0 ; cnt < max ; cnt++)
@@ -383,7 +396,7 @@ void process_speedwalk(struct session *ses, char *input)
 
 	for (dir[1] = 0 ; *input ; input++)
 	{
-		if (isdigit((int) *input))
+		if (is_digit(*input))
 		{
 			sscanf(input, "%d%c", &cnt, dir);
 
@@ -416,9 +429,7 @@ struct session *parse_tintin_command(struct session *ses, char *input)
 	char line[BUFFER_SIZE];
 	struct session *sesptr;
 
-	input = get_arg_stop_spaces(ses, input, line, GET_ONE);
-
-	substitute(ses, line, line, SUB_VAR|SUB_FUN);
+	input = sub_arg_in_braces(ses, input, line, GET_ONE, SUB_VAR|SUB_FUN);
 
 	if (is_number(line))
 	{
@@ -462,7 +473,7 @@ struct session *parse_tintin_command(struct session *ses, char *input)
 
 	tintin_printf2(ses, "#ERROR: #UNKNOWN TINTIN-COMMAND '%s'.", line);
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 1, "UNKNOWN COMMAND", line);
+	check_all_events(ses, SUB_SEC|EVENT_FLAG_SYSTEM, 0, 1, "UNKNOWN COMMAND", line);
 
 	return ses;
 }
@@ -567,14 +578,24 @@ char *get_arg_all(struct session *ses, char *string, char *result, int verbatim)
 
 char *sub_arg_all(struct session *ses, char *string, char *result, int verbatim, int sub)
 {
-	char *buffer = str_alloc(UMAX(strlen(string), BUFFER_SIZE));
+	char *buffer;
+
+	if (*string == 0)
+	{
+		*result = 0;
+
+		return string;
+	}
+
+	push_call("sub_arg_all(%p,%p,%p,%d,%d)",ses,string,result,verbatim,sub);
+
+	buffer = str_alloc_stack(strlen(string));
 
 	string = get_arg_all(ses, string, buffer, verbatim);
 
 	substitute(ses, buffer, result, sub);
 
-	str_free(buffer);
-
+	pop_call();
 	return string;
 }
 
@@ -656,14 +677,24 @@ char *get_arg_in_braces(struct session *ses, char *string, char *result, int fla
 
 char *sub_arg_in_braces(struct session *ses, char *string, char *result, int flag, int sub)
 {
-	char *buffer = str_alloc(strlen(string) + BUFFER_SIZE);
+	char *buffer;
+
+	if (*string == 0)
+	{
+		*result = 0;
+		
+		return string;
+	}
+
+	push_call("sub_arg_in_braces(%p,%p,%p,%d,%d)",ses,string,result,flag,sub);
+
+	buffer = str_alloc_stack(strlen(string) * 2);
 
 	string = get_arg_in_braces(ses, string, buffer, flag);
 
 	substitute(ses, buffer, result, sub);
 
-	str_free(buffer);
-
+	pop_call();
 	return string;
 }
 
@@ -763,7 +794,7 @@ char *get_arg_stop_spaces(struct session *ses, char *string, char *result, int f
 		{
 			break;
 		}
-		else if (isspace((int) *pti) && nest == 0)
+		else if (is_space(*pti) && nest == 0)
 		{
 			pti++;
 			break;
@@ -791,6 +822,29 @@ char *get_arg_stop_spaces(struct session *ses, char *string, char *result, int f
 	return pti;
 }
 
+char *sub_arg_stop_spaces(struct session *ses, char *string, char *result, int flag, int sub)
+{
+	char *buffer;
+
+	if (*string == 0)
+	{
+		*result = 0;
+
+		return string;
+	}
+
+	push_call("sub_arg_stop_braces(%p,%p,%p,%d,%d)",ses,string,result,flag,sub);
+
+	buffer = str_alloc_stack(strlen(string) * 2);
+
+	string = get_arg_stop_spaces(ses, string, buffer, flag);
+
+	substitute(ses, buffer, result, sub);
+
+	pop_call();
+	return string;
+}
+
 // Get one arg, stop at numbers, used for speedwalks
 
 char *get_arg_stop_digits(struct session *ses, char *string, char *result, int flag)
@@ -818,7 +872,7 @@ char *get_arg_stop_digits(struct session *ses, char *string, char *result, int f
 		{
 			break;
 		}
-		else if (isdigit((int) *pti) && nest == 0)
+		else if (is_digit(*pti) && nest == 0)
 		{
 			break;
 		}
@@ -851,7 +905,7 @@ char *get_arg_stop_digits(struct session *ses, char *string, char *result, int f
 
 char *space_out(char *string)
 {
-	while (isspace((int) *string))
+	while (is_space(*string))
 	{
 		string++;
 	}
@@ -1068,13 +1122,23 @@ void write_mud(struct session *ses, char *command, int flags)
 	{
 		if (ses->map == NULL || ses->map->nofollow == 0)
 		{
-			check_append_path(ses, command, NULL, 1);
+			check_append_path(ses, command, NULL, 0.0, 1);
 		}
 	}
 
 	if (gtd->level->ignore == 0 && ses->map && ses->map->in_room && ses->map->nofollow == 0)
 	{
-		if (follow_map(ses, command))
+		int quiet, follow;
+
+		quiet = HAS_BIT(ses->map->flags, MAP_FLAG_QUIET);
+
+		gtd->level->input += quiet;
+
+		follow = follow_map(ses, command);
+
+		gtd->level->input -= quiet;
+
+		if (follow)
 		{
 			return;
 		}
@@ -1090,28 +1154,30 @@ void write_mud(struct session *ses, char *command, int flags)
 
 void do_one_line(char *line, struct session *ses)
 {
-	char *strip;
-
-	push_call("do_one_line(%s,%p)",ses->name,line);
+	char *strip, *buf;
 
 	if (gtd->level->ignore)
 	{
-		pop_call();
 		return;
 	}
 
-	strip = str_alloc_stack();
+	push_call("do_one_line(%s,%p)",ses->name,line);
+
+	push_script_stack(ses, LIST_VARIABLE);
+
+	strip = str_alloc_stack(0);
+	buf   = str_alloc_stack(0);
 
 	strip_vt102_codes(line, strip);
 
 	if (!HAS_BIT(ses->list[LIST_ACTION]->flags, LIST_FLAG_IGNORE))
 	{
-		check_all_actions(ses, line, strip);
+		check_all_actions(ses, line, strip, buf);
 	}
 
 	if (!HAS_BIT(ses->list[LIST_PROMPT]->flags, LIST_FLAG_IGNORE))
 	{
-		check_all_prompts(ses, line, strip, TRUE);
+		check_all_prompts(ses, line, strip);
 	}
 
 	if (!HAS_BIT(ses->list[LIST_GAG]->flags, LIST_FLAG_IGNORE))
@@ -1136,6 +1202,8 @@ void do_one_line(char *line, struct session *ses)
 		DEL_BIT(ses->logmode, LOG_FLAG_NEXT);
 	}
 
+	pop_script_stack();
+
 	pop_call();
 	return;
 }

+ 118 - 47
src/path.c

@@ -38,7 +38,7 @@ DO_COMMAND(do_path)
 	{
 		info:
 
-		tintin_header(ses, " PATH OPTIONS ");
+		tintin_header(ses, 80, " PATH OPTIONS ");
 
 		for (cnt = 0 ; *path_table[cnt].fun != NULL ; cnt++)
 		{
@@ -47,7 +47,7 @@ DO_COMMAND(do_path)
 				tintin_printf2(ses, "  [%-13s] %s", path_table[cnt].name, path_table[cnt].desc);
 			}
 		}
-		tintin_header(ses, "");
+		tintin_header(ses, 80, "");
 
 		return ses;
 	}
@@ -129,7 +129,7 @@ DO_PATH(path_stop)
 	}
 	else
 	{
-		if (root->list[root->update]->val64)
+		if (root->update < root->used && root->list[root->update]->val64)
 		{
 			for (index = 0 ; index < root->used ; index++)
 			{
@@ -193,7 +193,14 @@ DO_PATH(path_describe)
 		{
 			if (root->used > 2)
 			{
-				tintin_printf2(ses, "The path is %d rooms long and leads back to where you are at.", root->used);
+				if (root->update == root->used)
+				{
+					tintin_printf2(ses, "The path is %d rooms long.", root->used);
+				}
+				else
+				{
+					tintin_printf2(ses, "The path is %d rooms long and appears to circle back to where you are at.", root->used);
+				}
 			}
 			else
 			{
@@ -202,12 +209,12 @@ DO_PATH(path_describe)
 		}
 		else
 		{
-			tintin_printf2(ses, "The path is %d rooms long and the destination lies %d rooms %s of you.", root->used, abs(z), z < 0 ? "below" : "above", s);
+			tintin_printf2(ses, "The path is %d rooms long and the destination lies %d rooms %s you.", root->used, abs(z), z < 0 ? "below" : "above", s);
 		}
 	}
 	else
 	{
-		tintin_printf2(ses, "The path is %d rooms long and the destination lies %d rooms to the %s of you at %s.", root->used, a, dirs[d], slopes[s]);
+		tintin_printf2(ses, "The path is %d rooms long and the destination lies %d rooms to the %s from you at %s.", root->used, a, dirs[d], slopes[s]);
 	}
 
 	if (root->update == 0)
@@ -240,7 +247,14 @@ DO_PATH(path_map)
 
 		for (i = 0 ; i < root->update ; i++)
 		{
-			cat_sprintf(buf, " %s", root->list[i]->arg1);
+			if (strchr(root->list[i]->arg1, ' '))
+			{
+				cat_sprintf(buf, " {%s}", root->list[i]->arg1);
+			}
+			else
+			{
+				cat_sprintf(buf, " %s", root->list[i]->arg1);
+			}
 		}
 
 		if (i != root->used)
@@ -249,7 +263,14 @@ DO_PATH(path_map)
 
 			for (i = root->update + 1 ; i < root->used ; i++)
 			{
-				cat_sprintf(buf, " %s", root->list[i]->arg1);
+				if (strchr(root->list[i]->arg1, ' '))
+				{
+					cat_sprintf(buf, " {%s}", root->list[i]->arg1);
+				}
+				else
+				{
+					cat_sprintf(buf, " %s", root->list[i]->arg1);
+				}
 			}
 		}
 
@@ -300,7 +321,7 @@ DO_PATH(path_get)
 DO_PATH(path_save)
 {
 	struct listroot *root = ses->list[LIST_PATH];
-	char result[STRING_SIZE], arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
+	char result[STRING_SIZE], arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], *ptr;
 	int i;
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
@@ -310,9 +331,15 @@ DO_PATH(path_save)
 	{
 		tintin_puts2(ses, "#PATH SAVE: LOAD OR CREATE A PATH FIRST.");
 	}
+	else if (*arg1 == 0)
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH SAVE <BACKWARD|BOTH|FORWARD> <VARIABLE NAME>");
+	}
 	else if (*arg2 == 0)
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #PATH SAVE <BACKWARD|FORWARD> <VARIABLE NAME>");
+		sprintf(result, "BOTH {%s}", arg1);
+
+		path_save(ses, result);
 	}
 	else if (is_abbrev(arg1, "BACKWARDS"))
 	{
@@ -348,6 +375,20 @@ DO_PATH(path_save)
 
 		show_message(ses, LIST_COMMAND, "#PATH SAVE: FORWARD PATH SAVED TO {%s}", arg2);
 	}
+	else if (is_abbrev(arg1, "BOTH"))
+	{
+		ptr = result;
+
+		*result = 0;
+
+		for (i = 0 ; i < root->used ; i++)
+		{
+			ptr += sprintf(ptr, ";{%s}{%s}{%s}", root->list[i]->arg1, root->list[i]->arg2, root->list[i]->arg3);
+		}
+		set_nest_node_ses(ses, arg2, "%s", result);
+
+		show_message(ses, LIST_COMMAND, "#PATH SAVE: PATH SAVED TO {%s}", arg2);
+	}
 	else if (is_abbrev(arg1, "LENGTH"))
 	{
 		sprintf(result, "%d", root->used);
@@ -377,7 +418,7 @@ DO_PATH(path_load)
 	char arg1[BUFFER_SIZE], temp[BUFFER_SIZE];
 	struct listnode *node;
 
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
 
 	if ((node = search_nest_node_ses(ses, arg1)) == NULL)
 	{
@@ -392,24 +433,22 @@ DO_PATH(path_load)
 
 	root->update = 0;
 
+	DEL_BIT(ses->flags, SES_FLAG_PATHMAPPING);
+
+	gtd->level->input++;
+
 	while (*arg)
 	{
 		if (*arg == ';')
 		{
 			arg++;
 		}
+		arg = get_arg_all(ses, arg, temp, 0);
 
-		arg = get_arg_in_braces(ses, arg, temp, GET_ALL);
-
-		if ((node = search_node_list(root, temp)))
-		{
-			create_node_list(root, node->arg1, node->arg2, "0", "");
-		}
-		else
-		{
-			create_node_list(root, temp, temp, "0", "");
-		}
+		path_insert(ses, temp);
 	}
+	gtd->level->input--;
+
 	show_message(ses, LIST_COMMAND, "#PATH LOAD: PATH WITH %d NODES LOADED.", root->used);
 }
 
@@ -430,7 +469,7 @@ DO_PATH(path_delete)
 	}
 	else
 	{
-		tintin_puts(ses, "#PATH DELETE: NO MOVES LEFT.");
+		tintin_printf(ses, "#PATH DELETE: NO MOVES LEFT.");
 	}
 
 }
@@ -438,10 +477,11 @@ DO_PATH(path_delete)
 DO_PATH(path_insert)
 {
 	struct listroot *root = ses->list[LIST_PATH];
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
+	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE];
 
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
-	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
+	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
+	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
+	arg = sub_arg_in_braces(ses, arg, arg3, GET_ALL, SUB_VAR|SUB_FUN);
 
 	if (*arg1 == 0 && *arg2 == 0)
 	{
@@ -449,9 +489,9 @@ DO_PATH(path_insert)
 	}
 	else
 	{
-		create_node_list(root, arg1, arg2, "0", "");
+		create_node_list(root, arg1, arg2, arg3, "");
 
-		show_message(ses, LIST_COMMAND, "#PATH INSERT: FORWARD {%s} BACKWARD {%s}.", arg1, arg2);
+		show_message(ses, LIST_COMMAND, "#PATH INSERT: FORWARD {%s} BACKWARD {%s} DELAY {%s}.", arg1, arg2, arg3);
 
 		if (HAS_BIT(ses->flags, SES_FLAG_PATHMAPPING))
 		{
@@ -474,7 +514,7 @@ DO_PATH(path_run)
 
 	if (root->update == root->used)
 	{
-		tintin_puts(ses, "#PATH RUN: #END OF PATH.");
+		tintin_printf(ses, "#PATH RUN: #END OF PATH.");
 	}
 	else
 	{
@@ -490,6 +530,8 @@ DO_PATH(path_run)
 			{
 				root->list[index]->val64 = gtd->utime + total;
 
+				total += atof(root->list[index]->arg3) * 1000000.0;
+
 				total += delay;
 			}
 		}
@@ -499,6 +541,7 @@ DO_PATH(path_run)
 			{
 				script_driver(ses, LIST_COMMAND, root->list[root->update++]->arg1);
 			}
+			check_all_events(ses, EVENT_FLAG_MAP, 0, 0, "END OF RUN");
 		}
 	}
 
@@ -520,7 +563,7 @@ DO_PATH(path_walk)
 	{
 		if (root->update == 0)
 		{
-			tintin_puts(ses, "#PATH WALK: #START OF PATH.");
+			tintin_printf(ses, "#PATH WALK: #START OF PATH.");
 		}
 		else
 		{
@@ -528,7 +571,7 @@ DO_PATH(path_walk)
 
 			if (root->update == 0)
 			{
-				check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "START OF PATH");
+				check_all_events(ses, EVENT_FLAG_MAP, 0, 0, "START OF PATH");
 			}
 		}
 	}
@@ -536,7 +579,7 @@ DO_PATH(path_walk)
 	{
 		if (root->update == root->used)
 		{
-			tintin_puts(ses, "#PATH WALK: #END OF PATH.");
+			tintin_printf(ses, "#PATH WALK: #END OF PATH.");
 		}
 		else
 		{
@@ -544,7 +587,7 @@ DO_PATH(path_walk)
 
 			if (root->update == root->used)
 			{
-				check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "END OF PATH");
+				check_all_events(ses, EVENT_FLAG_MAP, 0, 0, "END OF PATH");
 			}
 		}
 	}
@@ -608,16 +651,15 @@ DO_PATH(path_zip)
 	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
 	int i, cnt;
 
-	cnt   =  1;
+	cnt   = 1;
+	*arg1 = 0;
 
-	*arg1 =  0;
-	*arg2 = 0;
 
 	for (i = 0 ; i < root->used ; i++)
 	{
-		if (search_node_list(root, root->list[i]->arg1) == NULL || strlen(root->list[i]->arg1) != 1)
+		if (search_node_list(ses->list[LIST_PATHDIR], root->list[i]->arg1) == NULL || strlen(root->list[i]->arg1) != 1)
 		{
-			if (i && search_node_list(root, root->list[i - 1]->arg1) != NULL && strlen(root->list[i - 1]->arg1) == 1)
+			if (i && search_node_list(ses->list[LIST_PATHDIR], root->list[i - 1]->arg1) != NULL && strlen(root->list[i - 1]->arg1) == 1)
 			{
 				cat_sprintf(arg1, "%c", COMMAND_SEPARATOR);
 			}
@@ -642,11 +684,14 @@ DO_PATH(path_zip)
 		}
 	}
 
+	cnt   = 1;
+	*arg2 = 0;
+
 	for (i = root->used - 1 ; i >= 0 ; i--)
 	{
-		if (search_node_list(root, root->list[i]->arg2) == NULL || strlen(root->list[i]->arg2) != 1)
+		if (search_node_list(ses->list[LIST_PATHDIR], root->list[i]->arg2) == NULL || strlen(root->list[i]->arg2) != 1)
 		{
-			if (i != root->used - 1 && search_node_list(root, root->list[i + 1]->arg2) != NULL && strlen(root->list[i + 1]->arg2) == 1)
+			if (i != root->used - 1 && search_node_list(ses->list[LIST_PATHDIR], root->list[i + 1]->arg2) != NULL && strlen(root->list[i + 1]->arg2) == 1)
 			{
 				cat_sprintf(arg2, "%c", COMMAND_SEPARATOR);
 			}
@@ -712,11 +757,11 @@ DO_PATH(path_unzip)
 				continue;
 		}
 
-		if (isdigit((int) *arg))
+		if (is_digit(*arg))
 		{
 			ptn = num;
 
-			while (isdigit((int) *arg))
+			while (is_digit(*arg))
 			{
 				if (ptn - num < 5)
 				{
@@ -772,7 +817,7 @@ DO_PATH(path_unzip)
 
 			for (dir[1] = 0 ; *str ; str++)
 			{
-				if (isdigit((int) *str))
+				if (is_digit(*str))
 				{
 					sscanf(str, "%d%c", &cnt, dir);
 
@@ -934,7 +979,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, int follow)
+void check_append_path(struct session *ses, char *forward, char *backward, float delay, int follow)
 {
 	struct listroot *root = ses->list[LIST_PATH];
 	struct listnode *node;
@@ -943,7 +988,9 @@ void check_append_path(struct session *ses, char *forward, char *backward, int f
 	{
 		if ((node = search_node_list(ses->list[LIST_PATHDIR], forward)))
 		{
-			create_node_list(root, node->arg1, node->arg2, "0", "");
+			show_debug(ses, LIST_PATHDIR, "#DEBUG PATHDIR {%s} {%s}", node->arg1, node->arg2);
+
+			create_node_list(root, node->arg1, node->arg2, ftos(delay), "");
 
 			root->update = root->used;
 		}
@@ -952,11 +999,15 @@ void check_append_path(struct session *ses, char *forward, char *backward, int f
 	{
 		if ((node = search_node_list(ses->list[LIST_PATHDIR], forward)))
 		{
-			create_node_list(root, node->arg1, node->arg2, "0", "");
+			show_debug(ses, LIST_PATHDIR, "#DEBUG PATHDIR {%s} {%s}", node->arg1, node->arg2);
+
+			create_node_list(root, node->arg1, node->arg2, ftos(delay), "");
 		}
 		else
 		{
-			create_node_list(root, forward, backward, "0", "");
+			show_debug(ses, LIST_PATHDIR, "#DEBUG PATHDIR {%s} {%s}", forward, backward);
+
+			create_node_list(root, forward, backward, ftos(delay), "");
 		}
 	}
 }
@@ -1033,6 +1084,15 @@ DO_COMMAND(do_unpathdir)
 	return ses;
 }
 
+int is_pathdir(struct session *ses, char *dir)
+{
+	struct listnode *node;
+
+	node = search_node_list(ses->list[LIST_PATHDIR], dir);
+
+	return node != NULL;
+}
+
 int exit_to_dir(struct session *ses, char *name)
 {
 	struct listnode *node;
@@ -1049,6 +1109,17 @@ int exit_to_dir(struct session *ses, char *name)
 	}
 }
 
+// Prone to misuse, so double checking
+
+unsigned char pdir(struct listnode *node)
+{
+	if (node->val32[0] < 0 || node->val32[0] >= 64)
+	{
+		tintin_printf2(NULL, "pdir: node->val32[0] = %d", node->val32[0]);
+	}
+	return node->val32[0];
+}
+
 char *dir_to_exit(struct session *ses, int dir)
 {
 	struct listroot *root;
@@ -1067,7 +1138,7 @@ char *dir_to_exit(struct session *ses, int dir)
 	{
 		node = root->list[root->update];
 
-		if (node->val32[0] == dir)
+		if (pdir(node) == dir)
 		{
 			return node->arg1;
 		}

+ 138 - 70
src/port.c

@@ -45,13 +45,13 @@ DO_COMMAND(do_port)
 	{
 		info:
 
-		tintin_header(ses, " PORT OPTIONS ");
+		tintin_header(ses, 80, " PORT OPTIONS ");
 
 		for (cnt = 0 ; *port_table[cnt].name != 0 ; cnt++)
 		{
 			tintin_printf2(ses, "  [%-13s] %s", port_table[cnt].name, port_table[cnt].desc);
 		}
-		tintin_header(ses, "");
+		tintin_header(ses, 80, "");
 
 		return ses;
 	}
@@ -88,9 +88,9 @@ DO_COMMAND(do_port)
 DO_PORT(port_initialize)
 {
 	char temp[BUFFER_SIZE], file[BUFFER_SIZE];
-	struct sockaddr_in sa;
+	struct sockaddr_in sin;
 	struct linger ld;
-	int sock, port, reuse = 1;
+	int sock = 0, port, reuse = 1;
 
 	arg = sub_arg_in_braces(ses, arg, file,  GET_ONE, SUB_VAR|SUB_FUN);
 
@@ -117,61 +117,75 @@ DO_PORT(port_initialize)
 
 	tintin_printf(ses, "#TRYING TO LAUNCH '%s' ON PORT '%s'.", arg1, arg2);
 
-	sprintf(temp, "{localport} {%d} {%.*s}", atoi(arg2), PATH_SIZE, file);
+	sprintf(temp, "{localhost} {%d} {%.*s}", atoi(arg2), PATH_SIZE, file);
 
 	port = atoi(arg2);
 
-	sa.sin_family      = AF_INET;
-	sa.sin_addr.s_addr = INADDR_ANY;
-	sa.sin_port        = htons(port);
+	if (port)
+	{
+		sin.sin_family      = AF_INET;
+		sin.sin_addr.s_addr = INADDR_ANY;
+		sin.sin_port        = htons(port);
 
-	sock = socket(AF_INET, SOCK_STREAM, 0);
+		sock = socket(AF_INET, SOCK_STREAM, 0);
 
-	if (sock < 0)
-	{
-		syserr_printf(ses, "port_initialize: socket");
+		if (sock < 0)
+		{
+			syserr_printf(ses, "port_initialize: socket");
 
-		return ses;
-	}
+			return ses;
+		}
 
-	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)) == -1)
-	{
-		syserr_printf(ses, "port_initialize: setsockopt");
+		if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)) == -1)
+		{
+			syserr_printf(ses, "port_initialize: setsockopt");
 
-		return ses;
-	}
+			return ses;
+		}
 
-	ld.l_onoff  = 0; 
-	ld.l_linger = 100;
+		ld.l_onoff  = 0; 
+		ld.l_linger = 100;
 
-	setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *) &ld, sizeof(ld));
+		setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *) &ld, sizeof(ld));
 
-	if (fcntl(sock, F_SETFL, O_NDELAY|O_NONBLOCK) == -1)
-	{
-		syserr_printf(ses, "port_initialize: fcntl O_NDELAY|O_NONBLOCK");
+		if (fcntl(sock, F_SETFL, O_NDELAY|O_NONBLOCK) == -1)
+		{
+			syserr_printf(ses, "port_initialize: fcntl O_NDELAY|O_NONBLOCK");
 
-		return ses;
-	}
+			return ses;
+		}
 
-	if (bind(sock, (struct sockaddr *) &sa, sizeof(sa)) < 0)
-	{
-		tintin_printf(NULL, "#PORT INITIALIZE: PORT %d IS ALREADY IN USE.", port);
+		if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0)
+		{
+			tintin_printf(NULL, "#PORT INITIALIZE: PORT %d IS ALREADY IN USE.", port);
 
-		close(sock);
+			close(sock);
 
-		return ses;
-	}
+			return ses;
+		}
 
-	if (listen(sock, 32) == -1)
-	{
-		syserr_printf(ses, "port_initialize: listen");
+		if (listen(sock, 32) == -1)
+		{
+			syserr_printf(ses, "port_initialize: listen");
 
-		close(sock);
+			close(sock);
 
-		return ses;
-	}
+			return ses;
+		}
+/*
+		socklen_t len = sizeof(sin);
+
+		if (getsockname(sock, (struct sockaddr *) &sin, &len) == -1)
+		{
+			syserr_printf(ses, "port_initialize: getsockname");
+		}
+		else
+		{
+			printf("debug: %d\n", sin.sin_port);
+		}
+*/
 
-	// kind of dodgy, but should be a mere formality.
+	}
 
 	ses = new_session(ses, arg1, temp, -1, 0);
 
@@ -186,9 +200,9 @@ DO_PORT(port_initialize)
 	ses->port->ip       = strdup("<Unknown>");
 	ses->port->prefix   = strdup("<PORT> ");
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "PORT INITIALIZED", ses->name, ntos(ses->port->port));
+	check_all_events(ses, EVENT_FLAG_PORT, 0, 3, "PORT INITIALIZED", ses->name, ntos(ses->port->port), ntos(ses->port->fd));
 
-	if (!check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "GAG PORT INITIALIZED", ses->name, ntos(ses->port->port)))
+	if (!check_all_events(ses, EVENT_FLAG_PORT, 0, 2, "GAG PORT INITIALIZED", ses->name, ntos(ses->port->port)))
 	{
 		tintin_printf(ses, "#PORT INITIALIZE: SESSION {%s} IS LISTENING ON PORT %d.", ses->name, ses->port->port);
 	}
@@ -205,18 +219,24 @@ DO_PORT(port_uninitialize)
 	{
 		close_port(ses, ses->port->next, TRUE);
 	}
+
 	close_port(ses, ses->port, FALSE);
 
 	ses->port = NULL;
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "PORT UNINITIALIZED", ses->name, ntos(port));
+	check_all_events(ses, EVENT_FLAG_PORT, 0, 2, "PORT UNINITIALIZED", ses->name, ntos(port));
 
-	if (!check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "GAG PORT UNINITIALIZED", ses->name, ntos(port)))
+	if (!check_all_events(ses, EVENT_FLAG_PORT, 0, 2, "GAG PORT UNINITIALIZED", ses->name, ntos(port)))
 	{
 		tintin_printf(ses, "#PORT UNINITIALIZE: CLOSED PORT {%d}.", port);
 	}
 
-	return ses;
+	if (!HAS_BIT(ses->flags, SES_FLAG_CLOSED))
+	{
+		cleanup_session(ses);
+	}
+
+	return gtd->ses;
 }
 
 
@@ -287,12 +307,12 @@ int port_new(struct session *ses, int sock)
 
 	port_printf(ses, "New connection: %s D%d.", new_buddy->ip, new_buddy->fd);
 
-	if (HAS_BIT(ses->flags, SES_FLAG_TELNET))
+	if (HAS_BIT(ses->config_flags, CONFIG_FLAG_TELNET))
 	{
 		announce_support(ses, new_buddy);
 	}
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 3, "PORT CONNECTION", new_buddy->name, new_buddy->ip, ntos(new_buddy->port));
+	check_all_events(ses, EVENT_FLAG_PORT, 0, 3, "PORT CONNECTION", new_buddy->name, new_buddy->ip, ntos(new_buddy->port));
 
 	pop_call();
 	return 0;
@@ -329,11 +349,10 @@ void close_port(struct session *ses, struct port_data *buddy, int unlink)
 		{
 			port_printf(ses, "Closing connection to %s@%s D%d.", buddy->name, buddy->ip, buddy->fd);
 		}
+		check_all_events(ses, EVENT_FLAG_PORT, 0, 3, "PORT DISCONNECTION", buddy->name, buddy->ip, ntos(buddy->port));
 	}
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 3, "PORT DISCONNECTION", buddy->name, buddy->ip, ntos(buddy->port));
-
-	if (close(buddy->fd) == -1)
+	if (buddy->fd && close(buddy->fd) == -1)
 	{
 		syserr_printf(ses, "close_port: close");
 	}
@@ -450,47 +469,53 @@ void port_telnet_printf(struct session *ses, struct port_data *buddy, size_t len
 
 void port_printf(struct session *ses, char *format, ...)
 {
-	char buf[STRING_SIZE], tmp[STRING_SIZE];
+	char buf[BUFFER_SIZE / 2], tmp[BUFFER_SIZE];
+	int len;
 	va_list args;
 
+	len = BUFFER_SIZE / 2 - strlen(ses->port->prefix) - 5;
+
 	va_start(args, format);
-	vsnprintf(buf, BUFFER_SIZE, format, args);
+	vsnprintf(buf, len, format, args);
 	va_end(args);
 
-	sprintf(tmp, "%s%.*s", ses->port->prefix, BUFFER_SIZE, buf);
+	sprintf(tmp, "%s%s", ses->port->prefix, buf);
 
 	strip_vt102_codes_non_graph(tmp, buf);
 
-	sprintf(tmp, "%s%.*s%s", ses->port->color, BUFFER_SIZE, buf, "\e[0m");
+	sprintf(tmp, "%s%s\e[0m", ses->port->color, buf);
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "PORT MESSAGE", tmp, buf);
+	check_all_events(ses, SUB_SEC|EVENT_FLAG_PORT, 0, 2, "PORT MESSAGE", tmp, buf);
 
-	if (!check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "CATCH PORT MESSAGE", tmp, buf))
+	if (!check_all_events(ses, SUB_SEC|EVENT_FLAG_CATCH, 0, 2, "CATCH PORT MESSAGE", tmp, buf))
 	{
-		tintin_puts(ses, tmp);
+		tintin_printf(ses, "%s", tmp);
 	}
 }
 
 void port_log_printf(struct session *ses, struct port_data *buddy, char *format, ...)
 {
-	char buf[STRING_SIZE], tmp[STRING_SIZE];
+	char buf[BUFFER_SIZE / 2], tmp[BUFFER_SIZE];
+	int len;
 	va_list args;
 
+	len = BUFFER_SIZE / 2 - strlen(ses->port->prefix) - strlen(buddy->name) - strlen(buddy->ip) - 7;
+
 	va_start(args, format);
-	vsnprintf(buf, BUFFER_SIZE, format, args);
+	vsnprintf(buf, len, format, args);
 	va_end(args);
 
-	sprintf(tmp, "%s%s@%s %.*s", ses->port->prefix, buddy->name, buddy->ip, BUFFER_SIZE, buf);
+	sprintf(tmp, "%s%s@%s %s", ses->port->prefix, buddy->name, buddy->ip, buf);
 
 	strip_vt102_codes_non_graph(tmp, buf);
 
-	sprintf(tmp, "%s%.*s\e[0m", ses->port->color, BUFFER_SIZE, buf);
+	sprintf(tmp, "%s%s\e[0m", ses->port->color, buf);
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 5, "PORT LOG MESSAGE", buddy->name, buddy->ip, ntos(buddy->fd), tmp, buf);
+	check_all_events(ses, EVENT_FLAG_PORT, 0, 5, "PORT LOG MESSAGE", buddy->name, buddy->ip, ntos(buddy->fd), tmp, buf);
 
-	if (!check_all_events(ses, SUB_ARG|SUB_SEC, 0, 5, "CATCH PORT LOG MESSAGE", buddy->name, buddy->ip, ntos(buddy->fd), tmp, buf))
+	if (!check_all_events(ses, EVENT_FLAG_CATCH, 0, 5, "CATCH PORT LOG MESSAGE", buddy->name, buddy->ip, ntos(buddy->fd), tmp, buf))
 	{
-		tintin_puts(ses, tmp);
+		tintin_printf(ses, "%s", tmp);
 	}
 }
 
@@ -566,8 +591,10 @@ int process_port_input(struct session *ses, struct port_data *buddy)
 		if (buddy->intop > BUFFER_SIZE / 4)
 		{
 			port_socket_printf(ses, buddy, "\e[1;31mYou overflowed your input buffer, you must reconnect.\n");
+			input[BUFFER_SIZE / 2] = 0;
+			port_socket_printf(ses, buddy, "%s\n", input);
 			port_log_printf(ses, buddy, "Buffer overflow, closing connection.");
-			
+
 			pop_call();
 			return -1;
 		}
@@ -605,9 +632,9 @@ void get_port_commands(struct session *ses, struct port_data *buddy, char *buf,
 
 	strip_vt102_codes(buf, txt);
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 5, "PORT RECEIVED MESSAGE", buddy->name, buddy->ip, ntos(buddy->port), buf, txt);
+	check_all_events(ses, SUB_SEC|EVENT_FLAG_PORT, 0, 5, "PORT RECEIVED MESSAGE", buddy->name, buddy->ip, ntos(buddy->port), buf, txt);
 
-	if (!check_all_events(ses, SUB_ARG|SUB_SEC, 0, 5, "CATCH PORT RECEIVED MESSAGE", buddy->name, buddy->ip, ntos(buddy->port), buf, txt))
+	if (!check_all_events(ses, SUB_SEC|EVENT_FLAG_CATCH, 0, 5, "CATCH PORT RECEIVED MESSAGE", buddy->name, buddy->ip, ntos(buddy->port), buf, txt))
 	{
 		port_receive_message(ses, buddy, buf);
 	}
@@ -741,7 +768,7 @@ DO_PORT(port_call)
 	new_buddy->color    = strdup("");
 	new_buddy->prefix   = strdup("");
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 3, "PORT CONNECTION", new_buddy->name, new_buddy->ip, ntos(new_buddy->port));
+	check_all_events(ses, EVENT_FLAG_PORT, 0, 3, "PORT CONNECTION", new_buddy->name, new_buddy->ip, ntos(new_buddy->port));
 
 	FD_ZERO(&rds);
 	FD_SET(sock, &rds);
@@ -835,6 +862,43 @@ DO_PORT(port_prefix)
 	return ses;
 }
 
+DO_PORT(port_proxy)
+{
+	struct session *bridge;
+	struct port_data *buddy;
+
+	if ((buddy = find_port_buddy(ses, arg1)) == NULL)
+	{
+		port_printf(ses, "You are not connected to anyone named '%s'.", arg1);
+
+		return ses;
+	}
+
+	if (buddy->ses && *arg2 == 0)
+	{
+		port_printf(ses, "Socket '%s' is no longer a proxy for '%s'.", arg1, buddy->ses->name);
+
+		buddy->ses->proxy = NULL;
+		buddy->ses = NULL;
+
+		return ses;
+	}
+
+	if ((bridge = find_session(arg2)) == NULL)
+	{
+		port_printf(ses, "The session '%s' could not be found.", arg2);
+
+		return ses;
+	}
+
+	buddy->ses = ses;
+	bridge->proxy = buddy;
+
+	port_printf(ses, "Socket '%s' is now a proxy for '%s'.", arg1, buddy->ses->name);
+
+	return ses;
+}
+
 DO_PORT(port_send)
 {
 	struct port_data *buddy;
@@ -1105,20 +1169,24 @@ DO_PORT(port_ignore)
 
 
 
+
 struct port_data *find_port_buddy(struct session *ses, char *arg)
 {
 	struct port_data *buddy;
+	int fd;
 
 	if (*arg == 0)
 	{
 		return NULL;
 	}
 
-	if (is_number(arg))
+	fd = is_number(arg);
+
+	if (fd)
 	{
 		for (buddy = ses->port->next ; buddy ; buddy = buddy->next)
 		{
-			if (atoi(arg) == buddy->fd)
+			if (fd == buddy->fd)
 			{
 				return buddy;
 			}

+ 26 - 19
src/regex.c

@@ -62,7 +62,6 @@ DO_COMMAND(do_regexp)
 	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, arg3, GET_ALL);
-	arg = get_arg_in_braces(ses, arg, arg4, GET_ALL);
 
 	if (*arg3 == 0)
 	{
@@ -76,9 +75,16 @@ DO_COMMAND(do_regexp)
 
 			ses = script_driver(ses, LIST_COMMAND, arg3);
 		}
-		else if (*arg4)
+		else
 		{
-			ses = script_driver(ses, LIST_COMMAND, arg4);
+			arg4 = str_alloc_stack(0);
+
+			arg = get_arg_in_braces(ses, arg, arg4, GET_ALL);
+
+			if (*arg4)
+			{
+				ses = script_driver(ses, LIST_COMMAND, arg4);
+			}
 		}
 	}
 	return ses;
@@ -253,7 +259,7 @@ int get_regex_range(char *in, char *out, int *var, int *arg)
 				continue;
 
 			case 'a':
-				pto += sprintf(pto, "(.");
+				pto += sprintf(pto, "([^\\0]");
 				break;
 			case 'A':
 				pto += sprintf(pto, "(\\n");
@@ -277,7 +283,7 @@ int get_regex_range(char *in, char *out, int *var, int *arg)
 				pto += sprintf(pto, "(\\S");
 				break;
 			case 'u':
-				pto += sprintf(pto, "((?:[\\xC0-\\xFE][\\x80-\\xC0]{1,3})");
+				pto += sprintf(pto, "((?:[\\x00-\\x7F]|[\\xC0-\\xFE][\\x80-\\xC0]{1,3})");
 				break;
 			case 'U':
 				pto += sprintf(pto, "([\\x00-\\x7F\\xFF]");
@@ -476,7 +482,7 @@ int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int
 				break;
 
 			case '$':
-				if (pti[1] != DEFAULT_OPEN && !isalnum((int) pti[1]))
+				if (pti[1] != DEFAULT_OPEN && !is_alnum(pti[1]))
 				{
 					int i = 0;
 
@@ -507,9 +513,9 @@ int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int
 					case '8':
 					case '9':
 						fix = REGEX_FLAG_FIX;
-						arg = isdigit((int) pti[2]) ? (pti[1] - '0') * 10 + (pti[2] - '0') : pti[1] - '0';
+						arg = is_digit(pti[2]) ? (pti[1] - '0') * 10 + (pti[2] - '0') : pti[1] - '0';
 						gtd->args[next_arg(var)] = next_arg(arg);
-						pti += isdigit((int) pti[2]) ? 3 : 2;
+						pti += is_digit(pti[2]) ? 3 : 2;
 						strcpy(pto, *pti == 0 ? "(.*)" : "(.*?)");
 						pto += strlen(pto);
 						break;
@@ -517,7 +523,7 @@ int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int
 					case 'a':
 						gtd->args[next_arg(var)] = next_arg(arg);
 						pti += 2;
-						strcpy(pto, *pti == 0 ? "([^\\n]*)" : "([^\\n]*?)");
+						strcpy(pto, *pti == 0 ? "([^\\0]*)" : "([^\\0]*?)");
 						pto += strlen(pto);
 						break;
 
@@ -590,10 +596,11 @@ int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int
 					case 'U':
 						gtd->args[next_arg(var)] = next_arg(arg);
 						pti += 2;
-						strcpy(pto, *pti == 0 ? "(^[\xFF]*)" : "([\\x00-\\x7F\\xFF]*?)");
+						strcpy(pto, *pti == 0 ? "(^[\\xF5-\\xFF]*)" : "([\\xF5-\\xFF]*?)");
 						pto += strlen(pto);
 						break;
 
+
 					case 'w':
 						gtd->args[next_arg(var)] = next_arg(arg);
 						pti += 2;
@@ -645,7 +652,7 @@ int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int
 							case 'a':
 								gtd->args[next_arg(var)] = next_arg(arg);
 								pti += 2;
-								strcpy(pto, *pti == 0 ? "[^\\n]*" : "[^\\n]*?");
+								strcpy(pto, *pti == 0 ? "[^\\0]*" : "[^\\0]*?");
 								pto += strlen(pto);
 								break;
 
@@ -693,14 +700,14 @@ int tintin_regexp(struct session *ses, pcre *nodepcre, char *str, char *exp, int
 							case 'u':
 								gtd->args[next_arg(var)] = next_arg(arg);
 								pti += 3;
-								strcpy(pto, *pti == 0 ? "(?:[\\xC0-\\xFE][\\x80-\\xC0]{1,3})*" : "(?:[\\xC0-\\xFE][\\x80-\\xC0]{1,3})*?");
+								strcpy(pto, *pti == 0 ? "(?:[\\x00-\\x7F]|[\\xC0-\\xFE][\\x80-\\xC0]{1,3})*" : "(?:[\\x00-\\x7F]|[\\xC0-\\xFE][\\x80-\\xC0]{1,3})*?");
 								pto += strlen(pto);
 								break;
 
 							case 'U':
 								gtd->args[next_arg(var)] = next_arg(arg);
 								pti += 3;
-								strcpy(pto, *pti == 0 ? "[\\x00-\\x7F\\xFF]*" : "[\\x00-\\x7F\\xFF]*?");
+								strcpy(pto, *pti == 0 ? "[\\xF5-\\xFF]*" : "[\\xF5-\\xFF]*?");
 								pto += strlen(pto);
 								break;
 
@@ -835,7 +842,7 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 				break;
 
 			case '&':
-				if (pti[1] == DEFAULT_OPEN || isalnum((int) pti[1]) || pti[1] == '&')
+				if (pti[1] == DEFAULT_OPEN || is_alnum(pti[1]) || pti[1] == '&')
 				{
 					return NULL;
 				}
@@ -843,7 +850,7 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 				break;
 
 			case '@':
-				if (pti[1] == DEFAULT_OPEN || isalnum((int) pti[1]) || pti[1] == '@')
+				if (pti[1] == DEFAULT_OPEN || is_alnum(pti[1]) || pti[1] == '@')
 				{
 					return NULL;
 				}
@@ -851,7 +858,7 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 				break;
 
 			case '$':
-				if (pti[1] == DEFAULT_OPEN || isalnum((int) pti[1]))
+				if (pti[1] == DEFAULT_OPEN || is_alnum(pti[1]))
 				{
 					return NULL;
 				}
@@ -898,7 +905,7 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 					case '7':
 					case '8':
 					case '9':
-						pti += isdigit((int) pti[2]) ? 3 : 2;
+						pti += is_digit(pti[2]) ? 3 : 2;
 						strcpy(pto, *pti == 0 ? "(.*)" : "(.*?)");
 						pto += strlen(pto);
 						break;
@@ -951,13 +958,13 @@ pcre *tintin_regexp_compile(struct session *ses, struct listnode *node, char *ex
 
 					case 'u':
 						pti += 2;
-						strcpy(pto, *pti == 0 ? "((?:[\\xC0-\\xFE][\\x80-\\xC0]{1,3})*)" : "((?:[\\xC0-\\xFE][\\x80-\\xC0]{1,3})*?)");
+						strcpy(pto, *pti == 0 ? "((?:[\\x00-\\x7F]|[\\xC0-\\xFE][\\x80-\\xC0]{1,3})*)" : "((?:[\\x00-\\x7F]|[\\xC0-\\xFE][\\x80-\\xC0]{1,3})*?)");
 						pto += strlen(pto);
 						break;
 
 					case 'U':
 						pti += 2;
-						strcpy(pto, *pti == 0 ? "([\\x00-\\x7F\\xFF]*)" : "([\\x00-\\x7F\\xFF]*?)");
+						strcpy(pto, *pti == 0 ? "([\\xF5-\\xFF]*)" : "([\\xF5-\\xFF]*?)");
 						pto += strlen(pto);
 						break;
 

+ 264 - 143
src/scan.c

@@ -26,12 +26,99 @@
 #include "tintin.h"
 
 #ifdef HAVE_PTY_H
-#include <pty.h>
+  #include <pty.h>
 #else
-#ifdef HAVE_UTIL_H
-#include <util.h>
-#endif
+  #ifdef HAVE_UTIL_H
+    #include <util.h>
+  #endif
 #endif
+#include <dirent.h>
+
+DO_COMMAND(do_scan)
+{
+	char cmd[BUFFER_SIZE];
+	FILE *fp = NULL;
+	int cnt;
+
+	arg = sub_arg_in_braces(ses, arg, cmd, GET_ONE, SUB_VAR|SUB_FUN);
+
+	if (*cmd == 0)
+	{
+		tintin_header(ses, 80, " SCAN OPTIONS ");
+
+		for (cnt = 0 ; *scan_table[cnt].name != 0 ; cnt++)
+		{
+			tintin_printf2(ses, "  [%-13s] %s", scan_table[cnt].name, scan_table[cnt].desc);
+		}
+		tintin_header(ses, 80, "");
+
+		return ses;
+	}
+
+	for (cnt = 0 ; *scan_table[cnt].name != 0 ; cnt++)
+	{
+		if (!is_abbrev(cmd, scan_table[cnt].name))
+		{
+			continue;
+		}
+
+		arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+
+		if (HAS_BIT(scan_table[cnt].flags, SCAN_FLAG_FILE))
+		{
+			if (*arg1 == 0)
+			{
+				show_error(ses, LIST_COMMAND, "#SYNTAX: #SCAN {%s} {<FILENAME>}", scan_table[cnt].name);
+
+				return ses;
+			}
+
+			if ((fp = fopen(arg1, "r")) == NULL)
+			{
+				show_error(ses, LIST_COMMAND, "#ERROR: #SCAN {%s} FILE {%s} NOT FOUND.", scan_table[cnt].name, arg1);
+
+				return ses;
+			}
+		}
+
+		if (HAS_BIT(scan_table[cnt].flags, SCAN_FLAG_SCAN))
+		{
+			gtd->level->scan++;
+		}
+
+		ses = scan_table[cnt].fun(ses, fp, arg, arg1, arg2);
+
+		if (HAS_BIT(scan_table[cnt].flags, SCAN_FLAG_SCAN))
+		{
+			gtd->level->scan--;
+		}
+
+		if (HAS_BIT(scan_table[cnt].flags, SCAN_FLAG_FILE))
+		{
+			fclose(fp);
+		}
+		return ses;
+	}
+
+	show_error(ses, LIST_COMMAND, "\e[1;31mTHE SCAN COMMAND HAS CHANGED, EXECUTING #SCAN {TXT} {%s} INSTEAD.", cmd);
+
+	ses = command(ses, do_scan, "{TXT} {%s}", cmd);
+
+	return ses;
+}
+
+DO_SCAN(scan_abort)
+{
+	if (gtd->level->scan)
+	{
+		SET_BIT(ses->flags, SES_FLAG_SCANABORT);
+	}
+	else
+	{
+		show_error(ses, LIST_COMMAND, "#SCAN ABORT: NOT CURRENTLY SCANNING.");
+	}
+	return ses;
+}
 
 /* support routines for comma separated value files */
 
@@ -99,49 +186,12 @@ char *get_arg_in_quotes(struct session *ses, char *string, char *result, int fla
 	return pti;
 }
 
-struct session *scan_bulk_file(struct session *ses, FILE *fp, char *filename, char *arg)
-{
-	char line[STRING_SIZE], *str_out, *str_rip, *str_sub;
-	int cnt = 0;
-
-	str_out = str_dup("");
-
-	while (fgets(line, BUFFER_SIZE - 1, fp))
-	{
-		cnt++;
-		str_cat(&str_out, line);
-	}
 
-	str_rip = str_alloc(str_len(str_out));
-
-	strip_vt102_codes(str_out, str_rip);
-
-	RESTRING(gtd->cmds[0], str_out);
-	RESTRING(gtd->cmds[1], str_rip);
-	RESTRING(gtd->cmds[2], ntos(str_len(str_out)));
-	RESTRING(gtd->cmds[3], ntos(strlen(str_rip)));
-	RESTRING(gtd->cmds[4], ntos(cnt));
-
-	str_sub = str_alloc(strlen(arg) + STRING_SIZE);
-
-	substitute(ses, arg, str_sub, SUB_CMD);
-
-	show_message(ses, LIST_COMMAND, "#SCAN BULK: FILE {%s} SCANNED.", filename);
-
-	DEL_BIT(ses->flags, SES_FLAG_SCAN);
-
-	ses = script_driver(ses, LIST_COMMAND, str_sub);
-
-	return ses;
-}
-
-struct session *scan_csv_file(struct session *ses, FILE *fp, char *filename)
+DO_SCAN(scan_csv)
 {
-	char line[STRING_SIZE], temp[BUFFER_SIZE], *arg;
+	char line[STRING_SIZE];
 	int i, header = FALSE;
 
-	SET_BIT(ses->flags, SES_FLAG_SCAN);
-
 	while (fgets(line, BUFFER_SIZE, fp))
 	{
 		arg = strchr(line, '\r');
@@ -167,9 +217,9 @@ struct session *scan_csv_file(struct session *ses, FILE *fp, char *filename)
 
 		for (i = 1 ; i < 100 ; i++)
 		{
-			arg = get_arg_in_quotes(ses, arg, temp, FALSE);
+			arg = get_arg_in_quotes(ses, arg, arg2, FALSE);
 
-			RESTRING(gtd->vars[i], temp);
+			RESTRING(gtd->vars[i], arg2);
 
 			if (*arg == 0)
 			{
@@ -188,11 +238,11 @@ struct session *scan_csv_file(struct session *ses, FILE *fp, char *filename)
 		{
 			header = TRUE;
 
-			check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "SCAN CSV HEADER");
+			check_all_events(ses, SUB_SEC|EVENT_FLAG_SCAN, 0, 0, "SCAN CSV HEADER");
 		}
 		else
 		{
-			check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "SCAN CSV LINE");
+			check_all_events(ses, SUB_SEC|EVENT_FLAG_SCAN, 0, 0, "SCAN CSV LINE");
 		}
 
 		if (HAS_BIT(ses->flags, SES_FLAG_SCANABORT))
@@ -201,19 +251,168 @@ struct session *scan_csv_file(struct session *ses, FILE *fp, char *filename)
 		}
 	}
 
-	DEL_BIT(ses->flags, SES_FLAG_SCAN);
-
 	if (HAS_BIT(ses->flags, SES_FLAG_SCANABORT))
 	{
 		DEL_BIT(ses->flags, SES_FLAG_SCANABORT);
 
-		show_message(ses, LIST_COMMAND, "#SCAN CSV: FILE {%s} PARTIALLY SCANNED.", filename);
+		show_message(ses, LIST_COMMAND, "#SCAN CSV: FILE {%s} PARTIALLY SCANNED.", arg1);
 	}
 	else
 	{
-		show_message(ses, LIST_COMMAND, "#SCAN CSV: FILE {%s} SCANNED.", filename);
+		show_message(ses, LIST_COMMAND, "#SCAN CSV: FILE {%s} SCANNED.", arg1);
 	}
-	fclose(fp);
+
+	return ses;
+}
+
+DO_SCAN(scan_dir)
+{
+	char filename[PATH_SIZE];
+	struct dirent **dirlist;
+	struct stat info;
+	int size, index;
+
+	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
+
+	if (*arg2 == 0)
+	{
+		show_error(ses, LIST_COMMAND, "SYNTAX: #SCAN DIR {%s} <VARIABLE NAME>", arg1);
+
+		return ses;
+	}
+
+	set_nest_node_ses(ses, arg2, "");
+
+	size = scandir(arg1, &dirlist, 0, NULL);
+
+	if (size == -1)
+	{
+		if (stat(arg1, &info) == -1)
+		{
+			syserr_printf(ses, "scan_dir: stat:");
+			
+			return ses;
+		}
+
+		arg = arg1;
+
+		while (strchr(arg, '\\'))
+		{
+			arg = strchr(arg, '\\');
+		}
+
+		add_nest_node_ses(ses, arg2, "{%s}{{FILE}{%d}{MODE}{%u}{SIZE}{%u}{TIME}{%lld}}",
+			arg,
+			!S_ISDIR(info.st_mode),
+			info.st_mode,
+			info.st_size,
+			info.st_mtime);
+
+		return ses;
+	}
+
+	for (index = 0 ; index < size ; index++)
+	{
+		sprintf(filename, "%s%s%s", arg1, is_suffix(arg1, "/") ? "" : "/", dirlist[index]->d_name);
+
+		if (stat(filename, &info) == -1)
+		{
+			syserr_printf(ses, "scan_dir: stat:");
+			
+			return ses;
+		}
+
+		add_nest_node_ses(ses, arg2, "{%s}{{FILE}{%d}{MODE}{%u}{SIZE}{%u}{TIME}{%lld}}",
+			dirlist[index]->d_name,
+			!S_ISDIR(info.st_mode),
+			info.st_mode,
+			info.st_size,
+			info.st_mtime);
+	}
+
+	for (index = 0 ; index < size ; index++)
+	{
+		free(dirlist[index]);
+	}
+	free(dirlist);
+
+	show_message(ses, LIST_COMMAND, "#SCAN DIR: DIRECTORY {%s} SAVED TO {%s}.", arg1, arg2);
+
+	return ses;
+}
+
+DO_SCAN(scan_file)
+{
+	char line[STRING_SIZE], *str_out, *str_rip, *str_sub;
+	int cnt = 0;
+
+	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
+
+	str_out = str_alloc_stack(0);
+
+	while (fgets(line, BUFFER_SIZE - 1, fp))
+	{
+		cnt++;
+		str_cat(&str_out, line);
+	}
+
+	str_rip = str_alloc_stack(str_len(str_out));
+
+	strip_vt102_codes(str_out, str_rip);
+
+	RESTRING(gtd->cmds[0], str_out);
+	RESTRING(gtd->cmds[1], str_rip);
+	RESTRING(gtd->cmds[2], ntos(str_len(str_out)));
+	RESTRING(gtd->cmds[3], ntos(strlen(str_rip)));
+	RESTRING(gtd->cmds[4], ntos(cnt));
+
+	str_sub = str_alloc_stack(strlen(arg) * 2);
+
+	substitute(ses, arg2, str_sub, SUB_CMD);
+
+	show_message(ses, LIST_COMMAND, "#SCAN FILE: FILE {%s} SCANNED.", arg1);
+
+	ses = script_driver(ses, LIST_COMMAND, str_sub);
+
+	return ses;
+}
+
+DO_SCAN(scan_forward)
+{
+	char line[STRING_SIZE], *lnf;
+	float delay = 0;
+
+	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
+
+	if (!HAS_BIT(ses->flags, SES_FLAG_CONNECTED))
+	{
+		show_error(ses, LIST_COMMAND, "#SCAN FORWARD: SESSION {%s} IS NOT CONNECTED.", ses->name);
+
+		return ses;
+	}
+
+	while (fgets(line, BUFFER_SIZE - 1, fp))
+	{
+		lnf = strchr(line, '\n');
+
+		if (lnf)
+		{
+			*lnf = 0;
+		}
+
+		if (*arg2)
+		{
+			delay += get_number(ses, arg2);
+
+			command(ses, do_delay, "%.3f #send {%s}", delay, line);
+		}
+		else
+		{
+			write_mud(ses, line, SUB_EOL);
+		}
+	}
+
+	show_message(ses, LIST_COMMAND, "#SCAN FORWARD: FILE {%s} FORWARDED.", arg1);
 
 	return ses;
 }
@@ -241,12 +440,12 @@ char *get_arg_stop_tabs(struct session *ses, char *string, char *result, int fla
 	return pti;
 }
 
-struct session *scan_tsv_file(struct session *ses, FILE *fp, char *filename)
+DO_SCAN(scan_tsv)
 {
-	char line[STRING_SIZE], temp[BUFFER_SIZE], *arg;
+	char line[STRING_SIZE];
 	int i, header = FALSE;
 
-	SET_BIT(ses->flags, SES_FLAG_SCAN);
+	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
 
 	while (fgets(line, BUFFER_SIZE, fp))
 	{
@@ -273,9 +472,9 @@ struct session *scan_tsv_file(struct session *ses, FILE *fp, char *filename)
 
 		for (i = 1 ; i < 100 ; i++)
 		{
-			arg = get_arg_stop_tabs(ses, arg, temp, FALSE);
+			arg = get_arg_stop_tabs(ses, arg, arg2, FALSE);
 
-			RESTRING(gtd->vars[i], temp);
+			RESTRING(gtd->vars[i], arg2);
 
 			if (*arg == 0)
 			{
@@ -294,11 +493,11 @@ struct session *scan_tsv_file(struct session *ses, FILE *fp, char *filename)
 		{
 			header = TRUE;
 
-			check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "SCAN TSV HEADER");
+			check_all_events(ses, SUB_SEC|EVENT_FLAG_SCAN, 0, 0, "SCAN TSV HEADER");
 		}
 		else
 		{
-			check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "SCAN TSV LINE");
+			check_all_events(ses, SUB_SEC|EVENT_FLAG_SCAN, 0, 0, "SCAN TSV LINE");
 		}
 
 		if (HAS_BIT(ses->flags, SES_FLAG_SCANABORT))
@@ -307,28 +506,24 @@ struct session *scan_tsv_file(struct session *ses, FILE *fp, char *filename)
 		}
 	}
 
-	DEL_BIT(ses->flags, SES_FLAG_SCAN);
-
 	if (HAS_BIT(ses->flags, SES_FLAG_SCANABORT))
 	{
 		DEL_BIT(ses->flags, SES_FLAG_SCANABORT);
 
-		show_message(ses, LIST_COMMAND, "#SCAN TSV: FILE {%s} PARTIALLY SCANNED.", filename);
+		show_message(ses, LIST_COMMAND, "#SCAN TSV: FILE {%s} PARTIALLY SCANNED.", arg1);
 	}
 	else
 	{
-		show_message(ses, LIST_COMMAND, "#SCAN TSV: FILE {%s} SCANNED.", filename);
+		show_message(ses, LIST_COMMAND, "#SCAN TSV: FILE {%s} SCANNED.", arg1);
 	}
 	return ses;
 }
 
 /* support routines for text files */
 
-struct session *scan_txt_file(struct session *ses, FILE *fp, char *filename)
+DO_SCAN(scan_txt)
 {
-	char line[STRING_SIZE], *arg;
-
-	SET_BIT(ses->flags, SES_FLAG_SCAN);
+	char line[STRING_SIZE];
 
 	while (fgets(line, BUFFER_SIZE - 1, fp))
 	{
@@ -357,90 +552,16 @@ struct session *scan_txt_file(struct session *ses, FILE *fp, char *filename)
 		}
 	}
 
-	DEL_BIT(ses->flags, SES_FLAG_SCAN);
-
 	if (HAS_BIT(ses->flags, SES_FLAG_SCANABORT))
 	{
 		DEL_BIT(ses->flags, SES_FLAG_SCANABORT);
 
-		show_message(ses, LIST_COMMAND, "#SCAN TXT: FILE {%s} PARTIALLY SCANNED.", filename);
+		show_message(ses, LIST_COMMAND, "#SCAN TXT: FILE {%s} PARTIALLY SCANNED.", arg1);
 	}
 	else
 	{
-		show_message(ses, LIST_COMMAND, "#SCAN TXT: FILE {%s} SCANNED.", filename);
+		show_message(ses, LIST_COMMAND, "#SCAN TXT: FILE {%s} SCANNED.", arg1);
 	}
 	return ses;
 }
 
-DO_COMMAND(do_scan)
-{
-	FILE *fp;
-
-	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
-	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
-
-	if (*arg1 == 0)
-	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCAN {ABORT|CSV|TXT} {<FILENAME>}");
-
-		return ses;
-	}
-
-	if (is_abbrev(arg1, "ABORT"))
-	{
-		if (!HAS_BIT(ses->flags, SES_FLAG_SCAN))
-		{
-			show_error(ses, LIST_COMMAND, "#SCAN ABORT: NOT CURRENTLY SCANNING.");
-		}
-		else
-		{
-			SET_BIT(ses->flags, SES_FLAG_SCANABORT);
-		}
-		return ses;
-	}
-
-	if (*arg2 == 0)
-	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCAN {ABORT|CSV|TXT} {<FILENAME>}");
-
-		return ses;
-	}
-
-	if ((fp = fopen(arg2, "r")) == NULL)
-	{
-		show_error(ses, LIST_COMMAND, "#ERROR: #SCAN - FILE {%s} NOT FOUND.", arg2);
-
-		return ses;
-	}
-
-	SET_BIT(ses->flags, SES_FLAG_SCAN);
-
-	if (is_abbrev(arg1, "FILE"))
-	{
-		ses = scan_bulk_file(ses, fp, arg2, arg);
-	}
-	else if (is_abbrev(arg1, "CSV"))
-	{
-		ses = scan_csv_file(ses, fp, arg2);
-	}
-	else if (is_abbrev(arg1, "TSV"))
-	{
-		ses = scan_tsv_file(ses, fp, arg2);
-	}
-	else if (is_abbrev(arg1, "TXT"))
-	{
-		ses = scan_txt_file(ses, fp, arg2);
-	}
-	else
-	{
-		DEL_BIT(ses->flags, SES_FLAG_SCAN);
-
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCAN {ABORT|CSV|FILE|TSV|TXT} {<FILENAME>}");
-	}
-
-	DEL_BIT(ses->flags, SES_FLAG_SCAN);
-
-	fclose(fp);
-
-	return ses;
-}

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 335 - 206
src/screen.c


+ 87 - 91
src/session.c

@@ -24,6 +24,8 @@
 *                         coded by Peter Unold 1992                           *
 ******************************************************************************/
 
+#include <sys/wait.h>
+
 #include "tintin.h"
 
 DO_COMMAND(do_all)
@@ -66,7 +68,7 @@ DO_COMMAND(do_session)
 
 	if (*arg1 == 0)
 	{
-		tintin_puts(ses, "#THESE SESSIONS HAVE BEEN DEFINED:");
+		tintin_puts2(ses, "#THESE SESSIONS HAVE BEEN DEFINED:");
 
 		for (sesptr = gts->next ; sesptr ; sesptr = sesptr->next)
 		{
@@ -100,7 +102,7 @@ DO_COMMAND(do_session)
 			}
 			*pto = 0;
 
-			ses = new_session(ses, "telnet", temp, 0, 0);
+			return new_session(ses, "telnet", temp, 0, 0);
 		}
 
 		if (*arg1 == '+')
@@ -124,7 +126,7 @@ DO_COMMAND(do_session)
 			}
 		}
 
-		tintin_puts(ses, "#THAT SESSION IS NOT DEFINED.");
+		tintin_puts2(ses, "#THAT SESSION IS NOT DEFINED.");
 	}
 	else
 	{
@@ -139,8 +141,8 @@ DO_COMMAND(do_snoop)
 	struct session *sesptr = ses;
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
-	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
-
+	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
+	
 	if (*arg1)
 	{
 		sesptr = find_session(arg1);
@@ -214,15 +216,16 @@ DO_COMMAND(do_zap)
 		sesptr = ses;
 	}
 
-	tintin_puts(sesptr, "");
+	tintin_printf(sesptr, "");
 
-	tintin_puts(sesptr, "#ZZZZZZZAAAAAAAAPPPP!!!!!!!!! LET'S GET OUTTA HERE!!!!!!!!");
+	tintin_printf(sesptr, "#ZZZZZZZAAAAAAAAPPPP!!!!!!!!! LET'S GET OUTTA HERE!!!!!!!!");
 
 	if (sesptr == gts)
 	{
+		command(ses, do_end, "");
+
 		pop_call();
-		return execute(ses, "#END");
-//		do_end(NULL, "");
+		return gts;
 	}
 
 	if (ses == sesptr)
@@ -243,18 +246,19 @@ void show_session(struct session *ses, struct session *ptr)
 {
 	char temp[BUFFER_SIZE];
 
-	sprintf(temp, "%-10s %18s:%-5s", ptr->name, ptr->session_host, ptr->session_port);
-
-	cat_sprintf(temp, " %8s", ptr == gtd->ses ? "(active)" :  "");
+	sprintf(temp, "%-10s %18s:%-5s %5s %6s",
+		ptr->name,
+		ptr->session_host,
+		ptr->session_port,
+		ptr == gtd->ses ? "(ats)" : "",
+		ptr->ssl ? "(ssl)" : ptr->port ? "(port)" : HAS_BIT(ptr->flags, SES_FLAG_RUN) ? " (run)" : "");
 
-	cat_sprintf(temp, " %10s", ptr->mccp2 ? (ptr->mccp3 ? "(mccp 2+3)" : "(mccp 2)  ") : ptr->mccp3 ? "(mccp 3)" : "");
+	cat_sprintf(temp, " %10s", ptr->mccp2 && ptr->mccp3 ? "(mccp 2+3)" : ptr->mccp2 ? "(mccp 2)" : ptr->mccp3 ? "(mccp 3)" : "");
 
 	cat_sprintf(temp, " %7s", HAS_BIT(ptr->flags, SES_FLAG_SNOOP) ? "(snoop)" : "");
 
 	cat_sprintf(temp, " %5s", ptr->logfile ? "(log)" : "");
 
-	cat_sprintf(temp, " %5s", ptr->ssl ? "(ssl)" : "");
-
 	tintin_puts2(ses, temp);
 }
 
@@ -298,18 +302,18 @@ struct session *newactive_session(void)
 
 struct session *activate_session(struct session *ses)
 {
-	check_all_events(gtd->ses, SUB_ARG, 0, 1, "SESSION DEACTIVATED", gtd->ses->name);
+	check_all_events(gtd->ses, EVENT_FLAG_SESSION, 0, 1, "SESSION DEACTIVATED", gtd->ses->name);
 
 	gtd->ses = ses;
 
 	dirty_screen(ses);
 
-	if (!check_all_events(ses, SUB_ARG, 0, 1, "GAG SESSION ACTIVATED", ses->name))
+	if (!check_all_events(ses, EVENT_FLAG_GAG, 0, 1, "GAG SESSION ACTIVATED", ses->name))
 	{
 		show_message(ses, LIST_COMMAND, "#SESSION '%s' ACTIVATED.", ses->name);
 	}
 
-	check_all_events(ses, SUB_ARG, 0, 1, "SESSION ACTIVATED", ses->name);
+	check_all_events(ses, EVENT_FLAG_SESSION, 0, 1, "SESSION ACTIVATED", ses->name);
 
 	return ses;
 }
@@ -340,7 +344,7 @@ struct session *new_session(struct session *ses, char *name, char *arg, int desc
 	{
 		if (*host == 0)
 		{
-			tintin_puts(ses, "#HEY! SPECIFY AN ADDRESS WILL YOU?");
+			tintin_puts2(ses, "#HEY! SPECIFY AN ADDRESS WILL YOU?");
 
 			pop_call();
 			return ses;
@@ -354,38 +358,40 @@ struct session *new_session(struct session *ses, char *name, char *arg, int desc
 
 	if (find_session(name))
 	{
-		tintin_puts(ses, "#THERE'S A SESSION WITH THAT NAME ALREADY.");
+		tintin_printf2(ses, "#THERE'S A SESSION NAMED {%s} ALREADY.", name);
 
 		pop_call();
 		return ses;
 	}
 
-	newses                = (struct session *) calloc(1, sizeof(struct session));
+	newses                 = (struct session *) calloc(1, sizeof(struct session));
 
-	newses->name          = strdup(name);
-	newses->session_host  = strdup(host);
-	newses->session_ip    = strdup("");
-	newses->session_port  = strdup(port);
-	newses->created       = gtd->time;
+	newses->name           = strdup(name);
+	newses->session_host   = strdup(host);
+	newses->session_ip     = strdup("");
+	newses->session_port   = strdup(port);
+	newses->created        = gtd->time;
 
-	newses->group         = strdup(gts->group);
-	newses->flags         = gts->flags;
-	newses->color         = gts->color;
-	newses->logmode       = gts->logmode;
-	newses->charset       = gts->charset;
+	newses->group          = strdup(gts->group);
+	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;
-	newses->auto_tab      = gts->auto_tab;
-	newses->packet_patch  = gts->packet_patch;
-	newses->tab_width     = gts->tab_width;
-	newses->cmd_color     = strdup(gts->cmd_color);
+	newses->telopts        = gts->telopts;
+	newses->scrollback_tab = gts->scrollback_tab; // may need to go in input data
+	newses->packet_patch   = gts->packet_patch;
+	newses->tab_width      = gts->tab_width;
+	newses->cmd_color      = strdup(gts->cmd_color);
 
-	newses->read_max      = gts->read_max;
-	newses->read_buf      = (unsigned char *) calloc(1, gts->read_max);
+	newses->read_max       = gts->read_max;
+	newses->read_buf       = (unsigned char *) calloc(1, gts->read_max);
 
-	newses->lognext_name  = strdup("");
-	newses->logline_name  = strdup("");
-	newses->rand          = utime();
+	newses->logname        = strdup("");
+	newses->lognext_name   = strdup("");
+	newses->logline_name   = strdup("");
+	newses->rand           = utime();
 
 	LINK(newses, gts->next, gts->prev);
 
@@ -427,32 +433,13 @@ struct session *new_session(struct session *ses, char *name, char *arg, int desc
 
 	newses->input         = calloc(1, sizeof(struct input_data));
 
-	memcpy(newses->input, gts->input, sizeof(struct input_data));
-
-	newses->input->buf    = str_alloc(BUFFER_SIZE);
-	newses->input->tmp    = str_alloc(BUFFER_SIZE);
-/*
-	newses->input->sav_top_row = gts->input->sav_top_row;
-	newses->input->sav_top_col = gts->input->sav_top_col;
-	newses->input->sav_bot_row = gts->input->sav_bot_row;
-	newses->input->sav_bot_col = gts->input->sav_bot_col;
-
-	newses->input->top_row = gts->input->top_row;
-	newses->input->top_col = gts->input->top_col;
-	newses->input->bot_row = gts->input->bot_row;
-	newses->input->bot_col = gts->input->bot_col;
-*/
-	// may need to set additional values.
-
-	newses->input->off = gts->input->off;
-	newses->input->pos = gts->input->pos;
-	newses->input->hid = gts->input->hid;
+	init_input(newses, 0, 0, 0, 0);
 
 	memcpy(&newses->cur_terminal, &gts->cur_terminal, sizeof(gts->cur_terminal));
 
 	if (desc == 0)
 	{
-		if (!check_all_events(newses, SUB_ARG, 0, 4, "GAG SESSION CREATED", newses->name, newses->session_host, newses->session_ip, newses->session_port))
+		if (!check_all_events(newses, EVENT_FLAG_GAG, 0, 4, "GAG SESSION CREATED", newses->name, newses->session_host, newses->session_ip, newses->session_port))
 		{
 			tintin_printf(ses, "#TRYING TO CONNECT '%s' TO '%s' PORT '%s'.", newses->name, newses->session_host, newses->session_port);
 		}
@@ -463,17 +450,17 @@ struct session *new_session(struct session *ses, char *name, char *arg, int desc
 	}
 	else
 	{
-		if (!check_all_events(newses, SUB_ARG, 0, 4, "GAG SESSION CREATED", newses->name, newses->session_host, newses->session_ip, newses->session_port))
+		if (!check_all_events(newses, EVENT_FLAG_GAG, 0, 4, "GAG SESSION CREATED", newses->name, newses->session_host, newses->session_ip, newses->session_port))
 		{
 			tintin_printf(ses, "#TRYING TO LAUNCH '%s' RUNNING '%s'.", newses->name, newses->session_host);
 		}
 	}
 
-	dirty_screen(newses);
-
 	if (gtd->level->background == 0)
 	{
 		gtd->ses = newses;
+
+		dirty_screen(newses);
 	}
 
 	if (desc == 0)
@@ -482,7 +469,7 @@ struct session *new_session(struct session *ses, char *name, char *arg, int desc
 	}
 	else if (desc == -1)
 	{
-		SET_BIT(newses->flags, SES_FLAG_PORT);
+		// #PORT INITIALIZE {NAME} {PORT} {FILE}
 	}
 	else
 	{
@@ -517,9 +504,10 @@ struct session *new_session(struct session *ses, char *name, char *arg, int desc
 
 	if (*file)
 	{
-		newses = execute(newses, "#READ %s", file);
+		newses = command(newses, do_read, "%s", file);
 	}
-	check_all_events(newses, SUB_ARG, 0, 4, "SESSION CREATED", newses->name, newses->session_host, newses->session_ip, newses->session_port);
+
+	check_all_events(newses, EVENT_FLAG_SESSION, 0, 4, "SESSION CREATED", newses->name, newses->session_host, newses->session_ip, newses->session_port);
 
 	if (gtd->level->background == 0)
 	{
@@ -567,12 +555,12 @@ struct session *connect_session(struct session *ses)
 
 		SET_BIT(ses->flags, SES_FLAG_CONNECTED);
 
-		if (!check_all_events(ses, SUB_ARG, 0, 4, "GAG SESSION CONNECTED", ses->name, ses->session_host, ses->session_ip, ses->session_port))
+		if (!check_all_events(ses, EVENT_FLAG_GAG, 0, 4, "GAG SESSION CONNECTED", ses->name, ses->session_host, ses->session_ip, ses->session_port))
 		{
 			tintin_printf(ses, "\n#SESSION '%s' CONNECTED TO '%s' PORT '%s'", ses->name, ses->session_host, ses->session_port);
 		}
 
-		check_all_events(ses, SUB_ARG, 0, 4, "SESSION CONNECTED", ses->name, ses->session_host, ses->session_ip, ses->session_port);
+		check_all_events(ses, EVENT_FLAG_SESSION, 0, 4, "SESSION CONNECTED", ses->name, ses->session_host, ses->session_ip, ses->session_port);
 
 		pop_call();
 		return ses;
@@ -646,25 +634,28 @@ void cleanup_session(struct session *ses)
 		{
 			syserr_printf(ses, "cleanup_session: close");
 		}
-//		else
-//		{
-//			int status;
+/*		else
+		{
+			int status;
 
-//			wait(&status);
-//		}
+			wait(&status);
+		}*/
 
 		// the PID is stored in the session's port.
-/*
+
 		if (HAS_BIT(ses->flags, SES_FLAG_RUN))
 		{
-			kill(atoi(ses->session_port), SIGTERM);
+			int status, pid;
+
+			pid = waitpid(atoi(ses->session_port), &status, WNOHANG);
+
+			if (pid == -1)
+			{
+				syserr_printf(ses, "cleanup_session: waitpid");
+			}
+//			kill(atoi(ses->session_port), SIGTERM);
 		}
-*/
-	}
 
-	if (ses->port)
-	{
-		port_uninitialize(ses, "", "", "");
 	}
 
 	SET_BIT(ses->flags, SES_FLAG_CLOSED);
@@ -672,29 +663,33 @@ void cleanup_session(struct session *ses)
 	client_end_mccp2(ses);
 	client_end_mccp3(ses);
 
-	if (HAS_BIT(ses->flags, SES_FLAG_PORT) || HAS_BIT(ses->flags, SES_FLAG_CONNECTED))
+	if (HAS_BIT(ses->flags, SES_FLAG_CONNECTED))
 	{
 		DEL_BIT(ses->flags, SES_FLAG_CONNECTED);
 
-		if (!check_all_events(ses, SUB_ARG, 0, 4, "GAG SESSION DISCONNECTED", ses->name, ses->session_host, ses->session_ip, ses->session_port))
+		if (!check_all_events(ses, EVENT_FLAG_GAG, 0, 4, "GAG SESSION DISCONNECTED", ses->name, ses->session_host, ses->session_ip, ses->session_port))
 		{
 			tintin_printf(gtd->ses, "#SESSION '%s' DIED.", ses->name);
 		}
 
-		check_all_events(ses, SUB_ARG, 0, 4, "SESSION DISCONNECTED", ses->name, ses->session_host, ses->session_ip, ses->session_port);
-
-
+		check_all_events(ses, EVENT_FLAG_SESSION, 0, 4, "SESSION DISCONNECTED", ses->name, ses->session_host, ses->session_ip, ses->session_port);
+	}
+	else if (ses->port)
+	{
+		port_uninitialize(ses, "", "", "");
 	}
 	else
 	{
-		if (!check_all_events(ses, SUB_ARG, 0, 4, "GAG SESSION TIMED OUT", ses->name, ses->session_host, ses->session_ip, ses->session_port))
+		if (!check_all_events(ses, EVENT_FLAG_GAG, 0, 4, "GAG SESSION TIMED OUT", ses->name, ses->session_host, ses->session_ip, ses->session_port))
 		{
 			tintin_printf(gtd->ses, "#SESSION '%s' TIMED OUT.", ses->name);
 		}
 
-		check_all_events(ses, SUB_ARG, 0, 4, "SESSION TIMED OUT", ses->name, ses->session_host, ses->session_ip, ses->session_port);
+		check_all_events(ses, EVENT_FLAG_SESSION, 0, 4, "SESSION TIMED OUT", ses->name, ses->session_host, ses->session_ip, ses->session_port);
 	}
 
+	check_all_events(ses, EVENT_FLAG_SESSION, 0, 4, "SESSION DESTROYED", ses->name, ses->session_host, ses->session_ip, ses->session_port);
+
 	if (ses == gtd->ses)
 	{
 		gtd->ses = newactive_session();
@@ -750,6 +745,8 @@ void dispose_session(struct session *ses)
 
 	init_buffer(ses, 0);
 
+	free_input(ses);
+
 	free(ses->name);
 	free(ses->session_host);
 	free(ses->session_ip);
@@ -757,11 +754,10 @@ 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);
-	str_free(ses->input->buf);
-	str_free(ses->input->tmp);
 	free(ses->input);
 
 	free(ses);

+ 76 - 28
src/show.c

@@ -33,14 +33,12 @@ DO_COMMAND(do_showme)
 	char *out, *tmp;
 	int lnf;
 
-	push_call("do_showme(%p,%p)",ses,arg);
-
-	out = str_alloc_stack();
-	tmp = str_alloc_stack();
+	out = str_alloc_stack(0);
+	tmp = str_alloc_stack(0);
 
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
 
-	lnf = !str_suffix(arg1, "\\");
+	lnf = is_suffix(arg1, "\\") && !is_suffix(arg1, "\\\\");
 
 	substitute(ses, arg1, tmp, SUB_VAR|SUB_FUN);
 	substitute(ses, tmp, arg1, SUB_COL|SUB_ESC);
@@ -56,15 +54,13 @@ DO_COMMAND(do_showme)
 
 		show_debug(ses, LIST_GAG, "#DEBUG GAG {%d} {%s}", ses->gagline + 1, arg1);
 
-		pop_call();
 		return ses;
 	}
 
 	if (*arg2)
 	{
-		split_show(ses, arg1, (int) get_number(ses, arg2), (int) get_number(ses, arg3));
+		split_show(ses, arg1, arg2, arg3);
 
-		pop_call();
 		return ses;
 	}
 
@@ -96,7 +92,6 @@ DO_COMMAND(do_showme)
 		}
 	}
 
-	pop_call();
 	return ses;
 }
 
@@ -133,7 +128,15 @@ void show_message(struct session *ses, int index, char *format, ...)
 	display:
 
 	va_start(args, format);
-	vasprintf(&buffer, format, args);
+
+	if (vasprintf(&buffer, format, args) == -1)
+	{
+		syserr_printf(ses, "show_message: vasprintf1:");
+
+		pop_call();
+		return;
+	}
+
 	va_end(args);
 
 	tintin_puts2(ses, buffer);
@@ -145,13 +148,19 @@ void show_message(struct session *ses, int index, char *format, ...)
 
 	end:
 
-
 	if (HAS_BIT(root->flags, LIST_FLAG_LOG))
 	{
 		if (ses->logfile)
 		{
 			va_start(args, format);
-			vasprintf(&buffer, format, args);
+
+			if (vasprintf(&buffer, format, args) == -1)
+			{
+				syserr_printf(ses, "print_lines: vasprintf2:");
+				
+				pop_call();
+				return;
+			}
 			va_end(args);
 
 			logit(ses, buffer, ses->logfile, LOG_FLAG_LINEFEED);
@@ -173,9 +182,17 @@ void show_error(struct session *ses, int index, char *format, ...)
 	push_call("show_error(%p,%p,%p)",ses,index,format);
 
 	va_start(args, format);
-	vasprintf(&buffer, format, args);
+	if (vasprintf(&buffer, format, args) == -1)
+	{
+		syserr_printf(ses, "show_error: vasprintf:");
+
+		pop_call();
+		return;
+	}
 	va_end(args);
 
+	check_all_events(ses, SUB_SEC|EVENT_FLAG_SYSTEM, 0, 1, "RECEIVED ERROR", buffer);
+
 	if (gtd->level->verbose || gtd->level->debug)
 	{
 		tintin_puts2(ses, buffer);
@@ -300,18 +317,24 @@ void print_lines(struct session *ses, int flags, char *format, ...)
 	push_call("print_lines(%p,%d,%p,...)",ses,flags,format);
 
 	va_start(args, format);
-	vasprintf(&buffer, format, args);
+
+	if (vasprintf(&buffer, format, args) == -1)
+	{
+		syserr_printf(ses, "print_lines: vasprintf:");
+
+		pop_call();
+		return;
+	}
+
 	va_end(args);
 
 	if (flags)
 	{
-		str_buf = str_alloc(BUFFER_SIZE + strlen(buffer) * 2);
+		str_buf = str_alloc_stack(strlen(buffer) * 2);
 
 		substitute(ses, buffer, str_buf, flags);
 
 		show_lines(ses, str_buf);
-
-		str_free(str_buf);
 	}
 	else
 	{
@@ -349,7 +372,7 @@ void show_lines(struct session *ses, char *str)
 }
 
 
-void tintin_header(struct session *ses, char *format, ...)
+void tintin_header(struct session *ses, int width, char *format, ...)
 {
 	char arg[BUFFER_SIZE], buf[BUFFER_SIZE];
 	va_list args;
@@ -361,7 +384,14 @@ void tintin_header(struct session *ses, char *format, ...)
 	vsprintf(arg, format, args);
 	va_end(args);
 
-	cols = get_scroll_cols(ses);
+	if (width)
+	{
+		cols = UMIN(width, get_scroll_cols(ses));
+	}
+	else
+	{
+		cols = get_scroll_cols(ses);
+	}
 
 	if (cols < 2)
 	{
@@ -374,7 +404,7 @@ void tintin_header(struct session *ses, char *format, ...)
 		arg[cols - 2] = 0;
 	}
 
-	if (HAS_BIT(ses->flags, SES_FLAG_SCREENREADER))
+	if (HAS_BIT(ses->config_flags, CONFIG_FLAG_SCREENREADER))
 	{
 		memset(buf, ' ', cols);
 	}
@@ -401,7 +431,13 @@ void tintin_printf2(struct session *ses, char *format, ...)
 	push_call("tintin_printf2(%p,%p,...)",ses,format);
 
 	va_start(args, format);
-	vasprintf(&buffer, format, args);
+	if (vasprintf(&buffer, format, args) == -1)
+	{
+		syserr_printf(ses, "tintin_printf2: vasprintf:");
+
+		pop_call();
+		return;
+	}
 	va_end(args);
 
 	tintin_puts2(ses, buffer);
@@ -463,11 +499,11 @@ void tintin_puts2(struct session *ses, char *string)
 
 	push_call("tintin_puts2(%p,%p)",ses,string);
 
-	output = str_dup_printf("%s%s%s", COLOR_TEXT, string, COLOR_TEXT);
+	output = str_alloc_stack(0);
 
-	tintin_puts3(ses, output);
+	str_cpy_printf(&output, "%s%s%s", COLOR_TEXT, string, COLOR_TEXT);
 
-	str_free(output);
+	tintin_puts3(ses, output);
 
 	pop_call();
 	return;
@@ -490,19 +526,33 @@ void tintin_puts3(struct session *ses, char *string)
 		ses = gtd->ses;
 	}
 
+	if (ses->line_capturefile)
+	{
+		if (ses->line_captureindex == 1)
+		{
+			set_nest_node_ses(ses, ses->line_capturefile, "{%d}{%s}", ses->line_captureindex++, string);
+		}
+		else
+		{
+			add_nest_node_ses(ses, ses->line_capturefile, "{%d}{%s}", ses->line_captureindex++, string);
+		}
+	}
+
 	if (gtd->level->quiet && gtd->level->verbose == 0)
 	{
 		pop_call();
 		return;
 	}
 
+	output = str_alloc_stack(0);
+
 	if (strip_vt102_strlen(ses, ses->more_output) != 0)
 	{
-		output = str_dup_printf("\n%s", string);
+		str_cpy_printf(&output, "\n%s", string);
 	}
 	else
 	{
-		output = str_dup_printf("%s", string);
+		str_cpy_printf(&output, "%s", string);
 	}
 
 	add_line_buffer(ses, output, FALSE);
@@ -524,8 +574,6 @@ void tintin_puts3(struct session *ses, char *string)
 		}
 	}
 
-	str_free(output);
-
 	pop_call();
 	return;
 }

+ 11 - 14
src/sort.c

@@ -1453,26 +1453,23 @@ int cmp_float(const void * a, const void * b)
 
 int cmp_num(const void * a, const void * b)
 {
-	if (is_number(*(char **) a) && is_number(*(char **) b))
+	unsigned char isnum_a, isnum_b;
+
+	isnum_a = is_number(*(char **) a);
+	isnum_b = is_number(*(char **) b);
+
+	if (isnum_a && isnum_b)
 	{
-		long double num_a = is_number(*(char **) a) ? tintoi(*(char **) a) : 0;
-		long double num_b = is_number(*(char **) b) ? tintoi(*(char **) b) : 0;
+		long double num_a = tintoi(*(char **) a);
+		long double num_b = tintoi(*(char **) b);
 
-		if (num_a < num_b)
-		{
-			return -1;
-		}
-		if (num_a > num_b)
-		{
-			return 1;
-		}
-		return 0;
+		return num_a < num_b ? -1 : num_a > num_b ? 1 : 0;
 	}
-	else if (is_number(*(char **) a))
+	else if (isnum_a)
 	{
 		return -1;
 	}
-	else if (is_number(*(char **) b))
+	else if (isnum_b)
 	{
 		return 1;
 	}

+ 77 - 55
src/split.c

@@ -29,19 +29,15 @@
 
 DO_COMMAND(do_split)
 {
+	int input;
+
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
 
 	if ((*arg1 && !is_math(ses, arg1)) || (*arg2 && !is_math(ses, arg2)))
 	{
-		if (*arg == 0)
-		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: #SPLIT {TOP BAR} {BOTTOM BAR}");
-		}
-		else
-		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: #SPLIT {TOP BAR} {BOT BAR} {LEFT BAR} {RIGHT BAR}");
-		}
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SPLIT [TOP BAR] [BOTTOM BAR] [LEFT BAR] [RIGHT BAR] [INPUT BAR]");
+
 		return ses;
 	}
 
@@ -69,10 +65,29 @@ DO_COMMAND(do_split)
 		ses->split->sav_bot_col = *arg2 ? get_number(ses, arg2) : 0;
 	}
 
+	if (*arg)
+	{
+		arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
+		
+		input = get_number(ses, arg1);
+
+		input *= -1;
+	}
+	else
+	{
+		input = -1;
+	}
+
+	init_input(ses, input, 1, -1, -1);
+
+	ses->split->sav_bot_row += inputline_rows(ses) - 1;
+
 	DEL_BIT(ses->flags, SES_FLAG_SCROLLSPLIT);
 	SET_BIT(ses->flags, SES_FLAG_SPLIT);
 
-	init_split(ses, ses->split->sav_top_row, ses->split->sav_top_col, ses->split->sav_bot_row,  ses->split->sav_bot_col);
+	ses->input->str_off = 1;
+
+	init_split(ses, ses->split->sav_top_row, ses->split->sav_top_col, ses->split->sav_bot_row, ses->split->sav_bot_col);
 
 	return ses;
 }
@@ -97,7 +112,7 @@ DO_COMMAND(do_unsplit)
 		DEL_BIT(ses->flags, SES_FLAG_SPLIT);
 		DEL_BIT(ses->flags, SES_FLAG_SCROLLSPLIT);
 	}
-	check_all_events(ses, SUB_ARG, 0, 4, "SCREEN UNSPLIT", ntos(ses->split->top_row), ntos(ses->split->top_col), ntos(ses->split->bot_row), ntos(ses->split->bot_col));
+	check_all_events(ses, EVENT_FLAG_SCREEN, 0, 4, "SCREEN UNSPLIT", ntos(ses->split->top_row), ntos(ses->split->top_col), ntos(ses->split->bot_row), ntos(ses->split->bot_col));
 	return ses;
 }
 
@@ -107,7 +122,7 @@ void init_split(struct session *ses, int top_row, int top_col, int bot_row, int
 
 	SET_BIT(ses->scroll->flags, SCROLL_FLAG_RESIZE);
 
-	init_inputregion(ses, ses->input->sav_top_row, ses->input->sav_top_col, ses->input->sav_bot_row, ses->input->sav_bot_col);
+	init_input(ses, ses->input->sav_top_row, ses->input->sav_top_col, ses->input->sav_bot_row, ses->input->sav_bot_col);
 
 	if (!HAS_BIT(ses->flags, SES_FLAG_SPLIT))
 	{
@@ -139,26 +154,29 @@ void init_split(struct session *ses, int top_row, int top_col, int bot_row, int
 	{
 		ses->split->top_row = top_row > 0 ? top_row + 1 : top_row < 0 ? gtd->screen->rows + top_row + 1 : 1;
 		ses->split->top_col = top_col > 0 ? top_col + 1 : top_col < 0 ? gtd->screen->cols + top_col + 1 : 1;
-
 		ses->split->bot_row = bot_row > 0 ? gtd->screen->rows - bot_row - 1 : bot_row < 0 ? bot_row * -1 : gtd->screen->rows - 1;
 		ses->split->bot_col = bot_col > 0 ? gtd->screen->cols - bot_col : bot_col < 0 ? bot_col * -1 : gtd->screen->cols;
 	}
 
 	ses->split->top_row = URANGE(1, ses->split->top_row, gtd->screen->rows -3);
-	ses->split->bot_row = URANGE(ses->split->top_row + 1,  ses->split->bot_row, gtd->screen->rows - 1);
-
 	ses->split->top_col = URANGE(1, ses->split->top_col, gtd->screen->cols - 2);
+	ses->split->bot_row = URANGE(ses->split->top_row + 1,  ses->split->bot_row, gtd->screen->rows - 1);
 	ses->split->bot_col = URANGE(ses->split->top_col + 1, ses->split->bot_col, gtd->screen->cols);
 
+	ses->split->sav_top_row = ses->split->top_row - 1;
+	ses->split->sav_top_col = ses->split->top_col - 1;
+	ses->split->sav_bot_row = gtd->screen->rows - ses->split->bot_row - 1;
+	ses->split->sav_bot_col = gtd->screen->cols - ses->split->bot_col;
+
 	ses->wrap = ses->split->bot_col - (ses->split->top_col - 1);
 
 	scroll_region(ses, ses->split->top_row, ses->split->bot_row);
 
-	init_pos(ses, gtd->screen->rows, 1);
+	init_pos(ses, ses->input->top_row, ses->input->top_col);
 
 	if (HAS_BIT(ses->telopts, TELOPT_FLAG_NAWS))
 	{
-		client_send_sb_naws(ses, 0, NULL);
+		SET_BIT(ses->telopts, TELOPT_FLAG_UPDATENAWS);
 	}
 
 	if (ses->map && HAS_BIT(ses->map->flags, MAP_FLAG_VTMAP))
@@ -167,21 +185,21 @@ void init_split(struct session *ses, int top_row, int top_col, int bot_row, int
 	}
 
 
-	check_all_events(ses, SUB_ARG, 0, 4, "SCREEN SPLIT FILL", ntos(ses->split->top_row), ntos(ses->split->top_col), ntos(ses->split->bot_row), ntos(ses->split->bot_col));
+	check_all_events(ses, EVENT_FLAG_SCREEN, 0, 4, "SCREEN SPLIT FILL", ntos(ses->split->top_row), ntos(ses->split->top_col), ntos(ses->split->bot_row), ntos(ses->split->bot_col), ntos(ses->split->sav_top_row), ntos(ses->split->sav_bot_row), ntos(ses->split->sav_top_col), ntos(ses->split->sav_bot_col));
 
-	if (!check_all_events(ses, SUB_ARG, 0, 4, "CATCH SCREEN SPLIT FILL", ntos(ses->split->top_row), ntos(ses->split->top_col), ntos(ses->split->bot_row), ntos(ses->split->bot_col)))
+	if (!check_all_events(ses, EVENT_FLAG_CATCH, 0, 8, "CATCH SCREEN SPLIT FILL", ntos(ses->split->top_row), ntos(ses->split->top_col), ntos(ses->split->bot_row), ntos(ses->split->bot_col), ntos(ses->split->sav_top_row), ntos(ses->split->sav_bot_row), ntos(ses->split->sav_top_col), ntos(ses->split->sav_bot_col)))
 	{
-		if (!HAS_BIT(ses->flags, SES_FLAG_SCROLLSPLIT))
+		if (ses == gtd->ses && !HAS_BIT(ses->flags, SES_FLAG_SCROLLSPLIT))
 		{
-			if (HAS_BIT(ses->flags, SES_FLAG_VERBOSE) || gtd->level->verbose || gtd->level->quiet == 0)
+			if (HAS_BIT(ses->config_flags, CONFIG_FLAG_VERBOSE) || gtd->level->verbose || gtd->level->quiet == 0)
 			{
-				execute(ses, "#SCREEN FILL DEFAULT");
+				command(ses, do_screen, "FILL DEFAULT");
 			}
 		}
 
 	}
 
-	check_all_events(ses, SUB_ARG, 0, 4, "SCREEN SPLIT", ntos(ses->split->top_row), ntos(ses->split->top_col), ntos(ses->split->bot_row), ntos(ses->split->bot_col));
+	check_all_events(ses, EVENT_FLAG_SCREEN, 0, 4, "SCREEN SPLIT", ntos(ses->split->top_row), ntos(ses->split->top_col), ntos(ses->split->bot_row), ntos(ses->split->bot_col));
 
 	pop_call();
 	return;
@@ -210,11 +228,13 @@ void dirty_screen(struct session *ses)
 
 	refresh_session_terminal(ses);
 
-	print_stdout("\e=");
+	print_stdout(0, 0, "\e=");
 
 	if (HAS_BIT(ses->flags, SES_FLAG_SPLIT))
 	{
 		init_split(ses, ses->split->sav_top_row, ses->split->sav_top_col, ses->split->sav_bot_row, ses->split->sav_bot_col);
+
+		init_input(ses, ses->input->sav_top_row, ses->input->sav_top_col, ses->input->sav_bot_row, ses->input->sav_bot_col);
 	}
 	else if (IS_SPLIT(ses))
 	{
@@ -227,7 +247,7 @@ void dirty_screen(struct session *ses)
 
 	if (IS_SPLIT(ses) && ses == gtd->ses)
 	{
-		init_pos(ses, gtd->screen->rows, 1);
+		init_pos(ses, ses->input->top_row, ses->input->top_col);
 	}
 
 	pop_call();
@@ -235,52 +255,57 @@ void dirty_screen(struct session *ses)
 }
 
 
-void split_show(struct session *ses, char *prompt, int row, int col)
+void split_show(struct session *ses, char *prompt, char *row_str, char *col_str)
 {
 	char buf1[BUFFER_SIZE];
-	int original_row, original_col, len, clear;
+	int row, col, len, width, clear;
 
-	original_row = row;
-	original_col = col;
+	row = 0;
 
-	if (row < 0)
+	if (*row_str)
 	{
-		row = 1 + gtd->screen->rows + row;
+		row = get_row_index_arg(ses, row_str);
 	}
-	else if (row == 0)
+
+	if (row == 0)
 	{
-		row = gtd->screen->rows - 1;
+		row = URANGE(1, ses->input->top_row - 1, gtd->screen->rows);
 	}
 
-	clear = 0;
+	col = 0;
 
-	if (col < 0)
+	if (*col_str)
 	{
-		col = 1 + gtd->screen->cols + col;
+		col = get_col_index_arg(ses, col_str);
 	}
-	else if (col == 0)
+
+	if (col == 0)
 	{
 		col = 1;
 		clear = 1;
 	}
+	else
+	{
+		clear = 0;
+	}
 
 	if (row < 1 || row > gtd->screen->rows)
 	{
-		show_error(ses, LIST_PROMPT, "#ERROR: PROMPT ROW IS OUTSIDE THE SCREEN: {%s} {%d} {%d}.", prompt, original_row, original_col);
+		show_error(ses, LIST_PROMPT, "#ERROR: PROMPT ROW IS OUTSIDE THE SCREEN: {%s} {%s} {%s} [%d].", prompt, row_str, col_str, row);
 
 		return;
 	}
 
 	if (col < 0 || col > gtd->screen->cols)
 	{
-		show_error(ses, LIST_PROMPT, "#ERROR: PROMPT COLUMN IS OUTSIDE THE SCREEN: {%s} {%d} {%d}.", prompt, original_row, original_col);
+		show_error(ses, LIST_PROMPT, "#ERROR: PROMPT COLUMN IS OUTSIDE THE SCREEN: {%s} {%s} {%s} [%d].", prompt, row_str, col_str, col);
 
 		return;
 	}
 
 	if (inside_scroll_region(ses, row, col))
 	{
-		show_error(ses, LIST_PROMPT, "#ERROR: PROMPT ROW IS INSIDE THE SCROLLING REGION: {%s} {%d}.", prompt, original_row);
+		show_error(ses, LIST_PROMPT, "#ERROR: PROMPT ROW IS INSIDE THE SCROLLING REGION: {%s} {%s} [%d].", prompt, row_str, row);
 
 		return;
 	}
@@ -290,15 +315,9 @@ void split_show(struct session *ses, char *prompt, int row, int col)
 		return;
 	}
 
-	len = strip_color_strlen(ses, prompt);
-
-/*	if (len == 0)
-	{
-		sprintf(buf1, "%.*s", gtd->screen->cols + 4, "\e[0m--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------");
-	}
-	else */
+	len = strip_vt102_width(ses, prompt, &width);
 
-	if (col - 1 + len <= gtd->screen->cols)
+	if (col - 1 + width <= gtd->screen->cols)
 	{
 		sprintf(buf1, "%s", prompt);
 	}
@@ -306,20 +325,20 @@ void split_show(struct session *ses, char *prompt, int row, int col)
 	{
 		show_debug(ses, LIST_PROMPT, "#DEBUG PROMPT {%s}", prompt);
 
-		show_debug(ses, LIST_PROMPT, "#PROMPT SIZE %d WITH OFFSET %d LONGER THAN ROW SIZE %d.", len, col, gtd->screen->cols);
+		show_debug(ses, LIST_PROMPT, "#PROMPT WIDTH %d WITH OFFSET %d LONGER THAN ROW SIZE %d.", width, col, gtd->screen->cols);
 
-		sprintf(buf1, "#PROMPT SIZE %d WITH OFFSET %d LONGER THAN ROW SIZE %d.", len, 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);
 
 	if (row == gtd->screen->rows)
 	{
-		gtd->ses->input->off = len + 1;
+		gtd->ses->input->str_off = len + 1;
 
 		goto_pos(ses, row, col);
 
-		print_stdout("%s%s", buf1, gtd->ses->input->buf);
+		print_stdout(0, 0, "%s%s", buf1, gtd->ses->input->buf);
 
 		// bit of a hack
 
@@ -330,12 +349,15 @@ void split_show(struct session *ses, char *prompt, int row, int col)
 	{
 		goto_pos(ses, row, col);
 
-		print_stdout("%s%s", clear ? "\e[2K" : "", buf1);
+		if (clear)
+		{
+			erase_cols(gtd->screen->cols);
+		}
+	
+		print_stdout(0, 0, "%s", buf1);
 	}
 
-	set_line_screen(ses, buf1, row - 1, col - 1);
+	set_line_screen(ses, buf1, row, col);
 
 	restore_pos(ses);
 }
-
-

+ 13 - 26
src/ssl.c

@@ -115,7 +115,7 @@ static int get_cert_file(struct session *ses, char *result)
 		{
 			*ptr++ = '.';
 		}
-		else if (isalnum((int) *ptr) || *ptr == '-' || *ptr == '.' || *ptr == '_')
+		else if (is_alnum(*ptr) || *ptr == '-' || *ptr == '.' || *ptr == '_')
 		{
 			ptr++;
 		}
@@ -125,7 +125,7 @@ static int get_cert_file(struct session *ses, char *result)
 		}
 	}
 
-	sprintf(result, "%s/%s/ssl/%s.crt", gtd->home, TINTIN_DIR, name);
+	sprintf(result, "%s/ssl/%s.crt", gtd->system->tt_dir, name);
 
 	return 1;
 }
@@ -175,18 +175,16 @@ static void save_cert(struct session *ses, gnutls_x509_crt_t cert, int new)
 		return;
 	}
 
-	sprintf(filename, "%s/%s", gtd->home, TINTIN_DIR);
+	sprintf(filename, "%s", gtd->system->tt_dir);
 
-	if (mkdir(filename, 0777) && errno != EEXIST)
+	if (mkdir(filename, 0755) && errno != EEXIST)
 	{
 		tintin_printf(ses, "#SSL: FAILED TO CREATE TINTIN DIR %s (%s)", filename, strerror(errno));
 
 		return;
 	}
 
-	sprintf(filename, "%s/%s/ssl", gtd->home, TINTIN_DIR);
-
-	mkdir(filename, 0755);
+	sprintf(filename, "%s/ssl", gtd->system->tt_dir);
 
 	if (mkdir(filename, 0755) && errno != EEXIST)
 	{
@@ -258,7 +256,7 @@ static int diff_certs(gnutls_x509_crt_t c1, gnutls_x509_crt_t c2)
 
 static int ssl_check_cert(struct session *ses, gnutls_session_t ssl_ses)
 {
-	char filename[BUFFER_SIZE], buf2[BUFFER_SIZE], *bptr;
+	char filename[BUFFER_SIZE], buf2[BUFFER_SIZE];
 	time_t t;
 	gnutls_x509_crt_t cert, oldcert;
 	const gnutls_datum_t *cert_list;
@@ -288,34 +286,23 @@ static int ssl_check_cert(struct session *ses, gnutls_session_t ssl_ses)
 		err = "#SSL: SERVER'S CERTIFICATE IS INVALID.";
 		goto badcert;
 	}
-	
+
 	t = time(0);
 
 	if (gnutls_x509_crt_get_activation_time(cert) > t)
 	{
-		sprintf(buf2, "%s", ctime(&t));
+		sprintf(buf2, "CERTIFICATE ACTIVATION TIME IS IN THE FUTURE (%s)", str_time(ses, "%c", gnutls_x509_crt_get_activation_time(cert)));
 
-		if ((bptr = strchr(buf2, '\n')))
-		{
-			*bptr = 0;
-		}
-		sprintf(filename, "CERTIFICATE ACTIVATION TIME IS IN THE FUTURE (%s)", buf2);
-
-		err = filename;
+		err = buf2;
 	}
 	
-	if (gnutls_x509_crt_get_expiration_time(cert)<t)
+	if (gnutls_x509_crt_get_expiration_time(cert) < t)
 	{
-		sprintf(buf2, "%s", ctime(&t));
+		sprintf(buf2, "CERTIFICATE HAS EXPIRED (%s)", str_time(ses, "%c", gnutls_x509_crt_get_expiration_time(cert)));
 
-		if ((bptr = strchr(buf2, '\n')))
-		{
-			*bptr = 0;
-		}
-		sprintf(filename, "CERTIFICATE HAS EXPIRED (%s)", buf2);
-		err = filename;
+		err = buf2;
 	}
-	
+
 	if (!oldcert)
 	{
 		save_cert(ses, cert, 1);

+ 309 - 16
src/string.c

@@ -25,38 +25,74 @@
 
 #include "tintin.h"
 
-int str_len_str(struct session *ses, char *str, int start, int end)
+int get_raw_off_str_range_raw_width(struct session *ses, char *str, int start, int end, int *raw_width)
 {
-	int raw_cnt, str_cnt, ret_cnt, width, raw_len, tmp_cnt;
+	int raw_cnt, str_cnt, raw_off, ret_raw, raw_len, skip, width;
 
+	raw_off = 0;
 	raw_cnt = 0;
 	str_cnt = 0;
-	ret_cnt = 0;
+	ret_raw = 0;
 
 	raw_len = str_len(str);
 
 	while (raw_cnt < raw_len)
+	{
+		skip = get_vt102_width(ses, &str[raw_cnt], &width);
+
+		if (str_cnt >= start)
+		{
+			ret_raw += skip;
+		}
+		else
+		{
+			raw_off += skip;
+		}
+
+		raw_cnt += skip;
+
+		if (end >= 0 && str_cnt + width > end)
+		{
+			break;
+		}
+		str_cnt += width;
+	}
+	*raw_width = ret_raw;
+
+	return raw_off;
+}
+
+int str_len_str(struct session *ses, char *str, int start, int end)
+{
+	int str_cnt, ret_cnt, width, tmp_cnt;
+
+	str_cnt = 0;
+	ret_cnt = 0;
+
+	while (*str)
 	{
 		if (end >= 0 && str_cnt >= end)
 		{
 			break;
 		}
 
-		tmp_cnt = skip_vt102_codes(&str[raw_cnt]);
+		tmp_cnt = skip_vt102_codes(str);
 
 		if (tmp_cnt)
 		{
-			raw_cnt += tmp_cnt;
+			str += tmp_cnt;
 		}
-		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&str[raw_cnt]))
+		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(str))
 		{
-			raw_cnt += get_utf8_width(&str[raw_cnt], &width);
+			tmp_cnt = get_utf8_width(str, &width);
 
 			if (str_cnt >= start)
 			{
 				ret_cnt += width;
 			}
 			str_cnt += width;
+
+			str += tmp_cnt;
 		}
 		else
 		{
@@ -64,8 +100,9 @@ int str_len_str(struct session *ses, char *str, int start, int end)
 			{
 				ret_cnt++;
 			}
-			raw_cnt++;
 			str_cnt++;
+
+			str++;
 		}
 	}
 	return ret_cnt;
@@ -77,6 +114,7 @@ int str_len_raw(struct session *ses, char *str, int start, int end)
 
 	raw_cnt = start;
 	ret_cnt = 0;
+
 	raw_len = str_len(str);
 
 	while (raw_cnt < raw_len)
@@ -128,7 +166,66 @@ int raw_len_str(struct session *ses, char *str, int start, int end)
 			{
 				ret_cnt += tmp_cnt;
 			}
-			width = 0;
+			continue;
+		}
+		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&str[raw_cnt]))
+		{ 
+			tmp_cnt = get_utf8_width(&str[raw_cnt], &width);
+
+			if (str_cnt >= start)
+			{
+				ret_cnt += tmp_cnt;
+			}
+			raw_cnt += tmp_cnt;
+		}
+		else
+		{
+			if (str_cnt >= start)
+			{
+				ret_cnt++;
+			}
+			raw_cnt++;
+			width = 1;
+		}
+
+		if (end >= 0 && str_cnt + width > end)
+		{
+			break;
+		}
+		str_cnt += width;
+	}
+	return ret_cnt;
+}
+
+// minimum string length
+
+int raw_len_str_min(struct session *ses, char *str, int start, int end)
+{
+	int raw_cnt, str_cnt, ret_cnt, width, tmp_cnt, raw_len;
+
+	raw_cnt = 0;
+	str_cnt = 0;
+	ret_cnt = 0;
+	raw_len = strlen(str);
+
+	while (raw_cnt < raw_len)
+	{
+		if (str_cnt >= end)
+		{
+			break;
+		}
+
+		tmp_cnt = skip_vt102_codes(&str[raw_cnt]);
+
+		if (tmp_cnt)
+		{
+			raw_cnt += tmp_cnt;
+
+			if (str_cnt >= start)
+			{
+				ret_cnt += tmp_cnt;
+			}
+			continue;
 		}
 		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&str[raw_cnt]))
 		{    
@@ -160,16 +257,28 @@ int raw_len_str(struct session *ses, char *str, int start, int end)
 
 int raw_len_raw(struct session *ses, char *str, int start, int end)
 {
+	if (end == -1)
+	{
+		return strlen(str) - start;
+	}
+
 	if (start >= end)
 	{
 		return 0;
 	}
+
 	return end - start;
 }
 
 char *str_ins_str(struct session *ses, char **str, char *ins, int str_start, int str_end)
 {
-	int len, raw_start, raw_end, raw_len, ins_raw_len;
+	char old[COLOR_SIZE], tmp;
+	int len, raw_start, raw_end, raw_len, ins_raw_len, col_len;
+
+	if (str_end == -1)
+	{
+		str_end = str_start + strip_vt102_strlen(ses, ins);
+	}
 
 	len = str_len_str(ses, *str, 0, str_end);
 
@@ -180,14 +289,32 @@ char *str_ins_str(struct session *ses, char **str, char *ins, int str_start, int
 
 	ins_raw_len = raw_len_str(ses, ins, 0, str_end - str_start);
 
-	raw_start = raw_len_str(ses, *str, 0, str_start);
-	raw_len   = raw_len_str(ses, *str, 0, -1);
-	raw_end   = raw_len_str(ses, *str, 0, str_end);
+	raw_start = raw_len_str_min(ses, *str, 0, str_start);
+	raw_len   = str_len(*str);
+	raw_end   = raw_len_str_min(ses, *str, 0, str_end);
+
+	tmp = (*str)[raw_end];
+
+	*old = (*str)[raw_end] = 0;
+
+	get_color_codes(old, *str, old, GET_ALL);
 
-	if (raw_len < raw_end + ins_raw_len)
+	(*str)[raw_end] = tmp;
+
+	col_len = strlen(old);
+
+	str_resize(str, ins_raw_len + col_len + 1);
+
+	if (raw_len < raw_end + ins_raw_len || raw_len > raw_end)
 	{
-		str_resize(str, ins_raw_len);
+		memmove(*str + raw_start + ins_raw_len + col_len, *str + raw_end, raw_len - raw_end + 1);
+
+		memcpy(*str + raw_start + ins_raw_len, old, col_len);
 
+		memcpy(*str + raw_start, ins, ins_raw_len);
+	}
+	else if (raw_len > raw_end)
+	{
 		memmove(*str + raw_start + ins_raw_len, *str + raw_end, raw_len - raw_end + 1);
 
 		memcpy(*str + raw_start, ins, ins_raw_len);
@@ -196,9 +323,175 @@ char *str_ins_str(struct session *ses, char **str, char *ins, int str_start, int
 	{
 		memcpy(*str + raw_start, ins, ins_raw_len);
 
-		(*str)[raw_start + ins_raw_len] = 0;
+		if (len < str_end)
+		{
+			(*str)[raw_start + ins_raw_len] = 0;
+		}
 	}
 	str_fix(*str);
 
 	return *str;
 }
+
+char *calign(struct session *ses, char *in, char *out, int width)
+{
+	int width_in;
+
+	in = space_out(in);
+
+	if (*in)
+	{
+		int len = strlen(in) - 1;
+
+		while (is_space(in[len]))
+		{
+			in[len--] = 0;
+		}
+	}
+
+	strip_vt102_width(ses, in, &width_in);
+
+	width = UMAX(0, width - width_in);
+
+	sprintf(out, "%*s%s%*s", width / 2, "", in, width - width / 2, "");
+
+	return out;
+}
+
+char *lalign(struct session *ses, char *in, char *out, int width)
+{
+	int width_in;
+
+	in = space_out(in);
+
+	if (*in)
+	{
+		int len = strlen(in) - 1;
+
+		while (is_space(in[len]))
+		{
+			in[len--] = 0;
+		}
+	}
+
+	strip_vt102_width(ses, in, &width_in);
+
+	width = UMAX(0, width - width_in);
+
+	sprintf(out, "%s%*s", in, width, "");
+
+	return out;
+}
+
+char *ralign(struct session *ses, char *in, char *out, int width)
+{
+	int width_in;
+
+	in = space_out(in);
+
+	if (*in)
+	{
+		int len = strlen(in) - 1;
+
+		while (is_space(in[len]))
+		{
+			in[len--] = 0;
+		}
+	}
+
+	strip_vt102_width(ses, in, &width_in);
+
+	width = UMAX(0, width - width_in);
+
+	sprintf(out, "%*s%s", width, "", in);
+
+	return out;
+}
+
+
+char *ualign(struct session *ses, char *in, char *out, int width)
+{
+	char *pti, *pto;
+
+	pti = in;
+	pto = out;
+
+	while (*pti)
+	{
+		if (*pti == '\n')
+		{
+			switch (pti[1])
+			{
+				case '\0':
+					*pto++ = *pti++;
+					break;
+
+				case '\n':
+					while (*pti == '\n')
+					{
+						*pto++ = *pti++;
+					}
+					break;
+
+				default:
+					pti++;
+					*pto++ = ' ';
+					break;
+			}
+		}
+		else
+		{
+			*pto++ = *pti++;
+		}
+	}
+	*pto = 0;
+
+	return out;
+}
+
+// unused
+
+char char_cmp(char left, char right)
+{
+	return left / 64 == right / 64 && left % 32 == right % 32;
+}
+
+char is_alnum(char input)
+{
+	return HAS_BIT(character_table[(unsigned char) input], CHAR_FLAG_ALPHA|CHAR_FLAG_DIGIT);
+}
+
+char is_alpha(char input)
+{
+	return HAS_BIT(character_table[(unsigned char) input], CHAR_FLAG_ALPHA);
+}
+
+char is_digit(char input)
+{
+	return HAS_BIT(character_table[(unsigned char) input], CHAR_FLAG_DIGIT);
+}
+
+char is_hex(char input)
+{
+	return HAS_BIT(character_table[(unsigned char) input], CHAR_FLAG_HEX);
+}
+
+char is_space(char input)
+{
+	return HAS_BIT(character_table[(unsigned char) input], CHAR_FLAG_SPACE);
+}
+
+char is_varchar(char input)
+{
+	return HAS_BIT(character_table[(unsigned char) input], CHAR_FLAG_VAR);
+}
+
+char is_csichar(char input)
+{
+	return HAS_BIT(character_table[(unsigned char) input], CHAR_FLAG_CSI);
+}
+
+char is_print(char input)
+{
+	return HAS_BIT(character_table[(unsigned char) input], CHAR_FLAG_PRINT);
+}

+ 153 - 65
src/substitute.c

@@ -310,14 +310,14 @@ int is_variable(struct session *ses, char *str)
 		return TRUE;
 	}
 
-	if (str[i] != '_' && isalpha((int) str[i]) == 0)
+	if (str[i] != '_' && !is_alpha(str[i]))
 	{
 		return FALSE;
 	}
 
 	ptt = temp;
 
-	while (isalnum((int) str[i]) || str[i] == '_')
+	while (is_alnum(str[i]) || str[i] == '_')
 	{
 		*ptt++ = str[i];
 
@@ -325,16 +325,24 @@ int is_variable(struct session *ses, char *str)
 	}
 	*ptt = 0;
 
-	root = local_list(ses);
+	root = search_nest_base_ses(ses, temp);
 
-	if (search_node_list(root, temp) == NULL)
+	if (root == NULL)
 	{
-		root = ses->list[LIST_VARIABLE];
+		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 (search_node_list(root, temp) == NULL)
+	{
+		if (str[0] == '&' && HAS_BIT(gtd->flags, TINTIN_FLAG_GETNUMBER))
 		{
-			return FALSE;
+			show_error(ses, LIST_VARIABLE, "\e[1;31m#WARNING: FOUND %c%s. USE %c{%s} INSTEAD?", str[0], temp, str[0], temp);
 		}
+		return FALSE;
 	}
 
 	return TRUE;
@@ -350,14 +358,14 @@ int is_function(struct session *ses, char *str)
 		i++;
 	}
 
-	if (str[i] != '_' && isalpha((int) str[i]) == 0)
+	if (str[i] != '_' && !is_alpha(str[i]))
 	{
 		return FALSE;
 	}
 
 	ptt = temp;
 
-	while (isalnum((int) str[i]) || str[i] == '_')
+	while (is_alnum(str[i]) || str[i] == '_')
 	{
 		*ptt++ = str[i];
 
@@ -464,7 +472,7 @@ char *fuzzy_color_code(struct session *ses, char *in)
 
 			if (pti[4] == '>')
 			{
-				if (isdigit((int) pti[1]) && isdigit((int) pti[2]) && isdigit((int) pti[3]))
+				if (is_digit(pti[1]) && is_digit(pti[2]) && is_digit(pti[3]))
 				{
 					pto += sprintf(pto, "<%c%c%c>", pti[1], pti[2], pti[3]);
 				}
@@ -476,7 +484,7 @@ char *fuzzy_color_code(struct session *ses, char *in)
 				{
 					pto += sprintf(pto, "<%s%s%s>", fuzzy_char(ses, 0, pti[1], 8), fuzzy_char(ses, 0, pti[2], 8), fuzzy_char(ses, 0, pti[3], 8));
 				}
-				else if ((pti[1] == 'g' || pti[1] == 'G') && isdigit((int) pti[2]) && isdigit((int) pti[3]))
+				else if ((pti[1] == 'g' || pti[1] == 'G') && is_digit(pti[2]) && is_digit(pti[3]))
 				{
 					tmp = (pti[2] - '0') * 10 + (pti[3] - '0') - 3 + generate_rand(ses) % 7;
 
@@ -490,7 +498,7 @@ char *fuzzy_color_code(struct session *ses, char *in)
 			}
 			else if (toupper((int) pti[1]) == 'F')
 			{
-				if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && pti[5] == '>')
+				if (is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && pti[5] == '>')
 				{
 					pto += sprintf(pto, "<F%s%s%s>", fuzzy_char(ses, 0, pti[2], 12), fuzzy_char(ses, 0, pti[3], 12), fuzzy_char(ses, 0, pti[4], 12));
 
@@ -504,7 +512,7 @@ char *fuzzy_color_code(struct session *ses, char *in)
 
 					pti += 6;
 				}
-				else if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && isxdigit((int) pti[5]) && isxdigit((int) pti[6]) && isxdigit((int) pti[7]) && pti[8] == '>')
+				else if (is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && is_hex(pti[5]) && is_hex(pti[6]) && is_hex(pti[7]) && pti[8] == '>')
 				{
 					pto += sprintf(pto, "<F%s%s%s>", fuzzy_char(ses, pti[3], pti[4], 24), fuzzy_char(ses, pti[4], pti[5], 24), fuzzy_char(ses, pti[7], pti[7], 24));
 
@@ -517,7 +525,7 @@ char *fuzzy_color_code(struct session *ses, char *in)
 			}
 			else if (toupper((int) pti[1]) == 'B')
 			{
-				if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && pti[5] == '>')
+				if (is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && pti[5] == '>')
 				{
 					pto += sprintf(pto, "<B%s%s%s>", fuzzy_char(ses, 0, pti[2], 12), fuzzy_char(ses, 0, pti[3], 12), fuzzy_char(ses, 0, pti[4], 12));
 
@@ -531,7 +539,7 @@ char *fuzzy_color_code(struct session *ses, char *in)
 
 					pti += 6;
 				}
-				else if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && isxdigit((int) pti[5]) && isxdigit((int) pti[6]) && isxdigit((int) pti[7]) && pti[8] == '>')
+				else if (is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && is_hex(pti[5]) && is_hex(pti[6]) && is_hex(pti[7]) && pti[8] == '>')
 				{
 					pto += sprintf(pto, "<B%s%s%s>", fuzzy_char(ses, pti[2], pti[3], 24), fuzzy_char(ses, pti[4], pti[5], 24), fuzzy_char(ses, pti[6], pti[7], 24));
 
@@ -645,7 +653,7 @@ char *dim_color_code(struct session *ses, char *in, int mod)
 
 			if (pti[4] == '>')
 			{
-				if (isdigit((int) pti[1]) && isdigit((int) pti[2]) && isdigit((int) pti[3]))
+				if (is_digit(pti[1]) && is_digit(pti[2]) && is_digit(pti[3]))
 				{
 					pto += sprintf(pto, "<%c%c%c>", pti[1], pti[2], pti[3]);
 				}
@@ -657,7 +665,7 @@ char *dim_color_code(struct session *ses, char *in, int mod)
 				{
 					pto += sprintf(pto, "<%s%s%s>", dim_char(ses, 0, pti[1], mod, 8), dim_char(ses, 0, pti[2], mod, 8), dim_char(ses, 0, pti[3], mod, 8));
 				}
-				else if ((pti[1] == 'g' || pti[1] == 'G') && isdigit((int) pti[2]) && isdigit((int) pti[3]))
+				else if ((pti[1] == 'g' || pti[1] == 'G') && is_digit(pti[2]) && is_digit(pti[3]))
 				{
 					tmp = (pti[2] - '0') * 10 + (pti[3] - '0') - mod;
 
@@ -676,13 +684,13 @@ char *dim_color_code(struct session *ses, char *in, int mod)
 					c4096_rnd(ses, &pti[2]);
 				}
 
-				if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && pti[5] == '>')
+				if (is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && pti[5] == '>')
 				{
 					pto += sprintf(pto, "<F%s%s%s>", dim_char(ses, 0, pti[2], mod, 12), dim_char(ses, 0, pti[3], mod, 12), dim_char(ses, 0, pti[4], mod, 12));
 
 					pti += 6;
 				}
-				else if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && isxdigit((int) pti[5]) && isxdigit((int) pti[6]) && isxdigit((int) pti[7]) && pti[8] == '>')
+				else if (is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && is_hex(pti[5]) && is_hex(pti[6]) && is_hex(pti[7]) && pti[8] == '>')
 				{
 					pto += sprintf(pto, "<F%s%s%s>", dim_char(ses, pti[2], pti[3], mod, 24), dim_char(ses, pti[4], pti[5], mod, 24), dim_char(ses, mod, pti[6], pti[7], 24));
 
@@ -700,13 +708,13 @@ char *dim_color_code(struct session *ses, char *in, int mod)
 					c4096_rnd(ses, &pti[2]);
 				}
 
-				if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && pti[5] == '>')
+				if (is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && pti[5] == '>')
 				{
 					pto += sprintf(pto, "<B%s%s%s>", dim_char(ses, 0, pti[2], mod, 12), dim_char(ses, 0, pti[3], mod, 12), dim_char(ses, 0, pti[4], mod, 12));
 
 					pti += 6;
 				}
-				else if (toupper((int) pti[1]) == 'B' && isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && isxdigit((int) pti[5]) && isxdigit((int) pti[6]) && isxdigit((int) pti[7]) && pti[8] == '>')
+				else if (toupper((int) pti[1]) == 'B' && is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && is_hex(pti[5]) && is_hex(pti[6]) && is_hex(pti[7]) && pti[8] == '>')
 				{
 					pto += sprintf(pto, "<B%s%s%s>", dim_char(ses, pti[2], pti[3], mod, 24), dim_char(ses, pti[4], pti[5], mod, 24), dim_char(ses, pti[6], pti[7], mod, 24));
 
@@ -765,7 +773,7 @@ char *lit_color_code(struct session *ses, char *pti, int mod)
 
 		if (pti[4] == '>')
 		{
-			if (isdigit((int) pti[1]) && isdigit((int) pti[2]) && isdigit((int) pti[3]))
+			if (is_digit(pti[1]) && is_digit(pti[2]) && is_digit(pti[3]))
 			{
 				sprintf(fuzzy[cnt], "<%c%c%c>%.9s", pti[1], pti[2], pti[3], &pti[5]);
 
@@ -790,7 +798,7 @@ char *lit_color_code(struct session *ses, char *pti, int mod)
 		{
 			if (pti[1] == 'g' || pti[1] == 'G')
 			{
-				if (isdigit((int) pti[2]) && isdigit((int) pti[3]))
+				if (is_digit(pti[2]) && is_digit(pti[3]))
 				{
 					tmp = (pti[2] - '0') * 10 + (pti[3] - '0');
 
@@ -811,7 +819,7 @@ char *lit_color_code(struct session *ses, char *pti, int mod)
 
 		if (toupper((int) pti[1]) == 'F')
 		{
-			if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && pti[5] == '>')
+			if (is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && pti[5] == '>')
 			{
 				sprintf(fuzzy[cnt], "<F%c%c%c>%.9s", lit_char(ses, 'F', pti[2], mod, 12), lit_char(ses, 'F', pti[3], mod, 12), lit_char(ses, 'F', pti[4], mod, 12), &pti[6]);
 
@@ -825,7 +833,7 @@ char *lit_color_code(struct session *ses, char *pti, int mod)
 
 				return dim_color_code(ses, fuzzy[cnt], mod);
 			}
-			else if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && isxdigit((int) pti[5]) && isxdigit((int) pti[6]) && isxdigit((int) pti[7]) && pti[8] == '>')
+			else if (is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && is_hex(pti[5]) && is_hex(pti[6]) && is_hex(pti[7]) && pti[8] == '>')
 			{
 				sprintf(fuzzy[cnt], "<F%c%c%c>%.9s", lit_char(ses, 'F', pti[2], mod, 12), lit_char(ses, 'F', pti[4], mod, 12), lit_char(ses, mod, pti[6], 'F', 12), &pti[9]);
 
@@ -836,7 +844,7 @@ char *lit_color_code(struct session *ses, char *pti, int mod)
 
 		if (toupper((int) pti[1]) == 'B')
 		{
-			if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && pti[5] == '>')
+			if (is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && pti[5] == '>')
 			{
 				sprintf(fuzzy[cnt], "<B%c%c%c>%.9s", lit_char(ses, 'F', pti[2], mod, 12), lit_char(ses, 'F', pti[3], mod, 12), lit_char(ses, 'F', pti[4], mod, 12), &pti[6]);
 
@@ -850,7 +858,7 @@ char *lit_color_code(struct session *ses, char *pti, int mod)
 
 				return dim_color_code(ses, fuzzy[cnt], mod);
 			}
-			if (toupper((int) pti[1]) == 'B' && isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && isxdigit((int) pti[5]) && isxdigit((int) pti[6]) && isxdigit((int) pti[7]) && pti[8] == '>')
+			if (toupper((int) pti[1]) == 'B' && is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && is_hex(pti[5]) && is_hex(pti[6]) && is_hex(pti[7]) && pti[8] == '>')
 			{
 				sprintf(fuzzy[cnt], "<B%c%c%c>%.9s", lit_char(ses, 'F', pti[2], mod, 12), lit_char(ses, 'F', pti[4], mod, 12), lit_char(ses, mod, pti[6], 'F', 12), &pti[9]);
 
@@ -867,12 +875,16 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 	struct listnode *node;
 	struct listroot *root;
 	struct session *sesptr;
-	char temp[BUFFER_SIZE], buf[BUFFER_SIZE], buffer[BUFFER_SIZE], *pti, *pto, *ptt, *str;
+	char *temp, *buf, *buffer, *pti, *pto, *ptt, *str;
 	char *pte, old[10] = { 0 };
 	int i, skip, cnt, escape = FALSE, flags_neol = flags;
 
 	push_call("substitute(%p,%p,%p,%d)",ses,string,result,flags);
 
+	temp   = str_alloc_stack(0);
+	buf    = str_alloc_stack(0);
+	buffer = str_alloc_stack(0);
+
 	pti = string;
 	pto = (string == result) ? buffer : result;
 
@@ -938,7 +950,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 						i++;
 					}
 
-					for (ptt = temp ; isalnum((int) pti[i]) || pti[i] == '_' ; i++)
+					for (ptt = temp ; is_alnum(pti[i]) || pti[i] == '_' ; i++)
 					{
 						*ptt++ = pti[i];
 					}
@@ -1035,9 +1047,33 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 
 					script_driver(ses, LIST_FUNCTION, buf);
 
-					substitute(ses, "$result", pto, flags_neol|SUB_VAR);
+					node = search_nest_node_ses(ses, "result");
 
-					pto += strlen(pto);
+					if (node)
+					{
+						if (node->root)
+						{
+							str = str_dup("");
+
+							show_nest_node(node, &str, TRUE);
+
+							pto += substitute(ses, str, pto, flags_neol);
+
+							str_free(str);
+						}
+						else
+						{
+							show_debug(ses, LIST_FUNCTION, "#DEBUG FUNCTION: (%s) (%s) [%d]", node->arg1, node->arg2, flags_neol);
+
+							// sub color codes
+
+							pto += substitute(ses, node->arg2, pto, flags_neol);
+						}
+					}
+					else
+					{
+						pto += sprintf(pto, "$result");
+					}
 				}
 				else
 				{
@@ -1050,7 +1086,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 				break;
 
 			case '*':
-				if (HAS_BIT(flags, SUB_VAR) && !HAS_BIT(ses->list[LIST_VARIABLE]->flags, LIST_FLAG_IGNORE) && pti[1])
+				if (HAS_BIT(flags, SUB_VAR) && !HAS_BIT(ses->list[LIST_VARIABLE]->flags, LIST_FLAG_IGNORE) && is_variable(ses, pti))
 				{
 					int brace = FALSE;
 					i = 1;
@@ -1077,7 +1113,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 					{
 						ptt = temp;
 
-						while (isalnum((int) pti[i]) || pti[i] == '_')
+						while (is_alnum(pti[i]) || pti[i] == '_')
 						{
 							*ptt++ = pti[i];
 
@@ -1155,7 +1191,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 				break;
 
 			case '$':
-				if (HAS_BIT(flags, SUB_VAR) && !HAS_BIT(ses->list[LIST_VARIABLE]->flags, LIST_FLAG_IGNORE) && pti[1])
+				if (HAS_BIT(flags, SUB_VAR) && !HAS_BIT(ses->list[LIST_VARIABLE]->flags, LIST_FLAG_IGNORE) && is_variable(ses, pti))
 				{
 					int brace = FALSE;
 					i = 1;
@@ -1182,7 +1218,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 					{
 						ptt = temp;
 
-						while (isalnum((int) pti[i]) || pti[i] == '_')
+						while (is_alnum(pti[i]) || pti[i] == '_')
 						{
 							*ptt++ = pti[i];
 
@@ -1247,6 +1283,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 					get_nest_node_val(root, buf, &str, brace);
 
 					substitute(ses, str, pto, flags_neol - SUB_VAR);
+//					substitute(ses, str, pto, flags_neol);
 
 					pto += strlen(pto);
 
@@ -1263,7 +1300,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 				break;
 
 			case '&':
-				if (HAS_BIT(flags, SUB_CMD) && (isdigit((int) pti[1]) || pti[1] == '&'))
+				if (HAS_BIT(flags, SUB_CMD) && (is_digit(pti[1]) || pti[1] == '&'))
 				{
 					if (pti[1] == '&')
 					{
@@ -1271,7 +1308,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 						{
 							*pto++ = *pti++;
 						}
-						if (isdigit((int) pti[1]))
+						if (is_digit(pti[1]))
 						{
 							pti++;
 						}
@@ -1282,16 +1319,16 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 					}
 					else
 					{
-						i = isdigit((int) pti[2]) ? (pti[1] - '0') * 10 + pti[2] - '0' : pti[1] - '0';
+						i = is_digit(pti[2]) ? (pti[1] - '0') * 10 + pti[2] - '0' : pti[1] - '0';
 
 						for (cnt = 0 ; gtd->cmds[i][cnt] ; cnt++)
 						{
 							*pto++ = gtd->cmds[i][cnt];
 						}
-						pti += isdigit((int) pti[2]) ? 3 : 2;
+						pti += is_digit(pti[2]) ? 3 : 2;
 					}
 				}
-				else if (HAS_BIT(flags, SUB_VAR) && !HAS_BIT(ses->list[LIST_VARIABLE]->flags, LIST_FLAG_IGNORE))
+				else if (HAS_BIT(flags, SUB_VAR) && !HAS_BIT(ses->list[LIST_VARIABLE]->flags, LIST_FLAG_IGNORE) && is_variable(ses, pti))
 				{
 					int brace = FALSE;
 					i = 1;
@@ -1318,7 +1355,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 					{
 						ptt = temp;
 
-						while (isalnum((int) pti[i]) || pti[i] == '_')
+						while (is_alnum(pti[i]) || pti[i] == '_')
 						{
 							*ptt++ = pti[i];
 
@@ -1395,7 +1432,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 				break;
 
 			case '%':
-				if (HAS_BIT(flags, SUB_ARG) && (isdigit((int) pti[1]) || pti[1] == '%'))
+				if (HAS_BIT(flags, SUB_ARG) && (is_digit(pti[1]) || pti[1] == '%'))
 				{
 					if (pti[1] == '%')
 					{
@@ -1407,7 +1444,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 					}
 					else
 					{
-						i = isdigit((int) pti[2]) ? (pti[1] - '0') * 10 + pti[2] - '0' : pti[1] - '0';
+						i = is_digit(pti[2]) ? (pti[1] - '0') * 10 + pti[2] - '0' : pti[1] - '0';
 
 						ptt = gtd->vars[i];
 
@@ -1424,6 +1461,20 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 							{
 								switch (*ptt)
 								{
+									case '\e':
+										skip = find_secure_color_code(ptt);
+
+										if (skip)
+										{
+											pto += sprintf(pto, "%.*s", skip, ptt);
+											ptt += skip - 1;
+										}
+										else
+										{
+											*pto++ = *ptt;
+										}
+										break;
+
 									case '\\':
 										*pto++ = '\\';
 										*pto++ = '\\';
@@ -1485,7 +1536,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 								*pto++ = *ptt++;
 							}
 						}
-						pti += isdigit((int) pti[2]) ? 3 : 2;
+						pti += is_digit(pti[2]) ? 3 : 2;
 					}
 				}
 				else if (pti[1] == '*') // avoid %*variable triggers
@@ -1502,15 +1553,19 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 			case '<':
 				if (HAS_BIT(flags, SUB_COL))
 				{
-					if (HAS_BIT(flags, SUB_CMP) && old[0] && !strncmp(old, pti, strlen(old)))
+					if (old[0] && !strncmp(old, pti, strlen(old)))
 					{
 						pti += strlen(old);
 					}
 					else if (pti[1] && pti[2] && pti[3] && pti[4] == '>')
 					{
-						if (isdigit((int) pti[1]) && isdigit((int) pti[2]) && isdigit((int) pti[3]))
+						if (is_digit(pti[1]) && is_digit(pti[2]) && is_digit(pti[3]))
 						{
-							if (pti[1] != '8' || pti[2] != '8' || pti[3] != '8')
+							if (pti[1] == '9' && pti[2] == '0' && pti[3] == '0')
+							{
+								pto += sprintf(pto, "%s", gtd->color_reset);
+							}
+							else if (pti[1] != '8' || pti[2] != '8' || pti[3] != '8')
 							{
 								*pto++ = ASCII_ESC;
 								*pto++ = '[';
@@ -1559,7 +1614,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 							
 							if (ses->color >= 256)
 							{
-								pto += sprintf(pto, "\e[38;5;%dm", cnt);
+								pto += sprintf(pto, "\e[22;38;5;%dm", cnt);
 							}
 							else if (ses->color == 16)
 							{
@@ -1581,13 +1636,13 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 							}
 							pti += sprintf(old, "<%c%c%c>", pti[1], pti[2], pti[3]);
 						}
-						else if (pti[1] == 'g' && isdigit((int) pti[2]) && isdigit((int) pti[3]) && pti[4] == '>')
+						else if (pti[1] == 'g' && is_digit(pti[2]) && is_digit(pti[3]) && pti[4] == '>')
 						{
 							cnt = 232 + (pti[2] - '0') * 10 + (pti[3] - '0');
 
 							if (ses->color >= 256)
 							{
-								pto += sprintf(pto, "\e[38;5;%dm", cnt);
+								pto += sprintf(pto, "\e[22;38;5;%dm", cnt);
 							}
 							else if (ses->color == 16)
 							{
@@ -1595,7 +1650,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 							}
 							pti += sprintf(old, "<g%c%c>", pti[2], pti[3]);
 						}
-						else if (pti[1] == 'G' && isdigit((int) pti[2]) && isdigit((int) pti[3]) && pti[4] == '>')
+						else if (pti[1] == 'G' && is_digit(pti[2]) && is_digit(pti[3]) && pti[4] == '>')
 						{
 							cnt = 232 + (pti[2] - '0') * 10 + (pti[3] - '0');
 
@@ -1614,7 +1669,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 							*pto++ = *pti++;
 						}
 					}
-					else if (toupper((int) pti[1]) == 'F' && isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && pti[5] == '>')
+					else if (toupper((int) pti[1]) == 'F' && is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && pti[5] == '>')
 					{
 						if (ses->color == 4096)
 						{
@@ -1648,7 +1703,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 						}
 						pti += sprintf(old, "<F%c%c%c>", pti[2], pti[3], pti[4]);
 					}
-					else if (toupper((int) pti[1]) == 'F' && isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && isxdigit((int) pti[5]) && isxdigit((int) pti[6]) && isxdigit((int) pti[7]) && pti[8] == '>')
+					else if (toupper((int) pti[1]) == 'F' && is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && is_hex(pti[5]) && is_hex(pti[6]) && is_hex(pti[7]) && pti[8] == '>')
 					{
 						if (ses->color == 4096)
 						{
@@ -1664,7 +1719,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 						}
 						pti += sprintf(old, "<F%c%c%c%c%c%c>", pti[2], pti[3], pti[4], pti[5], pti[6], pti[7]);
 					}
-					else if (toupper((int) pti[1]) == 'B' && isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && pti[5] == '>')
+					else if (toupper((int) pti[1]) == 'B' && is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && pti[5] == '>')
 					{
 						if (ses->color == 4096)
 						{
@@ -1698,7 +1753,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 						}
 						pti += sprintf(old, "<F%c%c%c>", pti[2], pti[3], pti[4]);
 					}
-					else if (toupper((int) pti[1]) == 'B' && isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && isxdigit((int) pti[5]) && isxdigit((int) pti[6]) && isxdigit((int) pti[7]) && pti[8] == '>')
+					else if (toupper((int) pti[1]) == 'B' && is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && is_hex(pti[5]) && is_hex(pti[6]) && is_hex(pti[7]) && pti[8] == '>')
 					{
 						if (ses->color == 4096)
 						{
@@ -1798,6 +1853,7 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 						case 'v':
 							*pto++ = '\v';
 							break;
+
 						case '0':
 							if (pti[1] == 0)
 							{
@@ -1813,13 +1869,31 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 							break;
 
 						case '\0':
+							*pto = 0;
+
 							DEL_BIT(flags, SUB_EOL);
 							DEL_BIT(flags, SUB_LNF);
 							continue;
 
-						default:
+						case '$':
+						case '&':
+						case '*':
+						case '@':
+						case '\\':
 							*pto++ = *pti;
 							break;
+
+						default:
+							if (HAS_BIT(flags, SUB_LIT))
+							{
+								pti--;
+								*pto++ = *pti;
+							}
+							else
+							{
+								*pto++ = *pti;
+							}
+							break;
 					}
 					pti++;
 				}
@@ -1868,6 +1942,20 @@ int substitute(struct session *ses, char *string, char *result, int flags)
 				{
 					switch (*pti)
 					{
+						case '\e':
+							skip = find_secure_color_code(pti);
+
+							if (skip)
+							{
+								pto += sprintf(pto, "%.*s", skip, pti);
+								pti += skip;
+							}
+							else
+							{
+								*pto++ = *pti++;
+							}
+							break;
+
 						case '{':
 							*pto++ = '\\';
 							*pto++ = 'x';
@@ -1916,7 +2004,7 @@ int is_color_code(char *pti)
 		if (pti[4] == '>')
 		{
 
-			if (isdigit((int) pti[1]) && isdigit((int) pti[2]) && isdigit((int) pti[3]))
+			if (is_digit(pti[1]) && is_digit(pti[2]) && is_digit(pti[3]))
 			{
 				return 5;
 			}
@@ -1931,7 +2019,7 @@ int is_color_code(char *pti)
 
 			if (pti[1] == 'g' || pti[1] == 'G')
 			{
-				if (isdigit((int) pti[2]) && isdigit((int) pti[3]))
+				if (is_digit(pti[2]) && is_digit(pti[3]))
 				{
 					return 5;
 				}
@@ -1948,7 +2036,7 @@ int is_color_code(char *pti)
 
 		if (toupper((int) pti[1]) == 'F')
 		{
-			if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && pti[5] == '>')
+			if (is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && pti[5] == '>')
 			{
 				return 6;
 			}
@@ -1956,7 +2044,7 @@ int is_color_code(char *pti)
 			{
 				return 6;
 			}
-			else if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && isxdigit((int) pti[5]) && isxdigit((int) pti[6]) && isxdigit((int) pti[7]) && pti[8] == '>')
+			else if (is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && is_hex(pti[5]) && is_hex(pti[6]) && is_hex(pti[7]) && pti[8] == '>')
 			{
 				return 9;
 			}
@@ -1965,7 +2053,7 @@ int is_color_code(char *pti)
 
 		if (toupper((int) pti[1]) == 'B')
 		{
-			if (isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && pti[5] == '>')
+			if (is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && pti[5] == '>')
 			{
 				return 6;
 			}
@@ -1973,7 +2061,7 @@ int is_color_code(char *pti)
 			{
 				return 6;
 			}
-			if (toupper((int) pti[1]) == 'B' && isxdigit((int) pti[2]) && isxdigit((int) pti[3]) && isxdigit((int) pti[4]) && isxdigit((int) pti[5]) && isxdigit((int) pti[6]) && isxdigit((int) pti[7]) && pti[8] == '>')
+			if (toupper((int) pti[1]) == 'B' && is_hex(pti[2]) && is_hex(pti[3]) && is_hex(pti[4]) && is_hex(pti[5]) && is_hex(pti[6]) && is_hex(pti[7]) && pti[8] == '>')
 			{
 				return 9;
 			}
@@ -2028,7 +2116,7 @@ int is_color_name(char *string)
 				continue;
 		}
 
-		if (isalpha((int) *string))
+		if (is_alpha(*string))
 		{
 			for (cnt = 0 ; *color_table[cnt].name ; cnt++)
 			{
@@ -2116,7 +2204,7 @@ int translate_color_names(struct session *ses, char *string, char *result)
 				continue;
 		}
 
-		if (isalpha((int) *string))
+		if (is_alpha(*string))
 		{
 			for (cnt = 0 ; *color_table[cnt].name ; cnt++)
 			{
@@ -2215,7 +2303,7 @@ int get_color_names(struct session *ses, char *string, char *result)
 				continue;
 		}
 
-		if (isalpha((int) *string))
+		if (is_alpha(*string))
 		{
 			for (cnt = 0 ; *color_table[cnt].name ; cnt++)
 			{

+ 13 - 4
src/system.c

@@ -37,8 +37,8 @@
 #include <dirent.h>
 #include <termios.h>
 #include <sys/un.h>
-
 #include <sys/wait.h>
+#include <signal.h>
 
 DO_COMMAND(do_run)
 {
@@ -79,6 +79,12 @@ DO_COMMAND(do_run)
 			break;
 
 		default:
+/*
+			if (fcntl(desc, F_SETFD, FD_CLOEXEC) == -1)
+			{
+				syserr_printf(ses, "do_run: fcntl");
+			}
+*/
 			sprintf(temp, "{%s} {%d} {%s}", arg2, pid, arg3);
 			ses = new_session(ses, arg1, temp, desc, 0);
 			break;
@@ -166,7 +172,7 @@ DO_COMMAND(do_script)
 
 DO_COMMAND(do_suspend)
 {
-	print_stdout("\e[r\e[%d;%dH", gtd->screen->rows, 1);
+	print_stdout(0, 0, "\e[?1049l\e[r\e[%d;%dH", gtd->screen->rows, 1);
 
 	fflush(NULL);
 
@@ -178,7 +184,7 @@ DO_COMMAND(do_suspend)
 
 	dirty_screen(gtd->ses);
 
-	tintin_puts(NULL, "#RETURNING BACK TO TINTIN++.");
+	tintin_printf(gtd->ses, "#RETURNING BACK TO TINTIN++.");
 
 	return ses;
 }
@@ -290,7 +296,10 @@ DO_COMMAND(do_system)
 		goto_pos(gtd->ses, gtd->ses->split->bot_row, 1);
 	}
 
-	system(arg1);
+	if (system(arg1) == -1)
+	{
+		syserr_printf(ses, "do_system: system:");
+	}
 
 	if (!HAS_BIT(gtd->ses->flags, SES_FLAG_READMUD) && IS_SPLIT(gtd->ses))
 	{

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 402 - 545
src/tables.c


+ 105 - 164
src/telopt_client.c

@@ -29,7 +29,6 @@
 extern  int  client_send_do_eor(struct session *ses, int cplen, unsigned char *cpsrc);
 extern  int  client_mark_prompt(struct session *ses, int cplen, unsigned char *cpsrc);
 extern  int  client_recv_do_naws(struct session *ses, int cplen, unsigned char *cpsrc);
-extern  int  client_send_sb_naws(struct session *ses, int cplen, unsigned char *cpsrc);
 extern  int  client_recv_sb_tspeed(struct session *ses, int cplen, unsigned char *cpsrc);
 extern  int  client_recv_dont_ttype(struct session *ses, int cplen, unsigned char *cpsrc);
 extern  int  client_recv_sb_ttype(struct session *ses, int cplen, unsigned char *cpsrc);
@@ -243,7 +242,7 @@ int client_translate_telopts(struct session *ses, unsigned char *src, int cplen)
 
 	while (cplen > 0)
 	{
-		if (*cpsrc == IAC && HAS_BIT(ses->flags, SES_FLAG_TELNET) && !HAS_BIT(ses->flags, SES_FLAG_RUN))
+		if (*cpsrc == IAC && HAS_BIT(ses->config_flags, CONFIG_FLAG_TELNET) && !HAS_BIT(ses->flags, SES_FLAG_RUN))
 		{
 			skip = 2;
 
@@ -342,7 +341,7 @@ int client_translate_telopts(struct session *ses, unsigned char *src, int cplen)
 					case WILL:
 						if (cplen > 2)
 						{
-							if (!check_all_events(ses, SUB_ARG|SUB_SEC, 1, 0, "IAC WILL %s", telopt_table[cpsrc[2]].name) && !check_all_events(ses, SUB_ARG|SUB_SEC, 1, 0, "CATCH IAC WILL %s", telopt_table[cpsrc[2]].name))
+							if (!check_all_events(ses, EVENT_FLAG_TELNET, 1, 0, "IAC WILL %s", telopt_table[cpsrc[2]].name) && !check_all_events(ses, EVENT_FLAG_CATCH, 1, 0, "CATCH IAC WILL %s", telopt_table[cpsrc[2]].name))
 							{
 								if (!HAS_BIT(ses->telopt_flag[cpsrc[2] / 32], 1 << cpsrc[2] % 32))
 								{
@@ -364,7 +363,7 @@ int client_translate_telopts(struct session *ses, unsigned char *src, int cplen)
 					case DO:
 						if (cplen > 2)
 						{
-							if (!check_all_events(ses, SUB_ARG|SUB_SEC, 1, 0, "IAC DO %s", telopt_table[cpsrc[2]].name) && !check_all_events(ses, SUB_ARG|SUB_SEC, 1, 0, "IAC DO %s", telopt_table[cpsrc[2]].name))
+							if (!check_all_events(ses, EVENT_FLAG_TELNET, 1, 0, "IAC DO %s", telopt_table[cpsrc[2]].name) && !check_all_events(ses, EVENT_FLAG_CATCH, 1, 0, "CATCH IAC DO %s", telopt_table[cpsrc[2]].name))
 							{
 								if (!HAS_BIT(ses->telopt_flag[cpsrc[2] / 32], 1 << cpsrc[2] % 32))
 								{
@@ -387,7 +386,7 @@ int client_translate_telopts(struct session *ses, unsigned char *src, int cplen)
 					case DONT:
 						if (cplen > 2)
 						{
-							check_all_events(ses, SUB_ARG|SUB_SEC, 2, 0, "IAC %s %s", TELCMD(cpsrc[1]), telopt_table[cpsrc[2]].name);
+							check_all_events(ses, EVENT_FLAG_TELNET, 2, 0, "IAC %s %s", TELCMD(cpsrc[1]), telopt_table[cpsrc[2]].name);
 
 							DEL_BIT(ses->telopt_flag[cpsrc[2] / 32], 1 << cpsrc[2] % 32);
 						}
@@ -466,7 +465,7 @@ int client_translate_telopts(struct session *ses, unsigned char *src, int cplen)
 					continue;
 
 				case ASCII_ENQ:
-					if (check_all_events(ses, SUB_ARG, 0, 1, "CATCH VT100 ENQ", gtd->term))
+					if (check_all_events(ses, EVENT_FLAG_TELNET, 0, 1, "CATCH VT100 ENQ", gtd->system->term))
 					{
 						cpsrc++;
 						cplen--;
@@ -474,85 +473,8 @@ int client_translate_telopts(struct session *ses, unsigned char *src, int cplen)
 					}
 					break;
 
-				default:
-					if (cpsrc[0] == ASCII_ESC)
-					{
-						if (cplen >= 2 && cpsrc[1] == 'Z')
-						{
-							check_all_events(ses, SUB_ARG, 0, 0, "VT100 DECID");
-							cpsrc += 2;
-							cplen -= 2;
-							continue;
-						}
-
-						if (cplen >= 3 && cpsrc[1] == '[')
-						{
-							if (cpsrc[2] == 'c')
-							{
-								check_all_events(ses, SUB_ARG, 0, 0, "VT100 DA");
-								cpsrc += 3;
-								cplen -= 3;
-								continue;
-							}
-
-							if (cplen >= 4)
-							{
-								if (cpsrc[2] == '0' && cpsrc[3] == 'c')
-								{
-									check_all_events(ses, SUB_ARG, 0, 0, "VT100 DA");
-									cpsrc += 4;
-									cplen -= 4;
-									continue;
-								}
-								if (cpsrc[2] >= '5' && cpsrc[2] <= '6' && cpsrc[3] == 'n')
-								{
-									if (cpsrc[2] == '5')
-									{
-										check_all_events(ses, SUB_ARG, 0, 0, "VT100 DSR");
-									}
-									if (cpsrc[2] == '6')
-									{
-										check_all_events(ses, SUB_ARG, 0, 2, "VT100 CPR", ntos(gtd->screen->cols), ntos(gtd->screen->rows));
-									}
-									cpsrc += 4;
-									cplen -= 4;
-									continue;
-								}
-								if (cpsrc[2] == '0' && cpsrc[3] == 'c')
-								{
-									check_all_events(ses, SUB_ARG, 0, 0, "VT100 DA");
-									cpsrc += 4;
-									cplen -= 4;
-									continue;
-								}
-							}
-						}
-
-						if (cplen >= 3 && cpsrc[1] == ']')
-						{
-							char osc[BUFFER_SIZE];
-
-							for (skip = 2 ; cplen >= skip ; skip++)
-							{
-								if (cpsrc[skip] == ASCII_BEL)
-								{
-									break;
-								}
-							}
-							sprintf(osc, "%.*s", skip - 2, cpsrc + 2);
-
-							check_all_events(ses, SUB_ARG|SUB_SEC, 0, 1, "VT100 OSC", osc);
-
-							if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 1, "CATCH VT100 OSC", osc))
-							{
-								cpsrc += skip;
-								cplen -= skip;
-
-								continue;
-							}
-						}
-					}
 
+				default:
 					if (HAS_BIT(ses->telopts, TELOPT_FLAG_PROMPT))
 					{
 						DEL_BIT(ses->telopts, TELOPT_FLAG_PROMPT);
@@ -567,6 +489,18 @@ int client_translate_telopts(struct session *ses, unsigned char *src, int cplen)
 							gtd->mud_output_len++;
 						}
 					}
+
+					if (*cpsrc == ASCII_ESC)
+					{
+						skip = catch_vt102_codes(ses, cpsrc, cplen);
+
+						if (skip)
+						{
+							cpsrc += skip;
+							cplen -= skip;
+							continue;
+						}
+					}
 					break;
 			}
 			*cpdst++ = *cpsrc++;
@@ -587,9 +521,9 @@ int client_translate_telopts(struct session *ses, unsigned char *src, int cplen)
 
 int client_recv_will_sga(struct session *ses, int cplen, unsigned char *cpsrc)
 {
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC WILL SGA");
+	check_all_events(ses, EVENT_FLAG_TELNET, 0, 0, "IAC WILL SGA");
 
-	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "CATCH IAC WILL SGA"))
+	if (check_all_events(ses, EVENT_FLAG_CATCH, 0, 0, "CATCH IAC WILL SGA"))
 	{
 		return 3;
 	}
@@ -609,9 +543,9 @@ int client_recv_will_sga(struct session *ses, int cplen, unsigned char *cpsrc)
 
 int client_recv_do_sga(struct session *ses, int cplen, unsigned char *cpsrc)
 {
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC DO SGA");
+	check_all_events(ses, EVENT_FLAG_TELNET, 0, 0, "IAC DO SGA");
 
-	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "CATCH IAC DO SGA"))
+	if (check_all_events(ses, EVENT_FLAG_CATCH, 0, 0, "CATCH IAC DO SGA"))
 	{
 		return 3;
 	}
@@ -632,15 +566,15 @@ int client_recv_do_sga(struct session *ses, int cplen, unsigned char *cpsrc)
 int client_mark_prompt(struct session *ses, int cplen, unsigned char *cpsrc)
 {
 	SET_BIT(ses->telopts, TELOPT_FLAG_PROMPT);
-	SET_BIT(ses->flags, SES_FLAG_AUTOPROMPT);
+	SET_BIT(ses->config_flags, CONFIG_FLAG_AUTOPROMPT);
 
 	if (cpsrc[1] == GA)
 	{
-		check_all_events(ses, SUB_ARG, 0, 0, "IAC GA");
+		check_all_events(ses, EVENT_FLAG_TELNET, 0, 0, "IAC GA");
 	}
 	else if (cpsrc[1] == EOR)
 	{
-		check_all_events(ses, SUB_ARG, 0, 0, "IAC EOR");
+		check_all_events(ses, EVENT_FLAG_TELNET, 0, 0, "IAC EOR");
 	}
 	return 2;
 }
@@ -651,9 +585,9 @@ int client_mark_prompt(struct session *ses, int cplen, unsigned char *cpsrc)
 
 int client_recv_dont_ttype(struct session *ses, int cplen, unsigned char *cpsrc)
 {
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC DONT TTYPE");
+	check_all_events(ses, EVENT_FLAG_TELNET, 0, 0, "IAC DONT TTYPE");
 
-	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "CATCH IAC DONT TTYPE"))
+	if (check_all_events(ses, EVENT_FLAG_CATCH, 0, 0, "CATCH IAC DONT TTYPE"))
 	{
 		return 3;
 	}
@@ -667,9 +601,9 @@ int client_recv_dont_ttype(struct session *ses, int cplen, unsigned char *cpsrc)
 
 int client_recv_sb_ttype(struct session *ses, int cplen, unsigned char *cpsrc)
 {
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 1, "IAC SB TTYPE", ntos(cpsrc[3]));
+	check_all_events(ses, EVENT_FLAG_TELNET, 0, 1, "IAC SB TTYPE", ntos(cpsrc[3]));
 
-	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 1, "CATCH IAC SB TTYPE", ntos(cpsrc[3])))
+	if (check_all_events(ses, EVENT_FLAG_CATCH, 0, 1, "CATCH IAC SB TTYPE", ntos(cpsrc[3])))
 	{
 		return 6;
 	}
@@ -683,7 +617,7 @@ int client_recv_sb_ttype(struct session *ses, int cplen, unsigned char *cpsrc)
 			(HAS_BIT(ses->flags, SES_FLAG_SPLIT) ? 0 : 2) +
 			(HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && !HAS_BIT(ses->charset, CHARSET_FLAG_ALL_TOUTF8) ? 4 : 0) +
 			(ses->color > 16 ? 8 : 0) +
-			(HAS_BIT(ses->flags, SES_FLAG_SCREENREADER) ? 64 : 0) +
+			(HAS_BIT(ses->config_flags, CONFIG_FLAG_SCREENREADER) ? 64 : 0) +
 			(ses->color > 256 ? 256 : 0));
 
 		telnet_printf(ses, 6 + strlen(mtts), "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 0, mtts, IAC, SE);
@@ -692,9 +626,9 @@ int client_recv_sb_ttype(struct session *ses, int cplen, unsigned char *cpsrc)
 	}
 	else if (HAS_BIT(ses->telopts, TELOPT_FLAG_TTYPE))
 	{
-		telnet_printf(ses, 6 + strlen(gtd->term), "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 0, gtd->term, IAC, SE);
+		telnet_printf(ses, 6 + strlen(gtd->system->term), "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 0, gtd->system->term, IAC, SE);
 
-		client_telopt_debug(ses, "SENT IAC SB TTYPE %s", gtd->term);
+		client_telopt_debug(ses, "SENT IAC SB TTYPE %s", gtd->system->term);
 
 		SET_BIT(ses->telopts, TELOPT_FLAG_MTTS);
 	}
@@ -716,9 +650,9 @@ int client_recv_sb_ttype(struct session *ses, int cplen, unsigned char *cpsrc)
 
 int client_recv_sb_tspeed(struct session *ses, int cplen, unsigned char *cpsrc)
 {
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 1, "IAC SB TSPEED", ntos(cpsrc[3]));
+	check_all_events(ses, EVENT_FLAG_TELNET, 0, 1, "IAC SB TSPEED", ntos(cpsrc[3]));
 
-	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 1, "CATCH IAC SB TSPEED", ntos(cpsrc[3])))
+	if (check_all_events(ses, EVENT_FLAG_CATCH, 0, 1, "CATCH IAC SB TSPEED", ntos(cpsrc[3])))
 	{
 		return 6;
 	}
@@ -739,9 +673,9 @@ int client_recv_sb_tspeed(struct session *ses, int cplen, unsigned char *cpsrc)
 
 int client_recv_do_naws(struct session *ses, int cplen, unsigned char *cpsrc)
 {
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC DO NAWS");
+	check_all_events(ses, EVENT_FLAG_TELNET, 0, 0, "IAC DO NAWS");
 
-	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "CATCH IAC DO NAWS"))
+	if (check_all_events(ses, EVENT_FLAG_CATCH, 0, 0, "CATCH IAC DO NAWS"))
 	{
 		return 3;
 	}
@@ -769,9 +703,9 @@ int client_send_sb_naws(struct session *ses, int cplen, unsigned char *cpsrc)
 
 	cols = get_scroll_cols(ses);
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "IAC SB NAWS", ntos(rows), ntos(cols));
+	check_all_events(ses, EVENT_FLAG_TELNET, 0, 2, "IAC SB NAWS", ntos(rows), ntos(cols));
 
-	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "CATCH IAC SB NAWS", ntos(rows), ntos(cols)))
+	if (check_all_events(ses, EVENT_FLAG_CATCH, 0, 2, "CATCH IAC SB NAWS", ntos(rows), ntos(cols)))
 	{
 		return 3;
 	}
@@ -804,9 +738,9 @@ int client_send_sb_naws(struct session *ses, int cplen, unsigned char *cpsrc)
 
 int client_recv_wont_echo(struct session *ses, int cplen, unsigned char *cpsrc)
 {
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC WONT ECHO");
+	check_all_events(ses, EVENT_FLAG_TELNET, 0, 0, "IAC WONT ECHO");
 
-	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "CATCH IAC WONT ECHO"))
+	if (check_all_events(ses, EVENT_FLAG_CATCH, 0, 0, "CATCH IAC WONT ECHO"))
 	{
 		return 3;
 	}
@@ -833,9 +767,9 @@ int client_recv_wont_echo(struct session *ses, int cplen, unsigned char *cpsrc)
 
 int client_recv_will_echo(struct session *ses, int cplen, unsigned char *cpsrc)
 {
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC WILL ECHO");
+	check_all_events(ses, EVENT_FLAG_TELNET, 0, 0, "IAC WILL ECHO");
 
-	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "CATCH IAC WILL ECHO"))
+	if (check_all_events(ses, EVENT_FLAG_CATCH, 0, 0, "CATCH IAC WILL ECHO"))
 	{
 		return 3;
 	}
@@ -861,9 +795,9 @@ int client_recv_will_echo(struct session *ses, int cplen, unsigned char *cpsrc)
 
 int client_recv_do_echo(struct session *ses, int cplen, unsigned char *cpsrc)
 {
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC DO ECHO");
+	check_all_events(ses, EVENT_FLAG_TELNET, 0, 0, "IAC DO ECHO");
 
-	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "CATCH IAC DO ECHO"))
+	if (check_all_events(ses, EVENT_FLAG_CATCH, 0, 0, "CATCH IAC DO ECHO"))
 	{
 		return 3;
 	}
@@ -947,7 +881,7 @@ int client_send_do_telopt(struct session *ses, int cplen, unsigned char *cpsrc)
 
 int client_recv_will_mssp(struct session *ses, int cplen, unsigned char *cpsrc)
 {
-	if (!check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC WILL MSSP") && !check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "CATCH IAC WILL MSSP"))
+	if (!check_all_events(ses, EVENT_FLAG_TELNET, 0, 0, "IAC WILL MSSP") && !check_all_events(ses, EVENT_FLAG_CATCH, 0, 0, "CATCH IAC WILL MSSP"))
 	{
 		if (HAS_BIT(ses->telopts, TELOPT_FLAG_DEBUG))
 		{
@@ -999,8 +933,8 @@ int client_recv_sb_mssp(struct session *ses, int cplen, unsigned char *src)
 
 				client_telopt_debug(ses, "RCVD IAC SB MSSP VAR %-20s VAL %s", var, val);
 
-				check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "IAC SB MSSP", var, val);
-				check_all_events(ses, SUB_ARG|SUB_SEC, 1, 2, "IAC SB MSSP %s", var, var, val);
+				check_all_events(ses, EVENT_FLAG_TELNET, 0, 2, "IAC SB MSSP", var, val);
+				check_all_events(ses, EVENT_FLAG_TELNET, 1, 2, "IAC SB MSSP %s", var, var, val);
 				break;
 
 			default:
@@ -1011,7 +945,7 @@ int client_recv_sb_mssp(struct session *ses, int cplen, unsigned char *src)
 
 	client_telopt_debug(ses, "RCVD IAC SB MSSP IAC SE");
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC SB MSSP IAC SE");
+	check_all_events(ses, EVENT_FLAG_TELNET, 0, 0, "IAC SB MSSP IAC SE");
 
 	return UMIN(i + 1, cplen);
 }
@@ -1105,8 +1039,8 @@ int client_recv_sb_msdp(struct session *ses, int cplen, unsigned char *src)
 					{
 						strip_vt102_codes(val, plain);
 						client_telopt_debug(ses, "RCVD IAC SB MSDP VAR %-20s VAL %s", var, val);
-						check_all_events(ses, SUB_ARG, 1, 3, "IAC SB MSDP %s", var, var, val, plain);
-						check_all_events(ses, SUB_ARG, 0, 3, "IAC SB MSDP", var, val, plain);
+						check_all_events(ses, EVENT_FLAG_TELNET, 1, 3, "IAC SB MSDP %s", var, var, val, plain);
+						check_all_events(ses, EVENT_FLAG_TELNET, 0, 3, "IAC SB MSDP", var, val, plain);
 					}
 					pto = var;
 				}
@@ -1134,8 +1068,8 @@ int client_recv_sb_msdp(struct session *ses, int cplen, unsigned char *src)
 					{
 						strip_vt102_codes(val, plain);
 						client_telopt_debug(ses, "RCVD IAC SB MSDP VAR %-20s VAL %s", var, val);
-						check_all_events(ses, SUB_ARG, 1, 3, "IAC SB MSDP %s", var, var, val, plain);
-						check_all_events(ses, SUB_ARG, 0, 3, "IAC SB MSDP", var, val, plain);
+						check_all_events(ses, EVENT_FLAG_TELNET, 1, 3, "IAC SB MSDP %s", var, var, val, plain);
+						check_all_events(ses, EVENT_FLAG_TELNET, 0, 3, "IAC SB MSDP", var, val, plain);
 					}
 					pto = val;
 				}
@@ -1184,8 +1118,8 @@ int client_recv_sb_msdp(struct session *ses, int cplen, unsigned char *src)
 		{
 			strip_vt102_codes(val, plain);
 			client_telopt_debug(ses, "RCVD IAC SB MSDP VAR %-20s VAL %s", var, val);
-			check_all_events(ses, SUB_ARG, 1, 3, "IAC SB MSDP %s", var, var, val, plain);
-			check_all_events(ses, SUB_ARG, 0, 3, "IAC SB MSDP", var, val, plain);
+			check_all_events(ses, EVENT_FLAG_TELNET, 1, 3, "IAC SB MSDP %s", var, var, val, plain);
+			check_all_events(ses, EVENT_FLAG_TELNET, 0, 3, "IAC SB MSDP", var, val, plain);
 		}
 		i++;
 	}
@@ -1264,8 +1198,8 @@ int client_recv_sb_msdp(struct session *ses, int cplen, unsigned char *src)
 					if (last)
 					{
 						strip_vt102_codes(val, plain);
-						check_all_events(ses, SUB_ARG, 1, 2, "IAC SB MSDP2JSON %s", var, var, plain);
-						check_all_events(ses, SUB_ARG, 0, 2, "IAC SB MSDP2JSON", var, plain);
+						check_all_events(ses, EVENT_FLAG_TELNET, 1, 2, "IAC SB MSDP2JSON %s", var, var, plain);
+						check_all_events(ses, EVENT_FLAG_TELNET, 0, 2, "IAC SB MSDP2JSON", var, plain);
 					}
 					pto = var;
 				}
@@ -1298,8 +1232,8 @@ int client_recv_sb_msdp(struct session *ses, int cplen, unsigned char *src)
 					if (last != MSDP_VAR)
 					{
 						strip_vt102_codes(val, plain);
-						check_all_events(ses, SUB_ARG, 1, 2, "IAC SB MSDP2JSON %s", var, var, plain);
-						check_all_events(ses, SUB_ARG, 0, 2, "IAC SB MSDP2JSON", var, plain);
+						check_all_events(ses, EVENT_FLAG_TELNET, 1, 2, "IAC SB MSDP2JSON %s", var, var, plain);
+						check_all_events(ses, EVENT_FLAG_TELNET, 0, 2, "IAC SB MSDP2JSON", var, plain);
 					}
 					pto = val;
 				}
@@ -1344,15 +1278,15 @@ int client_recv_sb_msdp(struct session *ses, int cplen, unsigned char *src)
 		if (last)
 		{
 			strip_vt102_codes(val, plain);
-			check_all_events(ses, SUB_ARG, 1, 2, "IAC SB MSDP2JSON %s", var, var, plain);
-			check_all_events(ses, SUB_ARG, 0, 2, "IAC SB MSDP2JSON", var, plain);
+			check_all_events(ses, EVENT_FLAG_TELNET, 1, 2, "IAC SB MSDP2JSON %s", var, var, plain);
+			check_all_events(ses, EVENT_FLAG_TELNET, 0, 2, "IAC SB MSDP2JSON", var, plain);
 		}
 		i++;
 	}
 
 	client_telopt_debug(ses, "RCVD IAC SB MSDP IAC SE");
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC SB MSDP IAC SE");
+	check_all_events(ses, EVENT_FLAG_TELNET, 0, 0, "IAC SB MSDP IAC SE");
 
 	return UMIN(i + 1, cplen);
 }
@@ -1407,10 +1341,10 @@ int client_recv_sb_charset(struct session *ses, int cplen, unsigned char *src)
 
 		client_telopt_debug(ses, "RCVD IAC SB CHARSET %s %s", buf, var);
 
-		check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "IAC SB CHARSET", buf, var);
-		check_all_events(ses, SUB_ARG|SUB_SEC, 2, 2, "IAC SB CHARSET %s %s", buf, var, buf, var);
+		check_all_events(ses, EVENT_FLAG_TELNET, 0, 2, "IAC SB CHARSET", buf, var);
+		check_all_events(ses, EVENT_FLAG_TELNET, 2, 2, "IAC SB CHARSET %s %s", buf, var, buf, var);
 
-		if (!check_all_events(ses, SUB_ARG|SUB_SEC, 2, 2, "CATCH IAC SB CHARSET %s %s", buf, var, buf, var))
+		if (!check_all_events(ses, EVENT_FLAG_CATCH, 2, 2, "CATCH IAC SB CHARSET %s %s", buf, var, buf, var))
 		{
 			if (!strcmp(buf, "REQUEST"))
 			{
@@ -1446,7 +1380,7 @@ int client_recv_sb_charset(struct session *ses, int cplen, unsigned char *src)
 				}
 				else if (!strcasecmp(var, "FANSI"))
 				{
-					if (!check_all_events(ses, SUB_ARG|SUB_SEC, 2, 2, "CATCH IAC SB CHARSET %s %s", buf, var, buf, var))
+					if (!check_all_events(ses, EVENT_FLAG_CATCH, 2, 2, "CATCH IAC SB CHARSET %s %s", buf, var, buf, var))
 					{
 						if (HAS_BIT(ses->charset, CHARSET_FLAG_FANSITOUTF8))
 						{
@@ -1464,7 +1398,7 @@ int client_recv_sb_charset(struct session *ses, int cplen, unsigned char *src)
 				}
 				else if (!strcasecmp(var, "ISO-8859-1") || !strcasecmp(var, "ISO-1"))
 				{
-					if (!check_all_events(ses, SUB_ARG|SUB_SEC, 2, 2, "CATCH IAC SB CHARSET %s %s", buf, var, buf, var))
+					if (!check_all_events(ses, EVENT_FLAG_CATCH, 2, 2, "CATCH IAC SB CHARSET %s %s", buf, var, buf, var))
 					{
 						if (HAS_BIT(ses->charset, CHARSET_FLAG_ISO1TOUTF8))
 						{
@@ -1482,7 +1416,7 @@ int client_recv_sb_charset(struct session *ses, int cplen, unsigned char *src)
 				}
 				else if (!strcasecmp(var, "ISO-8859-2") || !strcasecmp(var, "ISO-2"))
 				{
-					if (!check_all_events(ses, SUB_ARG|SUB_SEC, 2, 2, "CATCH IAC SB CHARSET %s %s", buf, var, buf, var))
+					if (!check_all_events(ses, EVENT_FLAG_CATCH, 2, 2, "CATCH IAC SB CHARSET %s %s", buf, var, buf, var))
 					{
 						if (HAS_BIT(ses->charset, CHARSET_FLAG_ISO2TOUTF8))
 						{
@@ -1500,7 +1434,7 @@ int client_recv_sb_charset(struct session *ses, int cplen, unsigned char *src)
 				}
 				else if (!strcasecmp(var, "GBK-1"))
 				{
-					if (!check_all_events(ses, SUB_ARG|SUB_SEC, 2, 2, "CATCH IAC SB CHARSET %s %s", buf, var, buf, var))
+					if (!check_all_events(ses, EVENT_FLAG_CATCH, 2, 2, "CATCH IAC SB CHARSET %s %s", buf, var, buf, var))
 					{
 						if (HAS_BIT(ses->charset, CHARSET_FLAG_GBK1TOUTF8))
 						{
@@ -1523,7 +1457,7 @@ int client_recv_sb_charset(struct session *ses, int cplen, unsigned char *src)
 
 	client_telopt_debug(ses, "RCVD IAC SB CHARSET IAC SE");
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC SB CHARSET IAC SE");
+	check_all_events(ses, EVENT_FLAG_TELNET, 0, 0, "IAC SB CHARSET IAC SE");
 
 	return i + 1;
 }
@@ -1543,7 +1477,7 @@ int get_mtts_val(struct session *ses)
 		+
 		(ses->color > 16 ? 8 : 0)
 		+
-		(HAS_BIT(ses->flags, SES_FLAG_SCREENREADER) ? 64 : 0)
+		(HAS_BIT(ses->config_flags, CONFIG_FLAG_SCREENREADER) ? 64 : 0)
 		+
 //		proxy ? 128 : 0
 //		+
@@ -1622,13 +1556,13 @@ int client_recv_sb_new_environ(struct session *ses, int cplen, unsigned char *sr
 				{
 					client_telopt_debug(ses, "RCVD IAC SB NEW-ENVIRON SEND %s %s", sub2, var);
 
-					check_all_events(ses, SUB_ARG|SUB_SEC, 0, 4, "IAC SB NEW-ENVIRON", sub1, sub2, var, "");
+					check_all_events(ses, EVENT_FLAG_TELNET, 0, 4, "IAC SB NEW-ENVIRON", sub1, sub2, var, "");
 
-					if (!check_all_events(ses, SUB_ARG|SUB_SEC, 0, 4, "CATCH IAC SB NEW-ENVIRON", sub1, sub2, var, ""))
+					if (!check_all_events(ses, EVENT_FLAG_CATCH, 0, 4, "CATCH IAC SB NEW-ENVIRON", sub1, sub2, var, ""))
 					{
-						check_all_events(ses, SUB_ARG|SUB_SEC, 1, 4, "IAC SB NEW-ENVIRON SEND %s", var, sub1, sub2, var, "");
+						check_all_events(ses, EVENT_FLAG_TELNET, 1, 4, "IAC SB NEW-ENVIRON SEND %s", var, sub1, sub2, var, "");
 
-						if (!check_all_events(ses, SUB_ARG|SUB_SEC, 1, 4, "CATCH IAC SB NEW-ENVIRON SEND %s", var, sub1, sub2, var, ""))
+						if (!check_all_events(ses, EVENT_FLAG_CATCH, 1, 4, "CATCH IAC SB NEW-ENVIRON SEND %s", var, sub1, sub2, var, ""))
 						{
 							if (!strcmp(var, ""))
 							{
@@ -1638,7 +1572,7 @@ int client_recv_sb_new_environ(struct session *ses, int cplen, unsigned char *sr
 									client_telopt_debug(ses, "SENT IAC SB NEW-ENVIRON IS VAR %s VAL %s", "CLIENT_NAME", CLIENT_NAME);
 									client_telopt_debug(ses, "SENT IAC SB NEW-ENVIRON IS VAR %s VAL %s", "CLIENT_VERSION", CLIENT_VERSION);
 									client_telopt_debug(ses, "SENT IAC SB NEW-ENVIRON IS VAR MTTS VAL %d", get_mtts_val(ses));
-									client_telopt_debug(ses, "SENT IAC SB NEW-ENVIRON IS VAR TERMINAL_TYPE VAL %s", gtd->term);
+									client_telopt_debug(ses, "SENT IAC SB NEW-ENVIRON IS VAR TERMINAL_TYPE VAL %s", gtd->system->term);
 
 									telnet_printf(ses, -1, "%c%c%c" "%c%c%s%c%s" "%c%c%s%c%s" "%c%c%s%c%s" "%c%c%s%c%d" "%c%c%s%c%s" "%c%c",
 										IAC, SB, TELOPT_NEW_ENVIRON,
@@ -1646,7 +1580,7 @@ int client_recv_sb_new_environ(struct session *ses, int cplen, unsigned char *sr
 										ENV_IS, ENV_VAR, "CLIENT_NAME", ENV_VAL, CLIENT_NAME,
 										ENV_IS, ENV_VAR, "CLIENT_VERSION", ENV_VAL, CLIENT_VERSION,
 										ENV_IS, ENV_VAR, "MTTS", ENV_VAL, get_mtts_val(ses),
-										ENV_IS, ENV_VAR, "TERMINAL_TYPE", ENV_VAL, gtd->term,
+										ENV_IS, ENV_VAR, "TERMINAL_TYPE", ENV_VAL, gtd->system->term,
 										IAC, SE);
 								}
 							}
@@ -1676,9 +1610,9 @@ int client_recv_sb_new_environ(struct session *ses, int cplen, unsigned char *sr
 							}
 							else if (!strcmp(var, "TERMINAL_TYPE"))
 							{
-								telnet_printf(ses, -1, "%c%c%c%c%c%s%c%s%c%c", IAC, SB, TELOPT_NEW_ENVIRON, ENV_IS, ENV_VAR, "TERMINAL_TYPE", ENV_VAL, gtd->term, IAC, SE);
+								telnet_printf(ses, -1, "%c%c%c%c%c%s%c%s%c%c", IAC, SB, TELOPT_NEW_ENVIRON, ENV_IS, ENV_VAR, "TERMINAL_TYPE", ENV_VAL, gtd->system->term, IAC, SE);
 
-								client_telopt_debug(ses, "SENT IAC SB NEW-ENVIRON IS VAR TERMINAL_TYPE VAL %s", gtd->term);
+								client_telopt_debug(ses, "SENT IAC SB NEW-ENVIRON IS VAR TERMINAL_TYPE VAL %s", gtd->system->term);
 							}
 						}
 					}
@@ -1699,8 +1633,8 @@ int client_recv_sb_new_environ(struct session *ses, int cplen, unsigned char *sr
 
 				client_telopt_debug(ses, "RCVD IAC SB NEW-ENVIRON %s %s VAR %s VAL %s", sub1, sub2, var, val);
 
-				check_all_events(ses, SUB_ARG|SUB_SEC, 0, 4, "IAC SB NEW-ENVIRON", sub1, sub2, var, val);
-				check_all_events(ses, SUB_ARG|SUB_SEC, 2, 4, "IAC SB NEW-ENVIRON %s %s", sub1, sub2, sub1, sub2, var, val);
+				check_all_events(ses, EVENT_FLAG_TELNET, 0, 4, "IAC SB NEW-ENVIRON", sub1, sub2, var, val);
+				check_all_events(ses, EVENT_FLAG_TELNET, 2, 4, "IAC SB NEW-ENVIRON %s %s", sub1, sub2, sub1, sub2, var, val);
 				break;
 
 			default:
@@ -1712,7 +1646,7 @@ int client_recv_sb_new_environ(struct session *ses, int cplen, unsigned char *sr
 
 	client_telopt_debug(ses, "RCVD IAC SB NEW-ENVIRON IAC SE");
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC SB NEW-ENVIRON IAC SE");
+	check_all_events(ses, EVENT_FLAG_TELNET, 0, 0, "IAC SB NEW-ENVIRON IAC SE");
 
 	return i + 2;
 }
@@ -1755,7 +1689,7 @@ int client_recv_sb_zmp(struct session *ses, int cplen, unsigned char *src)
 				{
 					client_telopt_debug(ses, "IAC SB ZMP %s", var);
 
-					check_all_events(ses, SUB_ARG|SUB_SEC, 1, 1, "IAC SB ZMP %s", var, val);
+					check_all_events(ses, EVENT_FLAG_TELNET, 1, 1, "IAC SB ZMP %s", var, val);
 				}
 				break;
 		}
@@ -1763,7 +1697,7 @@ int client_recv_sb_zmp(struct session *ses, int cplen, unsigned char *src)
 
 	client_telopt_debug(ses, "IAC SB ZMP %s IAC SE", var);
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 1, 0, "IAC SB ZMP %s IAC SE", var);
+	check_all_events(ses, EVENT_FLAG_TELNET, 1, 0, "IAC SB ZMP %s IAC SE", var);
 
 	return UMIN(i + 1, cplen);
 }
@@ -2021,7 +1955,9 @@ int client_recv_sb_gmcp(struct session *ses, int cplen, unsigned char *src)
 
 	client_telopt_debug(ses, "IAC SB GMCP %s IAC SE", mod);
 
-	check_all_events(ses, SUB_ARG, 1, 2, "IAC SB GMCP %s IAC SE", mod, val, json);
+	check_all_events(ses, EVENT_FLAG_TELNET, 0, 3, "IAC SB GMCP", mod, val, json);
+
+	check_all_events(ses, EVENT_FLAG_TELNET, 1, 2, "IAC SB GMCP %s IAC SE", mod, val, json);
 
 	pop_call();
 	return UMIN(i + 1, cplen);
@@ -2033,14 +1969,14 @@ int client_recv_sb_gmcp(struct session *ses, int cplen, unsigned char *src)
 
 int client_recv_will_mccp2(struct session *ses, int cplen, unsigned char *cpsrc)
 {
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC WILL MCCP2");
+	check_all_events(ses, EVENT_FLAG_TELNET, 0, 0, "IAC WILL MCCP2");
 
-	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "CATCH IAC WILL MCCP2"))
+	if (check_all_events(ses, EVENT_FLAG_CATCH, 0, 0, "CATCH IAC WILL MCCP2"))
 	{
 		return 3;
 	}
 
-	if (HAS_BIT(ses->flags, SES_FLAG_MCCP))
+	if (HAS_BIT(ses->config_flags, CONFIG_FLAG_MCCP))
 	{
 		telnet_printf(ses, 3, "%c%c%c", IAC, DO, TELOPT_MCCP2);
 
@@ -2100,16 +2036,21 @@ void client_end_mccp2(struct session *ses)
 	{
 		return;
 	}
-
+/*
 	ses->mccp2->next_in     = NULL;
 	ses->mccp2->avail_in    = 0;
 
 	ses->mccp2->next_out    = gtd->mccp_buf;
 	ses->mccp2->avail_out   = gtd->mccp_len;
 
-	if (deflateEnd(ses->mccp2) == Z_STREAM_ERROR)
+	if (deflate(ses->mccp2, Z_FINISH) != Z_STREAM_END)
+	{
+		tintin_printf2(ses, "MCCP2: FAILED TO DEFLATE");
+	}
+*/
+	if (inflateEnd(ses->mccp2) == Z_STREAM_ERROR)
 	{
-		client_telopt_debug(ses, "MCCP2: deflateEnd failed:");
+		client_telopt_debug(ses, "MCCP2: inflateEnd failed:");
 	}
 
 	free(ses->mccp2);
@@ -2126,14 +2067,14 @@ void client_end_mccp2(struct session *ses)
 
 int client_recv_will_mccp3(struct session *ses, int cplen, unsigned char *cpsrc)
 {
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC WILL MCCP3");
+	check_all_events(ses, EVENT_FLAG_TELNET, 0, 0, "IAC WILL MCCP3");
 
-	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "CATCH IAC WILL MCCP3"))
+	if (check_all_events(ses, EVENT_FLAG_CATCH, 0, 0, "CATCH IAC WILL MCCP3"))
 	{
 		return 3;
 	}
 
-	if (HAS_BIT(ses->flags, SES_FLAG_MCCP))
+	if (HAS_BIT(ses->config_flags, CONFIG_FLAG_MCCP))
 	{
 		telnet_printf(ses, 3, "%c%c%c", IAC, DO, TELOPT_MCCP3);
 
@@ -2153,9 +2094,9 @@ int client_recv_will_mccp3(struct session *ses, int cplen, unsigned char *cpsrc)
 
 int client_recv_dont_mccp3(struct session *ses, int cplen, unsigned char *cpsrc)
 {
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC DONT MCCP3");
+	check_all_events(ses, EVENT_FLAG_TELNET, 0, 0, "IAC DONT MCCP3");
 
-	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "CATCH IAC DONT MCCP3"))
+	if (check_all_events(ses, EVENT_FLAG_CATCH, 0, 0, "CATCH IAC DONT MCCP3"))
 	{
 	 	return 3;
 	}
@@ -2169,9 +2110,9 @@ int client_recv_dont_mccp3(struct session *ses, int cplen, unsigned char *cpsrc)
 
 int client_recv_wont_mccp3(struct session *ses, int cplen, unsigned char *cpsrc)
 {
-	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "IAC WONT MCCP3");
+	check_all_events(ses, EVENT_FLAG_TELNET, 0, 0, "IAC WONT MCCP3");
 
-	if (check_all_events(ses, SUB_ARG|SUB_SEC, 0, 0, "CATCH IAC WONT MCCP3"))
+	if (check_all_events(ses, EVENT_FLAG_CATCH, 0, 0, "CATCH IAC WONT MCCP3"))
 	{
 	 	return 3;
 	}
@@ -2358,7 +2299,7 @@ int client_recv_sb(struct session *ses, int cplen, unsigned char *cpsrc)
 	*pt1 = 0;
 	*pt2 = 0;
 
-	check_all_events(ses, SUB_ARG|SUB_SEC, 1, 2, "IAC SB %s", telopt_table[cpsrc[2]].name, var1, var2);
+	check_all_events(ses, EVENT_FLAG_TELNET, 1, 2, "IAC SB %s", telopt_table[cpsrc[2]].name, var1, var2);
 
 	return i + 2;
 }

+ 1 - 1
src/telopt_server.c

@@ -553,7 +553,7 @@ int process_sb_ttype_is(struct session *ses, struct port_data *buddy, unsigned c
 				}
 				else
 				{
-					if (sscanf(val, "MTTS %lld", &buddy->mtts_flags) == 1)
+					if (sscanf(val, "MTTS %d", &buddy->mtts_flags) == 1)
 					{
 						if (HAS_BIT(buddy->mtts_flags, MTTS_FLAG_256COLORS))
 						{

+ 12 - 10
src/terminal.c

@@ -64,6 +64,7 @@ void init_terminal(struct session *ses)
 	DEL_BIT(io.c_cflag, CSIZE|PARENB);
 */
 
+
 	DEL_BIT(io.c_lflag, ECHO|ECHONL|IEXTEN|ISIG);
 //	DEL_BIT(io.c_lflag, ECHO|ECHONL|IEXTEN|ISIG);
 
@@ -79,8 +80,7 @@ void init_terminal(struct session *ses)
 		syserr_fatal(-1, "init_terminal: tcgetattr 2");
 	}
 
-	print_stdout("\e=");
-	print_stdout("\e[>4;1m");
+	print_stdout(0, 0, "\e=\e[>4;1m");
 }
 
 void reset_terminal(struct session *ses)
@@ -95,11 +95,9 @@ void reset_terminal(struct session *ses)
 
 	if (HAS_BIT(gtd->flags, TINTIN_FLAG_MOUSETRACKING))
 	{
-		print_stdout("\e[?1000l\e[?1002l\e[?1004l\e[?1006l");
+		print_stdout(0, 0, "\e[?1000l\e[?1002l\e[?1004l\e[?1006l");
 	}
-	print_stdout("\e[?25h");
-	print_stdout("\e[23t");
-	print_stdout("\e[>4n");
+	print_stdout(0, 0, "\e[?25h\e[23t\e[>4n\e[?47l\e[r\e[0#t");
 }
 
 
@@ -155,7 +153,11 @@ void init_terminal_size(struct session *ses)
 			{
 				char buf[100];
 				sprintf(buf, "\e[8;%d;%dt\e[4;%d;%dt\e[7t", screen.ws_row, screen.ws_col, screen.ws_ypixel, screen.ws_xpixel);
-				write(gtd->attach_sock, buf, strlen(buf));
+
+				if (write(gtd->attach_sock, buf, strlen(buf)) == -1)
+				{
+					printf("error: init_terminal_size: write:\n");
+				}
 			}
 		}
 	}
@@ -172,15 +174,15 @@ void init_terminal_size(struct session *ses)
 
 	init_split(ses, ses->split->sav_top_row, ses->split->sav_top_col, ses->split->sav_bot_row, ses->split->sav_bot_col);
 
-	check_all_events(ses, SUB_ARG, 0, 4, "SCREEN RESIZE", ntos(gtd->screen->rows), ntos(gtd->screen->cols), ntos(gtd->screen->height), ntos(gtd->screen->width));
+	check_all_events(ses, EVENT_FLAG_SCREEN, 0, 4, "SCREEN RESIZE", ntos(gtd->screen->rows), ntos(gtd->screen->cols), ntos(gtd->screen->height), ntos(gtd->screen->width));
 
 	if (old_rows <= old_cols / 2 && gtd->screen->rows > gtd->screen->cols / 2)
 	{
-		check_all_events(ses, SUB_ARG, 0, 4, "SCREEN ROTATE PORTRAIT", ntos(gtd->screen->rows), ntos(gtd->screen->cols), ntos(gtd->screen->height), ntos(gtd->screen->width));
+		check_all_events(ses, EVENT_FLAG_SCREEN, 0, 4, "SCREEN ROTATE PORTRAIT", ntos(gtd->screen->rows), ntos(gtd->screen->cols), ntos(gtd->screen->height), ntos(gtd->screen->width));
 	}
 	else if (old_rows >= old_cols / 2 && gtd->screen->rows < gtd->screen->cols / 2)
 	{
-		check_all_events(ses, SUB_ARG, 0, 4, "SCREEN ROTATE LANDSCAPE", ntos(gtd->screen->rows), ntos(gtd->screen->cols), ntos(gtd->screen->height), ntos(gtd->screen->width));
+		check_all_events(ses, EVENT_FLAG_SCREEN, 0, 4, "SCREEN ROTATE LANDSCAPE", ntos(gtd->screen->rows), ntos(gtd->screen->cols), ntos(gtd->screen->height), ntos(gtd->screen->width));
 	}
 
 	msdp_update_all("SCREEN_ROWS",   "%d", gtd->screen->rows);

+ 50 - 25
src/text.c

@@ -33,13 +33,13 @@ void print_line(struct session *ses, char **str, int prompt)
 
 	push_call("print_line(%p,%p,%d)",ses,*str,prompt);
 
-	if (ses->scroll->line != -1 && HAS_BIT(ses->flags, SES_FLAG_SCROLLLOCK))
+	if (ses->scroll->line != -1 && HAS_BIT(ses->config_flags, CONFIG_FLAG_SCROLLLOCK))
 	{
 		pop_call();
 		return;
 	}
 
-	if (HAS_BIT(ses->flags, SES_FLAG_SCAN) && gtd->level->verbose == 0)
+	if (gtd->level->scan && gtd->level->verbose == 0)
 	{
 		pop_call();
 		return;
@@ -47,22 +47,23 @@ void print_line(struct session *ses, char **str, int prompt)
 
 	if (HAS_BIT(ses->flags, SES_FLAG_SPLIT) && ses->wrap != gtd->screen->cols)
 	{
+		SET_BIT(gtd->flags, TINTIN_FLAG_SESSIONUPDATE);
 		SET_BIT(ses->flags, SES_FLAG_PRINTLINE);
 
 		pop_call();
 		return;
 	}
 
-	out = str_alloc(BUFFER_SIZE + strlen(*str));
+	out = str_alloc_stack(strlen(*str) * 2);
 
-	if (HAS_BIT(ses->flags, SES_FLAG_CONVERTMETA) || gtd->level->convert)
+	if (HAS_BIT(ses->config_flags, CONFIG_FLAG_CONVERTMETA) || gtd->level->convert)
 	{
 		convert_meta(*str, out, TRUE);
 
 		str_cpy(str, out);
 	}
 
-	if (HAS_BIT(ses->flags, SES_FLAG_SPLIT) || HAS_BIT(ses->flags, SES_FLAG_WORDWRAP))
+	if (HAS_BIT(ses->flags, SES_FLAG_SPLIT) || HAS_BIT(ses->config_flags, CONFIG_FLAG_WORDWRAP))
 	{
 		word_wrap(ses, *str, out, TRUE, &height, &width);
 	}
@@ -73,21 +74,20 @@ void print_line(struct session *ses, char **str, int prompt)
 
 	if (prompt)
 	{
-		print_stdout("%s", out);
+		print_stdout(0, 0, "%s", out);
 	}
 	else
 	{
-		print_stdout("%s\n", out);
+		print_stdout(0, 0, "%s\n", out);
 	}
-//	add_line_screen(out);
 
-	str_free(out);
+//	add_line_screen(out);
 
 	pop_call();
 	return;
 }
 
-void print_stdout(char *format, ...)
+void print_stdout(int row, int col, char *format, ...)
 {
 	char *buffer;
 	va_list args;
@@ -101,7 +101,10 @@ void print_stdout(char *format, ...)
 	{
 		if (gtd->detach_sock)
 		{
-			write(gtd->detach_sock, buffer, len);
+			if (write(gtd->detach_sock, buffer, len) == -1)
+			{
+				printf("error: print_stdout: write:\n");
+			}
 		}
 	}
 	else
@@ -109,8 +112,12 @@ void print_stdout(char *format, ...)
 		SET_BIT(gtd->flags, TINTIN_FLAG_DISPLAYUPDATE);
 
 		fputs(buffer, stdout);
-	
 //		printf("%s", buffer);
+
+		if (row && col)
+		{
+			set_line_screen(gtd->ses, buffer, row, col);
+		}
 	}
 	free(buffer);
 }
@@ -121,7 +128,7 @@ void print_stdout(char *format, ...)
 
 int word_wrap(struct session *ses, char *textin, char *textout, int flags, int *height, int *width)
 {
-	char color[COLOR_SIZE] = { 0 };
+	char color[COLOR_SIZE];
 	char *pti, *pto, *lis, *los, *chi, *cho;
 	int cur_height, cur_width, size, i, skip, lines, cur_col, tab, wrap, cur_space;
 
@@ -130,12 +137,14 @@ int word_wrap(struct session *ses, char *textin, char *textout, int flags, int *
 	pti = chi = lis = textin;
 	pto = cho = los = textout;
 
-	cur_height   = 1;
+	*color       = 0;
+	cur_height   = 0;
 	lines        = 0;
 	*height      = 0;
 
 	cur_col      = ses->cur_col;
 	ses->cur_col = 1;
+	cur_space    = 1;
 
 	cur_width    = 0;
 	*width       = 0;
@@ -209,7 +218,7 @@ int word_wrap(struct session *ses, char *textin, char *textout, int flags, int *
 		{
 			cur_height++;
 
-			if (HAS_BIT(ses->flags, SES_FLAG_WORDWRAP))
+			if (HAS_BIT(ses->config_flags, CONFIG_FLAG_WORDWRAP))
 			{
 				if (ses->cur_col - cur_space >= 15 || wrap <= 20 || !SCROLL(ses))
 				{
@@ -324,7 +333,7 @@ int word_wrap_split(struct session *ses, char *textin, char *textout, int wrap,
 
 		if (ses->wrap == 0)
 		{
-			print_stdout("debug: word_wrap_split: wrap is 0\n");
+			print_stdout(0, 0, "debug: word_wrap_split: wrap is 0\n");
 			pop_call();
 			return 1;
 		}
@@ -336,17 +345,18 @@ int word_wrap_split(struct session *ses, char *textin, char *textout, int wrap,
 	cur_width  = 0;
 	*width     = 0;
 	cur_col    = 1;
+	cur_space  = cur_col;
 
 	if (HAS_BIT(flags, WRAP_FLAG_SPLIT) && end == 0)
 	{
-		print_stdout("debug: word_wrap_split: end point is 0.");
+		print_stdout(0, 0, "debug: word_wrap_split: end point is 0.");
 	}
 
 	while (*pti && pto - textout < BUFFER_SIZE - 20)
 	{
 		if (cur_height > 10000 || cur_width > 100000)
 		{
-			print_stdout("debug: word_wrap_split: wrap %d height %d width %d los %d start %d end %d\n", wrap, cur_height, cur_width, pto - los, start, end);
+			print_stdout(0, 0, "debug: word_wrap_split: wrap %d height %d width %d los %d start %d end %d\n", wrap, cur_height, cur_width, pto - los, start, end);
 			pop_call();
 			return 1;
 		}
@@ -373,6 +383,14 @@ int word_wrap_split(struct session *ses, char *textin, char *textout, int wrap,
 
 		if (*pti == '\n')
 		{
+			if (!HAS_BIT(flags, WRAP_FLAG_SPLIT) || (cur_height >= start && cur_height < end))
+			{
+				if (cur_width > *width)
+				{
+					*width = cur_width;
+				}
+			}
+
 			lines++;
 			cur_height++;
 
@@ -396,11 +414,6 @@ int word_wrap_split(struct session *ses, char *textin, char *textout, int wrap,
 				}
 			}
 
-			if (cur_width > *width)
-			{
-				*width = cur_width;
-			}
-
 			cur_col = 1;
 			cur_space = 1;
 			cur_width = 0;
@@ -416,9 +429,21 @@ int word_wrap_split(struct session *ses, char *textin, char *textout, int wrap,
 
 		if (cur_col > wrap)
 		{
+			if (!HAS_BIT(flags, WRAP_FLAG_SPLIT) || (cur_height >= start && cur_height < end))
+			{
+				if (wrap > *width)
+				{
+					*width = wrap;
+				}
+			}
+			else
+			{
+				cur_width = 0;
+			}
+
 			cur_height++;
 
-			if (HAS_BIT(ses->flags, SES_FLAG_WORDWRAP))
+			if (HAS_BIT(ses->config_flags, CONFIG_FLAG_WORDWRAP))
 			{
 				if (cur_col - cur_space > 15 || wrap <= 20)
 				{
@@ -509,7 +534,7 @@ int word_wrap_split(struct session *ses, char *textin, char *textout, int wrap,
 			}
 			else
 			{
-				print_stdout("debug: word_wrap_split: utf8 error\n");
+				print_stdout(0, 0, "debug: word_wrap_split: utf8 error\n");
 				*pto++ = *pti++;
 				cur_width++;
 				cur_col++;

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 369 - 297
src/tintin.h


+ 129 - 88
src/tokenize.c

@@ -25,18 +25,7 @@
 
 #include "tintin.h"
 
-
-struct scriptdata
-{
-	long long              min;
-	long long              max;
-	long long              cnt;
-	int                    inc;
-	char                 * cpy;
-	char                 * hlt;
-	char                 * str;
-	char                 * arg;
-};
+extern struct command_type command_table[];
 
 struct scriptnode
 {
@@ -53,6 +42,18 @@ struct scriptnode
 	short                  cmd;
 };
 
+struct scriptdata
+{
+	long long              min;
+	long long              max;
+	long long              cnt;
+	int                    inc;
+	char                 * cpy;
+	char                 * hlt;
+	char                 * str;
+	char                 * arg;
+};
+
 struct script_regex
 {
 	char                 * str;
@@ -69,49 +70,53 @@ void debugtoken(struct session *ses, struct scriptroot *root, struct scriptnode
 	{
 		switch (token->type)
 		{
+			case TOKEN_TYPE_REPEAT:
+				show_debug(ses, root->list, "%s" COLOR_REPEAT "!\e[0m%s", indent(token->lvl + 1), token->str);
+				break;
+
 			case TOKEN_TYPE_STRING:
 			case TOKEN_TYPE_SESSION:
-				show_debug(ses, root->list, "[%02d] %s%s", token->type, indent(token->lvl), token->str);
+				show_debug(ses, root->list, "%s%s", indent(token->lvl + 1), token->str);
 				break;
 
 			case TOKEN_TYPE_ELSE:
 			case TOKEN_TYPE_END:
-				show_debug(ses, root->list, "[%02d] %s" COLOR_STATEMENT "%s\e[0m", token->type, indent(token->lvl), token->str);
+				show_debug(ses, root->list, "%s" COLOR_TINTIN "%c" COLOR_STATEMENT "%s\e[0m", indent(token->lvl + 1), gtd->tintin_char, token->str);
 				break;
 
 			case TOKEN_TYPE_DEFAULT:
-				show_debug(ses, root->list, "[%02d] %s" COLOR_STATEMENT "%s\e[0m", token->type, indent(token->lvl), command_table[token->cmd].name);
+				show_debug(ses, root->list, "%s" COLOR_TINTIN "%c" COLOR_STATEMENT "%s\e[0m", indent(token->lvl + 1), gtd->tintin_char, command_table[token->cmd].name);
 				break;
 
 			case TOKEN_TYPE_BREAK:
 			case TOKEN_TYPE_CONTINUE:
-				show_debug(ses, root->list, "[%02d] %s" COLOR_STATEMENT "%s\e[0m", token->type, indent(token->lvl), command_table[token->cmd].name);
+				show_debug(ses, root->list, "%s" COLOR_TINTIN "%c" COLOR_STATEMENT "%s\e[0m", indent(token->lvl + 1), gtd->tintin_char, command_table[token->cmd].name);
 				break;
 
 			case TOKEN_TYPE_COMMAND:
-				show_debug(ses, root->list, "[%02d] %s" COLOR_COMMAND   "%s " COLOR_STRING "%s\e[0m", token->type, indent(token->lvl), command_table[token->cmd].name, token->str);
+				show_debug(ses, root->list, "%s" COLOR_TINTIN "%c" COLOR_COMMAND   "%s " COLOR_STRING "%s\e[0m", indent(token->lvl + 1), gtd->tintin_char, command_table[token->cmd].name, token->str);
 				break;
 
 			case TOKEN_TYPE_RETURN:
-				show_debug(ses, root->list, "[%02d] %s" COLOR_STATEMENT "%s " COLOR_STRING "%s\e[0m", token->type, indent(token->lvl), command_table[token->cmd].name, token->str);
+				show_debug(ses, root->list, "%s" COLOR_TINTIN "%c" COLOR_STATEMENT "%s " COLOR_STRING "%s\e[0m", indent(token->lvl + 1), gtd->tintin_char, command_table[token->cmd].name, token->str);
 				break;
 
 			case TOKEN_TYPE_CASE:
 			case TOKEN_TYPE_ELSEIF:
 			case TOKEN_TYPE_IF:
 			case TOKEN_TYPE_WHILE:
-				show_debug(ses, root->list, "[%02d] %s" COLOR_STATEMENT "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\e[0m", token->type, indent(token->lvl), command_table[token->cmd].name, token->str);
+				show_debug(ses, root->list, "%s" COLOR_TINTIN "%c" COLOR_STATEMENT "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\e[0m", indent(token->lvl + 1), gtd->tintin_char, command_table[token->cmd].name, token->str);
 				break;
 
 			case TOKEN_TYPE_FOREACH:
 			case TOKEN_TYPE_LOOP:
 			case TOKEN_TYPE_PARSE:
 			case TOKEN_TYPE_SWITCH:
-				show_debug(ses, root->list, "[%02d] %s" COLOR_STATEMENT "%s " COLOR_STRING "%s\e[0m", token->type, indent(token->lvl), command_table[token->cmd].name, token->data->hlt);
+				show_debug(ses, root->list, "%s" COLOR_TINTIN "%c" COLOR_STATEMENT "%s " COLOR_STRING "%s\e[0m", indent(token->lvl + 1), gtd->tintin_char, command_table[token->cmd].name, token->data->hlt);
 				break;
 
 			case TOKEN_TYPE_REGEX:
-				show_debug(ses, root->list, "[%02d] %s" COLOR_STATEMENT "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}\e[0m", token->type, indent(token->lvl), command_table[token->cmd].name, token->str, token->regex->str);
+				show_debug(ses, root->list, "%s" COLOR_TINTIN "%c" COLOR_STATEMENT "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "} {" COLOR_STRING "%s" COLOR_BRACE "}\e[0m", indent(token->lvl + 1), gtd->tintin_char, command_table[token->cmd].name, token->str, token->regex->str);
 				break;
 
 			default:
@@ -121,7 +126,7 @@ void debugtoken(struct session *ses, struct scriptroot *root, struct scriptnode
 				}
 				else
 				{
-					show_debug(ses, root->list, "[%02d] %s\e[1;33m%d {\e[0m%s\e[1;32m}\e[0m", token->type, indent(token->lvl), token->cmd, token->str);
+					show_debug(ses, root->list, "[%02d] %s\e[1;33m%d {\e[0m%s\e[1;32m}\e[0m", token->type, indent(token->lvl + 1), token->cmd, token->str);
 				}
 				break;
 		}
@@ -217,7 +222,9 @@ char *addforeachtoken(struct scriptroot *root, int lvl, int opr, int cmd, char *
 {
 	struct scriptdata *data;
 
-	char arg[BUFFER_SIZE], var[BUFFER_SIZE];
+	char *arg, var[BUFFER_SIZE];
+
+	arg = str_dup(str);
 
 	str = get_arg_in_braces(root->ses, str, arg, GET_ONE);
 	str = get_arg_in_braces(root->ses, str, var, GET_ONE);
@@ -233,6 +240,8 @@ char *addforeachtoken(struct scriptroot *root, int lvl, int opr, int cmd, char *
 
 	root->prev->data = data;
 
+	str_free(arg);
+
 	return str;
 }
 
@@ -262,7 +271,18 @@ void handlereturntoken(struct session *ses, struct scriptnode *token)
 
 	substitute(ses, token->str, arg, SUB_VAR|SUB_FUN);
 
-	set_nest_node_ses(ses, "result", "%s", arg);
+	if (gtd->script_index == 0)
+	{
+		set_nest_node_ses(ses, "result", "%s", arg);
+	}
+	else
+	{
+		DEL_BIT(gtd->flags, TINTIN_FLAG_LOCAL);
+
+		set_nest_node(gtd->script_stack[gtd->script_index - 1]->local, "result", "%s", arg);
+
+		SET_BIT(gtd->flags, TINTIN_FLAG_LOCAL);
+	}
 }
 
 void handleswitchtoken(struct session *ses, struct scriptnode *token)
@@ -376,8 +396,6 @@ char *addregextoken(struct scriptroot *root, int lvl, int type, int cmd, char *s
 
 void deltoken(struct scriptroot *root, struct scriptnode *token)
 {
-	push_call("deltoken(%p,%p)",root,token);
-
 	UNLINK(token, root->next, root->prev);
 
 	free(token->str);
@@ -403,9 +421,6 @@ void deltoken(struct scriptroot *root, struct scriptnode *token)
 	}
 
 	free(token);
-
-	pop_call();
-	return;
 }
 
 
@@ -418,9 +433,9 @@ int find_command(char *command)
 		return -1;
 	}
 
-	if (isalpha((int) *command) && command[1] != 0)
+	if (is_alpha(*command) && command[1] != 0)
 	{
-		for (cmd = gtd->command_ref[tolower((int) *command) - 'a'] ; *command_table[cmd].name ; cmd++)
+		for (cmd = gtd->command_ref[*command % 32] ; *command_table[cmd].name ; cmd++)
 		{
 			if (is_abbrev(command, command_table[cmd].name))
 			{
@@ -450,27 +465,60 @@ struct listroot *local_list(struct session *ses)
 {
 	struct listroot *root;
 
-	push_call("local_list(%p)",ses);
-
 	root = gtd->script_stack[gtd->script_index]->local;
 
-	pop_call();
 	return root;
 }
 
+struct scriptroot *push_script_stack(struct session *ses, int list)
+{
+	struct scriptroot *root;
+
+	root = (struct scriptroot *) calloc(1, sizeof(struct scriptroot));
+
+	root->ses = ses;
+	root->list = list;
+	root->local = init_list(ses, LIST_VARIABLE, LIST_SIZE);
+
+	gtd->script_stack[++gtd->script_index] = root;
+
+	return root;
+}
+
+void pop_script_stack(void)
+{
+	free_list(gtd->script_stack[gtd->script_index]->local);
+
+	free(gtd->script_stack[gtd->script_index]);
+
+	if (--gtd->script_index == 0)
+	{
+		if (HAS_BIT(gtd->flags, TINTIN_FLAG_LOCAL))
+		{
+			kill_list(gtd->script_stack[0]->local);
+
+			DEL_BIT(gtd->flags, TINTIN_FLAG_LOCAL);
+		}
+	}
+}
+
+
 void tokenize_script(struct scriptroot *root, int lvl, char *str)
 {
 	char *arg, *line;
 	int cmd;
 
+	push_call("tokenize_script(%p,%d,%p)",root,lvl,str);
+
 	if (*str == 0)
 	{
 		addtoken(root, lvl, TOKEN_TYPE_STRING, -1, "");
 
+		pop_call();
 		return;
 	}
 
-	line = (char *) calloc(1, UMAX(BUFFER_SIZE, strlen(str)));
+	line = str_alloc_stack(strlen(str));
 
 	while (*str)
 	{
@@ -481,15 +529,25 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 
 		if (*str != gtd->tintin_char)
 		{
-			str = get_arg_all(root->ses, str, line, VERBATIM(root->ses));
+			if (*str == gtd->repeat_char && gtd->level->repeat == 0)
+			{
+				str = get_arg_all(root->ses, str+1, line, VERBATIM(root->ses));
 
-			addtoken(root, lvl, TOKEN_TYPE_STRING, -1, line);
+				addtoken(root, lvl, TOKEN_TYPE_REPEAT, -1, line);
+			}
+			else
+			{
+				str = get_arg_all(root->ses, str, line, VERBATIM(root->ses));
+
+				addtoken(root, lvl, TOKEN_TYPE_STRING, -1, line);
+			}
 		}
 		else
 		{
-			arg = get_arg_stop_spaces(root->ses, str, line, 0);
+//			arg = get_arg_in_braces(root->ses, str+1, line, GET_ONE);
+			arg = sub_arg_in_braces(root->ses, str+1, line, GET_ONE, SUB_VAR|SUB_FUN);
 
-			cmd = find_command(line+1);
+			cmd = find_command(line);
 
 			if (cmd == -1)
 			{
@@ -622,7 +680,7 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 						str = get_arg_in_braces(root->ses, str, line, GET_ALL);
 						tokenize_script(root, lvl--, line);
 
-						addtoken(root, lvl, TOKEN_TYPE_END, -1, "end");
+						addtoken(root, lvl, TOKEN_TYPE_END, -1, "endswitch");
 						break;
 
 					case TOKEN_TYPE_WHILE:
@@ -648,10 +706,9 @@ void tokenize_script(struct scriptroot *root, int lvl, char *str)
 		{
 			str++;
 		}
-
 	}
-
-	free(line);
+	pop_call();
+	return;
 }
 
 
@@ -741,33 +798,33 @@ struct scriptnode *parse_script(struct scriptroot *root, int lvl, struct scriptn
 				continue;
 
 			case TOKEN_TYPE_COMMAND:
-				push_call("do_%s(%p,%p)", command_table[token->cmd].name, root->ses, token->str);
-
-				switch (command_table[token->cmd].args)
+				if (push_call_printf("do_%s(%s,%p)", command_table[token->cmd].name, root->ses->name, token->str))
 				{
-					case 0:
-						root->ses = (*command_table[token->cmd].command) (root->ses, token->str, NULL, NULL, NULL, NULL);
-						break;
-					case 1:
-						root->ses = (*command_table[token->cmd].command) (root->ses, token->str, str_alloc_stack(), NULL, NULL, NULL);
-						break;
-					case 2:
-						root->ses = (*command_table[token->cmd].command) (root->ses, token->str, str_alloc_stack(), str_alloc_stack(), NULL, NULL);
-						break;
-					case 3:
-						root->ses = (*command_table[token->cmd].command) (root->ses, token->str, str_alloc_stack(), str_alloc_stack(), str_alloc_stack(), NULL);
-						break;
-					case 4:
-						root->ses = (*command_table[token->cmd].command) (root->ses, token->str, str_alloc_stack(), str_alloc_stack(), str_alloc_stack(), str_alloc_stack());
-						break;
+					switch (command_table[token->cmd].args)
+					{
+						case 0:
+							root->ses = (*command_table[token->cmd].command) (root->ses, token->str, NULL, NULL, NULL, NULL);
+							break;
+						case 1:
+							root->ses = (*command_table[token->cmd].command) (root->ses, token->str, str_alloc_stack(0), NULL, NULL, NULL);
+							break;
+						case 2:
+							root->ses = (*command_table[token->cmd].command) (root->ses, token->str, str_alloc_stack(0), str_alloc_stack(0), NULL, NULL);
+							break;
+						case 3:
+							root->ses = (*command_table[token->cmd].command) (root->ses, token->str, str_alloc_stack(0), str_alloc_stack(0), str_alloc_stack(0), NULL);
+							break;
+						case 4:
+							tintin_printf2(gtd->ses, "error: parse_script: command_table[%d].command == 4", token->cmd);
+							root->ses = (*command_table[token->cmd].command) (root->ses, token->str, str_alloc_stack(0), str_alloc_stack(0), str_alloc_stack(0), str_alloc_stack(0));
+							break;
+					}
 				}
-
 				pop_call();
 /*
 	return;
 }
 */
-
 				break;
 
 			case TOKEN_TYPE_CONTINUE:
@@ -944,15 +1001,7 @@ struct scriptnode *parse_script(struct scriptroot *root, int lvl, struct scriptn
 			case TOKEN_TYPE_RETURN:
 				handlereturntoken(root->ses, token);
 
-				if (lvl)
-				{
-					return NULL;
-				}
-				else
-				{
-					return (struct scriptnode *) root->ses;
-				}
-				break;
+				goto end;
 
 			case TOKEN_TYPE_SESSION:
 				root->ses = parse_tintin_command(root->ses, token->str);
@@ -962,6 +1011,10 @@ struct scriptnode *parse_script(struct scriptroot *root, int lvl, struct scriptn
 				root->ses = parse_input(root->ses, token->str);
 				break;
 
+			case TOKEN_TYPE_REPEAT:
+				root->ses = repeat_history(root->ses, token->str);
+				break;
+
 			case TOKEN_TYPE_SWITCH:
 				handleswitchtoken(root->ses, token);
 
@@ -992,6 +1045,8 @@ struct scriptnode *parse_script(struct scriptroot *root, int lvl, struct scriptn
 		}
 	}
 
+	end:
+
 	if (lvl)
 	{
 		return NULL;
@@ -1178,27 +1233,14 @@ struct session *script_driver(struct session *ses, int list, char *str)
 
 	push_call("script_driver(%p,%d,%p)",ses,list,str);
 
-	root = (struct scriptroot *) calloc(1, sizeof(struct scriptroot));
-
-	root->ses = ses;
-	root->list = list;
-	root->local = init_list(ses, LIST_VARIABLE, LIST_SIZE);
+	root = push_script_stack(ses, list);
 
 	gtd->level->input += list != LIST_COMMAND;
 
-	gtd->script_stack[++gtd->script_index] = root;
-
 	tokenize_script(root, 0, str);
 
 	ses = (struct session *) parse_script(root, 0, root->next, root->prev);
 
-	if (--gtd->script_index == 0)
-	{
-		DEL_BIT(gtd->flags, TINTIN_FLAG_LOCAL);
-
-//		gtd->memory_index->len = 0;
-	}
-
 	gtd->level->input -= list != LIST_COMMAND;
 
 	while (root->prev)
@@ -1206,8 +1248,7 @@ struct session *script_driver(struct session *ses, int list, char *str)
 		deltoken(root, root->prev);
 	}
 
-	free_list(root->local);
-	free(root);
+	pop_script_stack();
 
 	if (HAS_BIT(ses->flags, SES_FLAG_CLOSED))
 	{

+ 75 - 37
src/trigger.c

@@ -46,6 +46,11 @@ DO_COMMAND(do_action)
 	}
 	else
 	{
+		if (*arg3 && (atof(arg3) < 1 || atof(arg3) >= 10))
+		{
+			show_error(ses, LIST_ACTION, "\e[1;31m#ERROR: #ACTION {%s} {..} {%s} SHOULD HAVE A PRIORITY BETWEEN 1.000 and 9.999.", arg1, arg3);
+		}
+
 		update_node_list(ses->list[LIST_ACTION], arg1, arg2, arg3, "");
 
 		show_message(ses, LIST_ACTION, "#OK. #ACTION {%s} NOW TRIGGERS {%s} @ {%s}.", arg1, arg2, arg3);
@@ -62,11 +67,10 @@ DO_COMMAND(do_unaction)
 }
 
 
-void check_all_actions(struct session *ses, char *original, char *line)
+void check_all_actions(struct session *ses, char *original, char *line, char *buf)
 {
 	struct listroot *root = ses->list[LIST_ACTION];
 	struct listnode *node;
-	char buf[BUFFER_SIZE];
 
 	for (root->update = 0 ; root->update < root->used ; root->update++)
 	{
@@ -135,7 +139,7 @@ int check_all_aliases(struct session *ses, char *input)
 {
 	struct listnode *node;
 	struct listroot *root;
-	char tmp[BUFFER_SIZE], line[BUFFER_SIZE], *arg;
+	char *buf, *line, *arg;
 	int i;
 
 	root = ses->list[LIST_ALIAS];
@@ -145,6 +149,15 @@ int check_all_aliases(struct session *ses, char *input)
 		return FALSE;
 	}
 
+	if (push_call_printf("check_all_aliases(%s,%s)",ses->name,input) == 0)
+	{
+		pop_call();
+		return FALSE;
+	}
+
+	buf  = str_alloc_stack(0);
+	line = str_alloc_stack(0);
+
 	substitute(ses, input, line, SUB_VAR|SUB_FUN);
 
 	for (root->update = 0 ; root->update < root->used ; root->update++)
@@ -174,9 +187,9 @@ int check_all_aliases(struct session *ses, char *input)
 
 				for (i = 1 ; i < 100 ; i++)
 				{
-					arg = get_arg_in_braces(ses, arg, tmp, GET_ONE);
+					arg = get_arg_in_braces(ses, arg, buf, GET_ONE);
 
-					RESTRING(gtd->vars[i], tmp);
+					RESTRING(gtd->vars[i], buf);
 
 					if (*arg == 0)
 					{
@@ -193,15 +206,15 @@ int check_all_aliases(struct session *ses, char *input)
 				}
 			}
 
-			substitute(ses, node->arg2, tmp, SUB_ARG);
+			substitute(ses, node->arg2, buf, SUB_ARG);
 
-			if (!strncmp(node->arg1, line, strlen(node->arg1)) && !strcmp(node->arg2, tmp) && *gtd->vars[0])
+			if (!strncmp(node->arg1, line, strlen(node->arg1)) && !strcmp(node->arg2, buf) && *gtd->vars[0])
 			{
-				sprintf(input, "%s %s", tmp, gtd->vars[0]);
+				sprintf(input, "%s %s", buf, gtd->vars[0]);
 			}
 			else
 			{
-				sprintf(input, "%s", tmp);
+				sprintf(input, "%s", buf);
 			}
 
 			show_debug(ses, LIST_ALIAS, "#DEBUG ALIAS {%s} {%s}", node->arg1, gtd->vars[0]);
@@ -210,9 +223,11 @@ int check_all_aliases(struct session *ses, char *input)
 			{
 				delete_node_list(ses, LIST_ALIAS, node);
 			}
+			pop_call();
 			return TRUE;
 		}
 	}
+	pop_call();
 	return FALSE;
 }
 
@@ -246,6 +261,7 @@ DO_COMMAND(do_button)
 	}
 	else
 	{
+		SET_BIT(gtd->event_flags, EVENT_FLAG_MOUSE);
 		SET_BIT(ses->event_flags, EVENT_FLAG_MOUSE);
 
 		node = update_node_list(ses->list[LIST_BUTTON], arg1, arg2, arg3, "");
@@ -290,7 +306,7 @@ DO_COMMAND(do_unbutton)
 
 void check_all_buttons(struct session *ses, short row, short col, char *arg1, char *arg2, char *word, char *line)
 {
-	char buf[BUFFER_SIZE], arg4[BUFFER_SIZE];
+	char *buf, *arg4;
 	struct listnode *node;
 	struct listroot *root;
 	short val[4];
@@ -302,6 +318,11 @@ void check_all_buttons(struct session *ses, short row, short col, char *arg1, ch
 		return;
 	}
 
+	push_call("check_all_buttons(%p,%d,%d,%p,%p,%p,%p)",ses,row,col,arg1,arg2,word,line);
+
+	buf  = str_alloc_stack(0);
+	arg4 = str_alloc_stack(0);
+
 	sprintf(arg4, "%s %s", arg1, arg2);
 
 	show_info(ses, LIST_BUTTON, "#INFO BUTTON {%d;%d;%d;%d;%s}", row, col, -1 - (gtd->screen->rows - row), -1 - (gtd->screen->cols - col), arg4);
@@ -345,9 +366,11 @@ void check_all_buttons(struct session *ses, short row, short col, char *arg1, ch
 			}
 			script_driver(ses, LIST_BUTTON, buf);
 
-			return;
+			break;
 		}
 	}
+	pop_call();
+	return;
 }
 
 
@@ -384,7 +407,7 @@ DO_COMMAND(do_delay)
 
 			get_number_string(ses, arg1, time);
 
-			update_node_list(ses->list[LIST_DELAY], arg3, arg2, time, "");
+			create_node_list(ses->list[LIST_DELAY], arg3, arg2, arg3, time);
 
 			show_message(ses, LIST_DELAY, "#OK, IN {%s} SECONDS {%s} IS EXECUTED.", time, arg2);
 		}
@@ -398,7 +421,7 @@ DO_COMMAND(do_delay)
 
 			node->shots = 1;
 
-			show_message(ses, LIST_TICKER, "#OK. #TICK {%s} WILL EXECUTE {%s} IN {%s} SECONDS.", arg1, arg2, time);
+			show_message(ses, LIST_TICKER, "#ONESHOT: #TICK {%s} WILL EXECUTE {%s} IN {%s} SECONDS.", arg1, arg2, time);
 		}
 	}
 	return ses;
@@ -408,7 +431,7 @@ DO_COMMAND(do_undelay)
 {
 	sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 
-	if (isalpha((int) *arg1))
+	if (is_alpha(*arg1))
 	{
 		delete_node_with_wild(ses, LIST_TICKER, arg);
 	}
@@ -578,11 +601,16 @@ void check_all_highlights(struct session *ses, char *original, char *line)
 	struct listroot *root = ses->list[LIST_HIGHLIGHT];
 	struct listnode *node;
 	char *pto, *ptl, *ptm;
-	char match[BUFFER_SIZE], color[BUFFER_SIZE], reset[BUFFER_SIZE], output[BUFFER_SIZE], plain[BUFFER_SIZE];
+	char *match, *color, *output, *plain;
 	int len;
 
 	push_call("check_all_highlights(%p,%p,%p)",ses,original,line);
 
+	match  = str_alloc_stack(0);
+	color  = str_alloc_stack(0);
+	output = str_alloc_stack(0);
+	plain  = str_alloc_stack(0);
+
 	for (root->update = 0 ; root->update < root->used ; root->update++)
 	{
 		node = root->list[root->update];
@@ -591,7 +619,7 @@ void check_all_highlights(struct session *ses, char *original, char *line)
 		{
 			get_color_names(ses, node->arg2, color);
 
-			*output = *reset = 0;
+			*output = *gtd->color_reset = 0;
 
 			pto = original;
 			ptl = line;
@@ -622,9 +650,9 @@ void check_all_highlights(struct session *ses, char *original, char *line)
 
 				*ptm = 0;
 
-				get_color_codes(reset, pto, reset, GET_ALL);
+				get_color_codes(gtd->color_reset, pto, gtd->color_reset, GET_ALL);
 
-				cat_sprintf(output, "%s%s%s\e[0m%s", pto, color, plain, reset);
+				cat_sprintf(output, "%s%s%s\e[0m%s", pto, color, plain, gtd->color_reset);
 
 				pto = ptm + len;
 
@@ -657,7 +685,6 @@ DO_COMMAND(do_macro)
 {
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
-//	arg = get_arg_in_braces(ses, arg, arg3, GET_ALL);
 
 	if (*arg1 == 0)
 	{
@@ -672,9 +699,9 @@ DO_COMMAND(do_macro)
 	}
 	else
 	{
-		tintin_macro_compile(arg1, arg4);
+		tintin_macro_compile(arg1, arg3);
 
-		update_node_list(ses->list[LIST_MACRO], arg1, arg2, "", arg4);
+		update_node_list(ses->list[LIST_MACRO], arg1, arg2, "", arg3);
 
 		show_message(ses, LIST_MACRO, "#OK. MACRO {%s} NOW TRIGGERS {%s}.", arg1, arg2);
 	}
@@ -717,6 +744,9 @@ DO_COMMAND(do_prompt)
 	}
 	else
 	{
+		arg3 = str_alloc_stack(0);
+		arg4 = str_alloc_stack(0);
+
 		arg = sub_arg_in_braces(ses, arg, arg3, GET_ONE, SUB_VAR|SUB_FUN);
 		arg = sub_arg_in_braces(ses, arg, arg4, GET_ONE, SUB_VAR|SUB_FUN);
 
@@ -736,12 +766,12 @@ DO_COMMAND(do_unprompt)
 }
 
 
-int check_all_prompts(struct session *ses, char *original, char *line, int check)
+int check_all_prompts(struct session *ses, char *original, char *line)
 {
 	struct listroot *root = ses->list[LIST_PROMPT];
 	struct listnode *node;
 
-	if (check && !HAS_BIT(ses->flags, SES_FLAG_SPLIT))
+	if (!HAS_BIT(ses->flags, SES_FLAG_SPLIT))
 	{
 		return 0;
 	}
@@ -752,22 +782,17 @@ int check_all_prompts(struct session *ses, char *original, char *line, int check
 
 		if (check_one_regexp(ses, node, line, original, 0))
 		{
-			if (!check)
-			{
-				return TRUE;
-			}
-
 			if (*node->arg2)
 			{
-				substitute(ses, node->arg2, original, SUB_ARG);
-				substitute(ses, original, original, SUB_VAR|SUB_FUN|SUB_COL|SUB_ESC);
+				substitute(ses, node->arg2, line, SUB_ARG);
+				substitute(ses, line, original, SUB_VAR|SUB_FUN|SUB_COL|SUB_ESC);
 
 				strip_vt102_codes(original, line);
 			}
 
 			show_debug(ses, LIST_PROMPT, "#DEBUG PROMPT {%s}", node->arg1);
 
-			split_show(ses, original, atoi(node->arg3), atoi(node->arg4));
+			split_show(ses, original, node->arg3, node->arg4);
 
 			if (node->shots && --node->shots == 0)
 			{
@@ -826,11 +851,18 @@ DO_COMMAND(do_unsubstitute)
 
 void check_all_substitutions(struct session *ses, char *original, char *line)
 {
-	char match[BUFFER_SIZE], subst[BUFFER_SIZE], output[BUFFER_SIZE], temp[BUFFER_SIZE], *ptl, *ptm, *pto;
+	char *match, *subst, *result, *temp, *ptl, *ptm, *pto, *ptr;
 	struct listroot *root = ses->list[LIST_SUBSTITUTE];
 	struct listnode *node;
 	int len;
 
+	push_call("check_all_substitutions(%p,%p,%p)",ses,original,line);
+
+	match  = str_alloc_stack(0);
+	subst  = str_alloc_stack(0);
+	result = str_alloc_stack(0);
+	temp   = str_alloc_stack(0);
+	
 	for (root->update = 0 ; root->update < root->used ; root->update++)
 	{
 		node = root->list[root->update];
@@ -839,8 +871,9 @@ void check_all_substitutions(struct session *ses, char *original, char *line)
 		{
 			pto = original;
 			ptl = line;
+			ptr = result;
 
-			*output = 0;
+			*result = *gtd->color_reset = 0;
 
 			do
 			{
@@ -852,7 +885,6 @@ void check_all_substitutions(struct session *ses, char *original, char *line)
 				strcpy(match, gtd->vars[0]);
 
 				substitute(ses, node->arg2, temp, SUB_ARG);
-				substitute(ses, temp, subst, SUB_VAR|SUB_FUN|SUB_COL|SUB_ESC);
 
 				if (*node->arg1 == '~')
 				{
@@ -869,7 +901,11 @@ void check_all_substitutions(struct session *ses, char *original, char *line)
 
 				*ptm = 0;
 
-				cat_sprintf(output, "%s%s", pto, subst);
+				get_color_codes(gtd->color_reset, pto, gtd->color_reset, GET_ALL);
+
+				substitute(ses, temp, subst, SUB_VAR|SUB_FUN|SUB_COL|SUB_ESC);
+
+				ptr += sprintf(ptr, "%s%s", pto, subst);
 
 				pto = ptm + len;
 
@@ -881,13 +917,15 @@ void check_all_substitutions(struct session *ses, char *original, char *line)
 			{
 				delete_node_list(ses, LIST_SUBSTITUTE, node);
 			}
-			strcat(output, pto);
+			strcpy(ptr, pto);
 
-			strcpy(original, output);
+			strcpy(original, result);
 
 			strip_vt102_codes(original, line);
 		}
 	}
+	pop_call();
+	return;
 }
 
 

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 364 - 208
src/update.c


+ 45 - 44
src/utf8.c

@@ -95,13 +95,13 @@ int linear_search(struct interval_type *table, int size, int key)
 	{
 		if (table[i].head > table[i].tail)
 		{
-			print_stdout("table[%d].head < table[%d].tail\n", i, i);
+			print_stdout(0, 0, "table[%d].head < table[%d].tail\n", i, i);
 		}
 		if (i < size - 1)
 		{
 			if (table[i].head >= table[i+1].head)
 			{
-				print_stdout("table[%d].head >= table[%d].head\n", i, i+1);
+				print_stdout(0, 0, "table[%d].head >= table[%d].head\n", i, i+1);
 			}
 		}
 	}
@@ -254,13 +254,13 @@ int get_utf8_size(char *str)
 	};
 	unsigned char *ptu = (unsigned char *) str;
 
-	switch (utf8_size[*ptu])
+	if (*ptu < 128)
 	{
-		case 0:
-			return 1;
-		case 1:
-			return 1;
+		return 1;
+	}
 
+	switch (utf8_size[*ptu])
+	{
 		case 2:
 			if (utf8_size[ptu[1]])
 			{
@@ -286,31 +286,41 @@ int get_utf8_size(char *str)
 	}
 }
 
+unsigned char utf8_width_table[256] =
+{
+	0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
+	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+	2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+	3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
+};
+
+int get_ascii_width(char *str, int *width)
+{
+	*width = utf8_width_table[(unsigned char) *str] ? 1 : 0;
+
+	return 1;
+}
+
 int get_utf8_width(char *str, int *width)
 {
-	static char utf8_width[256] =
-	{
-		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-		1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-		1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-		1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
-		1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-		1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-		2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-		3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
-	};
 	int size, index;
-	unsigned char *ptu = (unsigned char *) str;
+	unsigned char *ptu;
+
+	*width = size = utf8_width_table[(unsigned char) *str];
 
-	index = (int) *ptu;
+	if (size <= 1)
+	{
+		return 1;
+	}
 
-	*width = size = utf8_width[index];
+	ptu = (unsigned char *) str;
 
 	switch (*width)
 	{
-		case 0:
-		case 1:
-			return 1;
 		case 2:
 			if (get_utf8_size(str) != 2)
 			{
@@ -343,29 +353,18 @@ int get_utf8_width(char *str, int *width)
 
 int get_utf8_index(char *str, int *index)
 {
-	static unsigned char utf8_width[256] =
-	{
-		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-		1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-		1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-		1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
-		1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-		1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-		2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-		3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,1,1,1,1,1,1,1,1
-	};
 	int size, width;
 	unsigned char *ptu = (unsigned char *) str;
 
 	*index = (int) *ptu;
 
-	width = size = utf8_width[*index];
+	width = size = utf8_width_table[*index];
 
 	switch (width)
 	{
-		case 0:
-		case 1:
+		default:
 			return 1;
+
 		case 2:
 			if (get_utf8_size(str) != 2)
 			{
@@ -435,19 +434,21 @@ int unicode_to_utf8(int index, char *out)
 	}
 }
 
-int utf8_strlen(char *str)
+int utf8_strlen(char *str, int *str_len)
 {
-	int total, width;
+	int raw_len, size, width;
 
-	total = 0;
+	raw_len = *str_len = 0;
 
 	while (*str)
 	{
-		str += get_utf8_width(str, &width);
+		size = get_utf8_width(str, &width);
 
-		total += width;
+		*str_len += width;
+		raw_len += size;
 	}
-	return total;
+
+	return raw_len;
 }
 
 int utf8_to_all(struct session *ses, char *in, char *out)

+ 146 - 38
src/utils.c

@@ -29,7 +29,7 @@
 
 int hex_digit(char *str)
 {
-	if (isdigit((int) *str))
+	if (is_digit(*str))
 	{
 		return *str - '0';
 	}
@@ -45,7 +45,27 @@ unsigned long long hex_number_64bit(char *str)
 
 	for (len = 0 ; len < 16 ; len++)
 	{
-		if (!isxdigit((int) str[len]))
+		if (!is_hex(str[len]))
+		{
+			break;
+		}
+	}
+
+	for (mul = 1 ; len > 0 ; mul *= 16)
+	{
+		val += mul * hex_digit(str + --len);
+	}
+
+	return val;
+}
+
+unsigned int hex_number_32bit(char *str)
+{
+	unsigned long long len, mul, val = 0;
+
+	for (len = 0 ; len < 8 ; len++)
+	{
+		if (!is_hex(str[len]))
 		{
 			break;
 		}
@@ -65,7 +85,7 @@ int hex_number_8bit(char *str)
 
 	if (str)
 	{
-		if (isdigit((int) *str))
+		if (is_digit(*str))
 		{
 			value += 16 * (*str - '0');
 		}
@@ -78,7 +98,7 @@ int hex_number_8bit(char *str)
 
 	if (str)
 	{
-		if (isdigit((int) *str))
+		if (is_digit(*str))
 		{
 			value += *str - '0';
 		}
@@ -98,7 +118,7 @@ int oct_number(char *str)
 
 	if (str)
 	{
-		if (isdigit((int) *str))
+		if (is_digit(*str))
 		{
 			value += 8 * (*str - '0');
 		}
@@ -107,7 +127,7 @@ int oct_number(char *str)
 
 	if (str)
 	{
-		if (isdigit((int) *str))
+		if (is_digit(*str))
 		{
 			value += *str - '0';
 		}
@@ -122,7 +142,10 @@ int unicode_16_bit(char *str, char *out)
 	int val = 0;
 	unsigned char *pto = (unsigned char *) out;
 
-	if (isdigit((int) *str))
+	val += 4096 * hex_digit(str);
+
+/*
+	if (is_digit(*str))
 	{
 		val += 4096 * (*str - '0');
 	}
@@ -130,9 +153,13 @@ int unicode_16_bit(char *str, char *out)
 	{
 		val += 4096 * (toupper((int) *str) - 'A' + 10);
 	}
+*/
 	str++;
 
-	if (isdigit((int) *str))
+	val += 256 * hex_digit(str);
+
+/*
+	if (is_digit(*str))
 	{
 		val += 256 * (*str - '0');
 	}
@@ -140,9 +167,12 @@ int unicode_16_bit(char *str, char *out)
 	{
 		val += 256 * (toupper((int) *str) - 'A' + 10);
 	}
+*/
 	str++;
 
-	if (isdigit((int) *str))
+	val += 16 * hex_digit(str);
+/*
+	if (is_digit(*str))
 	{
 		val += 16 * (*str - '0');
 	}
@@ -150,9 +180,12 @@ int unicode_16_bit(char *str, char *out)
 	{
 		val += 16 * (toupper((int) *str) - 'A' + 10);
 	}
+*/
 	str++;
 
-	if (isdigit((int) *str))
+	val += hex_digit(str);
+/*
+	if (is_digit(*str))
 	{
 		val += (*str - '0');
 	}
@@ -160,6 +193,7 @@ int unicode_16_bit(char *str, char *out)
 	{
 		val += (toupper((int) *str) - 'A' + 10);
 	}
+*/
 	str++;
 
 	if (val < 128)
@@ -192,7 +226,7 @@ int unicode_21_bit(char *str, char *out)
 
 	if (str)
 	{
-		if (isdigit((int) *str))
+		if (is_digit(*str))
 		{
 			val += 1048576 * (*str - '0');
 		}
@@ -205,7 +239,7 @@ int unicode_21_bit(char *str, char *out)
 
 	if (str)
 	{
-		if (isdigit((int) *str))
+		if (is_digit(*str))
 		{
 			val += 65536 * (*str - '0');
 		}
@@ -218,7 +252,7 @@ int unicode_21_bit(char *str, char *out)
 
 	if (str)
 	{
-		if (isdigit((int) *str))
+		if (is_digit(*str))
 		{
 			val += 4096 * (*str - '0');
 		}
@@ -231,7 +265,7 @@ int unicode_21_bit(char *str, char *out)
 
 	if (str)
 	{
-		if (isdigit((int) *str))
+		if (is_digit(*str))
 		{
 			val += 256 * (*str - '0');
 		}
@@ -244,7 +278,7 @@ int unicode_21_bit(char *str, char *out)
 
 	if (str)
 	{
-		if (isdigit((int) *str))
+		if (is_digit(*str))
 		{
 			val += 16 * (*str - '0');
 		}
@@ -257,7 +291,7 @@ int unicode_21_bit(char *str, char *out)
 
 	if (str)
 	{
-		if (isdigit((int) *str))
+		if (is_digit(*str))
 		{
 			val += (*str - '0');
 		}
@@ -310,35 +344,70 @@ int unicode_21_bit(char *str, char *out)
 unsigned long long utime()
 {
 	struct timeval now_time;
+	unsigned long long utime;
 
 	gettimeofday(&now_time, NULL);
 
-	if (gtd->utime >= now_time.tv_sec * 1000000ULL + now_time.tv_usec)
+	utime = now_time.tv_sec * 1000000ULL + now_time.tv_usec;
+
+	if (gtd->utime >= utime)
 	{
 		gtd->utime++;
 	}
 	else
 	{
-		gtd->utime = now_time.tv_sec * 1000000ULL + now_time.tv_usec;
+		gtd->utime = utime;
 	}
+
 	return gtd->utime;
 }
 
+time_t get_time(struct session *ses, char *str)
+{
+	unsigned long long time = get_ulong(ses, str);
+
+	if (time >= 1000000000LL * 1000000LL)
+	{
+		time /= 1000000;
+	}
+
+	return time;
+}
+
+char *str_time(struct session *ses, char *format, time_t time)
+{
+	static char buf[10][NAME_SIZE];
+	static int cnt;
+	struct tm timeval_tm;
+
+	cnt = (cnt + 1) % 10;
+
+	timeval_tm = *localtime(&time);
+
+	strftime(buf[cnt], NAME_SIZE, format, &timeval_tm);
+
+	return buf[cnt];
+}
+	
 void seed_rand(struct session *ses, unsigned long long seed)
 {
 	ses->rand = seed % 4294967291ULL;
 	ses->rkey = seed % 5;
+
+	srand(ses->rand);
 }
 
 unsigned long long generate_rand(struct session *ses)
 {
-	static unsigned long long primes[] = {26196137413795067, 1062272168593625449, 5189794811, 237506310434573, 212938855558633 };
+	static unsigned long long primes[] = {26196137413795067, 1062272168593625449, 5189794811, 237506310434573, 212938855558633, 51741641338759 };
 
-	if (ses->rkey % 3 == 1)
+	return rand();
+
+/*	if (ses->rkey % 3 == 1)
 	{
 		ses->rand += 316595909ULL + primes[++ses->rkey % 5];
 	}
-	else
+	else*/
 	{
 		ses->rand += primes[++ses->rkey % 5];
 	}
@@ -362,7 +431,7 @@ uint32_t lcg_rand(uint32_t *state)
 */
 char *capitalize(char *str)
 {
-	static char outbuf[BUFFER_SIZE];
+	char *outbuf = str_alloc_stack(0);
 	int cnt;
 
 	for (cnt = 0 ; str[cnt] != 0 ; cnt++)
@@ -374,6 +443,34 @@ char *capitalize(char *str)
 	return outbuf;
 }
 
+char *ftos(float number)
+{
+	static char outbuf[10][NUMBER_SIZE];
+	static int cnt;
+	int len;
+
+	cnt = (cnt + 1) % 10;
+
+	sprintf(outbuf[cnt], "%f", number);
+
+	for (len = strlen(outbuf[cnt]) - 1 ; len ; len--)
+	{
+		if (outbuf[cnt][len] == '0')
+		{
+			outbuf[cnt][len] = 0;
+		}
+		else
+		{
+			if (outbuf[cnt][len] == '.')
+			{
+				outbuf[cnt][len] = 0;
+			}
+			break;
+		}
+	}
+	return outbuf[cnt];
+}
+
 char *ntos(long long number)
 {
 	static char outbuf[10][NUMBER_SIZE];
@@ -402,16 +499,16 @@ char *indent_one(int len)
 
 char *indent(int len)
 {
-	static char outbuf[10][STACK_SIZE];
-	static int cnt;
-
-	cnt = (cnt + 1) % 10;
+	static char outbuf[21][101];
 
-	memset(outbuf[cnt], ' ', UMAX(1, len * 5));
+	len = URANGE(0, len, 20);
 
-	outbuf[cnt][len * 5] = 0;
+	if (outbuf[len][0] == 0)
+	{
+		sprintf(outbuf[len], "%*s", len * 5, "");
+	}
 
-	return outbuf[cnt];
+	return outbuf[len];
 }
 
 int cat_sprintf(char *dest, char *fmt, ...)
@@ -430,22 +527,33 @@ int cat_sprintf(char *dest, char *fmt, ...)
 	return size;
 }
 
-void ins_sprintf(char *dest, char *fmt, ...)
+void ins_cpy(char *dest, char *str)
 {
-	char buf[STRING_SIZE], tmp[STRING_SIZE];
+	char tmp[STRING_SIZE];
 
+	strcpy(tmp, dest);
+	strcpy(dest, str);
+	strcat(dest, tmp);
+}
+
+// unused, also needs testing
+
+void ins_sprintf(char *dest, char *fmt, ...)
+{
+	char tmp[STRING_SIZE];
+	int len;
 	va_list args;
 
+	strcpy(tmp, dest);
+
 	va_start(args, fmt);
-	vsprintf(buf, fmt, args);
+	len = vsprintf(dest, fmt, args);
 	va_end(args);
 
-	strcpy(tmp, dest);
-	strcpy(dest, buf);
-	strcat(dest, tmp);
+	strcpy(dest + len, tmp);
 }
 
-int str_suffix(char *str1, char *str2)
+int is_suffix(char *str1, char *str2)
 {
 	int len1, len2;
 
@@ -456,10 +564,10 @@ int str_suffix(char *str1, char *str2)
 	{
 		if (!strcasecmp(str1 + len1 - len2, str2))
 		{
-			return FALSE;
+			return TRUE;
 		}
 	}
-	return TRUE;
+	return FALSE;
 }
 
 void socket_printf(struct session *ses, size_t length, char *format, ...)

+ 160 - 71
src/variable.c

@@ -49,13 +49,11 @@ DO_COMMAND(do_variable)
 			{
 				char *str_result;
 
-				str_result = str_dup("");
+				str_result = str_alloc_stack(0);
 
 				view_nest_node(node, &str_result, 0, 1);
 
 				print_lines(ses, SUB_NONE, COLOR_TINTIN "%c" COLOR_COMMAND "%s " COLOR_BRACE "{" COLOR_STRING "%s" COLOR_BRACE "}\n{\n" COLOR_STRING "%s" COLOR_BRACE "}" COLOR_RESET "\n", gtd->tintin_char, list_table[LIST_VARIABLE].name, node->arg1, str_result);
-
-				str_free(str_result);
 			}
 			else
 			{
@@ -71,10 +69,11 @@ DO_COMMAND(do_variable)
 	{
 		if (!valid_variable(ses, arg1))
 		{
-			show_message(ses, LIST_VARIABLE, "#VARIABLE: INVALID VARIALBE NAME {%s}.", arg1);
+			show_error(ses, LIST_VARIABLE, "#VARIABLE: INVALID VARIALBE NAME {%s}.", arg1);
+
 			return ses;
 		}
-		str = str_alloc(UMAX(strlen(arg), BUFFER_SIZE));
+		str = str_alloc_stack(strlen(arg));
 
 		arg = sub_arg_in_braces(ses, arg, str, GET_ALL, SUB_VAR|SUB_FUN);
 
@@ -93,8 +92,6 @@ DO_COMMAND(do_variable)
 		show_nest_node(node, &str, 1);
 
 		show_message(ses, LIST_VARIABLE, "#OK. VARIABLE {%s} HAS BEEN SET TO {%s}.", arg1, str);
-
-		str_free(str);
 	}
 	return ses;
 }
@@ -138,7 +135,7 @@ DO_COMMAND(do_local)
 	}
 	else
 	{
-		str = str_alloc(UMAX(strlen(arg), BUFFER_SIZE));
+		str = str_alloc_stack(strlen(arg));
 
 		arg = sub_arg_in_braces(ses, arg, str, GET_ALL, SUB_VAR|SUB_FUN);
 
@@ -161,8 +158,6 @@ DO_COMMAND(do_local)
 		show_nest_node(node, &str, 1);
 
 		show_message(ses, LIST_VARIABLE, "#OK. LOCAL VARIABLE {%s} HAS BEEN SET TO {%s}.", arg1, str);
-
-		str_free(str);
 	}
 	return ses;
 }
@@ -191,6 +186,7 @@ DO_COMMAND(do_unvariable)
 DO_COMMAND(do_cat)
 {
 	char *str;
+	struct listroot *root;
 	struct listnode *node;
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_NST, SUB_VAR|SUB_FUN);
@@ -201,7 +197,7 @@ DO_COMMAND(do_cat)
 	}
 	else
 	{
-		str = str_alloc(UMAX(strlen(arg), BUFFER_SIZE));
+		str = str_alloc_stack(strlen(arg));
 
 		if ((node = search_nest_node_ses(ses, arg1)) == NULL)
 		{
@@ -210,35 +206,44 @@ DO_COMMAND(do_cat)
 			node = set_nest_node(ses->list[LIST_VARIABLE], arg1, "%s", str);
 		}
 
+		root = search_nest_base_ses(ses, arg1);
+
 		while (*arg)
 		{
 			arg = sub_arg_in_braces(ses, arg, str, GET_ALL, SUB_VAR|SUB_FUN);
 
-			check_all_events(ses, SUB_ARG, 1, 2, "VARIABLE UPDATE %s", arg1, arg1, str);
+			check_all_events(ses, EVENT_FLAG_VARIABLE, 1, 2, "VARIABLE UPDATE %s", arg1, arg1, str);
 
 			if (*str)
 			{
-				str_cat(&node->arg2, str);
+				if (node->root)
+				{
+					add_nest_node(root, arg1, "%s", str);
+				}
+				else
+				{
+					str_cat(&node->arg2, str);
+				}
 			}
 		}
 
-		check_all_events(ses, SUB_ARG, 1, 1, "VARIABLE UPDATED %s", arg1, arg1, str);
+		check_all_events(ses, EVENT_FLAG_VARIABLE, 1, 1, "VARIABLE UPDATED %s", arg1, arg1, str);
 
-		show_message(ses, LIST_VARIABLE, "#CAT: VARIABLE {%s} HAS BEEN SET TO {%s}.", arg1, node->arg2);
+		show_nest_node(node, &str, 1);
 
-		str_free(str);
+		show_message(ses, LIST_VARIABLE, "#CAT: VARIABLE {%s} HAS BEEN SET TO {%s}.", arg1, str);
 	}
 	return ses;
 }
 
 DO_COMMAND(do_replace)
 {
-	char tmp[BUFFER_SIZE], *pti, *ptm, *str;
+	char *tmp, *pti, *ptm, *str;
 	struct listnode *node;
 
 	arg = sub_arg_in_braces(ses, arg, arg1, GET_NST, SUB_VAR|SUB_FUN);
 	arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
-	arg = sub_arg_in_braces(ses, arg, arg3, GET_ALL, SUB_VAR|SUB_FUN);
+	arg = sub_arg_in_braces(ses, arg, arg3, GET_ALL, SUB_VAR);
 
 	if (*arg1 == 0 || *arg2 == 0)
 	{
@@ -260,8 +265,11 @@ DO_COMMAND(do_replace)
 	}
 	else
 	{
+		show_debug(ses, LIST_VARIABLE, "#REPLACE {%s} {%s} {%s}", node->arg2, arg2, arg3);
+
 		pti = node->arg2;
-		str = str_dup("");
+		str = str_alloc_stack(0);
+		tmp = str_alloc_stack(0);
 
 		do
 		{
@@ -279,7 +287,7 @@ DO_COMMAND(do_replace)
 
 			*ptm = 0;
 
-			substitute(ses, arg3, tmp, SUB_CMD);
+			substitute(ses, arg3, tmp, SUB_CMD|SUB_FUN);
 
 			str_cat_printf(&str, "%s%s", pti, tmp);
 
@@ -291,7 +299,6 @@ DO_COMMAND(do_replace)
 
 		str_cpy(&node->arg2, str);
 
-		str_free(str);
 	}
 	return ses;
 }
@@ -308,6 +315,16 @@ int valid_variable(struct session *ses, char *arg)
 		return FALSE;
 	}
 
+	if (strlen(arg) > 4096)
+	{
+		return FALSE;
+	}
+
+	if (is_digit(*arg))
+	{
+		show_error(ses, LIST_COMMAND, "\e[1;31m#WARNING: VALIDATE {%s}: VARIABLES SHOULD NOT START WITH A NUMBER.", arg);
+	}
+
 	return TRUE;
 }
 
@@ -380,7 +397,7 @@ void stringtobasez(char *str, char *base)
 	switch (atoi(base))
 	{
 		case 64:
-			str_to_base64(buf, str, strlen(str));
+			str_to_base64z(buf, str, strlen(str));
 			break;
 
 		case 252:
@@ -408,7 +425,7 @@ void basetostringz(char *str, char *base)
 	switch (atoi(base))
 	{
 		case 64:
-			base64_to_str(buf, str, strlen(str));
+			base64z_to_str(buf, str, strlen(str));
 			break;
 
 		case 252:
@@ -513,34 +530,55 @@ void charactertohex(struct session *ses, char *str)
 
 void colorstring(struct session *ses, char *str)
 {
-	char result[BUFFER_SIZE];
+	char *result;
+
+	push_call("colorstring(%p,%p)",ses,str);
+
+	result = str_alloc_stack(0);
 
 	get_color_names(ses, str, result);
 
 	strcpy(str, result);
+
+	pop_call();
+	return;
 }
 
 void headerstring(struct session *ses, char *str, char *columns)
 {
-	char buf[BUFFER_SIZE], fill[BUFFER_SIZE];
+	char *buf, *fill;
 	int len, max;
 
-	len = string_raw_str_len(ses, str, 0, BUFFER_SIZE);
+	push_call("headerstring(%p,%p,%p)",ses,str,columns);
+
+	buf  = str_alloc_stack(0);
+	fill = str_alloc_stack(0);
+
+	max  = *columns ? atoi(columns) : get_scroll_cols(ses);
 
-	max = *columns ? atoi(columns) : get_scroll_cols(ses);
+	len  = string_raw_str_len(ses, str, 0, max);
 
 	if (len > max - 2)
 	{
-		str[max] = 0;
-
+		pop_call();
 		return;
 	}
 
-	memset(fill, '#', max);
+	if (HAS_BIT(ses->config_flags, CONFIG_FLAG_SCREENREADER))
+	{
+		memset(fill, ' ', max);
+	}
+	else
+	{
+		memset(fill, '#', max);
+	}
 
 	sprintf(buf, "%.*s%s%.*s%s", (max - len) / 2, fill, str, (max - len) / 2, fill, (max - len) % 2 ? "#" : "");
 
 	strcpy(str, buf);
+
+	pop_call();
+	return;
 }
 
 void lowerstring(char *str)
@@ -602,9 +640,14 @@ void mathstring(struct session *ses, char *str)
 
 void thousandgroupingstring(struct session *ses, char *str)
 {
-	char result[BUFFER_SIZE], strold[BUFFER_SIZE];
+	char *result, *strold;
 	int cnt1, cnt2, cnt3, cnt4;
 
+	push_call("thousandsgroupingstring(%p,%p)",ses,str);
+
+	result = str_alloc_stack(0);
+	strold = str_alloc_stack(0);
+
 	get_number_string(ses, str, strold);
 
 	cnt1 = strlen(strold);
@@ -615,14 +658,14 @@ void thousandgroupingstring(struct session *ses, char *str)
 
 	for (cnt3 = 0 ; cnt1 >= 0 ; cnt1--, cnt2--)
 	{
-		if (cnt3++ % 3 == 0 && cnt3 != 1 && cnt4 == 0 && isdigit((int) strold[cnt1]))
+		if (cnt3++ % 3 == 0 && cnt3 != 1 && cnt4 == 0 && is_digit(strold[cnt1]))
 		{
 			result[cnt2--] = ',';
 		}
 
 		result[cnt2] = strold[cnt1];
 
-		if (!isdigit((int) result[cnt2]))
+		if (!is_digit(result[cnt2]))
 		{
 			cnt4 = 0;
 			cnt3 = 0;
@@ -631,6 +674,9 @@ void thousandgroupingstring(struct session *ses, char *str)
 	}
 
 	strcpy(str, result + cnt2 + 1);
+
+	pop_call();
+	return;
 }
 
 void chronosgroupingstring(struct session *ses, char *str)
@@ -765,7 +811,7 @@ void stripspaces(char *str)
 
 	for (cnt = strlen(str) - 1 ; cnt >= 0 ; cnt--)
 	{
-		if (!isspace((int) str[cnt]))
+		if (!is_space(str[cnt]))
 		{
 			break;
 		}
@@ -774,7 +820,7 @@ void stripspaces(char *str)
 
 	for (cnt = 0 ; str[cnt] != 0 ; cnt++)
 	{
-		if (!isspace((int) str[cnt]))
+		if (!is_space(str[cnt]))
 		{
 			break;
 		}
@@ -785,13 +831,16 @@ void stripspaces(char *str)
 
 void wrapstring(struct session *ses, char *str, char *wrap)
 {
-	char  arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
+	char  *arg1, *arg2;
 	char *pts, *pte, *arg;
 	int cnt, width, height;
 
 	push_call("wrapstring(%p,%p,%p)",ses,str,wrap);
 
-	arg = sub_arg_in_braces(ses, str, arg1, GET_ALL, SUB_COL);
+	arg1 = str_alloc_stack(0);
+	arg2 = str_alloc_stack(0);
+
+	arg = sub_arg_in_braces(ses, str, arg1, GET_ALL, SUB_COL|SUB_LIT|SUB_ESC);
 
 	if (*arg == COMMAND_SEPARATOR)
 	{
@@ -838,7 +887,9 @@ void wrapstring(struct session *ses, char *str, char *wrap)
 		{
 			*pte++ = 0;
 
-			cat_sprintf(str, "{%d}{%s}", ++cnt, pts);
+			substitute(ses, pts, arg1, SUB_SEC);
+
+			cat_sprintf(str, "{%d}{%s}", ++cnt, arg1);
 
 			pts = pte;
 		}
@@ -847,7 +898,9 @@ void wrapstring(struct session *ses, char *str, char *wrap)
 			pte++;
 		}
 	}
-	cat_sprintf(str, "{%d}{%s}", ++cnt, pts);
+	substitute(ses, pts, arg1, SUB_SEC);
+
+	cat_sprintf(str, "{%d}{%s}", ++cnt, arg1);
 
 	pop_call();
 	return;
@@ -855,11 +908,19 @@ void wrapstring(struct session *ses, char *str, char *wrap)
 
 int stringlength(struct session *ses, char *str)
 {
-	char temp[BUFFER_SIZE];
+	int len;
+	char *temp;
+
+	push_call("stringlength(%p,%p)",ses,str);
+
+	temp = str_alloc_stack(0);
 
 	substitute(ses, str, temp, SUB_COL|SUB_ESC);
 
-	return strip_vt102_strlen(ses, temp);
+	len = strip_vt102_strlen(ses, temp);
+
+	pop_call();
+	return len;
 }
 
 
@@ -867,7 +928,7 @@ int stringlength(struct session *ses, char *str)
 
 int string_str_raw_len(struct session *ses, char *str, int start, int end)
 {
-	int raw_cnt, str_cnt, ret_cnt, tmp_cnt, tot_len, width, col_len;
+	int raw_cnt, str_cnt, ret_cnt, tmp_cnt, tot_len, width, col_len, skip;
 
 	raw_cnt = str_cnt = ret_cnt = 0;
 
@@ -875,16 +936,21 @@ int string_str_raw_len(struct session *ses, char *str, int start, int end)
 
 	while (raw_cnt < tot_len)
 	{
-		if (skip_vt102_codes(&str[raw_cnt]))
+		skip = skip_vt102_codes(&str[raw_cnt]);
+
+		if (skip)
 		{
-			ret_cnt += (str_cnt >= start) ? skip_vt102_codes(&str[raw_cnt]) : 0;
-			raw_cnt += skip_vt102_codes(&str[raw_cnt]);
+			if (str_cnt >= start)
+			{
+				ret_cnt += skip;
+			}
+			raw_cnt += skip;
 
 			continue;
 		}
 
 		col_len = is_color_code(&str[raw_cnt]);
-		
+
 		if (col_len)
 		{
 			ret_cnt += (str_cnt >= start) ? col_len : 0;
@@ -956,7 +1022,7 @@ int string_raw_str_len(struct session *ses, char *str, int raw_start, int raw_en
 
 	while (raw_cnt < tot_len)
 	{
-		if (raw_cnt >= raw_end)
+		if (raw_end >= 0 && raw_cnt >= raw_end)
 		{
 			break;
 		}
@@ -1016,11 +1082,15 @@ int string_raw_str_len(struct session *ses, char *str, int raw_start, int raw_en
 
 void timestring(struct session *ses, char *str)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], *arg;
-
+	char *arg, *arg1, *arg2;
 	struct tm timeval_tm;
 	time_t    timeval_t;
 
+	push_call("timestring(%p,%p)",ses,str);
+
+	arg1 = str_alloc_stack(0);
+	arg2 = str_alloc_stack(0);
+
 	arg = get_arg_in_braces(ses, str, arg1, GET_ALL);
 
 	if (*arg == COMMAND_SEPARATOR)
@@ -1041,48 +1111,67 @@ void timestring(struct session *ses, char *str)
 	timeval_tm = *localtime(&timeval_t);
 
 	strftime(str, BUFFER_SIZE, arg1, &timeval_tm);
+
+	pop_call();
+	return;
 }
 
 void justify_string(struct session *ses, char *in, char *out, int align, int cut)
 {
-	char temp[BUFFER_SIZE];
+	char *temp;
+
+	push_call("justify_string(%p,%p,%p,%d,%d)",ses,in,out,align,cut);
+
+	temp = str_alloc_stack(0);
 
 	if (align < 0)
 	{
-		sprintf(temp, "%%%d.%ds", align - ((int) strlen(in) - string_raw_str_len(ses, in, 0, BUFFER_SIZE)), string_str_raw_len(ses, in, 0, cut));
+		sprintf(temp, "%%%d.%ds", align - ((int) strlen(in) - string_raw_str_len(ses, in, 0, -1)), string_str_raw_len(ses, in, 0, cut));
 	}
 	else
 	{
-		sprintf(temp, "%%%d.%ds", align + ((int) strlen(in) - string_raw_str_len(ses, in, 0, BUFFER_SIZE)), string_str_raw_len(ses, in, 0, cut));
+		sprintf(temp, "%%%d.%ds", align + ((int) strlen(in) - string_raw_str_len(ses, in, 0, -1)), string_str_raw_len(ses, in, 0, cut));
 	}
 
 	sprintf(out, temp, in);
+
+	pop_call();
+	return;
 }
 
 void format_string(struct session *ses, char *format, char *arg, char *out)
 {
 	char *arglist[30];
-	char argformat[BUFFER_SIZE], newformat[BUFFER_SIZE], *ptf, *ptt, *pts, *ptn;
+	char *argformat, *newformat, *arg1, *arg2, *ptf, *ptt, *pts, *ptn;
 	struct tm timeval_tm;
 	time_t    timeval_t;
 	int i, max;
 
-	push_call("format_string(%p,%p,%p,%p)",ses,format,arg,out);
+	argformat = str_alloc_stack(0);
+	newformat = str_alloc_stack(0);
+
+	arg1 = str_alloc_stack(0);
+	arg2 = str_alloc_stack(0);
 
 	for (max = 0 ; max < 4 ; max++)
 	{
-		arglist[max] = str_alloc_stack();
+		arglist[max] = str_alloc_stack(0);
 
 		arg = sub_arg_in_braces(ses, arg, arglist[max], GET_ONE, SUB_VAR|SUB_FUN);
 	}
 
 	for (max = 4 ; *arg && max < 30 ; max++)
 	{
-		arglist[max] = str_alloc_stack();
+		arglist[max] = str_alloc_stack(0);
 
 		arg = sub_arg_in_braces(ses, arg, arglist[max], GET_ONE, SUB_VAR|SUB_FUN);
 	}
 
+	for (i = max ; i < 30 ; i++)
+	{
+		arglist[i] = "";
+	}
+
 	i = 0;
 
 	ptf = format;
@@ -1118,7 +1207,7 @@ void format_string(struct session *ses, char *format, char *arg, char *out)
 			}
 			else
 			{
-				while (!isalpha((int) *ptf))
+				while (!is_alpha(*ptf))
 				{
 					if (*ptf == 0)
 					{
@@ -1158,8 +1247,6 @@ void format_string(struct session *ses, char *format, char *arg, char *out)
 					default:
 						if (pts[1])
 						{
-							char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
-
 							ptt = arg1;
 							ptn = pts + 1;
 
@@ -1174,11 +1261,11 @@ void format_string(struct session *ses, char *format, char *arg, char *out)
 							{
 								if (atoi(arg1) < 0)
 								{
-									sprintf(argformat, "%%%d", atoi(arg1) - ((int) strlen(arglist[i]) - string_raw_str_len(ses, arglist[i], 0, BUFFER_SIZE)));
+									sprintf(argformat, "%%%d", atoi(arg1) - ((int) strlen(arglist[i]) - string_raw_str_len(ses, arglist[i], 0, -1)));
 								}
 								else
 								{
-									sprintf(argformat, "%%%d", atoi(arg1) + ((int) strlen(arglist[i]) - string_raw_str_len(ses, arglist[i], 0, BUFFER_SIZE)));
+									sprintf(argformat, "%%%d", atoi(arg1) + ((int) strlen(arglist[i]) - string_raw_str_len(ses, arglist[i], 0, -1)));
 								}
 							}
 							else
@@ -1196,13 +1283,13 @@ void format_string(struct session *ses, char *format, char *arg, char *out)
 								if (atoi(arg1) < 0)
 								{
 									sprintf(argformat, "%%%d.%d",
-										atoi(arg1) - ((int) strlen(arglist[i]) - string_raw_str_len(ses, arglist[i], 0, BUFFER_SIZE)),
+										atoi(arg1) - ((int) strlen(arglist[i]) - string_raw_str_len(ses, arglist[i], 0, -1)),
 										string_str_raw_len(ses, arglist[i], 0, atoi(arg2)));
 								}
 								else
 								{
 									sprintf(argformat, "%%%d.%d",
-										atoi(arg1) + ((int) strlen(arglist[i]) - string_raw_str_len(ses, arglist[i], 0, BUFFER_SIZE)),
+										atoi(arg1) + ((int) strlen(arglist[i]) - string_raw_str_len(ses, arglist[i], 0, -1)),
 										string_str_raw_len(ses, arglist[i], 0, atoi(arg2)));
 								}
 							}
@@ -1223,7 +1310,6 @@ void format_string(struct session *ses, char *format, char *arg, char *out)
 				{
 					case 'a':
 						numbertocharacter(ses, arglist[i]);
-//						sprintf(arglist[i], "%c", (char) get_number(ses, arglist[i]));
 						break;
 
 					case 'b':
@@ -1386,18 +1472,21 @@ void format_string(struct session *ses, char *format, char *arg, char *out)
 
 	snprintf(out, BUFFER_SIZE - 1, newformat, arglist[0], arglist[1], arglist[2], arglist[3], arglist[4], arglist[5], arglist[6], arglist[7], arglist[8], arglist[9], arglist[10], arglist[11], arglist[12], arglist[13], arglist[14], arglist[15], arglist[16], arglist[17], arglist[18], arglist[19], arglist[20], arglist[21], arglist[22], arglist[23], arglist[24], arglist[25], arglist[26], arglist[27], arglist[28], arglist[29]);
 
-	pop_call();
 	return;
 }
 
 DO_COMMAND(do_format)
 {
-	char destvar[BUFFER_SIZE], format[BUFFER_SIZE], result[BUFFER_SIZE];
+	char *argvar, *format, *result;
+
+	argvar = arg1;
+	format = arg2;
+	result = arg3;
 
-	arg = sub_arg_in_braces(ses, arg, destvar,  GET_NST, SUB_VAR|SUB_FUN);
-	arg = sub_arg_in_braces(ses, arg, format,   GET_ONE, SUB_VAR|SUB_FUN);
+	arg = sub_arg_in_braces(ses, arg, argvar, GET_NST, SUB_VAR|SUB_FUN);
+	arg = sub_arg_in_braces(ses, arg, format, GET_ONE, SUB_VAR|SUB_FUN);
 
-	if (*destvar == 0)
+	if (*argvar == 0)
 	{
 		show_error(ses, LIST_VARIABLE, "#SYNTAX: #format {variable} {format} {arg1} {arg2}");
 
@@ -1406,9 +1495,9 @@ DO_COMMAND(do_format)
 
 	format_string(ses, format, arg, result);
 
-	set_nest_node_ses(ses, destvar, "%s", result);
+	set_nest_node_ses(ses, argvar, "%s", result);
 
-	show_message(ses, LIST_VARIABLE, "#OK. VARIABLE {%s} HAS BEEN SET TO {%s}.", destvar, result);
+	show_message(ses, LIST_VARIABLE, "#OK. VARIABLE {%s} HAS BEEN SET TO {%s}.", argvar, result);
 
 	return ses;
 }

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 482 - 535
src/vt102.c


Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio