Scandum il y a 5 ans
Parent
commit
6d9cd508fe
45 fichiers modifiés avec 5367 ajouts et 1556 suppressions
  1. 22 12
      FAQ
  2. 1 1
      INSTALL
  3. 32 0
      NEWS
  4. 47 9
      SCRIPTS
  5. 12 44
      TODO
  6. 293 269
      docs/help.html
  7. 44 5
      docs/syntax.txt
  8. 87 3
      mods/igr.mods
  9. 1 1
      src/Makefile.in
  10. 344 0
      src/base.c
  11. 33 13
      src/buffer.c
  12. 2 2
      src/chat.c
  13. 1 1
      src/class.c
  14. 14 3
      src/config.c
  15. 218 201
      src/cursor.c
  16. 1 0
      src/data.c
  17. 134 15
      src/draw.c
  18. 102 78
      src/event.c
  19. 15 2
      src/files.c
  20. 492 54
      src/help.c
  21. 76 55
      src/input.c
  22. 22 0
      src/line.c
  23. 60 45
      src/list.c
  24. 3 1
      src/log.c
  25. 37 28
      src/main.c
  26. 234 73
      src/mapper.c
  27. 13 4
      src/math.c
  28. 2 2
      src/misc.c
  29. 47 5
      src/net.c
  30. 8 1
      src/parse.c
  31. 57 10
      src/path.c
  32. 1 1
      src/regex.c
  33. 775 358
      src/screen.c
  34. 57 20
      src/session.c
  35. 6 9
      src/show.c
  36. 1483 0
      src/sort.c
  37. 8 17
      src/split.c
  38. 91 31
      src/tables.c
  39. 1 0
      src/telopt_client.c
  40. 2 2
      src/text.c
  41. 175 71
      src/tintin.h
  42. 15 7
      src/trigger.c
  43. 15 2
      src/utils.c
  44. 226 83
      src/variable.c
  45. 58 18
      src/vt102.c

+ 22 - 12
FAQ

@@ -1,6 +1,6 @@
 This document will hopefully answer most questions regarding tintin++ (tt++).
 
-Last updated: 12/28/2010
+Last updated: 03/07/2020
 
 Q00) I'm new to tintin, how do I get started?
 
@@ -19,29 +19,29 @@ A00) Quite easy, start tintin using tt++ or ./tt++, to connect to a mud type:
 Q01) What machines does tintin work on?
 
 A01) Pretty much any UNIX machine with a modern compiler as well as Windows,
-     Mac OS X, and Android.
+     Mac OS X, Android, and iOS.
 
 Q02) What version should I use 1.50 or 1.86 or 2.00 ?
 
 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 known compatibility issues.
+     The NEWS file contains all known compatibility issues.
 
-Q06) I can't get tintin compiled still.  Where can I get more help?
+Q06) I can't get tintin compiled.  Where can I get more help?
 
 A06) See the INSTALL file.
 
-Q07) I can't get tintin compiled, can't you send me a binary of tintin?
+Q07) I still can't get tintin compiled?
 
-A07) See the install section on the website for help. A pre-compiled
-     binary is only available for Windows.
+A07) See the install section on the website for even more detailed help.
+     A pre-compiled binary is only available for Windows.
 
 Q08) I would like to help, how can I contribute to tintin?
 
-A08) You can assist people on the message board and give bug reports or
-     suggestions. A link to the beta version is often available on the
-     forum in the Announcements section, beta testing is very helpful to
-     avoid buggy releases.
+A08) You can assist people on the discord channel and give bug reports or
+     suggestions. A link to the beta version is available on the forum
+     in the Beta Testing section, beta testing is very important to the
+     continued development of TinTin++.
 
      TinTin++ is mostly a solo project and over 95% of the code has been
      written by Igor van den Hoven. If you however feel the need to
@@ -83,6 +83,7 @@ A14) If you read the COPYING file you will see you are allowed to modify and
      redistribute this version as long as you make it clear you made changes,
      and what those changes are. If you want to use tintin code in another
      program not licensed under GPL 3 you need permission from the author.
+
      Make sure to see if the exact code you want to use isn't existent in older
      tintin++ versions before contacting me, because I obviously cannot give
      permission for code I didn't write :) Also notice that older tintin++
@@ -111,7 +112,7 @@ A17) Use %%0 %%1 %%2 for the arguments of the nested action.
 
 Q18) How to enable support for chinese muds?
 
-A18  Use: #config BIG-5 on
+A18  Use: #config charset ? to get a list of support character sets.
 
 Q19) I use Mac OS X and ran tintin a few times, now every time I open a terminal
      window, it runs tintin automatically.
@@ -122,3 +123,12 @@ A19) You clicked "use settings as default" while running tintin. There's a few
      to redo anyting custom you set up (screen size, colors, etc.), but it
      will get the terminal back to the default of loading into your home
      directory.
+
+Q20) What is the recommended terminal emulator?
+
+A20) TinTin++ is being developed to work properly with xterm.
+
+Q21) What is the recommended font?
+
+A21) The default unicode settings are configured to work with Consolas and the 
+     mintty terminal for the Windows build.

+ 1 - 1
INSTALL

@@ -20,7 +20,7 @@ gnutls: gnutls.org
 If you have any trouble with installing/compiling tintin you should check out
 the install section on the website.
 
-https://tintin.sourceforge.io/install.php
+https://tintin.mudhalla.net/install.php
 
 If that doesn't do the trick you can ask for assistance on the forum.
 

+ 32 - 0
NEWS

@@ -1,6 +1,20 @@
 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.02
+----------------
+01) Most commands in a command file are executed quietly when using #read,
+    which includes #split. Use #line verbose #split to have split lines
+    displayed when the command is executed through #read.
+
+
+TinTin++ 2.02.01
+----------------
+
+01) In order to save configs and pathdirs you must use #class CONFIG write
+    <filename> and #class PATHDIR write <filename>
+
+
 TinTin++ 2.02.00
 ----------------
 
@@ -18,6 +32,7 @@ TinTin++ 2.02.00
 
     You can replace '%+' with '%+1..a', see #help regex for more information.
 
+
 TinTin++ 2.01.92
 ----------------
 
@@ -38,6 +53,7 @@ TinTin++ 2.01.92
     *variable[]. I'll change $variable[] eventually to be identical to
     $variable[%*].
 
+
 TinTin++ 2.01.90
 ---------------
 
@@ -87,6 +103,7 @@ TinTin++ 2.01.90
     because I've repeatedly swapped row and col in VT100 which can be a tricky
     bug to track down.
 
+
 TinTin++ 2.01.8
 ---------------
 
@@ -96,6 +113,7 @@ TinTin++ 2.01.8
     as %0 and %1. Instead you can use #info system save, which will save
     CLIENT_NAME and CLIENT_VERSION to the $info[SYSTEM] variable.
 
+
 TinTin++ 2.01.7
 ---------------
 
@@ -103,6 +121,7 @@ TinTin++ 2.01.7
     class is activated. This change will cause trouble for scripts that don't
     properly close classes.
 
+
 TinTin++ 2.01.5
 ---------------
 
@@ -111,16 +130,19 @@ TinTin++ 2.01.5
 02) Removed dot notation support for variables. #var bla.bli blo is no longer
     valid, nor is $bla.bli.
 
+
 TinTin++ 2.01.4
 ---------------
 
     Added support for *{variable} to show variable names.
 
+
 TinTin++ 2.00.2
 ---------------
 
     Removed the #suspend command, it's been moved to #cursor suspend.
 
+
 TinTin++ 1.99.7
 ---------------
 
@@ -158,6 +180,7 @@ TinTin++ 1.99.7
     and #RETURN statements have been added and should work more or less as
     expected.
 
+
 TinTin++ 1.99.1
 ---------------
 
@@ -178,23 +201,27 @@ TinTin++ 1.99.1
 
     #list friends create {{Alicia} {Bubba} {Cathie} {Kayla} {Zorro}}
 
+
 TinTin++ 1.99.1
 ---------------
 
     Triggers now use PCRE (Perl Compatible Regular Expressions).
     See #help regex for details.
 
+
 TinTin++ 1.96.6
 ---------------
 
     #PATHDIR is now specificly designed to hold a direction, the opposite
     direction, and the vector of said direction for the #MAP command.
 
+
 TinTin++ 1.95.0
 ---------------
 
     Removed #antisubsittute as its utility was too limited for inclusion.
 
+
 TinTin++ 1.94.4
 ---------------
 
@@ -206,16 +233,19 @@ TinTin++ 1.94.4
 
     #action {~\0;32m%0 says '%1'} {say I don't like green says.}
 
+
 TinTin++ 1.94.0
 ---------------
 
     #SLEEP has been removed. The #DELAY command can be used instead.
 
+
 TinTin++ 1.91.0
 ---------------
 
     Removed the #speedwalk command, it's been moved to the #config menu.
 
+
 TinTin++ 1.90.0
 ---------------
 
@@ -228,6 +258,7 @@ TinTin++ 1.90.0
     !s         --> repeats score
     !ll        --> sends !ll as a command
 
+
 TinTin++ 1.89.0
 ---------------
 
@@ -248,6 +279,7 @@ TinTin++ 1.89.0
     support strings, which must be enclosed in quotes. See #HELP MATH for more
     information.
 
+
 TinTin++ 1.88.0
 ---------------
 

+ 47 - 9
SCRIPTS

@@ -1,3 +1,7 @@
+#nop -------------------------------------------------------------------------
+#nop Learn by example
+#nop -------------------------------------------------------------------------
+
 #nop -------------------------------------------------------------------------
 #nop Loop through room 1 to 1000 and change the color of rooms with the
 #nop static (16) flag to <168>.
@@ -5,11 +9,13 @@
 
 #loop 1 1000 vnum
 {
-	#map goto $vnum;
-	#map get roomflags result;
-	#if {$result & 16}
+	#map at $vnum
 	{
-		#map set roomcolor <168>
+		#map get roomflags result;
+		#if {$result & 16}
+		{
+			#map set roomcolor <168>
+		}
 	}
 }
 
@@ -56,7 +62,7 @@
 {200}
 
 #nop -------------------------------------------------------------------------
-#nop Maintain a friendlist.
+#nop Maintain a friendlist. %i creates a case insensitive regex.
 #nop -------------------------------------------------------------------------
 
 #variable {friendlist}
@@ -66,9 +72,7 @@
 
 #function isfriend
 {
-	#format name %l {%0};
-
-	#return &friendlist[$name];
+	#return &friendlist[%i%0];
 }
 
 #act {%1 follows you.}
@@ -108,7 +112,8 @@
 }
 
 #nop -------------------------------------------------------------------------
-#nop Append a goto to your current room when saving a map
+#nop Append a goto to your current room when saving a map. You can use
+#nop #map return instead.
 #nop -------------------------------------------------------------------------
 
 #alias {savemap}
@@ -307,3 +312,36 @@
 }
 
 #substitute {{\b[a-zA-Z]+\b}} {@spellcheck{%1}}
+
+#nop -------------------------------------------------------------------------
+#nop This function tests the random number engine
+#nop -------------------------------------------------------------------------
+
+#alias random
+{
+	#var random {};
+	#loop 1 1000 cnt
+	{
+		#math tmp 1d1000000000 % 10;
+		#math random[$tmp] $random[$tmp] + 1
+	};
+	#var random
+}
+
+#nop -------------------------------------------------------------------------
+#nop This macro allows pasting multi-line code fragments on pressing ctrl-v
+#nop -------------------------------------------------------------------------
+
+#macro {\cv}
+{
+	#cursor {convert meta} on;
+	#line oneshot #event {CATCH RECEIVED INPUT}
+	{
+		#line sub {esc} #var paste {%0};
+		#replace paste {\\n\\n} {;};
+		#replace paste {\\n} {};
+		#replace paste {\\t} {};
+		#replace paste {;;} {;};
+		#1 {$paste}
+	}
+}

+ 12 - 44
TODO

@@ -2,34 +2,35 @@
 
 * STUFF THAT IS PROBABLY GONNA GET DONE
 
-  - provide the coordinate of the X on the vtmap.
+  - #message all log?
+
+  - Work on VT2020 protocol (mouse click)
+
+  - $var[%*][%*] support.
 
-  - screen move, negative arg handling.
+  - #line convert utf-8 support.
+
+  - better #draw font support
 
   - case insensitive tabbing (partial start with rewrite)
 
   - 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.
+  ! #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
-
-  - #math idea: 4 === 2+2 === 8-4
-  - #math true/false handling?
-
-  - highlight file being read with verbose
+  - provide the coordinate of the X on the vtmap.
+  - add maze flag for maze handling.
 
   - #draw table {1;2;3;4} {a;b;c;d} 
+    #draw scrollbar
     #draw graph
-    #draw rain
     #draw button
     #draw titanic
 
-  - %b %B mode. (compress + base mode)
-
   - proper vt100 skip detection for improper color codes.
 
   - I'll look and see if I can make { match both a { and \x7B as it's an annoying issue to debug.
@@ -38,8 +39,6 @@
 
   - Remote script loading
 
-  - Work on VT2020 protocol (mouse click)
-
   - make #path load bi-directional.
 
   - class bla assign {stuff} feature?
@@ -51,18 +50,8 @@
 
   - look into discord api / arachnos
 
-  - add maze flag for maze handling.
-
-
-
-  - make #split static and fix wrapping of split line on horizontal shrink.
-
-  - look into utf-8 text obfuscation.
-
   - better color syntax highlighting configuration.
 
-  - split up list data flag.
-
   - Add #log delete option.
   - Fix #log helpfile and look into #log {remove} option for wintin++
 
@@ -70,9 +59,6 @@
 
   - See about adding SESSIONS to the list table.
 
-  - disable packet patch in echo off mode / PACKET PATCH AUTO mode.
-  - set packet patch on EOR and GA detection. #config packet patch auto ?
-
   - Add debugger to syntax highlighter, substitution highlighing, 256 color support, and variable expansion.
 
   - look at scripts/bug.tin
@@ -86,34 +72,19 @@
 
   - fix readmud in net.c to not move the cursor on inactive sessions.
 
-  - add #con packet patch auto split mode / prompt telnet codes
-
   - add packets patched counter
 
-  - https://tintin.sourceforge.io/forum/viewtopic.php?f=2&t=2624
-    Check if telnet ECHO has proper loop protection.
-
-  - Check socket code for odd behavior on mass connect
-
   - Fix arrow key up history recall overwriting the prompt (partial redesign)
     Auto prompt fixing on overwrite.
 
   - reportable_sounds
 
-  - #default smaller equal greater options
-
-  - #buffer end after #split ?
-
   - https://tintin.sourceforge.io/forum/viewtopic.php?f=4&t=2597 #add #screen support
 
   - TELNET documentation.
 
   - Add JSON support to #scan
 
-  - add form feed \x0C
-
-  - look into \x7F not backspacing.
-
   - fix \x00 showme
 
   - support strikethrough html logging.
@@ -122,8 +93,6 @@
 
   - Add options to #cursor to implement custom behaviour.
 
-  - multiline gag
-
   - toggle global flags with #message all on, #debug all on, etc.
 
   - http://tintin.sourceforge.net/board/viewtopic.php?p=9625 (map undo issue) (not a big issue)
@@ -321,4 +290,3 @@
 - map sharing
 - cursor extension for vim
 - interactive script tutorial
-

Fichier diff supprimé car celui-ci est trop grand
+ 293 - 269
docs/help.html


+ 44 - 5
docs/syntax.txt

@@ -19,8 +19,7 @@ CHARACTERS
 
 " "       Quote characters are used for strings in the #math, #if, #switch,
           and #case commands. It is however suggested to use an extra
-          set of braces { } to define strings. Quote support will be
-          phased out eventually since TT++ is typeless.
+          set of braces { } to define strings.
 
 !         The exclamation sign is used to repeat commands, see #help history.
           The character can be redefined using #config.
@@ -53,6 +52,11 @@ $         The dollar sign is used to retrieve the value of a variable.
 &0- &99   The ampersand sign followed by a number is used for arguments in the
           regex command.
 
+%0- %99   The percent sign followed by a number is used for arguments by the
+          following triggers:
+
+          alias, action, button, delay, event, function, substitute, and tick.
+
 <000>     Three alphanumeric characters encapsulated by the less- and greater-
           than signs are used for 4 and 8 bit color codes.
 
@@ -66,24 +70,55 @@ $         The dollar sign is used to retrieve the value of a variable.
 
           More information is available at #help color.
 
-\         The back slash is used to escape a character. Available options
+\         The back slash is used to escape a character. All available options
           are listed at #help escape. Escapes are typically escaped when text
           leaves the client, by being send to a server, the shell, or being
           displayed on the screen.
 
+\t        08  horizontal tab character.
+\n        10  line feed character.
+\v        11  vertical tab character.
+\r        13  carriage return character.
+\e        27  escape character.
+\c            6 bit control character, \ca for ctrl-a.
+\x            8 bit character using 2 hexadecimal numbers.
+\u            16 bit unicode character, \uFFFD for example.
+
           All variables and functions can be escaped by doubling the sign,
           like $$variable_name or @@function_name. To escape a variable
           twice use $$$var_name. One escape is removed each time tintin
           needs to substitute a variable or function.
 
+          All command arguments can be escaped by doubling the ampersand,
+          like &&1. One escape is removed each time tintin substitutes
+          command arguments.
 
+          All trigger arguments can be escaped by double the ampersand,
+          like %%1. One escape is removed each time tintin substitutes
+          trigger arguments.
 
 COORDINATES
 -----------
 
           When the 0,0 coordinate is in the upper left corner TinTin++ uses
-          a y,x / rows,cols notation. When the 0,0 coordinate is in the
-          bottom left corner tintin uses a x,y / cols/rows notation.
+          a y,x / rows,cols notation, starting at 1,1. Subsequently -1,-1
+          will indicate the bottom right corner.
+
+          When the 0,0 coordinate is in the bottom left corner tintin uses
+          a standard x,y notation.
+
+SQUARES
+-------
+
+          A square argument takes 4 coordinates. The first two coordinates
+          define the upper left corner, the last two coordinates define the
+          bottom right corner.
+
+PANES
+-----
+          A panes argument takes 4 size values, which are: top pane, bottom
+          pane, left pane, right pane. When a negative value is provided the
+          size is the maximum size, minus the value.
 
 MATH
 ----
@@ -107,6 +142,8 @@ MATH
           <=              4            logical less than or equal
           ==              5            logical equal (can use regex)
           !=              5            logical not equal (can use regex)
+          ===             5            string equal
+          !==             5            string not equal
            &              6            bitwise and
            ^              7            bitwise xor
            |              8            bitwise or
@@ -120,6 +157,8 @@ MATH
 6:2:1:30  This means 6 days, 2 hours, 1 minute and 30 seconds.
           #math time 6:2:1:30 equals 525690
 
+M,K,m,u   These four metric suffixes are allowed for numbers.
+
 { }       Braces can be used in #math to perform string operations.
 {a} > {b} This checks if the string "a" is greater than "b".
 

+ 87 - 3
mods/igr.mods

@@ -1,6 +1,91 @@
-Jan 2020        2.02.01
+Jan 2020        2.02.02
 ------------------------------------------------------------------------------
 
+config.c        Added #config {packet patch} {auto} support which will
+                result in automatic telnet eor/ga handling and automatic
+                packet patching if #prompt is set correctly.
+
+help.c          Added auto-link generation for #help when mouse tracking is
+                enabled. Still experimental.
+
+mapper.c        Added #map get/set direction/pathdir to get/set the current
+                direction you are facing in numeric and alphabetic notation.
+
+tables.c        Added italic and unitalic #highlight keywords.
+
+tables.c        Pressing ctrl-delete will delete one word per default.
+
+mapper.c        Fixed #map undo issues with #map insert and #map dig.
+
+mapper.c        Now shows destination in #map exit <dir>
+
+base.c          Added %+64b and %+64B support to #format to convert to and
+                from base 64 encoding.
+
+                Added %+64z and %+64Z support to #format to zip the string
+                and convert it to base 64. May not compress it much but may
+                have some utility to store passwords. Security through
+                obscurity.
+
+                Added experimental %+252b/z and %+252B/Z options for Base
+                252 encoding.
+
+draw.c          Added FAT, CURSIVE, SCROLL, and SANSSERIF draw options.
+
+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, 
+                GAG SESSION DISCONNECTED, and GAG SESSION TIMED OUT events.
+
+mapper.c        Added #map roomflag fog. Works like #map roomflag hide but
+                the flag is auto cleared on entrance.
+
+line.c          Added #line convert options.
+
+mapper.c        Aded MAP CREATE ROOM and MAP DELETE ROOM events.
+
+utils.c         Increased the entropy of the random number generator.
+
+list.c          #list order sorts existing lists numerically.
+
+list.c          #list sort sorts existing lists alphabetically.
+
+sort.c          Added some fast sorting routines.
+
+list.c          Added #list reverse option.
+
+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:
+
+                #config mouse on
+                #showme {\e]68;\x01key\x02val\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
+                keyword with the \e[4m keyword \e[24m tags. When clicked with
+                mouse support enabled it'll spawn a LINK mouse event.
+
+map.c           Added #map exitflag <dir> <option> GET <variable> support.
+
+event.c         The %4 argument of mouse clicks once again reports the word
+                that has been clicked, with %5 reporting the line. Under
+                construction.
+
+screen.c        Added #screen input <square> to define the input region.
+                Currently only 1 line input regions are supported. Example:
+                #screen input 1 1 1 -1 will put the input line at the top of
+                the screen instead of the bottom. Under construction.
+
+Dec 2019        2.02.01
+------------------------------------------------------------------------------
 data.c          Added CWD field to #info system to get the current working
                 directory.
 
@@ -644,8 +729,7 @@ data.c          Added #INFO SYSTEM option, with #INFO SYSTEM SAVE saving the
                 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. This is still under
-                construction and non-functional.
+                word and line that was clicked. Under construction.
 
 net.c           Slightly improved traditional prompt handling, but the code
                 will need a proper update to work properly.

+ 1 - 1
src/Makefile.in

@@ -64,7 +64,7 @@ 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 \
 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
+regex.o substitute.o daemon.o dict.o sort.o base.o
 
 default: all
 

+ 344 - 0
src/base.c

@@ -0,0 +1,344 @@
+/******************************************************************************
+*   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"
+
+char base64_table[64] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };
+
+char str64_table[256] =
+{ 
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 62,  0,  0,  0, 63,
+	52, 53, 54, 55, 56, 57, 58, 59, 60, 61,  0,  0,  0,  0,  0,  0,
+	 0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
+	15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,  0,  0,  0,  0,  0,
+	 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,	 
+	41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,  0,  0,  0,  0,  0,	 
+
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,	 
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,	 
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,	 
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
+};
+
+int compress_data(char *in, size_t size_in, char *out, size_t size_out)
+{
+	z_stream *stream;
+	int size;
+
+	push_call("compress_data(%p,%zu,%p,%zu)",in,size_in,out,size_out);
+
+	stream              = calloc(1, sizeof(z_stream));
+
+	stream->next_in     = (unsigned char *) in;
+	stream->avail_in    = size_in;
+
+	stream->next_out    = (unsigned char *) out;
+	stream->avail_out   = size_out;
+
+	stream->data_type   = Z_ASCII;
+	stream->zalloc      = zlib_alloc;
+	stream->zfree       = zlib_free;
+	stream->opaque      = Z_NULL;
+
+	if (deflateInit(stream, Z_BEST_COMPRESSION) != Z_OK)
+	{
+		tintin_printf2(gtd->ses, "compress: failed deflateInit2");
+
+		free(stream);
+
+		pop_call();
+		return 0;
+	}
+
+	if (deflate(stream, Z_FINISH) != Z_STREAM_END)
+	{
+		tintin_printf2(gtd->ses, "compress: failed deflate");
+
+		free(stream);
+
+		pop_call();
+		return 0;
+	}
+
+	size = size_out - stream->avail_out;
+
+	deflateEnd(stream);
+
+	free(stream);
+
+	pop_call();
+	return size;
+}
+
+int decompress_data(char *in, size_t size_in, char *out, size_t size_out)
+{
+	z_stream *stream;
+	int size;
+
+	stream              = calloc(1, sizeof(z_stream));
+
+	stream->data_type   = Z_ASCII;
+	stream->zalloc      = zlib_alloc;
+	stream->zfree       = zlib_free;
+	stream->opaque      = Z_NULL;
+
+	if (inflateInit(stream) != Z_OK)
+	{
+		tintin_printf2(gtd->ses, "decompress_data: failed inflateInit");
+
+		free(stream);
+
+		return 0;
+	}
+
+	stream->next_in     = (unsigned char *) in;
+	stream->avail_in    = size_in;
+
+	stream->next_out    = (unsigned char *) out;
+	stream->avail_out   = size_out;
+
+	if (inflate(stream, Z_SYNC_FLUSH) == Z_BUF_ERROR)
+	{
+		tintin_printf2(gtd->ses, "decompress_data: failed inflate");
+	}
+
+	size = size_out - stream->avail_out;
+
+	inflateEnd(stream);
+
+	free(stream);
+
+	return size;
+}
+
+int str_to_base64(char *in, char *out, size_t size)
+{
+	char *pto;
+	int cnt;
+
+	push_call("str_to_base64(%p,%p,%zu)",in,out,size);
+
+	pto = out;
+
+	for (cnt = 0 ; cnt + 3 < size ; cnt += 3)
+	{
+		*pto++ = base64_table[(unsigned char) in[cnt + 0] % 64];
+		*pto++ = base64_table[(unsigned char) in[cnt + 0] / 64 + (unsigned char) in[cnt + 1] % 16 * 4];
+		*pto++ = base64_table[(unsigned char) in[cnt + 1] / 16 + (unsigned char) in[cnt + 2] % 4 * 16];
+		*pto++ = base64_table[(unsigned char) in[cnt + 2] /  4];
+	}
+
+	switch (size - cnt)
+	{
+		case 1:
+			*pto++ = base64_table[(unsigned char) in[cnt + 0] % 64];
+			*pto++ = base64_table[(unsigned char) in[cnt + 0] / 64];
+			*pto++ = '=';
+			*pto++ = '=';
+			break;
+		case 2:
+			*pto++ = base64_table[(unsigned char) in[cnt + 0] % 64];
+			*pto++ = base64_table[(unsigned char) in[cnt + 0] / 64 + (unsigned char) in[cnt + 1] % 16 * 4];
+			*pto++ = base64_table[(unsigned char) in[cnt + 1] / 16];
+			*pto++ = '=';
+			break;
+	}
+
+
+	*pto++ = 0;
+
+	pop_call();
+	return pto - out;
+}
+
+int base64_to_str(char *in, char *out, size_t size)
+{
+	char *pto;
+	int cnt;
+
+	pto = out;
+
+	for (cnt = 0 ; cnt + 4 <= size ; cnt += 4)
+	{
+		*pto++ = str64_table[(unsigned char) in[cnt + 0]] + str64_table[(unsigned char) in[cnt + 1]] % 4 * 64;
+
+		if (in[cnt + 1] == '=')
+		{
+			break;
+		}
+
+		*pto++ = str64_table[(unsigned char) in[cnt + 1]] / 4 + str64_table[(unsigned char) in[cnt + 2]] % 16 * 16;
+
+		if (in[cnt + 2] == '=')
+		{
+			break;
+		}
+
+		*pto++ = str64_table[(unsigned char) in[cnt + 2]] / 16 + str64_table[(unsigned char) in[cnt + 3]] * 4;
+	}
+	*pto++ = 0;
+
+	return pto - out;
+}
+
+
+int str_to_base252(char *in, char *out, size_t size)
+{
+	char *pto;
+	int cnt;
+
+	push_call("str_to_base252(%p,%p,%zu)",in,out,size);
+
+	pto = out;
+
+	for (cnt = 0 ; cnt < size ; cnt++)
+	{
+		switch ((unsigned char) in[cnt])
+		{
+			case 0:
+				*pto++ = 0xC0;
+				*pto++ = 0x80 + (unsigned char) in[cnt] % 64;
+				break;
+
+			case 0x10:
+			case 0x11:
+			case '{':
+			case '}':
+			case '\\':
+				*pto++ = 0xC0 + (unsigned char) in[cnt] / 64;
+				*pto++ = 0x80 + (unsigned char) in[cnt] % 64;
+				break;
+
+			case 0xC0:
+			case 0xC1:
+			case 0xFF:
+				*pto++ = 0x11;
+				*pto++ = 0x80 + (unsigned char) in[cnt] % 64;
+				break;
+
+			default:
+				*pto++ = in[cnt];
+				break;
+		}
+	}
+
+	*pto++ = 0;
+
+	pop_call();
+	return pto - out;
+}
+
+int base252_to_str(char *in, char *out, size_t size)
+{
+	char *pto;
+	int cnt;
+
+	pto = out;
+
+	for (cnt = 0 ; cnt < size ; cnt++)
+	{
+		switch ((unsigned char) in[cnt])
+		{
+			case 0xC0:
+				cnt++;
+				*pto++ =   0 + (unsigned char) in[cnt] % 64;
+				break;
+
+			case 0xC1:
+				cnt++;
+				*pto++ =  64 + (unsigned char) in[cnt] % 64;
+				break;
+
+			case 0x10:
+				cnt++;
+				*pto++ = 128 + (unsigned char) in[cnt] % 64;
+				break;
+
+			case 0x11:
+				cnt++;
+				*pto++ = 192 + (unsigned char) in[cnt] % 64;
+				break;
+
+			default:
+				*pto++ = in[cnt];
+				break;
+		}
+	}
+	*pto++ = 0;
+
+	return pto - out;
+}
+
+void str_to_base64z(char *in, char *out, size_t size)
+{
+	char buf[BUFFER_SIZE];
+	int len;
+
+	len = compress_data(in, size + 1, buf, BUFFER_SIZE);
+
+	if (len)
+	{
+		str_to_base64(buf, out, len);
+	}
+}
+
+void base64z_to_str(char *in, char *out, size_t size)
+{
+	char buf[BUFFER_SIZE];
+	int len;
+
+	len = base64_to_str(in, buf, size);
+
+	decompress_data(buf, len, out, BUFFER_SIZE);
+}
+
+void str_to_base252z(char *in, char *out, size_t size)
+{
+	char buf[BUFFER_SIZE];
+	int len;
+
+	len = compress_data(in, size + 1, buf, BUFFER_SIZE);
+
+	if (len)
+	{
+		str_to_base252(buf, out, len);
+	}
+}
+
+void base252z_to_str(char *in, char *out, size_t size)
+{
+	char buf[BUFFER_SIZE];
+	int len;
+
+	len = base252_to_str(in, buf, size);
+
+	decompress_data(buf, len, out, BUFFER_SIZE);
+}

+ 33 - 13
src/buffer.c

@@ -93,11 +93,11 @@ void check_buffer(struct session *ses)
 
 	wrap = get_scroll_cols(ses);
 
-	for (index = ses->scroll->used - 1 ; index > 0 ; index--)
+	for (index = ses->scroll->used - 1 ; index >= 0 ; index--)
 	{
 		buffer = ses->scroll->buffer[index];
 
-		if (buffer->width < wrap)
+		if (buffer->width < wrap && buffer->width < ses->scroll->wrap)
 		{
 			buffer->height = buffer->lines;
 		}
@@ -121,7 +121,7 @@ void add_line_buffer(struct session *ses, char *line, int prompt)
 	char temp[STRING_SIZE];
 	char *pti, *pto;
 	int cnt, purge;
-	int cur_row, cur_col, top_row, bot_row;
+	int skip, cur_row, cur_col, top_row, bot_row;
 	struct buffer_data *buffer;
 
 	push_call("add_line_buffer(%p,%s,%d)",ses,line,prompt);
@@ -167,25 +167,43 @@ void add_line_buffer(struct session *ses, char *line, int prompt)
 
 	while (*pti != 0)
 	{
-		while (skip_vt102_codes_non_graph(pti))
+		skip = skip_vt102_codes_non_graph(pti);
+
+		if (skip)
 		{
 			interpret_vt102_codes(ses, pti, FALSE);
 
-			pti += skip_vt102_codes_non_graph(pti);
-		}
+			pti += skip;
 
-		if (*pti == 0)
-		{
-			break;
+			continue;
 		}
 
+		skip = skip_vt102_codes(pti);
+
 		if (SCROLL(ses))
 		{
-			*pto++ = *pti++;
+			if (skip)
+			{
+				while (skip--)
+				{
+					*pto++ = *pti++;
+				}
+			}
+			else
+			{
+				*pto++ = *pti++;
+			}
 		}
 		else
 		{
-			pti++;
+			if (skip)
+			{
+				pti += skip;
+			}
+			else
+			{
+				pti++;
+			}
 		}
 	}
 	*pto = 0;
@@ -203,6 +221,8 @@ 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 (gtd->level->grep || prompt == -1)
 	{
 		SET_BIT(buffer->flags, BUFFER_FLAG_GREP);
@@ -887,7 +907,7 @@ DO_BUFFER(buffer_get)
 	{
 		min = ses->scroll->used + min;
 	}
-	min = URANGE(1, min, ses->scroll->used - 1);
+	min = URANGE(0, min, ses->scroll->used - 1);
 
 	if (*arg3 == 0)
 	{
@@ -902,7 +922,7 @@ DO_BUFFER(buffer_get)
 	{
 		max = ses->scroll->used + max;
 	}
-	max = URANGE(1, max, ses->scroll->used - 1);
+	max = URANGE(0, max, ses->scroll->used - 1);
 
 	if (min > max)
 	{

+ 2 - 2
src/chat.c

@@ -1532,9 +1532,9 @@ DO_CHAT(chat_paste)
 
 	if (arg1 == NULL)
 	{
-		if (strlen(gtd->input_buf))
+		if (*gtd->ses->input->buf)
 		{
-			sprintf(temp, "%s\n%s", gtd->chat->paste_buf, gtd->input_buf);
+			sprintf(temp, "%s\n%s", gtd->chat->paste_buf, gtd->ses->input->buf);
 
 			RESTRING(gtd->chat->paste_buf, temp);
 

+ 1 - 1
src/class.c

@@ -250,7 +250,7 @@ DO_CLASS(class_load)
 
 		return ses;
 	}
-	file = fmemopen(node->data, node->val32[1], "r");
+	file = fmemopen(node->data, (size_t) node->val32[1], "r");
 
 	read_file(ses, file, arg1);
 

+ 14 - 3
src/config.c

@@ -410,7 +410,7 @@ DO_CONFIG(config_connectretry)
 		gts->connect_retry = atoll(arg2) * 1000000LL;
 	}
 
-	sprintf(arg2, "%6.1Lf", (long double) gts->connect_retry / 1000000);
+	sprintf(arg2, "%.1Lf", (long double) gts->connect_retry / 1000000);
 
 	return ses;
 }
@@ -705,7 +705,18 @@ DO_CONFIG(config_packetpatch)
 
 	if (HAS_BIT(ses->flags, SES_FLAG_AUTOPATCH))
 	{
-		strcpy(arg2, "AUTO");
+		if (ses->list[LIST_PROMPT]->list[0])
+		{
+			strcpy(arg2, "AUTO PROMPT");
+		}
+		else if (HAS_BIT(ses->flags, SES_FLAG_AUTOPROMPT))
+		{
+			strcpy(arg2, "AUTO TELNET");
+		}
+		else
+		{
+			strcpy(arg2, "AUTO OFF");
+		}
 	}
 	else
 	{
@@ -759,7 +770,7 @@ DO_CONFIG(config_randomseed)
 			return NULL;
 		}
 	}
-	sprintf(arg2, "%llu", ses->rand);
+	sprintf(arg2, "%u", (unsigned int) ses->rand);
 
 	return ses;
 }

Fichier diff supprimé car celui-ci est trop grand
+ 218 - 201
src/cursor.c


+ 1 - 0
src/data.c

@@ -25,6 +25,7 @@
 
 #include "tintin.h"
 
+#include <limits.h>
 
 struct listroot *init_list(struct session *ses, int type, int size)
 {

+ 134 - 15
src/draw.c

@@ -31,8 +31,8 @@ static int  draw_cnt;
 DO_COMMAND(do_draw)
 {
 	char *sub_arg, arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], color[BUFFER_SIZE], code[BUFFER_SIZE], arg3[BUFFER_SIZE], input[BUFFER_SIZE];
-	int index, flags;
-	int top_row, top_col, bot_row, bot_col, rows, cols;
+	long long flags;
+	int index, top_row, top_col, bot_row, bot_col, rows, cols;
 
 	substitute(ses, arg, input, SUB_VAR|SUB_FUN);
 
@@ -102,6 +102,14 @@ DO_COMMAND(do_draw)
 			{
 				SET_BIT(flags, DRAW_FLAG_CROSSED);
 			}
+			else if (is_abbrev(arg1, "CURSIVE"))
+			{
+				SET_BIT(flags, DRAW_FLAG_CURSIVE);
+			}
+			else if (is_abbrev(arg1, "FAT"))
+			{
+				SET_BIT(flags, DRAW_FLAG_FAT);
+			}
 			else if (is_abbrev(arg1, "FILLED"))
 			{
 				SET_BIT(flags, DRAW_FLAG_FILLED);
@@ -146,6 +154,14 @@ DO_COMMAND(do_draw)
 			{
 				SET_BIT(flags, DRAW_FLAG_ROUNDED);
 			}
+			else if (is_abbrev(arg1, "SANSSERIF"))
+			{
+				SET_BIT(flags, DRAW_FLAG_SANSSERIF);
+			}
+			else if (is_abbrev(arg1, "SCROLL"))
+			{
+				SET_BIT(flags, DRAW_FLAG_SCROLL);
+			}
 			else if (is_abbrev(arg1, "SHADOWED"))
 			{
 				SET_BIT(flags, DRAW_FLAG_SHADOWED);
@@ -199,8 +215,8 @@ DO_COMMAND(do_draw)
 					arg = get_arg_in_braces(ses, arg, arg2, GET_ONE);
 				}
 
-				top_row = get_row_index(ses, arg1);
-				top_col = get_col_index(ses, arg2);
+				top_row = get_row_index_arg(ses, arg1);
+				top_col = get_col_index_arg(ses, arg2);
 
 				if (*sub_arg)
 				{
@@ -212,8 +228,8 @@ DO_COMMAND(do_draw)
 					arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
 					arg = get_arg_in_braces(ses, arg, arg2, GET_ONE);
 				}
-				bot_row = get_row_index(ses, arg1);
-				bot_col = get_col_index(ses, arg2);
+				bot_row = get_row_index_arg(ses, arg1);
+				bot_col = get_col_index_arg(ses, arg2);
 
 				if (top_row == 0 && top_col == 0)
 				{
@@ -228,6 +244,15 @@ DO_COMMAND(do_draw)
 
 					SET_BIT(flags, DRAW_FLAG_SCROLL);
 				}
+				else
+				{
+					if (ses != gtd->ses)
+					{
+						show_error(ses, LIST_COMMAND, "#ERROR: #DRAW %s %d %d %d %d: SESSION IS IN THE BACKGROUND.", draw_table[index].name, top_row, top_col, bot_row, bot_col);
+
+						return ses;
+					}
+				}
 
 				if (top_col == 0)
 				{
@@ -289,6 +314,99 @@ DO_COMMAND(do_draw)
 
 // utilities
 
+char *alnum_normal[] =
+{
+	"\x00",   "\x01",   "\x02",   "\x03",   "\x04",   "\x05",   "\x06",   "\x07",   "\x08",   "\x09",   "\x10",   "\x11",   "\x12",   "\x13",   "\x14",   "\x15",   "\x16",   "\x17",   "\x18",   "\x19",   "\x20",   "\x21",   "\x22",   "\x23",   "\x24",   "\x25",   "\x26",   "\x27",   "\x28",   "\x29",   "\x30",   "\x31",
+	" ",      "!",      "\"",     "#",      "$",      "%",      "&",      "'",      "(",      ")",      "*",      "+",      ",",      "-",      ".",      "/",      "0",      "1",      "2",      "3",      "4",      "5",      "6",      "7",      "8",      "9",      ":",      ";",      "<",      "=",      ">",      "?",
+	"@",      "A",      "B",      "C",      "D",      "E",      "F",      "G",      "H",      "I",      "J",      "K",      "L",      "M",      "N",      "O",      "P",      "Q",      "R",      "S",      "T",      "U",      "V",      "W",      "X",      "Y",      "Z",      "[",      "\\",     "]",      "^",      "_",
+	"`",      "a",      "b",      "c",      "d",      "e",      "f",      "g",      "h",      "i",      "j",      "k",      "l",      "m",      "n",      "o",      "p",      "q",      "r",      "s",      "t",      "u",      "v",      "w",      "x",      "y",      "z",      "{",      "|",      "}",      "~",      "\x7F"
+};
+
+char *alnum_normal_fat[] =
+{
+	"\x00",   "\x01",   "\x02",   "\x03",   "\x04",   "\x05",   "\x06",   "\x07",   "\x08",   "\x09",   "\x10",   "\x11",   "\x12",   "\x13",   "\x14",   "\x15",   "\x16",   "\x17",   "\x18",   "\x19",   "\x20",   "\x21",   "\x22",   "\x23",   "\x24",   "\x25",   "\x26",   "\x27",   "\x28",   "\x29",   "\x30",   "\x31",
+	" ",      "!",      "\"",     "#",      "$",      "%",      "&",      "'",      "(",      ")",      "*",      "+",      ",",      "-",      ".",      "/",      "𝟎",      "𝟏",      "𝟐",      "𝟑",      "𝟒",      "𝟓",      "𝟔",      "𝟕",      "𝟖",      "𝟗",      ":",      ";",      "<",      "=",      ">",      "?",
+	"@",      "𝐀",      "𝐁",      "𝐂",      "𝐃",      "𝐄",      "𝐅",      "𝐆",      "𝐇",      "𝐈",      "𝐉",      "𝐊",      "𝐋",      "𝐌",      "𝐍",      "𝐎",      "𝐏",      "𝐐",      "𝐑",      "𝐒",      "𝐓",      "𝐔",      "𝐕",      "𝐖",      "𝐗",      "𝐘",      "Z",      "𝐙",      "\\",     "]",      "^",      "_",
+	"`",      "𝐚",      "𝐛",      "𝐜",      "𝐝",      "𝐞",      "𝐟",      "𝐠",      "𝐡",      "𝐢",      "𝐣",      "𝐤",      "𝐥",      "𝐦",      "𝐧",      "𝐨",      "𝐩",      "𝐪",      "𝐫",      "𝐬",      "𝐭",      "𝐮",      "𝐯",      "𝐰",      "𝐱",      "𝐲",      "𝐳",      "{",      "|",      "}",      "~",      "\x7F"
+};
+
+char *alnum_cursive[] =
+{
+	"\x00",   "\x01",   "\x02",   "\x03",   "\x04",   "\x05",   "\x06",   "\x07",   "\x08",   "\x09",   "\x10",   "\x11",   "\x12",   "\x13",   "\x14",   "\x15",   "\x16",   "\x17",   "\x18",   "\x19",   "\x20",   "\x21",   "\x22",   "\x23",   "\x24",   "\x25",   "\x26",   "\x27",   "\x28",   "\x29",   "\x30",   "\x31",
+	" ",      "!",      "\"",     "#",      "$",      "%",      "&",      "'",      "(",      ")",      "*",      "+",      ",",      "-",      ".",      "/",      "0",      "1",      "2",      "3",      "4",      "5",      "6",      "7",      "8",      "9",      ":",      ";",      "<",      "=",      ">",      "?",
+	"@",      "𝒜",      "ℬ",      "𝒞",      "𝒟",      "ℰ",      "ℱ",      "𝒢",      "ℋ",      "ℐ",      "𝒥",      "𝒦",      "ℒ",      "ℳ",      "𝒩",      "𝒪",      "𝒫",      "𝒬",      "ℛ",      "𝒮",      "𝒯",      "𝒰",      "𝒱",      "𝒲",      "𝒳",      "𝒴",      "𝒵",      "[",      "\\",     "]",      "^",      "_",
+	"`",      "𝒶",      "𝒷",      "𝒸",      "𝒹",      "ℯ",      "𝒻",      "ℊ",      "𝒽",      "𝒾",      "𝒿",      "𝓀",      "𝓁",      "𝓂",      "𝓃",      "ℴ",      "𝓅",      "𝓆",      "𝓇",      "𝓈",      "𝓉",      "𝓊",      "𝓋",      "𝓌",      "𝓍",      "𝓎",      "𝓏",      "{",      "|",      "}",      "~",      "\x7F"
+};
+
+char *alnum_sansserif[] =
+{
+	"\x00",   "\x01",   "\x02",   "\x03",   "\x04",   "\x05",   "\x06",   "\x07",   "\x08",   "\x09",   "\x10",   "\x11",   "\x12",   "\x13",   "\x14",   "\x15",   "\x16",   "\x17",   "\x18",   "\x19",   "\x20",   "\x21",   "\x22",   "\x23",   "\x24",   "\x25",   "\x26",   "\x27",   "\x28",   "\x29",   "\x30",   "\x31",
+	" ",      "!",      "\"",     "#",      "$",      "%",      "&",      "'",      "(",      ")",      "*",      "+",      ",",      "-",      ".",      "/",      "𝟢",      "𝟣",      "𝟤",      "𝟥",      "𝟦",      "𝟧",      "𝟨",      "𝟩",      "𝟪",      "𝟫",      ":",      ";",      "<",      "=",      ">",      "?",
+	"@",      "𝖠",      "𝖡",      "𝖢",      "𝖣",      "𝖤",      "𝖥",      "𝖦",      "𝖧",      "𝖨",      "𝖩",      "𝖪",      "𝖫",      "𝖬",      "𝖭",      "𝖮",      "𝖯",      "𝖰",      "𝖱",      "𝖲",      "𝖳",      "𝖴",      "𝖵",      "𝖶",      "𝖷",      "𝖸",      "𝖹",      "[",      "\\",     "]",      "^",      "_",
+	"`",      "𝖺",      "𝖻",      "𝖼",      "𝖽",      "𝖾",      "𝖿",      "𝗀",      "𝗁",      "𝗂",      "𝗃",      "𝗄",      "𝗅",      "𝗆",      "𝗇",      "𝗈",      "𝗉",      "𝗊",      "𝗋",      "𝗌",      "𝗍",      "𝗎",      "𝗏",      "𝗐",      "𝗑",      "𝗒",      "𝗓",      "{",      "|",      "}",      "~",      "\x7F"
+};
+
+void string_to_font(struct session *ses, long long flags, char *in, char *out)
+{
+	char buf[BUFFER_SIZE];
+	char *pti, *pto;
+	int skip;
+
+	push_call("string_to_font(%p,%d,%p,%p)",ses,flags,in,out);
+
+	// DRAW_FLAG_FAT, DRAW_FLAG_ITALIC, DRAW_FLAG_SERIF, DRAW_FLAG_CURSIVE, DRAW_FLAG_GOTHIC, DRAW_FLAG_TRACED, DRAW_FLAG_MONO
+
+	strcpy(buf, in);
+
+	pti = buf;
+	pto = out;
+
+	while (*pti)
+	{
+		skip = skip_vt102_codes(pti);
+
+		if (skip)
+		{
+			pto += sprintf(pto, "%.*s", skip, pti);
+
+			pti += skip;
+			
+			continue;
+		}
+
+		if (*pti >= 32)
+		{
+			switch (HAS_BIT(flags, DRAW_FLAG_FAT|DRAW_FLAG_CURSIVE|DRAW_FLAG_SANSSERIF))
+			{
+				case DRAW_FLAG_CURSIVE:
+					pto += sprintf(pto, "%s", alnum_cursive[(int) *pti]);
+					break;
+
+				case DRAW_FLAG_FAT:
+					pto += sprintf(pto, "%s", alnum_normal_fat[(int) *pti]);
+					break;
+
+				case DRAW_FLAG_SANSSERIF:
+					pto += sprintf(pto, "%s", alnum_sansserif[(int) *pti]);
+					break;
+
+				default:
+					*pto++ = *pti;
+					break;
+			}
+			pti++;
+		}
+		else
+		{
+			*pto++ = *pti++;
+		}
+	}
+	*pto++ = 0;
+
+	pop_call();
+	return;
+}
+
 int find_stamp(char *in, char *out)
 {
 	int cnt;
@@ -307,7 +425,7 @@ int find_stamp(char *in, char *out)
 	return 0;
 }
 
-void stamp_cat(char *color, int flags, char *str, char *cat, char *out)
+void stamp_cat(char *color, long long flags, char *str, char *cat, char *out)
 {
 	char *pts = str;
 	char *ptc = cat;
@@ -417,7 +535,7 @@ void stamp_cat(char *color, int flags, char *str, char *cat, char *out)
 	*pto = 0;
 }
 
-void string_to_stamp(struct session *ses, int flags, char *in, char *out)
+void string_to_stamp(struct session *ses, long long flags, char *in, char *out)
 {
 	char *pti, buf1[BUFFER_SIZE], buf2[BUFFER_SIZE], buf3[BUFFER_SIZE], chr1[CHAR_SIZE], color[COLOR_SIZE] = { 0 };
 	int skip;
@@ -456,7 +574,7 @@ void string_to_stamp(struct session *ses, int flags, char *in, char *out)
 	return;
 }
 
-char *get_draw_corner(int flags, char *str)
+char *get_draw_corner(long long flags, char *str)
 {
 	draw_cnt = (draw_cnt + 1) % 100;
 
@@ -783,7 +901,7 @@ char *get_draw_corner(int flags, char *str)
 	return draw_buf[draw_cnt];
 }
 
-char *draw_horizontal(int flags, char *str)
+char *draw_horizontal(long long flags, char *str)
 {
 	draw_cnt = (draw_cnt + 1) % 100;
 
@@ -813,7 +931,7 @@ char *draw_horizontal(int flags, char *str)
 	return draw_buf[draw_cnt];
 }
 
-char *draw_vertical(int flags, char *str)
+char *draw_vertical(long long flags, char *str)
 {
 	draw_cnt = (draw_cnt + 1) % 100;
 
@@ -990,16 +1108,16 @@ DO_DRAW(draw_line)
 DO_DRAW(draw_map)
 {
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
-	top_row = get_row_index(ses, arg1);
+	top_row = get_row_index_arg(ses, arg1);
 
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
-	top_col = get_col_index(ses, arg1);
+	top_col = get_col_index_arg(ses, arg1);
 
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
-	bot_row = get_row_index(ses, arg1);
+	bot_row = get_row_index_arg(ses, arg1);
 
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
-	bot_col = get_col_index(ses, arg1);
+	bot_col = get_col_index_arg(ses, arg1);
 
 	rows = URANGE(1, 1 + bot_row - top_row, gtd->screen->rows);
 	cols = URANGE(1, 1 + bot_col - top_col, gtd->screen->cols);
@@ -1534,6 +1652,7 @@ DO_DRAW(draw_text)
 				arg++;
 			}
 		}
+		string_to_font(ses, flags, buf2, buf2);
 	}
 
 	if (HAS_BIT(flags, DRAW_FLAG_BOXED) /*|| HAS_BIT(flags, DRAW_FLAG_LINED)*/ || HAS_BIT(flags, DRAW_FLAG_TOP) || HAS_BIT(flags, DRAW_FLAG_PRUNED))

+ 102 - 78
src/event.c

@@ -173,16 +173,17 @@ int check_all_events(struct session *ses, int flags, int args, int vars, char *f
 	return 0;
 }
 
-void mouse_handler(struct session *ses, int flags, int row, int col, char type)
+void mouse_handler(struct session *ses, int flags, int row, int col)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], line[BUFFER_SIZE], word[BUFFER_SIZE];
+	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], line[BUFFER_SIZE];
+	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;
-
-	push_call("mouse_handler(%p,%d,%d,%d,%c)",ses,flags,row,col,type);
+	int debug, info, rev_row, rev_col, link;
 
+	push_call("mouse_handler(%p,%d,%d,%d,%c)",ses,flags,row,col);
+/*
 	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))
@@ -190,31 +191,27 @@ void mouse_handler(struct session *ses, int flags, int row, int col, char type)
 			return;
 		}
 	}
-
+*/
 	if (HAS_BIT(flags, MOUSE_FLAG_MOTION))
 	{
 		strcpy(arg1, "MOVED");
 	}
 	else
 	{
-		switch (type)
+		if (HAS_BIT(flags, MOUSE_FLAG_RELEASE))
 		{
-			case 'M':
-				if (HAS_BIT(flags, MOUSE_FLAG_WHEEL))
-				{
-					strcpy(arg1, "SCROLLED");
-				}
-				else
-				{
-					strcpy(arg1, "PRESSED");
-				}
-				break;
-			case 'm':
-				strcpy(arg1, "RELEASED");
-				break;
-			default:
-				strcpy(arg1, "UNKNOWN");
-				break;
+			strcpy(arg1, "RELEASED");
+		}
+		else
+		{
+			if (HAS_BIT(flags, MOUSE_FLAG_WHEEL))
+			{
+				strcpy(arg1, "SCROLLED");
+			}
+			else
+			{
+				strcpy(arg1, "PRESSED");
+			}
 		}
 	}
 
@@ -238,76 +235,57 @@ void mouse_handler(struct session *ses, int flags, int row, int col, char type)
 		strcat(arg2, "EXTRA ");
 	}
 
-	if (HAS_BIT(flags, MOUSE_FLAG_UNKNOWN))
-	{
-		strcat(arg2, "256 ");
-	}
-
-	if (HAS_BIT(flags, MOUSE_FLAG_WHEEL))
-	{
-		strcat(arg2, "MOUSE WHEEL ");
-	}
-	else
-	{
-		strcat(arg2, "MOUSE BUTTON ");
-	}
-
-	if (row - 1 < 0)
+	if (row < 1)
 	{
 		tintin_printf2(ses, "mouse_handler: bad row: (row,col)=(%d,%d)", row, col);
 		pop_call();
 		return;
 	}
-	else if (row - 1 > gtd->screen->rows)
+	else if (row > gtd->screen->rows)
 	{
 		tintin_printf2(ses, "mouse_handler: bad col: (row,col)=(%d,%d)", row, col);
 		pop_call();
 		return;
 	}
-	else
-	{
-		strcpy(line, "under development");
-		strcpy(word, "under development");
-//		get_line_screen(line, row - 1);
-//		get_word_screen(word, row - 1, col - 1);
-	}
+
+	get_line_screen(line, row - 1);
+
+	link = get_link_screen(ses, word, flags, row, col);
 
 	if (HAS_BIT(flags, MOUSE_FLAG_WHEEL))
 	{
-		if (HAS_BIT(flags, MOUSE_FLAG_BUTTON_A) && HAS_BIT(flags, MOUSE_FLAG_BUTTON_B))
-		{
-			strcat(arg2, "RIGHT");
-		}
-		else if (HAS_BIT(flags, MOUSE_FLAG_BUTTON_B))
-		{
-			strcat(arg2, "LEFT");
-		}
-		else if (HAS_BIT(flags, MOUSE_FLAG_BUTTON_A))
-		{
-			strcat(arg2, "DOWN");
-		}
-		else
+		switch (HAS_BIT(flags, MOUSE_FLAG_BUTTON_A|MOUSE_FLAG_BUTTON_B))
 		{
-			strcat(arg2, "UP");
+			case 0:
+				strcat(arg2, "MOUSE WHEEL UP");
+				break;
+			case MOUSE_FLAG_BUTTON_A:
+				strcat(arg2, "MOUSE WHEEL DOWN");
+				break;
+			case MOUSE_FLAG_BUTTON_B:
+				strcat(arg2, "MOUSE WHEEL LEFT");
+				break;
+			case MOUSE_FLAG_BUTTON_A|MOUSE_FLAG_BUTTON_B:
+				strcat(arg2, "MOUSE WHEEL RIGHT");
+				break;
 		}
 	}
 	else
 	{
-		if (HAS_BIT(flags, MOUSE_FLAG_BUTTON_A) && HAS_BIT(flags, MOUSE_FLAG_BUTTON_B))
-		{
-			strcat(arg2, "FOUR");
-		}
-		else if (HAS_BIT(flags, MOUSE_FLAG_BUTTON_B))
-		{
-			strcat(arg2, "THREE");
-		}
-		else if (HAS_BIT(flags, MOUSE_FLAG_BUTTON_A))
-		{
-			strcat(arg2, "TWO");
-		}
-		else
+		switch (HAS_BIT(flags, MOUSE_FLAG_BUTTON_A|MOUSE_FLAG_BUTTON_B))
 		{
-			strcat(arg2, "ONE");
+			case 0:
+				strcat(arg2, "MOUSE BUTTON ONE");
+				break;
+			case MOUSE_FLAG_BUTTON_A:
+				strcat(arg2, "MOUSE BUTTON TWO");
+				break;
+			case MOUSE_FLAG_BUTTON_B:
+				strcat(arg2, "MOUSE BUTTON THREE");
+				break;
+			case MOUSE_FLAG_BUTTON_A|MOUSE_FLAG_BUTTON_B:
+				strcat(arg2, "MOUSE");
+				break;
 		}
 	}
 
@@ -317,11 +295,29 @@ void mouse_handler(struct session *ses, int flags, int row, int col, char type)
 	gtd->level->debug += debug;
 	gtd->level->info  += info;
 
-	check_all_buttons(ses, row, col, arg1, arg2, word, line);
+	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));
+				
+				do_help(ses, 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);
@@ -349,7 +345,15 @@ void mouse_handler(struct session *ses, int flags, int row, int col, char type)
 			{
 				if (click[0] - click[2] < 500000)
 				{
-					check_all_buttons(ses, row, col, "TRIPLE-CLICKED", arg2, word, line);
+					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);
 
@@ -363,7 +367,15 @@ void mouse_handler(struct session *ses, int flags, int row, int col, char type)
 				}
 				else
 				{
-					check_all_buttons(ses, row, col, "DOUBLE-CLICKED", arg2, word, line);
+					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);
 
@@ -418,8 +430,13 @@ void mouse_handler(struct session *ses, int flags, int row, int col, char type)
 		}
 		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);
@@ -432,8 +449,15 @@ void mouse_handler(struct session *ses, int flags, int row, int col, char type)
 		{
 			if (abs(swipe[0] - swipe[4]) <= 3 && abs(swipe[1] - swipe[5]) <= 3)
 			{
-				check_all_buttons(ses, row, col, "SHORT-CLICKED", arg2, word, line);
+				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);

+ 15 - 2
src/files.c

@@ -52,7 +52,7 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 {
 	struct stat filedata;
 	char *bufi, *bufo, temp[INPUT_SIZE], *pti, *pto, last = 0;
-	int lvl, cnt, com, lnc, fix, ok;
+	int lvl, cnt, com, lnc, fix, ok, verbose;
 	int counter[LIST_MAX];
 
 	temp[0] = getc(fp);
@@ -91,6 +91,7 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 		return ses;
 	}
 
+
 	fread(bufi, 1, filedata.st_size, fp);
 
 	pti = bufi;
@@ -276,6 +277,8 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 	*pto++ = '\n';
 	*pto   = '\0';
 
+
+
 	if (lvl)
 	{
 		check_all_events(ses, SUB_ARG, 0, 2, "READ ERROR", filename, "MISSING BRACE OPEN OR CLOSE");
@@ -317,10 +320,18 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 		gtd->level->verbose--;
 	}
 
+	verbose = HAS_BIT(ses->flags, SES_FLAG_VERBOSE) ? 1 : 0;
+
+	gtd->level->input++;
+
+	gtd->level->verbose += verbose;
+
 	gtd->level->quiet++;
 
 	do_configure(ses, temp);
 
+	gtd->level->quiet--;
+
 	lvl = 0;
 	lnc = 0;
 	pti = bufo;
@@ -349,7 +360,9 @@ struct session *read_file(struct session *ses, FILE *fp, char *filename)
 		pti++;
 	}
 
-	gtd->level->quiet--;
+	gtd->level->verbose -= verbose;
+
+	gtd->level->input--;
 
 	if (!HAS_BIT(ses->flags, SES_FLAG_VERBOSE))
 	{

+ 492 - 54
src/help.c

@@ -50,11 +50,21 @@ char *help_related(struct session *ses, int index, int html)
 	{
 		arg = get_arg_in_braces(ses, arg, tmp, GET_ONE);
 
-		if (html)
+		if (html == 1)
 		{
 			sprintf(link, "\\c<a href='%s.php'\\c>%s\\c</a\\c>", tmp, tmp);
 			sprintf(tmp, "%s", link);
 		}
+		else if (html == 2)
+		{
+			sprintf(link, "\\c<a href='#%s'\\c>%s\\c</a\\c>", capitalize(tmp), tmp);
+			sprintf(tmp, "%s", link);
+		}
+		else if (HAS_BIT(gtd->flags, TINTIN_FLAG_MOUSETRACKING))
+		{
+			sprintf(link, "\e]68;2;%s\a\e[4m%s\e[24m", tmp, tmp);
+			sprintf(tmp, "%s", link);
+		}
 
 		if (*buf == 0)
 		{
@@ -78,7 +88,7 @@ char *help_related(struct session *ses, int index, int html)
 
 DO_COMMAND(do_help)
 {
-	char arg1[BUFFER_SIZE], buf[BUFFER_SIZE];
+	char arg1[BUFFER_SIZE], buf[BUFFER_SIZE], tmp[BUFFER_SIZE];
 	int cnt, found;
 
 	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
@@ -89,13 +99,22 @@ DO_COMMAND(do_help)
 
 		for (cnt = 0 ; *help_table[cnt].name != 0 ; cnt++)
 		{
-			if (strlen(buf) + 19 > ses->wrap)
+			if (HAS_BIT(gtd->flags, TINTIN_FLAG_MOUSETRACKING))
+			{
+				sprintf(tmp, "%.*s\e]68;2;%s\a\e[4m%s\e[24m", 15 - (int) strlen(help_table[cnt].name), "                ", help_table[cnt].name, help_table[cnt].name);
+			}
+			else
+			{
+				sprintf(tmp, "%15s", help_table[cnt].name);
+			}
+
+			if (strip_vt102_strlen(ses, buf) + 15 > ses->wrap)
 			{
 				print_lines(ses, SUB_COL, "<088>%s<088>\n", buf);
 
 				*buf = 0;
 			}
-			cat_sprintf(buf, "%19s ", help_table[cnt].name);
+			cat_sprintf(buf, "%s ", tmp);
 		}
 
 		if (*buf)
@@ -118,7 +137,7 @@ DO_COMMAND(do_help)
 
 		for (cnt = 0 ; *help_table[cnt].name != 0 ; cnt++)
 		{
-			if (cnt && cnt % 4 == 0)
+			if (cnt && cnt % 5 == 0)
 			{
 				substitute(ses, buf, buf, SUB_ESC|SUB_COL);
 
@@ -126,7 +145,7 @@ DO_COMMAND(do_help)
 
 				*buf = 0;
 			}
-			cat_sprintf(buf, "     \\c<a href='#%s'\\c>%15s\\c</a\\c>", help_table[cnt].name, help_table[cnt].name);
+			cat_sprintf(buf, " \\c<a href='#%s'\\c>%15s\\c</a\\c>", help_table[cnt].name, help_table[cnt].name);
 		}
 
 		cat_sprintf(buf, "\n\n");
@@ -155,7 +174,7 @@ DO_COMMAND(do_help)
 
 			if (*help_table[cnt].also)
 			{
-				substitute(ses, help_related(ses, cnt, 0), buf, SUB_COL);
+				substitute(ses, help_related(ses, cnt, 2), buf, SUB_ESC|SUB_COL);
 
 				logit(ses, buf, logfile, LOG_FLAG_LINEFEED);
 			}
@@ -214,7 +233,7 @@ DO_COMMAND(do_help)
 			if (is_abbrev(arg1, help_table[cnt].name))
 			{
 				print_lines(ses, SUB_COL, "%s<088>\n", help_table[cnt].text);
-				
+
 				if (*help_table[cnt].also)
 				{
 					print_lines(ses, SUB_COL, "%s<088>\n\n", help_related(ses, cnt, 0));
@@ -380,7 +399,7 @@ struct help_type help_table[] =
 		"         It's possible to adjust the alarm bell volume on some terminals.\n"
 		"\n"
 		"<178>Example<278>: #loop {1} {8} {cnt} {#line substitute variables\n"
-		"           #delay {$cnt} #showme {Volume $cnt: #bell volume $cnt;#bell}\n",
+		"           #delay {$cnt} {#showme Volume $cnt: #bell volume $cnt;#bell}\n",
 
 		"screen"
 	},
@@ -923,11 +942,13 @@ struct help_type help_table[] =
 		"\n"
 		"         ASCII      will draw in ASCII mode.\n"
 		"         BLANKED    will blank the lines and corners.\n"
+		"         BOLD       will draw text with bold letters.\n"
 		"         BOTTOM     will draw on the bottom side if possible.\n"
 		"         BUMPED     will precede the draw with an enter.\n"
 		"         CIRCLED    will circle the corners.\n"
 		"         CONVERT    will draw text with meta conversion.\n"
 		"         CROSSED    will cross the corners.\n"
+		"         CURSIVE    will draw text with cursive letters.\n"
 		"         FILLED     will fill circles and jewels.\n"
 		"         GRID       will draw TABLE as a grid.\n"
 		"         HORIZONTAL will draw horizontal if possible.\n"
@@ -939,6 +960,7 @@ struct help_type help_table[] =
 		"         PRUNED     will prune the corners.\n"
 		"         RIGHT      will draw on the right side if possible.\n"
 		"         ROUNDED    will round the corners.\n"
+		"         SCROLL     will draw in the scrolling region.\n"
 		"         SHADOWED   will shadow HUGE text.\n"
 		"         TEED       will tee the corners.\n"
 		"         TRACED     will trace HUGE text.\n"
@@ -1146,8 +1168,8 @@ struct help_type help_table[] =
 		"         WRITE ERROR            %0 filename %1 error message\n"
 		"         YEAR                   %0 year\n"
 		"\n"
-		"         To see all events trigger use #event info on. Since this can quite\n"
-		"         spammy it's possible to gag event info messages.\n"
+		"         To see all events trigger use #event info on. Since this can get\n"
+		"         rather spammy it's possible to gag event info messages.\n"
 		"\n"
 		"<178>Example<278>: #event {SESSION CONNECTED} {#read mychar.tin}\n"
 		"\n"
@@ -1264,6 +1286,8 @@ struct help_type help_table[] =
 		"\n"
 		"<178>Comment<278>: See '#help action', for more information about triggers.\n"
 		"\n"
+		"         There are a system messages that can be gagged using gag events.\n"
+		"\n"
 		"<178>Comment<278>: You can remove a gag with the #ungag command.\n",
 		
 		"action highlight prompt substitute"
@@ -1452,7 +1476,8 @@ struct help_type help_table[] =
 	{
 		"INDEX",
 
-		"<278>"
+		"<128>         INDEX\n"
+		"<278>\n"
 		"         On this page you'll find an introduction to using TinTin++. Additional\n"
 		"         information can be found in the individual help sections.\n"
 		"<128>\n"
@@ -1478,8 +1503,7 @@ struct help_type help_table[] =
 		"\n"
 		"         All TinTin++ commands starts with a '#'.\n"
 		"\n"
-		"<178>Example<278>: #help -- #help is a client command, and isn't send to the\n"
-		"         server.\n"
+		"<178>Example<278>: #help -- #help is a client command, and isn't send to the server.\n"
 		"\n"
 		"         All TinTin++ commands can be abbreviated when typed.\n"
 		"\n"
@@ -1737,7 +1761,6 @@ struct help_type help_table[] =
 	},
 	{
 		"KEYPAD",
-
 		"<278>When TinTin++ starts up it sends \\e= to the terminal to enable the terminal's\n"
 		"application keypad mode, which can be disabled using #showme {\\e>}\n"
 		"\n"
@@ -1806,6 +1829,9 @@ struct help_type help_table[] =
 		"         <178>#line capture <variable> <argument.\n"
 		"         <278>  Argument is executed and output stored in <variable>.\n"
 		"\n"
+		"         <178>#line convert <argument>\n"
+		"         <278>  Argument is executed with escaped meta characters.\n"
+		"\n"
 		"         <178>#line debug <argument>\n"
 		"         <278>  Argument is executed in debug mode.\n"
 		"\n"
@@ -1822,9 +1848,6 @@ struct help_type help_table[] =
 		"         <178>#line logmode <option> <argument>\n"
 		"         <278>  Argument is executed using the provided logmode, available\n"
 		"         <278>  modes are: html, plain, and raw.\n"
-//		"\n"
-//		"         <178>#line logverbatim {filename} {[text]}  Log text without variable\n"
-//		"         <278>                                  substitution.\n"
 		"\n"
 		"         <178>#line oneshot <argument>\n"
 		"         <278>  Argument is executed in oneshot mode, all triggers created will\n"
@@ -1868,6 +1891,7 @@ struct help_type help_table[] =
 		"         #list {var} {insert} {index} {string}  Insert {string} at given index\n"
 		"         #list {var} {find} {string} {variable} Return the found index\n"
 		"         #list {var} {get} {index} {variable}   Copy an item to {variable}\n"
+		"         #list {var} {order} {string}           Insert item in numerical order\n"
 		"         #list {var} {shuffle}                  Shuffle the list\n"
 		"         #list {var} {set} {index} {string}     Change the item at {index}\n"
 		"         #list {var} {simplify} {variable}      Copy simple list to {variable}\n"
@@ -1893,6 +1917,281 @@ struct help_type help_table[] =
 		"break continue foreach loop parse repeat return while"
 	},
 
+	{
+		"LISTS",
+
+		"<278>         There are several different types of lists in tintin which behave in a\n"
+		"         fairly universal manner. To properly explain lists it's easiest to\n"
+		"         explain the most basic variable type first before discussing more\n"
+		"         complex types.\n"
+		"\n"
+		"       - Basic variable: The standard key = value variable.\n"
+		"\n"
+		"       - Simple list: A string that contains semicolon delimited fields.\n"
+		"         {a;b;c}. Can be saved as a variable.\n"
+		"\n"
+		"       - Brace list: A string in which fields are delimited with braces.\n"
+		"         {a}{b}{c}. Brace lists cannot be stored as a variable because tables\n"
+		"         use braces as well, they must be stored as a simple list instead.\n"
+		"\n"
+		"       - Table: Think of this as variables nested within another variable. Or\n"
+		"          as variables contained within another variable.\n"
+		"\n"
+		"       - List: A table that uses integers for its indexes. Also known as an\n"
+		"         array. The #list command is a utility command for using tables as\n"
+		"         arrays.\n"
+		"<128>\n"
+		"         Simple Variables\n"
+		"<278>\n"
+		"<178>Example:<278>\n"
+		"         #variable {simple} {Hello World!}\n"
+		"         #showme $simple\n"
+		"\n"
+		"         To see if the 'simple' variable exists you can use &simple which will\n"
+		"         display 0 if the variable does not exist, or the variable's index if\n"
+		"         it exists.\n"
+		"\n"
+		"         If you have multiple variables they are sorted alphabetically and\n"
+		"         numerically. While it's not all that relevant for simple variables,\n"
+		"         the first variable has index 1, the second variable index 2, and so\n"
+		"         on.\n"
+		"\n"
+		"         Variable names need to start with a letter and only exist of letters,\n"
+		"         numbers, and underscores. If you need to use a non standard variable\n"
+		"         name this is possible using braces.\n"
+		"\n"
+		"<178>Example: <278>#variable {:)} {Happy Happy!};#showme ${:)}\n"
+		"\n"
+		"         Variables can be accessed using their index. While primarily useful\n"
+		"         for tables it is possible to do this for simple variables. Use +1 for\n"
+		"         the first variable, +2 for the second variable, etc. Use -1 for the\n"
+		"         last variable, -2 for the second last variable, etc.\n"
+		"\n"
+		"<178>Example:<278> #showme The first variable is: ${+1}\n"
+		"<128>\n"
+		"         Removing Variables\n"
+		"<278>\n"
+		"         To remove a variable, use #unvariable or #unvar (every command can be\n"
+		"         abbreviated). It's possible to remove multiple variables at once\n"
+		"         using #unvar {var 1} {var 2} {etc}\n"
+		"\n"
+		"         Variables are unique to each session, so if you have multiple\n"
+		"         sessions, removing a variable from one session won't remove it from\n"
+		"         other sessions.\n"
+		"\n"
+		"         If you remove a table variable, all variables contained within that\n"
+		"         table variable are removed as well.\n"
+		"<128>\n"
+		"         Simple Lists\n"
+		"<278>\n"
+		"         A simple list is a string that contains semicolon delimited fields.\n"
+		"         Commands can be entered as simple lists, for example:\n"
+		"         #showme {a};#showme {b} will execute a single line as two commands.\n"
+		"\n"
+		"         Several commands take a simple list as their input, these are:\n"
+		"         #foreach, #line substitute, #path load, #list create, and #highlight.\n"
+		"<128>\n"
+		"         Brace Lists\n"
+		"<278>\n"
+		"         A brace list is a string in which fields are delimited with braces.\n"
+		"         Most commands take a brace list for their arguments, for example:\n"
+		"         #session {x} {mud.com} {1234} {mud.tin}. The session command takes\n"
+		"         4 arguments, the 4th argument (command file) is optional.\n"
+		"\n"
+		"         Commands that take a simple list as their input will also accept a\n"
+		"         brace list, keep in mind you'll have to embed the brace list in an\n"
+		"         extra set of braces, for example: #path load {{n}{s}{w}{w}}, which is\n"
+		"         identical to: #path load {n;s;w;w}.\n"
+		"\n"
+		"         Brace lists cannot be stored as variables because TinTin++ will\n"
+		"         confuse them with tables. You can convert a brace list to a table\n"
+		"         variable using: #list {bracelist} {create} {{a}{b}{c}} this will look\n"
+		"         internally as: {{1}{a}{2}{b}{3}{c}}. You can then convert this table\n"
+		"         to a simple list using: #list {bracelist} {simplify} {simplelist}\n"
+		"         which will store {a;b;c} in the $simplelist variable.\n"
+		"\n"
+		"         Braces cannot easily be escaped in TinTin++. Using \\{ or \\} will not\n"
+		"         work. The reason for this is due to several factors, but primarily\n"
+		"         backward compatibility. To escape braces you must define them using\n"
+		"         hexadecimal notation using \\x7B and \\x7D. See #help escape for a list\n"
+		"         of escape options, and the help file will also remind you of how to\n"
+		"         escape braces.\n"
+		"<128>\n"
+		"         Tables\n"
+		"<278>\n"
+		"         Tables are key/value pairs stored within a variable. Tables are also\n"
+		"         known as associative arrays, dictionaries, maps, nested variables,\n"
+		"         structures, and probably a couple of other names. There are several\n"
+		"         ways to create and access tables.\n"
+		"\n"
+		"<178>Example:<278> #variable {friendlist} {{bob}{bob@mail.com} {bubba}{sunset@gmail.com}}\n"
+		"\n"
+		"         This will create a friendlist with two entries, the key is the name of\n"
+		"         the friend, the value is the email address of the friend. You can see\n"
+		"         the email address of bob using: #showme {$friendlist[bob]}. You can\n"
+		"         also define this table as following:\n"
+		"\n"
+		"<178>Example:<278>\n"
+		"         #variable {friendlist[bob]} {bob@mail.com}\n"
+		"         #variable {friendlist[bubba]} {sunset@gmail.com}\n"
+		"\n"
+		"         This would create the exact same table as the single line declaration\n"
+		"         used previously. To see the first key in the table use:\n"
+		"         *friendlist[+1], to see the first value in the table use:\n"
+		"         $friendlist[+1]. To see the size of the table use &friendlist[]. To\n"
+		"         print a bracelist of all friends use *friendlist[%*], to print a\n"
+		"         bracelist of all friends whose name starts with the letter 'a' you\n"
+		"         would use: *friendlist[a%*]. Similarly to see the number of friends\n"
+		"         you have whose name ends with the letter 'b' you would use:\n"
+		"         &friendlist[%*b].\n"
+		"\n"
+		"         See #help regexp for a brief overview of regular expression options.\n"
+		"         While TinTin++ supports PCRE (perl-compatible regular expressions), it\n"
+		"         embeds them within its own regular expression syntax that is simpler\n"
+		"         and less invasive, while still allowing the full power of PCRE for\n"
+		"         those who need it.\n"
+		"\n"
+		"<178>Example:<278> #unvariable {friendlist[bubba]}\n"
+		"\n"
+		"         This would remove {bubba} from the friendlist. To remove the entire\n"
+		"         friendlist you would use: #unvariable {friendlist}.\n"
+		"\n"
+		"<178>Example:<278> #variable {friendlist} {{bob} {{email}{bob@ma.il} {phone}{123456789}}}\n"
+		"\n"
+		"         There is no limit to the number of nests, simply add more braces. To\n"
+		"         see Bob's email in this example you would use:\n"
+		"         #showme {$friendlist[bob][email]}.\n"
+		"<278>\n"
+		"         Lists\n"
+		"\n"
+		"         Tables are sorted alphabetically with the exception of numbers which\n"
+		"         are sorted numerically. If you want to determine the sorting order\n"
+		"         yourself you can use use the #list command which helps you to use\n"
+		"         tables as arrays.\n"
+		"\n"
+		"<178>Example:<278> #action {%1 chats %2} {#list chats add {%0}}\n"
+		"\n"
+		"         Each time a chat is received it's added to the end of the 'chats' list\n"
+		"         variable. If you type #variable chats this might look like:\n"
+		"\n"
+		"         <138>#<168>VARIABLE <258>{<178>chats<258>}\n"
+		"         {\n"
+		"                 {<178>1<258>} {<178>Bubba chats Hi<258>}\n"
+		"                 {<178>2<258>} {<178>Bob chats Hi bub<258>}\n"
+		"                 {<178>3<258>} {<178>Bubba chats Bye<258>}\n"
+		"                 {<178>4<258>} {<178>Bob chats bub bye<258>}\n"
+		"         }\n"
+		"<128>\n"
+		"         Parsing\n"
+		"<278>\n"
+		"         There are various ways to parse lists and tables, using either #loop,\n"
+		"         #foreach, #while, or #<number>.\n"
+		"\n"
+		"         #loop takes two numeric arguments, incrementing or decrementing the\n"
+		"         first number until it matches the second number. The value of the loop\n"
+		"         counter is stored in the provided variable.\n"
+		"\n"
+		"         #foreach takes either a simple list or a brace list as its first\n"
+		"         argument. Foreach will go through each item in the list and store the\n"
+		"         value in the provided variable.\n"
+		"\n"
+		"         #while will perform an if check on the first argument, if the result\n"
+		"         is true it will execute the commands in the second argument. Then it\n"
+		"         performs an if check on the first argument again. It will continue to\n"
+		"         repeat until the if check returns 0 or the loop is interrupted with a\n"
+		"         control flow command. It takes special care to avoid infinite loops.\n"
+		"\n"
+		"         #<number> will execute the provided argument 'number' times. For\n"
+		"         example: #4 {#showme beep! \\a}\n"
+		"\n"
+		"         Here are some examples.\n"
+		"\n"
+		"<178>Example:<278> #list friends create {bob;bubba;zorro}\n"
+		"\n"
+		"         Internally this looks like {{1}{bob}{2}{bubba}{3}{zorro}} and the\n"
+		"         list can be parsed in various ways.\n"
+		"\n"
+		"<178>Example:<278> #foreach {$friends[%*]} {name} {#show $name}\n"
+		"\n"
+		"<178>Example:<278> #foreach {*friends[%*]} {i} {#show $friends[$i]}\n"
+		"\n"
+		"<178>Example:<278> #loop {1} {&friends[]} {i} {#show $friends[+$i]}\n"
+		"\n"
+		"<178>Example:<278> #math i 1;#while {&friends[+$i]} {#show $friends[+$i];\n"
+		"         #math i $i + 1}\n"
+		"\n"
+		"<178>Example:<278> #math i 1;#&friends[] {#show $friends[+$i];#math i $i + 1}\n"
+		"\n"
+		"         Each of the five examples above performs the same task; printing the\n"
+		"         three names in the friends list.\n"
+		"\n"
+		"         If you want to get a better look at what goes on behind the scenes\n"
+		"         while executing scripts you can use '#debug all on'. To stop seeing\n"
+		"         debug information use '#debug all off'.\n"
+		"<128>\n"
+		"         Optimization\n"
+		"<278>\n"
+		"         TinTin++ tables are exceptionally fast while they remain under 100\n"
+		"         items. Once a table grows beyond 10000 items there can be performance\n"
+		"         issues when inserting and removing items in the beginning or middle of\n"
+		"         the table.\n"
+		"\n"
+		"         The plan is to eventually implement an indexable and flexible data\n"
+		"         structure for large tables.\n"
+		"\n"
+		"         If you load a large table from file it's important to make sure it's\n"
+		"         sorted, when using #write to save a table it's automatically sorted.\n"
+		"\n"
+		"         If you notice performance issues on large tables it's relatively easy\n"
+		"         to create a hash table.\n"
+		"\n"
+		"<178>Example:<278>\n"
+		"\n"
+		"         #alias {sethash}\n"
+		"         {\n"
+		"         	#format hash %H %1;\n"
+		"         	#math hash1 $hash % 100;\n"
+		"         	#math hash2 $hash / 100 % 100;\n"
+		"         	#var hashtable[$hash1][$hash2][%1] %2\n"
+		"         }\n"
+		"\n"
+		"         #function {gethash}\n"
+		"         {\n"
+		"         	#format hash %H %1;\n"
+		"         	#math hash1 $hash % 100;\n"
+		"         	#math hash2 $hash / 100 % 100;\n"
+		"         	#return $hashtable[$hash1][$hash2][%1]\n"
+		"         }\n"
+		"\n"
+		"         #alias {test}\n"
+		"         {\n"
+		"         	sethash bli hey;\n"
+		"         	sethash bla hi;\n"
+		"         	sethash blo hello;\n"
+		"         	#showme The value of bla is: @gethash{bla}\n"
+		"         }\n"
+		"\n"
+		"         The above script will rapidly store and retrieve over 1 million items.\n"
+		"         Looping through a hash table is relatively easy as well.\n"
+		"\n"
+		"<178>Example:<278>\n"
+		"\n"
+		"         #alias {showhash}\n"
+		"         {\n"
+		"         	#foreach {*hashtable[%*]} {hash1}\n"
+		"         	{\n"
+		"         		#foreach {*hashtable[$hash1][%*]} {hash2}\n"
+		"         		{\n"
+		"         			#echo {%-20s = %s}\n"
+		"                                        {hashtable[$hash1][$hash2]}\n"
+		"                                        {$hashtable[$hash1][$hash2]}\n"
+		"         		}\n"
+		"         	}\n"
+		"        }\n",
+		
+		"break continue foreach loop parse repeat return while"
+	},
+	
 	{
 		"LOCAL",
 
@@ -2274,6 +2573,121 @@ struct help_type help_table[] =
 
 		"path pathdir"
 	},
+
+	{
+		"MAPPING",
+
+		"<278>\n"
+		"         TinTin++ has a powerful automapper that uses a room system similar to\n"
+		"         Diku MUDs which means that odd map layouts and weird exit\n"
+		"         configurations aren't a problem. The mapper provides tools to improve\n"
+		"         the visual map display. For basic path tracking see #help PATH.\n"
+		"\n"
+		"<178>         #map create [size]\n"
+		"<278>\n"
+		"         This command creates the initial map. The size is 50,000 by default\n"
+		"         and can be changed at any time with the #map resize command. If you\n"
+		"         play a MUD that uses MSDP or GMCP to provide room numbers you'll have\n"
+		"         to increase it to the highest reported room number. Increasing the\n"
+		"         size of the map doesn't decrease performance.\n"
+		"\n"
+		"<178>         #map goto <location>\n"
+		"<278>\n"
+		"         When you create the map you are not automatically inside the map. By\n"
+		"         default room number (vnum) 1 is created, so you can go to it using\n"
+		"         #map goto 1. Once you are inside the map new rooms are automatically\n"
+		"         created as you move around. Movement commands are defined with the\n"
+		"         pathdir command. By default n, ne, e, se, s, sw, w, nw, u, d are\n"
+		"         defined.\n"
+		"<178>\n"
+		"         #map map <rows> <cols> <append|overwrite|list|variable> <name>\n"
+		"<278>\n"
+		"         To see the map you can use #map map. It's annoying to have to\n"
+		"         constantly type #map map however. Instead it's possible to use #split\n"
+		"         to display a vt100 map. To do so execute:\n"
+		"         <178>#split 16 1\n"
+		"         #map flag vtmap on<278>\n"
+		"         The first command sets the top split lines to 16 and the bottom split\n"
+		"         line to 1. If you want a smaller or larger map display you can use a\n"
+		"         different value than 16.\n"
+		"\n"
+		"         If you don't need to display diagonal exits and prefer a more compact\n"
+		"         look you can use #map flag AsciiGraphics off. This will enable the\n"
+		"         standard display which uses UTF-8 box drawing characters, results may\n"
+		"         vary depending on the font used.\n"
+		"\n"
+		"         If your terminal supports UTF-8 you can also give #Map flag unicode on\n"
+		"         a try.\n"
+		"\n"
+		"         If you want to display the map in a different location of the screen\n"
+		"         use something like:\n"
+		"         <178>#split 0 1 0 -80\n"
+		"         #map offset 1 81 -4 -1<278>\n"
+		"         This will display the map on the right side of the screen, if the\n"
+		"         width of the screen is wide enough.\n"
+		"<178>\n"
+		"         #map undo\n"
+		"<278>\n"
+		"         If you accidentally walk into the wall on your MUD the mapper will\n"
+		"         still create a new room. You can easily fix this mistake by using\n"
+		"         #map undo. If you want to move around on the map without moving around\n"
+		"         on the MUD you can use: #map move {direction}. To delete a room\n"
+		"         manually you can use: #map delete {direction}. To create a room\n"
+		"         manually you can use: #map dig {direction}.\n"
+		"<178>\n"
+		"         #map write <filename>\n"
+		"<278>\n"
+		"         You can save your map using #map write, to load a map you can use\n"
+		"         #map read <filename>.\n"
+		"<178>\n"
+		"         #map set <option> <value>\n"
+		"<278>\n"
+		"         You can set the room name using #map set roomname <name>. You either\n"
+		"         have to do this manually or create triggers to set the room name\n"
+		"         automatically. Once the room name is set you can use #map goto with\n"
+		"         the room name to visit it. If there are two rooms with the same name\n"
+		"         #map goto will go to the most nearby room. If you want to always go\n"
+		"         to the same room you should memorize the room number. You can further\n"
+		"         narrow down the matches by providing additional arguments, for example:\n"
+		"<178>\n"
+		"         #map goto {dark alley} {roomexits} {n;e} {roomarea} {Haddock Ville}\n"
+		"<278>\n"
+		"         You can set the room weight using #map set roomweight {value}. The\n"
+		"         weight by default is set to 1.0 and it represents the difficulty of\n"
+		"         traversing the room. If you have a lake as an alternative route, and\n"
+		"         traversing water rooms is 4 times slower than regular rooms, then you\n"
+		"         could set the weight of the lake rooms to 4.0. If the lake is 3 rooms\n"
+		"         wide the total weight is 12. If walking around the lake has a weight\n"
+		"         less than 12 the mapper will go around the lake, if the weight is\n"
+		"         greater than 12 the mapper will take a route through the lake.\n"
+		"\n"
+		"         You can set the room symbol using #map set roomsymbol {value}. The\n"
+		"         symbol should be one, two, or three characters, which can be\n"
+		"         colorized. You can for example mark shops with an 'S' and colorize the\n"
+		"         'S' depending on what type of shop it is.\n"
+		"<178>\n"
+		"         #map run <location> <delay>\n"
+		"\n"
+		"         The run command will have tintin find the shortest path to the given\n"
+		"         location and execute the movement commands to get there. You can\n"
+		"         provide a delay in seconds with floating point precision, for example:\n"
+		"         <178>#map run {dark alley} {0.5}<278>\n"
+		"<178>\n"
+		"         #map insert {direction} {flag}\n"
+		"<278>\n"
+		"         The insert command is useful for adding spacer rooms called void rooms.\n"
+		"         Often rooms overlap, and by adding void rooms you can stretch out\n"
+		"         exits. For example: #map insert north void. You cannot enter void rooms\n"
+		"         once they've been created, so you'll have to use #map info in an\n"
+		"         adjacent room to find the room vnum, then use #map goto {vnum} to\n"
+		"         visit.\n"
+		"\n"
+		"         It's also possible to align rooms using void rooms. This is easily\n"
+		"         done using #map insert north void.\n",
+
+		"map path pathdir"
+	},
+
 	{
 		"MATH",
 
@@ -2410,36 +2824,37 @@ struct help_type help_table[] =
 	{
 		"METRIC SYSTEM",
 
-		"  Name  Symbol                              Factor\n"
-		"--------------------------------------------------\n"
-//		" Yotta       Y   1 000 000 000 000 000 000 000 000\n"
-//		" Zetta       Z       1 000 000 000 000 000 000 000\n"
-//		"   Exa       E           1 000 000 000 000 000 000\n"
-//		"  Peta       P               1 000 000 000 000 000\n"
-//		"  Tera       T                   1 000 000 000 000\n"
-//		"  Giga       G                       1 000 000 000\n"
-		"  Mega       M                           1 000 000\n"
-		"  Kilo       K                               1 000\n"
-		"\n"
-		" milli       m                               0.001\n"
-		" micro       u                           0.000 001\n",
-//		"  nano       n                       0.000 000 001\n"
-//		"  pico       p                   0.000 000 000 001\n"
-//		" femto       f               0.000 000 000 000 001\n"
-//		"  atto       a           0.000 000 000 000 000 001\n"
-//		" zepto       z       0.000 000 000 000 000 000 001\n"
-//		" yocto       y   0.000 000 000 000 000 000 000 001\n",
+		"<278>\n"
+		"             Name  Symbol                              Factor\n"
+		"           --------------------------------------------------\n"
+//		"            Yotta       Y   1 000 000 000 000 000 000 000 000\n"
+//		"            Zetta       Z       1 000 000 000 000 000 000 000\n"
+//		"              Exa       E           1 000 000 000 000 000 000\n"
+//		"             Peta       P               1 000 000 000 000 000\n"
+//		"             Tera       T                   1 000 000 000 000\n"
+//		"             Giga       G                       1 000 000 000\n"
+		"             Mega       M                           1 000 000\n"
+		"             Kilo       K                               1 000\n"
+		"\n"
+		"            milli       m                               0.001\n"
+		"            micro       u                           0.000 001\n",
+//		"             nano       n                       0.000 000 001\n"
+//		"             pico       p                   0.000 000 000 001\n"
+//		"            femto       f               0.000 000 000 000 001\n"
+//		"             atto       a           0.000 000 000 000 000 001\n"
+//		"            zepto       z       0.000 000 000 000 000 000 001\n"
+//		"            yocto       y   0.000 000 000 000 000 000 000 001\n",
 		
 		"echo format math"
 	},
-	
+
 	{
 		"MSDP",
 
 		"<278>\n"
-		"         MSDP is part of the #port functionality. See #help event for\n"
-		"         additional documentation as all MSDP events are available as\n"
-		"         regular events.\n"
+		"         MSDP (Mud Server Data Protocol) is part of the #port functionality.\n"
+		"         See #help event for additional documentation as all MSDP events are\n"
+		"         available as regular events.\n"
 		"\n"
 		"         Available MSDP events can be queried using the MSDP protocol\n"
 		"         as described in the specification.\n"
@@ -2448,6 +2863,23 @@ struct help_type help_table[] =
 
 		"event port"
 	},
+
+	{
+		"MSLP",
+
+		"<278>\n"
+		"         MSLP (Mud Server Link Protocol) is supported by TinTin++. See #help\n"
+		"         event for additional documentation as all MSLP events are available\n"
+		"         as regular events.\n"
+		"\n"
+		"         Available MSLP sequences can be generated using the MSLP protocol\n"
+		"         as described in the specification.\n"
+		"<178>\n"
+		"         https://tintin.mudhalla.net/protocols/mslp\n",
+
+		"event port"
+	},
+
 	{
 		"NOP",
 
@@ -2719,7 +3151,7 @@ struct help_type help_table[] =
 		"         To make matching easier text triggers (Actions, Gags, Highlights,\n"
 		"         Prompts, and Substitutes) have their color codes stripped. If you\n"
 		"         want to create a color trigger you must start the triggers with a ~\n"
-		"         (tilda). To make escape codes visible use #config {convert meta} on.\n"
+		"         (tilde). To make escape codes visible use #config {convert meta} on.\n"
 		"\n"
 		"Example: #action {~\\e[1;37m%1} {#var roomname %1}\n"
 		"\n"
@@ -3022,16 +3454,16 @@ struct help_type help_table[] =
 		"         <178>#screen fullscreen [on|off]\n"
 		"         <278>  Toggles fullscreen mode when used without an argument.\n"
 		"\n"
-		"         <178>#screen get <rows|cols|height|width> <var>\n"
-		"         <278>  Get the rows/cols size in characters or height/width in pixels.\n"
-		"\n"
-		"         <178>#screen get <top_row|bot_row|top_split|bot_split> <var>\n"
-		"         <278>  Get the top and bot row of the scrolling region or the height\n"
-		"         <888>  of the top and bot split bars.\n"
+		"         <178>#screen get <option> <var>\n"
+		"         <278>  Get various screen options and save them to <var>. Use #screen\n"
+		"         <278>  get without an argument to see all available options.\n"
 		"\n"
 		"         <178>#screen info\n"
 		"         <278>  Debugging information.\n"
 		"\n"
+		"         <178>#screen input <square>\n"
+		"         <278>  Set the input region\n"
+		"\n"
 		"         <178>#screen load <both|label|title>\n"
 		"         <278>  Reload the saved title, label, or both.\n"
 		"\n"
@@ -3059,6 +3491,9 @@ struct help_type help_table[] =
 		"         <178>#screen save <both|label|title>\n"
 		"         <278>  Save the title, label, or both.\n"
 		"\n"
+		"         <178>#screen scroll <square>\n"
+		"         <278>  Set the scrolling region, changes the split setting.\n"
+		"\n"
 		"         <178>#screen set <both|label|title>\n"
 		"         <278>  Set the title, label, or both. Only title works on Windows.\n",
 
@@ -3115,6 +3550,7 @@ struct help_type help_table[] =
 
 		"textin"
 	},
+
 	{
 		"SESSION",
 
@@ -3217,16 +3653,17 @@ struct help_type help_table[] =
 	{
 		"SPEEDWALK",
 
-		"         <278>Speedwalking allows you to enter multiple directions without using\n"
+		"<278>\n"
+		"         Speedwalking allows you to enter multiple directions without using\n"
 		"         semicolons. Directions should be prefixed with a number and will be\n"
 		"         executed the given number of times.\n"
 		"\n"
 		"         You can enable speedwalking with #CONFIG {SPEEDWALK} {ON}.\n"
 		"\n"
 		"<178>Example<278>: Without speedwalk, you have to type:\n"
-		"         s;s;w;w;w;w;w;s;s;s;w;w;w;n;n;w\n"
-		"         With speedwalk, you only have to type:\n"
-		"         2s5w3s3w2n1w\n",
+		"         <178>s;s;w;w;w;w;w;s;s;s;w;w;w;n;n;w\n"
+		"         <278>With speedwalk, you only have to type:\n"
+		"         <178>2s5w3s3w2n1w\n",
 
 		"alias cursor history keypad macro tab"
 	},
@@ -3292,8 +3729,9 @@ struct help_type help_table[] =
 	{
 		"STATEMENTS",
 
-		"         TinTin++ knows the following statements.\n"
 		"<278>\n"
+		"         TinTin++ knows the following statements.\n"
+		"\n"
 		"         #break\n"
 		"         #case {value} {true}\n"
 		"         #continue\n"
@@ -3466,7 +3904,7 @@ struct help_type help_table[] =
 		"         %z  5 digit timezone offset. (-1200 ... +1400)\n"
 		"         %Z  Abbreviated name of the time zone.\n",
 
-		"echo format"
+		"echo event format"
 	},
 	{
 		"VARIABLE",

+ 76 - 55
src/input.c

@@ -84,6 +84,22 @@ void process_input(void)
 		show_message(gtd->ses, LIST_COMMAND, "#DAEMON ATTACH: WRITE ERROR: UNATTACHING.");
 	}
 
+	if (HAS_BIT(gtd->flags, TINTIN_FLAG_CONVERTMETACHAR))
+	{
+		if (gtd->convert_time == 0)
+		{
+			gtd->convert_time = 100000LL + utime();
+		}
+		else
+		{
+			if (gtd->convert_time < gtd->utime)
+			{
+				gtd->convert_time = 0;
+				DEL_BIT(gtd->flags, TINTIN_FLAG_CONVERTMETACHAR);
+			}
+		}
+	}
+
 	if (HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_SGA) && !HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_ECHO))
 	{
 		read_key(input, len);
@@ -103,7 +119,7 @@ void process_input(void)
 
 	if (gtd->chat && gtd->chat->paste_time)
 	{
-		chat_paste(gtd->input_buf, NULL);
+		chat_paste(gtd->ses->input->buf, NULL);
 
 		pop_call();
 		return;
@@ -111,12 +127,12 @@ void process_input(void)
 
 	if (HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_ECHO))
 	{
-		add_line_history(gtd->ses, gtd->input_buf);
+		add_line_history(gtd->ses, gtd->ses->input->buf);
 	}
 
 	if (HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_ECHO))
 	{
-		echo_command(gtd->ses, gtd->input_buf);
+		echo_command(gtd->ses, gtd->ses->input->buf);
 	}
 	else
 	{
@@ -128,9 +144,9 @@ void process_input(void)
 		buffer_end(gtd->ses, "");
 	}
 
-	check_all_events(gtd->ses, SUB_ARG|SUB_SEC, 0, 1, "RECEIVED INPUT", gtd->input_buf);
+	check_all_events(gtd->ses, SUB_ARG|SUB_SEC, 0, 1, "RECEIVED INPUT", gtd->ses->input->buf);
 
-	if (check_all_events(gtd->ses, SUB_ARG|SUB_SEC, 0, 1, "CATCH RECEIVED INPUT", gtd->input_buf) == 1)
+	if (check_all_events(gtd->ses, SUB_ARG|SUB_SEC, 0, 1, "CATCH RECEIVED INPUT", gtd->ses->input->buf) == 1)
 	{
 		pop_call();
 		return;
@@ -138,11 +154,11 @@ void process_input(void)
 
 	if (HAS_BIT(gtd->flags, TINTIN_FLAG_CHILDLOCK))
 	{
-		write_mud(gtd->ses, gtd->input_buf, SUB_EOL);
+		write_mud(gtd->ses, gtd->ses->input->buf, SUB_EOL);
 	}
 	else
 	{
-		gtd->ses = script_driver(gtd->ses, LIST_COMMAND, gtd->input_buf);
+		gtd->ses = script_driver(gtd->ses, LIST_COMMAND, gtd->ses->input->buf);
 	}
 
 	if (IS_SPLIT(gtd->ses))
@@ -150,7 +166,7 @@ void process_input(void)
 		erase_toeol();
 	}
 
-	gtd->input_buf[0] = 0;
+	gtd->ses->input->buf[0] = 0;
 
 	fflush(NULL);
 
@@ -162,9 +178,9 @@ void read_line(char *input, int len)
 {
 	int size, width, index;
 
-//	gtd->input_buf[gtd->input_len] = 0;
+//	gtd->ses->input->buf[gtd->ses->input->len] = 0;
 
-	if (HAS_BIT(gtd->ses->flags, SES_FLAG_CONVERTMETA))
+	if (HAS_BIT(gtd->ses->flags, SES_FLAG_CONVERTMETA) || gtd->level->convert)
 	{
 		convert_meta(input, &gtd->macro_buf[strlen(gtd->macro_buf)], FALSE);
 	}
@@ -223,7 +239,7 @@ void read_line(char *input, int len)
 				{
 					size = get_utf8_width(gtd->macro_buf, &width);
 
-					if (HAS_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT) && gtd->input_len != gtd->input_cur)
+					if (HAS_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT) && gtd->ses->input->len != gtd->ses->input->cur)
 					{
 						if (width)
 						{
@@ -231,13 +247,13 @@ void read_line(char *input, int len)
 						}
 					}
 
-					ins_sprintf(&gtd->input_buf[gtd->input_cur], "%.*s", size, gtd->macro_buf);
+					ins_sprintf(&gtd->ses->input->buf[gtd->ses->input->cur], "%.*s", size, gtd->macro_buf);
 
-					gtd->input_pos += width;
-					gtd->input_cur += size;
-					gtd->input_len += size;
+					gtd->ses->input->pos += width;
+					gtd->ses->input->cur += size;
+					gtd->ses->input->len += size;
 
-					if (width && gtd->input_len != gtd->input_cur)
+					if (width && gtd->ses->input->len != gtd->ses->input->cur)
 					{
 						input_printf("\e[%d@%.*s", width, size, gtd->macro_buf);
 					}
@@ -249,18 +265,18 @@ void read_line(char *input, int len)
 				}
 				else
 				{
-					if (HAS_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT) && gtd->input_len != gtd->input_cur)
+					if (HAS_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT) && gtd->ses->input->len != gtd->ses->input->cur)
 					{
 						cursor_delete(gtd->ses, "");
 					}
 
-					ins_sprintf(&gtd->input_buf[gtd->input_cur], "%c", gtd->macro_buf[0]);
+					ins_sprintf(&gtd->ses->input->buf[gtd->ses->input->cur], "%c", gtd->macro_buf[0]);
 
-					gtd->input_len++;
-					gtd->input_cur++;
-					gtd->input_pos++;
+					gtd->ses->input->len++;
+					gtd->ses->input->cur++;
+					gtd->ses->input->pos++;
 
-					if (gtd->input_len != gtd->input_cur)
+					if (gtd->ses->input->len != gtd->ses->input->cur)
 					{
 						input_printf("\e[1@%c", gtd->macro_buf[0]);
 					}
@@ -272,8 +288,8 @@ void read_line(char *input, int len)
 				}
 
 //				gtd->macro_buf[0] = 0;
-				gtd->input_tmp[0] = 0;
-				gtd->input_buf[gtd->input_len] = 0;
+				gtd->ses->input->tmp[0] = 0;
+				gtd->ses->input->buf[gtd->ses->input->len] = 0;
 
 				cursor_check_line_modified(gtd->ses, "");
 
@@ -294,7 +310,7 @@ void read_key(char *input, int len)
 {
 	int cnt;
 
-	if (gtd->input_buf[0] == gtd->tintin_char)
+	if (gtd->ses->input->buf[0] == gtd->tintin_char)
 	{
 		read_line(input, len);
 
@@ -325,9 +341,9 @@ void read_key(char *input, int len)
 		{
 			case ASCII_CR:
 			case ASCII_LF:
-				gtd->input_buf[0] = 0;
+				gtd->ses->input->buf[0] = 0;
 				gtd->macro_buf[0] = 0;
-				gtd->input_len = 0;
+				gtd->ses->input->len = 0;
 
 				if (HAS_BIT(gtd->ses->flags, SES_FLAG_RUN))
 				{
@@ -340,9 +356,9 @@ void read_key(char *input, int len)
 				break;
 
 			default:
-				if (gtd->macro_buf[cnt] == gtd->tintin_char && gtd->input_buf[0] == 0)
+				if (gtd->macro_buf[cnt] == gtd->tintin_char && gtd->ses->input->buf[0] == 0)
 				{
-					if (gtd->input_len != gtd->input_cur)
+					if (gtd->ses->input->len != gtd->ses->input->cur)
 					{
 						print_stdout("\e[1@%c", gtd->macro_buf[cnt]);
 					}
@@ -350,19 +366,19 @@ void read_key(char *input, int len)
 					{
 						print_stdout("%c", gtd->macro_buf[cnt]);
 					}
-					gtd->input_buf[0] = gtd->tintin_char;
-					gtd->input_buf[1] = 0;
+					gtd->ses->input->buf[0] = gtd->tintin_char;
+					gtd->ses->input->buf[1] = 0;
 					gtd->macro_buf[0] = 0;
-					gtd->input_len = 1;
-					gtd->input_cur = 1;
-					gtd->input_pos = 1;
+					gtd->ses->input->len = 1;
+					gtd->ses->input->cur = 1;
+					gtd->ses->input->pos = 1;
 				}
 				else
 				{
 					socket_printf(gtd->ses, 1, "%c", gtd->macro_buf[cnt]);
-					gtd->input_buf[0] = 127;
+					gtd->ses->input->buf[0] = 127;
 					gtd->macro_buf[0] = 0;
-					gtd->input_len = 0;
+					gtd->ses->input->len = 0;
 				}
 				break;
 		}
@@ -390,7 +406,7 @@ int check_key(char *input, int len)
 			{
 				node = root->list[root->update];
 
-				if (*node->arg1 == '^' && gtd->input_len)
+				if (*node->arg1 == '^' && gtd->ses->input->len)
 				{
 					continue;
 				}
@@ -417,7 +433,7 @@ int check_key(char *input, int len)
 			}
 		}
 
-		if (!HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_SGA) || HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_ECHO) || gtd->input_buf[0] == gtd->tintin_char)
+		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)
 		{
 			for (cnt = 0 ; *cursor_table[cnt].fun != NULL ; cnt++)
 			{
@@ -444,7 +460,7 @@ int check_key(char *input, int len)
 		{
 			if (gtd->macro_buf[1] == '[')
 			{
-				if (gtd->macro_buf[2] == '<' && !HAS_BIT(gtd->ses->list[LIST_BUTTON]->flags, LIST_FLAG_IGNORE))
+				if (gtd->macro_buf[2] == '<' && HAS_BIT(gtd->flags, TINTIN_FLAG_MOUSETRACKING))
 				{
 					val[0] = val[1] = val[2] = cnt = input[0] = 0;
 
@@ -464,9 +480,10 @@ int check_key(char *input, int len)
 									break;
 
 								case 'm':
+									SET_BIT(val[0], MOUSE_FLAG_RELEASE);
 								case 'M':
 									val[cnt++] = get_number(gtd->ses, input);
-									mouse_handler(gtd->ses, val[0], val[2], val[1], gtd->macro_buf[len]); // swap x y to row col
+									mouse_handler(gtd->ses, val[0], val[2], val[1]); // swap x y to row col
 									gtd->macro_buf[0] = 0;
 									pop_call();
 									return TRUE;
@@ -652,17 +669,18 @@ void convert_meta(char *input, char *output, int eol)
 				{
 					*pto++ = '\\';
 					*pto++ = 'r';
-					*pto = 0;
-					DEL_BIT(gtd->flags, TINTIN_FLAG_CONVERTMETACHAR);
-					pop_call();
-					return;
+					pti++;
 				}
-				if (eol)
+				else if (eol)
 				{
 					*pto++ = '\\';
 					*pto++ = 'r';
+					*pto++ = *pti++;
+				}
+				else
+				{
+					*pto++ = *pti++;
 				}
-				*pto++ = *pti++;
 				break;
 
 			case ASCII_VTAB:
@@ -676,18 +694,18 @@ void convert_meta(char *input, char *output, int eol)
 				{
 					*pto++ = '\\';
 					*pto++ = 'n';
-					*pto = 0;
-					DEL_BIT(gtd->flags, TINTIN_FLAG_CONVERTMETACHAR);
-					pop_call();
-					return;
+					pti++;
 				}
-
-				if (eol)
+				else if (eol)
 				{
 					*pto++ = '\\';
 					*pto++ = 'n';
+					*pto++ = *pti++;
+				}
+				else
+				{
+					*pto++ = *pti++;
 				}
-				*pto++ = *pti++;
 
 				break;
 
@@ -716,7 +734,10 @@ void convert_meta(char *input, char *output, int eol)
 	}
 	*pto = 0;
 
-	DEL_BIT(gtd->flags, TINTIN_FLAG_CONVERTMETACHAR);
+	if (HAS_BIT(gtd->flags, TINTIN_FLAG_CONVERTMETACHAR))
+	{
+		gtd->convert_time = 200000LL + gtd->utime;
+	}
 
 	pop_call();
 	return;
@@ -791,7 +812,7 @@ void input_printf(char *format, ...)
 
 	if (!HAS_BIT(gtd->flags, TINTIN_FLAG_HISTORYSEARCH))
 	{
-		if (!HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_ECHO) && gtd->input_buf[0] != gtd->tintin_char)
+		if (!HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_ECHO) && gtd->ses->input->buf[0] != gtd->tintin_char)
 		{
 			return;
 		}

+ 22 - 0
src/line.c

@@ -147,6 +147,28 @@ DO_LINE(line_capture)
 	return ses;
 }
 
+DO_LINE(line_convert)
+{
+	char arg1[BUFFER_SIZE];
+
+	arg = get_arg_in_braces(ses, arg, arg1, GET_ALL);
+
+	if (*arg1 == 0)
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #LINE {CONVERT} {command}.");
+
+		return ses;
+	}
+
+	gtd->level->convert++;
+
+	ses = script_driver(ses, LIST_COMMAND, arg1);
+
+	gtd->level->convert--;
+
+	return ses;
+}
+
 DO_LINE(line_debug)
 {
 	char arg1[BUFFER_SIZE];

+ 60 - 45
src/list.c

@@ -405,6 +405,50 @@ DO_ARRAY(array_insert)
 	return ses;
 }
 
+DO_ARRAY(array_order)
+{
+	int cnt;
+	char **buffer;
+
+	array_add(ses, list, arg, var);
+
+	buffer = malloc(list->root->used * sizeof(char *));
+
+	for (cnt = 0 ; cnt < list->root->used ; cnt++)
+	{
+		buffer[cnt] = list->root->list[cnt]->arg2;
+	}
+
+	quadsort(buffer, list->root->used, sizeof(char *), cmp_num);
+
+	for (cnt = 0 ; cnt < list->root->used ; cnt++)
+	{
+		list->root->list[cnt]->arg2 = buffer[cnt];
+	}
+
+	free(buffer);
+
+	return ses;
+}
+
+DO_ARRAY(array_reverse)
+{
+	char *swap;
+	int cnt, rev;
+
+	array_add(ses, list, arg, var);
+
+	for (cnt = 0 ; cnt < list->root->used / 2 ; cnt++)
+	{
+		rev = list->root->used - 1 - cnt;
+
+		swap = list->root->list[cnt]->arg2;
+		list->root->list[cnt]->arg2 = list->root->list[rev]->arg2;
+		list->root->list[rev]->arg2 = swap;
+	}
+	return ses;
+}
+
 DO_ARRAY(array_simplify)
 {
 	char arg1[BUFFER_SIZE], *str;
@@ -495,9 +539,9 @@ DO_ARRAY(array_set)
 			return ses;
 		}
 
-		set_nest_node(list->root, ntos(index + 1), "%s", arg2);
+//		set_nest_node(list->root, ntos(index + 1), "%s", arg2);
 
-//		RESTRING(list->root->list[index]->arg2, arg2);
+		str_cpy(&list->root->list[index]->arg2, arg2);
 
 		return ses;
 	}
@@ -512,10 +556,7 @@ DO_ARRAY(array_shuffle)
 	char *swap;
 	int cnt, rnd;
 
-	if (!list->root)
-	{
-		list->root = init_list(ses, LIST_VARIABLE, LIST_SIZE);
-	}
+	array_add(ses, list, arg, var);
 
 	for (cnt = 0 ; cnt < list->root->used ; cnt++)
 	{
@@ -530,53 +571,27 @@ DO_ARRAY(array_shuffle)
 
 DO_ARRAY(array_sort)
 {
-	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], arg3[BUFFER_SIZE], *str;
 	int cnt;
+	char **buffer;
 
-	if (!list->root)
-	{
-		list->root = init_list(ses, LIST_VARIABLE, LIST_SIZE);
-	}
+	array_add(ses, list, arg, var);
 
-	while (*arg)
-	{
-		arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
+	buffer = malloc(list->root->used * sizeof(char *));
 
-		str = arg1;
-
-		while (*str)
-		{
-			str = get_arg_in_braces(ses, str, arg2, GET_ALL);
+	for (cnt = 0 ; cnt < list->root->used ; cnt++)
+	{
+		buffer[cnt] = list->root->list[cnt]->arg2;
+	}
 
-			for (cnt = 0 ; cnt < list->root->used ; cnt++)
-			{
-				if (strcmp(arg2, list->root->list[cnt]->arg2) <= 0)
-				{
-					break;
-				}
-			}
+	quadsort(buffer, list->root->used, sizeof(char *), cmp_str);
 
-			if (cnt == list->root->used)
-			{
-				sprintf(arg3, "{%d} {%s}", -1, arg2);
-			}
-			else
-			{
-				sprintf(arg3, "{%d} {%s}", cnt + 1, arg2);
-			}
+	for (cnt = 0 ; cnt < list->root->used ; cnt++)
+	{
+		list->root->list[cnt]->arg2 = buffer[cnt];
+	}
 
-			array_insert(ses, list, arg3, var);
+	free(buffer);
 
-			if (*str == COMMAND_SEPARATOR)
-			{
-				str++;
-			}
-		}
-		if (*arg == COMMAND_SEPARATOR)
-		{
-			arg++;
-		}
-	}
 	return ses;
 }
 

+ 3 - 1
src/log.c

@@ -162,7 +162,9 @@ void write_html_header(struct session *ses, FILE *fp)
 {
 	char header[BUFFER_SIZE];
 	
-		sprintf(header, "<html>\n"
+		sprintf(header,
+		"<!DOCTYPE html>\n"
+		"<html>\n"
 		"<head>\n"
 		"<meta http-equiv='content-type' content='text/html; charset=%s'>\n"
 		"<meta name='viewport' content='width=device-width, initial-scale=1.0'>\n"

+ 37 - 28
src/main.c

@@ -265,6 +265,10 @@ int main(int argc, char **argv)
 					SET_BIT(greeting, STARTUP_FLAG_SCREENREADER);
 					break;
 
+				case 'v':
+					SET_BIT(greeting, STARTUP_FLAG_VERBOSE);
+					break;
+
 				case 'V':
 					printf("\nTinTin++ " CLIENT_VERSION "\n");
 					printf("\n(C) 2004-2019 Igor van den Hoven\n");
@@ -319,9 +323,9 @@ int main(int argc, char **argv)
 					break;
 
 				case 'r':
-					gtd->level->input++;
+//					gtd->level->input++;
 					gtd->ses = do_read(gtd->ses, optarg);
-					gtd->level->input--;
+//					gtd->level->input--;
 					break;
 
 				case 'R':
@@ -342,7 +346,7 @@ int main(int argc, char **argv)
 					break;
 
 				case 'v':
-					do_configure(gtd->ses, "{VERBOSE} {ON}");
+//					do_configure(gtd->ses, "{VERBOSE} {ON}");
 					break;
 
 				default:
@@ -438,7 +442,7 @@ void init_tintin(int greeting)
 	gtd->mud_output_max = 16384;
 	gtd->mud_output_buf = (char *) calloc(1, gtd->mud_output_max);
 
-	gtd->input_off      = 1;
+
 
 	gtd->os             = strdup(getenv("OS")   ? getenv("OS")   : "UNKNOWN");
 	gtd->home           = strdup(getenv("HOME") ? getenv("HOME") : "~/");
@@ -525,16 +529,25 @@ void init_tintin(int greeting)
 		gts->list[index] = init_list(gts, index, 32);
 	}
 
-	gts->split  = calloc(1, sizeof(struct split_data));
-	gts->scroll = calloc(1, sizeof(struct scroll_data));
+	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);
 
-	gtd->level->input++;
+	init_buffer(gts, 10000);
+
+	if (HAS_BIT(greeting,  STARTUP_FLAG_VERBOSE))
+	{
+		gtd->level->verbose++;
+	}
 
-	do_class(gts, "{CONFIG} {OPEN}");
+	gtd->level->input++;
 
 	do_configure(gts, "{AUTO TAB}         {5000}");
 	do_configure(gts, "{BUFFER SIZE}     {10000}");
@@ -559,31 +572,27 @@ void init_tintin(int greeting)
 	do_configure(gts, "{TINTIN CHAR}         {#}");
 	do_configure(gts, "{VERBATIM}          {OFF}");
 	do_configure(gts, "{VERBATIM CHAR}      {\\}");
-	do_configure(gts, "{VERBOSE}           {OFF}");
+	do_configure(gts, HAS_BIT(greeting, STARTUP_FLAG_VERBOSE) ? "{VERBOSE} {ON}" : "{VERBOSE} {OFF}");
 	do_configure(gts, "{WORDWRAP}           {ON}");
 
-	do_class(gts, "{CONFIG} {CLOSE}");
-
-
-
-	do_class(gts, "{PATHDIR} {OPEN}");
-
-	insert_node_list(gts->list[LIST_PATHDIR],  "n",  "s",  "1", "");
-	insert_node_list(gts->list[LIST_PATHDIR],  "e",  "w",  "2", "");
-	insert_node_list(gts->list[LIST_PATHDIR],  "s",  "n",  "4", "");
-	insert_node_list(gts->list[LIST_PATHDIR],  "w",  "e",  "8", "");
-	insert_node_list(gts->list[LIST_PATHDIR],  "u",  "d", "16", "");
-	insert_node_list(gts->list[LIST_PATHDIR],  "d",  "u", "32", "");
-
-	insert_node_list(gts->list[LIST_PATHDIR], "ne", "sw",  "3", "");
-	insert_node_list(gts->list[LIST_PATHDIR], "nw", "se",  "9", "");
-	insert_node_list(gts->list[LIST_PATHDIR], "se", "nw",  "6", "");
-	insert_node_list(gts->list[LIST_PATHDIR], "sw", "ne", "12", "");
-
-	do_class(gts, "{PATHDIR} {CLOSE}");
+	do_pathdir(gts, " n  s  1");
+	do_pathdir(gts, " e  w  2");
+	do_pathdir(gts, " s  n  4");
+	do_pathdir(gts, " w  e  8");
+	do_pathdir(gts, " u  d 16");
+	do_pathdir(gts, " d  u 32");
+	do_pathdir(gts, "ne sw  3");
+	do_pathdir(gts, "nw se  9");
+	do_pathdir(gts, "se nw  6");
+	do_pathdir(gts, "sw ne 12");
 
 	gtd->level->input--;
 
+	if (HAS_BIT(greeting,  STARTUP_FLAG_VERBOSE))
+	{
+		gtd->level->verbose--;
+	}
+
 	init_terminal(gts);
 
 	reset_screen(gts);

+ 234 - 73
src/mapper.c

@@ -50,6 +50,7 @@ extern  int find_room(struct session *ses, char *arg);
 extern void goto_room(struct session *ses, int room);
 extern  int find_new_room(struct session *ses);
 extern struct exit_data *find_exit(struct session *ses, int room, char *arg);
+extern struct exit_data *find_exit_vnum(struct session *ses, int room, int vnum);
 extern  int get_exit_dir(struct session *ses, char *arg);
 extern  int get_exit_length(struct session *ses, struct exit_data *exit);
 extern char *get_exit_color(struct session *ses, int room, struct exit_data *exit);
@@ -57,7 +58,7 @@ extern  int dir_to_grid(int dir);
 extern  int revdir_to_grid(int dir);
 extern void set_room_exits(struct session *ses, int room);
 extern  int get_room_exits(struct session *ses, int room);
-extern  int get_terrain_index(struct session *ses, struct room_data *room, int x, int y);
+extern  int get_terrain_vnum(struct session *ses, struct room_data *room, int x, int y);
 extern char *draw_terrain_symbol(struct session *ses, struct room_data *room, int line, int col, int x, int y, int flags);
 extern void displaygrid_build(struct session *ses, int room, int x, int y, int z);
 extern void add_undo(struct session *ses, char *format, ...);
@@ -169,6 +170,7 @@ void create_map(struct session *ses, char *arg)
 	ses->map->max_grid_y = 101;
 
 	ses->map->grid_rooms = (struct room_data **) calloc(ses->map->max_grid_x * ses->map->max_grid_y, sizeof(struct room_data *));
+	ses->map->grid_vnums = (int *) calloc(ses->map->max_grid_x * ses->map->max_grid_y, sizeof(int));
 
 	ses->map->search = calloc(1, sizeof(struct search_data));
 
@@ -350,6 +352,8 @@ struct room_data *create_room(struct session *ses, char *format, ...)
 
 	show_message(ses, LIST_COMMAND, "#MAP CREATE ROOM %5d {%s}.", newroom->vnum, newroom->name);
 
+	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "MAP CREATE ROOM", ntos(newroom->vnum), newroom->name);
+
 	return newroom;
 }
 
@@ -358,6 +362,8 @@ void delete_room(struct session *ses, int room, int exits)
 	struct exit_data *exit, *exit_next;
 	int cnt;
 
+	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 2, "MAP DELETE ROOM", ntos(ses->map->room_list[room]->vnum), ses->map->room_list[room]->name);
+
 	while (ses->map->room_list[room]->f_exit)
 	{
 		delete_exit(ses, room, ses->map->room_list[room]->f_exit);
@@ -395,7 +401,6 @@ void delete_room(struct session *ses, int room, int exits)
 			}
 		}
 	}
-
 }
 
 struct exit_data *create_exit(struct session *ses, int vnum, char *format, ...)
@@ -657,7 +662,7 @@ void set_room_exits(struct session *ses, int vnum)
 	}
 }
 
-int get_terrain_index(struct session *ses, struct room_data *room, int x, int y)
+int get_terrain_vnum(struct session *ses, struct room_data *room, int x, int y)
 {
 	struct listroot *root = ses->list[LIST_TERRAIN];
 	struct room_data *wide_grid[11], *vast_grid[11];
@@ -665,7 +670,11 @@ int get_terrain_index(struct session *ses, struct room_data *room, int x, int y)
 
 	if (room)
 	{
-		return room->terrain_index;
+		if (room->terrain_index != -1)
+		{
+			return room->vnum;
+		}
+		return -1;
 	}
 
 	wide_grid[EXIT_GRID_N]  = ses->map->grid_rooms[x     + map_grid_x * (y + 1)];
@@ -683,7 +692,7 @@ int get_terrain_index(struct session *ses, struct room_data *room, int x, int y)
 
 		if ((wide_grid[EXIT_GRID_E] == NULL || wide_grid[EXIT_GRID_E]->terrain_index == terrain) && (wide_grid[EXIT_GRID_S] == NULL || wide_grid[EXIT_GRID_S]->terrain_index == terrain) && (wide_grid[EXIT_GRID_W] == NULL || wide_grid[EXIT_GRID_W]->terrain_index == terrain))
 		{
-			return wide_grid[EXIT_GRID_N]->terrain_index;
+			return wide_grid[EXIT_GRID_N]->vnum;
 		}
 	}
 
@@ -693,7 +702,7 @@ int get_terrain_index(struct session *ses, struct room_data *room, int x, int y)
 
 		if ((wide_grid[EXIT_GRID_S] == NULL || wide_grid[EXIT_GRID_S]->terrain_index == terrain) && (wide_grid[EXIT_GRID_W] == NULL || wide_grid[EXIT_GRID_W]->terrain_index == terrain) && (wide_grid[EXIT_GRID_N] == NULL || wide_grid[EXIT_GRID_N]->terrain_index == terrain))
 		{
-			return wide_grid[EXIT_GRID_E]->terrain_index;
+			return wide_grid[EXIT_GRID_E]->vnum;
 		}
 	}
 
@@ -703,7 +712,7 @@ int get_terrain_index(struct session *ses, struct room_data *room, int x, int y)
 
 		if ((wide_grid[EXIT_GRID_W] == NULL || wide_grid[EXIT_GRID_W]->terrain_index == terrain) && (wide_grid[EXIT_GRID_N] == NULL || wide_grid[EXIT_GRID_N]->terrain_index == terrain) && (wide_grid[EXIT_GRID_E] == NULL || wide_grid[EXIT_GRID_E]->terrain_index == terrain))
 		{
-			return wide_grid[EXIT_GRID_S]->terrain_index;
+			return wide_grid[EXIT_GRID_S]->vnum;
 		}
 	}
 
@@ -713,7 +722,7 @@ int get_terrain_index(struct session *ses, struct room_data *room, int x, int y)
 
 		if ((wide_grid[EXIT_GRID_N] == NULL || wide_grid[EXIT_GRID_N]->terrain_index == terrain) && (wide_grid[EXIT_GRID_E] == NULL || wide_grid[EXIT_GRID_E]->terrain_index == terrain) && (wide_grid[EXIT_GRID_S] == NULL || wide_grid[EXIT_GRID_S]->terrain_index == terrain))
 		{
-			return wide_grid[EXIT_GRID_W]->terrain_index;
+			return wide_grid[EXIT_GRID_W]->vnum;
 		}
 	}
 
@@ -737,7 +746,7 @@ int get_terrain_index(struct session *ses, struct room_data *room, int x, int y)
 
 		if ((wide_grid[EXIT_GRID_E] == NULL || wide_grid[EXIT_GRID_E]->terrain_index == terrain) && (wide_grid[EXIT_GRID_S] == NULL || wide_grid[EXIT_GRID_S]->terrain_index == terrain) && (wide_grid[EXIT_GRID_W] == NULL || wide_grid[EXIT_GRID_W]->terrain_index == terrain))
 		{
-			return vast_grid[EXIT_GRID_N]->terrain_index;
+			return vast_grid[EXIT_GRID_N]->vnum;
 		}
 	}
 
@@ -747,7 +756,7 @@ int get_terrain_index(struct session *ses, struct room_data *room, int x, int y)
 
 		if ((wide_grid[EXIT_GRID_S] == NULL || wide_grid[EXIT_GRID_S]->terrain_index == terrain) && (wide_grid[EXIT_GRID_W] == NULL || wide_grid[EXIT_GRID_W]->terrain_index == terrain) && (wide_grid[EXIT_GRID_N] == NULL || wide_grid[EXIT_GRID_N]->terrain_index == terrain))
 		{
-			return vast_grid[EXIT_GRID_E]->terrain_index;
+			return vast_grid[EXIT_GRID_E]->vnum;
 		}
 	}
 
@@ -757,7 +766,7 @@ int get_terrain_index(struct session *ses, struct room_data *room, int x, int y)
 
 		if ((wide_grid[EXIT_GRID_W] == NULL || wide_grid[EXIT_GRID_W]->terrain_index == terrain) && (wide_grid[EXIT_GRID_N] == NULL || wide_grid[EXIT_GRID_N]->terrain_index == terrain) && (wide_grid[EXIT_GRID_E] == NULL || wide_grid[EXIT_GRID_E]->terrain_index == terrain))
 		{
-			return vast_grid[EXIT_GRID_S]->terrain_index;
+			return vast_grid[EXIT_GRID_S]->vnum;
 		}
 	}
 
@@ -767,7 +776,7 @@ int get_terrain_index(struct session *ses, struct room_data *room, int x, int y)
 
 		if ((wide_grid[EXIT_GRID_N] == NULL || wide_grid[EXIT_GRID_N]->terrain_index == terrain) && (wide_grid[EXIT_GRID_E] == NULL || wide_grid[EXIT_GRID_E]->terrain_index == terrain) && (wide_grid[EXIT_GRID_S] == NULL || wide_grid[EXIT_GRID_S]->terrain_index == terrain))
 		{
-			return vast_grid[EXIT_GRID_W]->terrain_index;
+			return vast_grid[EXIT_GRID_W]->vnum;
 		}
 	}
 
@@ -1103,6 +1112,7 @@ char *blank_terrain_symbol(struct session *ses, struct room_data *room, int inde
 char *draw_terrain_symbol(struct session *ses, struct room_data *room, int line, int index, int x, int y, int flags)
 {
 	struct room_data *room_grid[11], *terrain_room;
+	int vnum_grid[11];
 	int terrain, width = 0, density, hash;
 
 	if (!HAS_BIT(ses->map->flags, MAP_FLAG_TERRAIN))
@@ -1131,7 +1141,17 @@ char *draw_terrain_symbol(struct session *ses, struct room_data *room, int line,
 	room_grid[EXIT_GRID_W]  = ses->map->grid_rooms[x - 1 + map_grid_x * (y    )];
 	room_grid[EXIT_GRID_NW]	= ses->map->grid_rooms[x - 1 + map_grid_x * (y + 1)];
 
-	hash = index + (room && room->vnum ? room->vnum : x + y);
+	vnum_grid[EXIT_GRID_0]  = ses->map->grid_vnums[x     + map_grid_x * (y    )];
+	vnum_grid[EXIT_GRID_N]  = ses->map->grid_vnums[x     + map_grid_x * (y + 1)];
+	vnum_grid[EXIT_GRID_NE] = ses->map->grid_vnums[x + 1 + map_grid_x * (y + 1)];
+	vnum_grid[EXIT_GRID_E]  = ses->map->grid_vnums[x + 1 + map_grid_x * (y    )];
+	vnum_grid[EXIT_GRID_SE] = ses->map->grid_vnums[x + 1 + map_grid_x * (y - 1)];
+	vnum_grid[EXIT_GRID_S]  = ses->map->grid_vnums[x     + map_grid_x * (y - 1)];
+	vnum_grid[EXIT_GRID_SW] = ses->map->grid_vnums[x - 1 + map_grid_x * (y - 1)];
+	vnum_grid[EXIT_GRID_W]  = ses->map->grid_vnums[x - 1 + map_grid_x * (y    )];
+	vnum_grid[EXIT_GRID_NW]	= ses->map->grid_vnums[x - 1 + map_grid_x * (y + 1)];
+
+	hash = index + vnum_grid[EXIT_GRID_0];
 
 	if (HAS_BIT(ses->map->flags, MAP_FLAG_ASCIIGRAPHICS))
 	{
@@ -1200,6 +1220,26 @@ char *draw_terrain_symbol(struct session *ses, struct room_data *room, int line,
 			{
 				return blank_terrain_symbol(ses, room, index, flags);
 			}
+
+			hash += vnum_grid[EXIT_GRID_N] ? vnum_grid[EXIT_GRID_N] :
+				vnum_grid[EXIT_GRID_E] ? vnum_grid[EXIT_GRID_E] :
+				vnum_grid[EXIT_GRID_S] ? vnum_grid[EXIT_GRID_S] :
+				vnum_grid[EXIT_GRID_W] ? vnum_grid[EXIT_GRID_W] :
+				vnum_grid[EXIT_GRID_NE] ? vnum_grid[EXIT_GRID_NE] :
+				vnum_grid[EXIT_GRID_SE] ? vnum_grid[EXIT_GRID_SE] :
+				vnum_grid[EXIT_GRID_SW] ? vnum_grid[EXIT_GRID_SW] :
+				vnum_grid[EXIT_GRID_NW] ? vnum_grid[EXIT_GRID_NW] : 0;
+		}
+		else
+		{
+			hash += vnum_grid[EXIT_GRID_N] ? 1 :
+				vnum_grid[EXIT_GRID_E] ? 2 :
+				vnum_grid[EXIT_GRID_S] ? 3 :
+				vnum_grid[EXIT_GRID_W] ? 4 :
+				vnum_grid[EXIT_GRID_NE] ? 5 :
+				vnum_grid[EXIT_GRID_SE] ? 6 :
+				vnum_grid[EXIT_GRID_SW] ? 7 :
+				vnum_grid[EXIT_GRID_NW] ? 8 : 9;
 		}
 
 		terrain = room->terrain_index;
@@ -1433,6 +1473,15 @@ char *draw_terrain_symbol(struct session *ses, struct room_data *room, int line,
 					}
 				}
 			}
+
+			hash += vnum_grid[EXIT_GRID_N] ? vnum_grid[EXIT_GRID_N] :
+				vnum_grid[EXIT_GRID_E] ? vnum_grid[EXIT_GRID_E] :
+				vnum_grid[EXIT_GRID_S] ? vnum_grid[EXIT_GRID_S] :
+				vnum_grid[EXIT_GRID_W] ? vnum_grid[EXIT_GRID_W] :
+				vnum_grid[EXIT_GRID_NE] ? vnum_grid[EXIT_GRID_NE] :
+				vnum_grid[EXIT_GRID_SE] ? vnum_grid[EXIT_GRID_SE] :
+				vnum_grid[EXIT_GRID_SW] ? vnum_grid[EXIT_GRID_SW] :
+				vnum_grid[EXIT_GRID_NW] ? vnum_grid[EXIT_GRID_NW] : 0;
 		}
 		else
 		{
@@ -1473,6 +1522,15 @@ char *draw_terrain_symbol(struct session *ses, struct room_data *room, int line,
 			{
 				return blank_terrain_symbol(ses, room, index, flags);
 			}
+
+			hash += vnum_grid[EXIT_GRID_N] ? 1 :
+				vnum_grid[EXIT_GRID_E] ? 2 :
+				vnum_grid[EXIT_GRID_S] ? 3 :
+				vnum_grid[EXIT_GRID_W] ? 4 :
+				vnum_grid[EXIT_GRID_NE] ? 5 :
+				vnum_grid[EXIT_GRID_SE] ? 6 :
+				vnum_grid[EXIT_GRID_SW] ? 7 :
+				vnum_grid[EXIT_GRID_NW] ? 8 : 9;
 		}
 
 		terrain = room->terrain_index;
@@ -1955,6 +2013,7 @@ void displaygrid_build(struct session *ses, int vnum, int x, int y, int z)
 	for (vnum = 0 ; vnum < x * y ; vnum++)
 	{
 		ses->map->grid_rooms[vnum] = NULL;
+		ses->map->grid_vnums[vnum] = 0;
 	}
 
 	while (head != tail)
@@ -1981,6 +2040,7 @@ void displaygrid_build(struct session *ses, int vnum, int x, int y, int z)
 			if (ses->map->grid_rooms[node->x + map_grid_x * node->y] == NULL)
 			{
 				ses->map->grid_rooms[node->x + map_grid_x * node->y] = room;
+				ses->map->grid_vnums[node->x + map_grid_x * node->y] = room->vnum;
 			}
 			else if (!HAS_BIT(room->flags, ROOM_FLAG_VOID))
 			{
@@ -1988,6 +2048,11 @@ void displaygrid_build(struct session *ses, int vnum, int x, int y, int z)
 			}
 		}
 
+		if (HAS_BIT(room->flags, ROOM_FLAG_FOG) && ses->map->in_room != room->vnum)
+		{
+			continue;
+		}
+
 		for (exit = room->f_exit ; exit ; exit = exit->next)
 		{
 			if (exit->dir == 0)
@@ -2078,11 +2143,14 @@ void displaygrid_build(struct session *ses, int vnum, int x, int y, int z)
 			{
 				if (ses->map->grid_rooms[x + map_grid_x * y] == NULL)
 				{
-					terrain = get_terrain_index(ses, NULL, x, y);
+					vnum = get_terrain_vnum(ses, NULL, x, y);
 
-					if (terrain != -1)
+					if (vnum != -1)
 					{
+						terrain = ses->map->room_list[vnum]->terrain_index;
+
 						ses->map->grid_rooms[x + map_grid_x * y] = ses->list[LIST_TERRAIN]->list[terrain]->room;
+						ses->map->grid_vnums[x + map_grid_x * y] = vnum;
 					}
 				}
 			}
@@ -2097,6 +2165,7 @@ void displaygrid_build(struct session *ses, int vnum, int x, int y, int z)
 void show_vtmap(struct session *ses)
 {
 	char buf[BUFFER_SIZE], out[BUFFER_SIZE], tmp[BUFFER_SIZE];
+	char *ptb;
 	int x, y, line;
 	int top_row, top_col, bot_row, bot_col, rows, cols, row;
 
@@ -2199,11 +2268,13 @@ void show_vtmap(struct session *ses)
 		{
 			for (line = 1 ; line <= 3 ; line++)
 			{
-				strcpy(buf, ses->map->color[MAP_COLOR_BACK]);
+				ptb = buf;
+
+				ptb += sprintf(ptb, "%s", ses->map->color[MAP_COLOR_BACK]);
 
 				for (x = 1 ; x < map_grid_x - 1 ; x++)
 				{
-					strcat(buf, draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], line, x, y));
+					ptb += sprintf(ptb, "%s", draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], line, x, y));
 				}
 				substitute(ses, buf, out, SUB_COL|SUB_CMP|SUB_LIT);
 
@@ -2221,7 +2292,9 @@ void show_vtmap(struct session *ses)
 				{
 					continue;
 				}
-				strcpy(buf, ses->map->color[MAP_COLOR_BACK]);
+				ptb = buf;
+
+				ptb += sprintf(ptb, "%s", ses->map->color[MAP_COLOR_BACK]);
 
 				for (x = 1 ; x < map_grid_x - 1 ; x++)
 				{
@@ -2229,11 +2302,11 @@ void show_vtmap(struct session *ses)
 					{
 						strcpy(tmp, draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], line, x, y));
 
-						cat_sprintf(buf, "%.*s", string_str_raw_len(ses, tmp, 0, 2), tmp);
+						ptb += sprintf(ptb, "%.*s", string_str_raw_len(ses, tmp, 0, 2), tmp);
 					}
 					else
 					{
-						strcat(buf, draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], line, x, y));
+						ptb += sprintf(ptb, "%s", draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], line, x, y));
 					}
 				}
 				substitute(ses, buf, out, SUB_COL|SUB_CMP|SUB_LIT);
@@ -2248,11 +2321,13 @@ void show_vtmap(struct session *ses)
 		{
 			for (line = 1 ; line <= 2 ; line++)
 			{
-				strcpy(buf, ses->map->color[MAP_COLOR_BACK]);
+				ptb = buf;
+
+				ptb += sprintf(ptb, "%s", ses->map->color[MAP_COLOR_BACK]);
 
 				for (x = 1 ; x < map_grid_x - 1 ; x++)
 				{
-					strcat(buf, draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], line, x, y));
+					ptb += sprintf(ptb, "%s", draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], line, x, y));
 				}
 				substitute(ses, buf, out, SUB_COL|SUB_CMP|SUB_LIT);
 
@@ -2264,11 +2339,13 @@ void show_vtmap(struct session *ses)
 	{
 		for (y = map_grid_y - 2 ; y >= 1 ; y--)
 		{
-			strcpy(buf, ses->map->color[MAP_COLOR_BACK]);
+			ptb = buf;
+
+			ptb += sprintf(ptb, "%s", ses->map->color[MAP_COLOR_BACK]);
 
 			for (x = 1 ; x < map_grid_x - 1 ; x++)
 			{
-				strcat(buf, draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], 0, x, y));
+				ptb += sprintf(ptb, "%s", draw_room(ses, ses->map->grid_rooms[x + map_grid_x * y], 0, x, y));
 			}
 			substitute(ses, buf, out, SUB_COL|SUB_CMP|SUB_LIT);
 
@@ -2303,6 +2380,11 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 		if (HAS_BIT(room->flags, ROOM_FLAG_PATH) && room->search_stamp == ses->map->search->stamp)
 		{
 			room_color = ses->map->color[MAP_COLOR_PATH];
+
+			if (symsize > 1)
+			{
+				symsize = 0;
+			}
 		}
 		else if (*room->color)
 		{
@@ -2326,6 +2408,10 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 			{
 				room_color = ses->map->color[MAP_COLOR_BLOCK];
 			}
+			else if (HAS_BIT(room->flags, ROOM_FLAG_FOG))
+			{
+				room_color = ses->map->color[MAP_COLOR_FOG];
+			}
 			else if (HAS_BIT(ses->map->flags, MAP_FLAG_SYMBOLGRAPHICS))
 			{
 				room_color = ses->map->color[MAP_COLOR_SYMBOL];
@@ -2422,7 +2508,6 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 			SET_BIT(exit_nw, UNICODE_DIR_NW);
 		}
 
-
 		if (room_n && HAS_BIT(room_n->exit_dirs, MAP_DIR_D))
 		{
 			SET_BIT(exit_n, MAP_DIR_D);
@@ -2440,12 +2525,12 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 
 		if (room && room->exit_grid[EXIT_GRID_W])
 		{
-			SET_BIT(exit_w, UNICODE_DIR_W);
+			SET_BIT(exit_w, MAP_DIR_W);
 		}
 
 		if (room_w && room_w->exit_grid[EXIT_GRID_E])
 		{
-			SET_BIT(exit_w, UNICODE_DIR_E);
+			SET_BIT(exit_w, MAP_DIR_E);
 		}
 
 		sprintf(buf, "%s", ses->map->color[MAP_COLOR_EXIT]);
@@ -2577,7 +2662,7 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 
 				if (room == NULL || room->vnum == 0)
 				{
-					if (HAS_BIT(exit_w, MAP_DIR_W))
+					if (HAS_BIT(exit_w, MAP_DIR_E))
 					{
 						sprintf(buf, "%s%s%s",
 							get_exit_color(ses, 0, room_w->exit_grid[EXIT_GRID_E]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_E],
@@ -2603,13 +2688,13 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 						strcat(buf, draw_terrain_symbol(ses, room, line, 1, x, y, TERRAIN_FLAG_DOUBLE));
 						strcat(buf, draw_terrain_symbol(ses, room, line, 2, x, y, TERRAIN_FLAG_DOUBLE));
 						break;
-					case UNICODE_DIR_E:
+					case MAP_DIR_E:
 						sprintf(buf, "%s%s%s", get_exit_color(ses, 0, room_w->exit_grid[EXIT_GRID_E]), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_E], draw_terrain_symbol(ses, room, line, 2, x, y, flags));
 						break;
-					case UNICODE_DIR_W:
+					case MAP_DIR_W:
 						sprintf(buf, "%s%s%s", get_exit_color(ses, 0, room->exit_grid[EXIT_GRID_W]), draw_terrain_symbol(ses, room, line, 1, x, y, flags), ses->map->legend[LEGEND_UNICODE_GRAPHICS + UNICODE_DIR_W]);
 						break;
-					case UNICODE_DIR_E|UNICODE_DIR_W:
+					case MAP_DIR_E|MAP_DIR_W:
 						if (room->exit_grid[EXIT_GRID_W]->vnum == room_w->vnum && room_w->exit_grid[EXIT_GRID_E]->vnum == room->vnum)
 						{
 							// ‒‒
@@ -2629,17 +2714,13 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 				{
 					cat_sprintf(buf, "%s%s%s%s", room_left, ses->map->color[MAP_COLOR_USER], ses->map->legend[offset + index], room_right);
 				}
-				else if (symsize > 3)
+				else if (symsize > 1)
 				{
 					cat_sprintf(buf, "%s%-3s", ses->map->color[MAP_COLOR_SYMBOL], room->symbol);
 				}
 				else
 				{
-					if (symsize > 1)
-					{
-						cat_sprintf(buf, "%s%-3s", ses->map->color[MAP_COLOR_SYMBOL], room->symbol);
-					}
-					else if (HAS_BIT(room->flags, ROOM_FLAG_VOID))
+					if (HAS_BIT(room->flags, ROOM_FLAG_VOID))
 					{
 						if (HAS_BIT(room->exit_dirs, MAP_DIR_W))
 						{
@@ -2736,7 +2817,14 @@ char *draw_room(struct session *ses, struct room_data *room, int line, int x, in
 					}
 					else
 					{
-						cat_sprintf(buf, "%s%s%-1s%s", room_left, ses->map->color[MAP_COLOR_SYMBOL], room->symbol, room_right);
+						if (symsize == 1)
+						{
+							cat_sprintf(buf, "%s%s%-1s%s", room_left, ses->map->color[MAP_COLOR_SYMBOL], room->symbol, room_right);
+						}
+						else
+						{
+							cat_sprintf(buf, "%s%s%-1s%s", room_left, ses->map->color[MAP_COLOR_SYMBOL], "", room_right);
+						}
 					}
 				}
 				cat_sprintf(buf, "%s", ses->map->color[MAP_COLOR_BACK]);
@@ -3987,6 +4075,7 @@ void goto_room(struct session *ses, int room)
 	ses->map->in_room = room;
 
 	DEL_BIT(ses->map->room_list[room]->flags, ROOM_FLAG_PATH);
+	DEL_BIT(ses->map->room_list[room]->flags, ROOM_FLAG_FOG);
 
 	if (last_room == 0)
 	{
@@ -4050,6 +4139,20 @@ struct exit_data *find_exit(struct session *ses, int room, char *arg)
 	return NULL;
 }
 
+struct exit_data *find_exit_vnum(struct session *ses, int room, int vnum)
+{
+	struct exit_data *exit;
+
+	for (exit = ses->map->room_list[room]->f_exit ; exit ; exit = exit->next)
+	{
+		if (exit->vnum == vnum)
+		{
+			return exit;
+		}
+	}
+	return NULL;
+}
+
 int check_global(struct session *ses, int room)
 {
 	if (HAS_BIT(ses->map->room_list[room]->flags, ROOM_FLAG_NOGLOBAL))
@@ -4927,7 +5030,7 @@ DO_MAP(map_at)
 
 		if (new_room == 0)
 		{
-			show_error(ses, LIST_COMMAND, "#MAP AT: Couldn't find room or exit {%s}.", arg1);
+			show_message(ses, LIST_COMMAND, "#MAP AT: Couldn't find room or exit {%s}.", arg1);
 
 			return;
 		}
@@ -5021,7 +5124,7 @@ DO_MAP(map_color)
 
 		if (map_color_table[index].name == NULL)
 		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP COLOR {AVOID|BACKGROUND|EXIT|HIDE|INVIS|PATH|ROOM|USER} {COLOR CODE}");
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP COLOR {AVOID|BACKGROUND|EXIT|FOG|HIDE|INVIS|PATH|ROOM|USER} {COLOR CODE}");
 
 			return;
 		}
@@ -5318,18 +5421,19 @@ DO_MAP(map_dig)
 
 void exit_edit(struct session *ses, struct exit_data *exit, char *arg, char *arg1, char *arg2, char *arg3)
 {
-	int room, dir;
+	int vnum, dir;
 
 	if (*arg2 == 0)
 	{
-		tintin_printf2(ses, "    color: %s", str_convert_meta(exit->color, TRUE));
-		tintin_printf2(ses, "  command: %s", exit->cmd);
-		tintin_printf2(ses, "direction: %d", exit->dir);
-		tintin_printf2(ses, "    flags: %d", exit->flags);
-		tintin_printf2(ses, "  get/set: %s", exit->data);
-		tintin_printf2(ses, "     name: %s", exit->name);
-		tintin_printf2(ses, "     vnum: %d", exit->vnum);
-		tintin_printf2(ses, "   weight: %.3f", exit->weight);
+		tintin_printf2(ses, "      color: %s", str_convert_meta(exit->color, TRUE));
+		tintin_printf2(ses, "    command: %s", exit->cmd);
+		tintin_printf2(ses, "destination: %d", tunnel_void(ses, ses->map->in_room, exit->vnum, exit->dir));
+		tintin_printf2(ses, "  direction: %d", exit->dir);
+		tintin_printf2(ses, "      flags: %d", exit->flags);
+		tintin_printf2(ses, "    get/set: %s", exit->data);
+		tintin_printf2(ses, "       name: %s", exit->name);
+		tintin_printf2(ses, "       vnum: %d", exit->vnum);
+		tintin_printf2(ses, "     weight: %.3f", exit->weight);
 	}
 	else if (is_abbrev(arg2, "COLOR"))
 	{
@@ -5406,20 +5510,20 @@ void exit_edit(struct session *ses, struct exit_data *exit, char *arg, char *arg
 	}
 	else if (is_abbrev(arg2, "VNUM"))
 	{
-		room = atoi(arg3);
+		vnum = atoi(arg3);
 
-		if (room <= 0 || room >= ses->map->size)
+		if (vnum <= 0 || vnum >= ses->map->size)
 		{
-			show_error(ses, LIST_COMMAND, "#MAP %s VNUM: Invalid room vnum: %d.", arg, room);
+			show_error(ses, LIST_COMMAND, "#MAP %s VNUM: Invalid room vnum: %d.", arg, vnum);
 			return;
 		}
 
-		if (ses->map->room_list[room] == NULL)
+		if (ses->map->room_list[vnum] == NULL)
 		{
-			show_error(ses, LIST_COMMAND, "#MAP %s VNUM: Non existant room vnum: %d.", arg, room);
+			show_error(ses, LIST_COMMAND, "#MAP %s VNUM: Non existant room vnum: %d.", arg, vnum);
 			return;
 		}
-		exit->vnum = room;
+		exit->vnum = vnum;
 
 		show_message(ses, LIST_COMMAND, "#MAP %s {%s} : VNUM SET TO {%s}.", arg, arg1, arg3);
 	}
@@ -5496,12 +5600,13 @@ DO_MAP(map_exit)
 DO_MAP(map_exitflag)
 {
 	struct exit_data *exit;
-	char arg3[BUFFER_SIZE];
+	char arg3[BUFFER_SIZE], arg4[BUFFER_SIZE];
 	int flag;
 
 	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, arg4, GET_ONE, SUB_VAR|SUB_FUN);
 
 	exit = find_exit(ses, ses->map->in_room, arg1);
 
@@ -5540,7 +5645,7 @@ DO_MAP(map_exitflag)
 	}
 	else
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP EXITFLAG {%s} <AVOID|HIDE|INVIS> [ON|OFF]", arg1);
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP EXITFLAG {%s} <AVOID|BLOCK|HIDE|INVIS> [ON|OFF]", arg1);
 
 		return;
 	}
@@ -5557,9 +5662,23 @@ DO_MAP(map_exitflag)
 	{
 		DEL_BIT(exit->flags, flag);
 	}
+	else if (is_abbrev(arg3, "GET"))
+	{
+		if (*arg4 == 0)
+		{
+			show_error(ses, LIST_COMMAND, "#SYNTAX #MAP EXITFLAG {%s} {%s} {GET} {<VARIABLE>}.", arg1, arg2);
+		}
+		else
+		{
+			set_nest_node_ses(ses, arg4, "%d", HAS_BIT(exit->flags, flag));
+		}
+		return;
+	}
 	else
 	{
-		show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP EXITFLAG {%s} {%s} [ON|OFF]", arg3);
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #MAP EXITFLAG {%s} {%s} [GET|ON|OFF]", arg1, arg2);
+
+		return;
 	}
 
 	if (is_abbrev(arg2, "AVOID"))
@@ -5780,6 +5899,8 @@ DO_MAP(map_get)
 	{
 		tintin_printf2(ses, " worldflags: %d", ses->map->flags);
 		tintin_printf2(ses, "  worldsize: %d", ses->map->size);
+		tintin_printf2(ses, "  direction: %d", ses->map->dir);
+		tintin_printf2(ses, "    pathdir: %s", dir_to_exit(ses, ses->map->dir));
 		tintin_printf2(ses, "");
 		tintin_printf2(ses, "   roomvnum: %d", room->vnum);
 		tintin_printf2(ses, "   roomarea: %s", room->area);
@@ -5805,7 +5926,7 @@ DO_MAP(map_get)
 			{
 				cat_sprintf(exits, "{%s}{%d}", exit->name, exit->vnum);
 			}
-			set_nest_node_ses(ses, arg2, "{area}{%s}{color}{%s}{data}{%s}{desc}{%s}{exits}{%s}{flags}{%d}{id}{%d}{name}{%s}{note}{%s}{symbol}{%s}{terrain}{%s}{vnum}{%d}{weight}{%.3f}", room->area, room->color, room->data, room->desc, exits, room->flags, room->id, room->name, room->note, room->symbol, room->terrain, room->vnum, room->weight);
+			set_nest_node_ses(ses, arg2, "{area}{%s}{color}{%s}{data}{%s}{desc}{%s}{direction}{%d}{exits}{%s}{flags}{%d}{id}{%d}{name}{%s}{note}{%s}{pathdir}{%s}{symbol}{%s}{terrain}{%s}{vnum}{%d}{weight}{%.3f}", room->area, room->color, room->data, room->desc, ses->map->dir, exits, room->flags, room->id, room->name, room->note, dir_to_exit(ses, ses->map->dir), room->symbol, room->terrain, room->vnum, room->weight);
 		}
 		else if (is_abbrev(arg1, "roomarea"))
 		{
@@ -5873,6 +5994,14 @@ DO_MAP(map_get)
 		{
 			set_nest_node_ses(ses, arg2, "%d", ses->map->size);
 		}
+		else if (is_abbrev(arg1, "direction"))
+		{
+			set_nest_node_ses(ses, arg2, "%d", ses->map->dir);
+		}
+		else if (is_abbrev(arg1, "pathdir"))
+		{
+			set_nest_node_ses(ses, arg2, "%s", dir_to_exit(ses, ses->map->dir));
+		}
 		else
 		{
 			show_message(ses, LIST_COMMAND, "#MAP GET: unknown option: %s.", arg1);
@@ -6568,7 +6697,10 @@ DO_MAP(map_list)
 
 	map_search_compile(ses, arg, var);
 
-	set_nest_node_ses(ses, var, "");
+	if (*var)
+	{
+		set_nest_node_ses(ses, var, "");
+	}
 
 	for (vnum = 0 ; vnum < ses->map->size ; vnum++)
 	{
@@ -6742,6 +6874,7 @@ DO_MAP(map_map)
 		}
 
 		ses->map->grid_rooms = (struct room_data **) realloc(ses->map->grid_rooms, ses->map->max_grid_x * ses->map->max_grid_y * sizeof(struct room_data *));
+		ses->map->grid_vnums = (int *) realloc(ses->map->grid_vnums, ses->map->max_grid_x * ses->map->max_grid_y * sizeof(int));
 	}
 
 	displaygrid_build(ses, ses->map->in_room, map_grid_x, map_grid_y, 0);
@@ -7133,6 +7266,7 @@ DO_MAP(map_read)
 					case 'A':
 					case 'B':
 					case 'E':
+					case 'F':
 					case 'H':
 					case 'I':
 					case 'P':
@@ -7341,13 +7475,17 @@ DO_MAP(map_roomflag)
 	{
 		tintin_printf2(ses, "#MAP: Avoid flag is set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_AVOID) ? "ON" : "OFF");
 		tintin_printf2(ses, "#MAP: Block flag is set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_BLOCK) ? "ON" : "OFF");
-		tintin_printf2(ses, "#MAP: Hide flag is set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_HIDE) ? "ON" : "OFF");
+		tintin_printf2(ses, "#MAP: Curved flag is set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_CURVED) ? "ON" : "OFF");
+		tintin_printf2(ses, "#MAP: Fog flag is set to %s.",   HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_FOG) ? "ON" : "OFF");
+		tintin_printf2(ses, "#MAP: Hide flag is set to %s.",  HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_HIDE) ? "ON" : "OFF");
 		tintin_printf2(ses, "#MAP: Invis flag is set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_INVIS) ? "ON" : "OFF");
 		tintin_printf2(ses, "#MAP: Leave flag is set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_LEAVE) ? "ON" : "OFF");
-		tintin_printf2(ses, "#MAP: Void flag is set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_VOID) ? "ON" : "OFF");
-		tintin_printf2(ses, "#MAP: Static flag is set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_STATIC) ? "ON" : "OFF");
-		tintin_printf2(ses, "#MAP: Curved flag is set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_CURVED) ? "ON" : "OFF");
 		tintin_printf2(ses, "#MAP: NoGlobal flag is set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_NOGLOBAL) ? "ON" : "OFF");
+		tintin_printf2(ses, "#MAP: Static flag is set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_STATIC) ? "ON" : "OFF");
+		tintin_printf2(ses, "#MAP: Void flag is set to %s.",  HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_VOID) ? "ON" : "OFF");
+
+
+
 		return;
 	}
 
@@ -7369,6 +7507,10 @@ DO_MAP(map_roomflag)
 		{
 			SET_BIT(flag, ROOM_FLAG_CURVED);
 		}
+		else if (is_abbrev(buf, "fog"))
+		{
+			SET_BIT(flag, ROOM_FLAG_FOG);
+		}
 		else if (is_abbrev(buf, "hide"))
 		{
 			SET_BIT(flag, ROOM_FLAG_HIDE);
@@ -7448,6 +7590,10 @@ DO_MAP(map_roomflag)
 	{
 		show_message(ses, LIST_COMMAND, "#MAP: Curved flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_CURVED) ? "ON" : "OFF");
 	}
+	if (HAS_BIT(flag, ROOM_FLAG_FOG))
+	{
+		show_message(ses, LIST_COMMAND, "#MAP: Fog flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_FOG) ? "ON" : "OFF");
+	}
 	if (HAS_BIT(flag, ROOM_FLAG_HIDE))
 	{
 		show_message(ses, LIST_COMMAND, "#MAP: Hide flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_HIDE) ? "ON" : "OFF");
@@ -7464,15 +7610,14 @@ DO_MAP(map_roomflag)
 	{
 		show_message(ses, LIST_COMMAND, "#MAP: NoGlobal flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_NOGLOBAL) ? "ON" : "OFF");
 	}
-	if (HAS_BIT(flag, ROOM_FLAG_VOID))
-	{
-		show_message(ses, LIST_COMMAND, "#MAP: Void flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_VOID) ? "ON" : "OFF");
-	}
 	if (HAS_BIT(flag, ROOM_FLAG_STATIC))
 	{
 		show_message(ses, LIST_COMMAND, "#MAP: Static flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_STATIC) ? "ON" : "OFF");
 	}
-
+	if (HAS_BIT(flag, ROOM_FLAG_VOID))
+	{
+		show_message(ses, LIST_COMMAND, "#MAP: Void flag set to %s.", HAS_BIT(ses->map->room_list[ses->map->in_room]->flags, ROOM_FLAG_VOID) ? "ON" : "OFF");
+	}
 }
 
 DO_MAP(map_set)
@@ -7584,6 +7729,14 @@ DO_MAP(map_set)
 				show_message(ses, LIST_COMMAND, "#MAP SET: roomweight set to: %.3f", room->weight);
 			}
 		}
+		else if (is_abbrev(arg1, "direction"))
+		{
+			ses->map->dir = URANGE(0, atoi(arg2), 63);
+		}
+		else if (is_abbrev(arg1, "pathdir"))
+		{
+			ses->map->dir = exit_to_dir(ses, arg2);
+		}
 		else
 		{
 			show_message(ses, LIST_COMMAND, "#MAP SET: unknown option: %s", arg1);
@@ -7918,25 +8071,33 @@ DO_MAP(map_undo)
 	}
 	else if (HAS_BIT(undo_flag, MAP_UNDO_LINK))
 	{
-		exit1 = find_exit(ses, room->vnum, link->str2);
+		exit1 = find_exit_vnum(ses, room->vnum, atoi(link->str2));
 
 		if (exit1)
 		{
 			show_message(ses, LIST_COMMAND, "#MAP UNDO: Deleting exit leading %s.", exit1->name);
 			delete_exit(ses, room->vnum, exit1);
 		}
+		else
+		{
+			show_message(ses, LIST_COMMAND, "#MAP UNDO: Could not find exit between %s and %d.", link->str2, room->vnum);
+		}
 
-		exit2 = find_exit(ses, atoi(link->str2), link->str1);
+		exit2 = find_exit_vnum(ses, atoi(link->str2), atoi(link->str1));
 
 		if (exit2)
 		{
 			show_message(ses, LIST_COMMAND, "#MAP UNDO: Deleting exit leading %s.", exit2->name);
 			delete_exit(ses, atoi(link->str2), exit2);
 		}
+		else
+		{
+			show_message(ses, LIST_COMMAND, "#MAP UNDO: Could not find exit leading %s and %s.", link->str2, link->str1);
+		}
 	}
 	else if (HAS_BIT(undo_flag, MAP_UNDO_INSERT))
 	{
-		exit1 = find_exit(ses, atoi(link->str2), link->str1);
+		exit1 = find_exit_vnum(ses, atoi(link->str2), atoi(link->str1));
 
 		if (exit1 == NULL)
 		{
@@ -7952,7 +8113,7 @@ DO_MAP(map_undo)
 			return;
 		}
 
-		exit3 = find_exit(ses, exit2->vnum, ntos(room->vnum));
+		exit3 = find_exit_vnum(ses, exit2->vnum, room->vnum);
 
 		if (exit3 == NULL)
 		{

+ 13 - 4
src/math.c

@@ -201,7 +201,7 @@ void mathexp(struct session *ses, char *str, char *result, int seed)
 	{                                                       \
 		badnumber = 0;                                  \
 		precision = 0;                                  \
-		show_debug(ses, LIST_VARIABLE, "#MATH EXP: INVALID NUMBER %s.", buf3); \
+		show_debug(ses, LIST_VARIABLE, "#MATH EXP {%s}: INVALID NUMBER %s.", str, buf3); \
 	}                                                       \
 	*pta = 0;                                               \
 	sprintf(buf1, "%02d", level);                           \
@@ -388,8 +388,8 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 						pti++;
 						break;
 
-					case ')':
 					case 'd':
+					case ')':
 					case '*':
 					case '/':
 					case '%':
@@ -428,7 +428,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 							*pta++ = *pti++;
 							*pta = 0;
 						}
-						else
+						else if (badnumber == 0)
 						{
 							MATH_NODE(FALSE, EXP_PR_VAR, EXP_OPERATOR);
 
@@ -448,6 +448,10 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 							}
 							metric = 1;
 						}
+						else
+						{
+							*pta++ = *pti++;
+						}
 						break;
 
 					case 'm':
@@ -469,7 +473,7 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 							*pta++ = *pti++;
 							*pta = 0;
 						}
-						else
+						else if (badnumber == 0)
 						{
 							MATH_NODE(FALSE, EXP_PR_VAR, EXP_OPERATOR);
 
@@ -491,6 +495,10 @@ int mathexp_tokenize(struct session *ses, char *str, int seed, int debug)
 							metric = 1;
 							precision = UMAX(precision, strlen(buf3) -1);
 						}
+						else
+						{
+							*pta++ = *pti++;
+						}
 						break;
 
 					default:
@@ -839,6 +847,7 @@ void mathexp_compute(struct session *ses, struct link_data *node)
                         max = max << 32ULL;
                         SET_BIT(min, (unsigned int) tintoi(node->prev->str3));
                         value64 = max | min;
+                        break;
 
 		case 'd':
 			if (tintoi(node->next->str3) <= 0)

+ 2 - 2
src/misc.c

@@ -65,7 +65,7 @@ DO_COMMAND(do_bell)
 		}
 		else
 		{
-			show_error(ses, LIST_COMMAND, "#SYNTAX: #BELL POP {ON|OFF}");
+			show_error(ses, LIST_COMMAND, "#SYNTAX: #BELL FOCUS {ON|OFF}");
 		}
 	}
 	else if (is_abbrev(arg1, "MARGIN"))
@@ -273,7 +273,7 @@ DO_COMMAND(do_test)
 			{
 				sprintf(arg4, "%f %d %s", (arg[4] - '0') * (arg[4] - '0') / 10.0, (arg[5] - '0') * (arg[5] - '0'), &arg[6]);
 
-				tintin_printf2(ses, "debug: %s", arg4);
+				tintin_printf2(ses, "do_test debug: %s", arg4);
 			}
 		}
 	}

+ 47 - 5
src/net.c

@@ -314,11 +314,38 @@ int read_buffer_mud(struct session *ses)
 	return TRUE;
 }
 
+int detect_prompt(struct session *ses, char *original)
+{
+	char strip[BUFFER_SIZE];
+	struct listroot *root = ses->list[LIST_PROMPT];
+	struct listnode *node;
+
+	if (HAS_BIT(ses->charset, CHARSET_FLAG_ALL_TOUTF8))
+	{
+		all_to_utf8(ses, original, strip);
+
+		strcpy(original, strip);
+	}
+
+	strip_vt102_codes(original, strip);
+
+	for (root->update = 0 ; root->update < root->used ; root->update++)
+	{
+		node = root->list[root->update];
+
+		if (check_one_regexp(ses, node, strip, original, 0))
+		{
+			return TRUE;
+		}
+	}
+	return FALSE;
+}
 
 void readmud(struct session *ses)
 {
 	char *line, *next_line;
 	char linebuf[BUFFER_SIZE];
+	int len;
 	struct session *cts;
 
 	push_call("readmud(%p)", ses);
@@ -366,9 +393,13 @@ void readmud(struct session *ses)
 				break;
 			}
 
+			len = strlen(line);
+
 			if (strlen(line) > BUFFER_SIZE / 3)
 			{
-				next_line = &line[BUFFER_SIZE / 3];
+				len = BUFFER_SIZE / 3;
+
+				next_line = &line[len];
 
 				*next_line++ = 0;
 			}
@@ -386,9 +417,20 @@ void readmud(struct session *ses)
 					}
 					else if (HAS_BIT(ses->flags, SES_FLAG_AUTOPATCH))
 					{
-						if (HAS_BIT(ses->flags, SES_FLAG_SPLIT))
+						if (ses->list[LIST_PROMPT]->list[0])
+						{
+							if (!detect_prompt(ses, line))
+							{
+								strcat(ses->more_output, line);
+								ses->check_output = utime() + 500000ULL;
+								break;
+							}
+						}
+						else if (HAS_BIT(ses->flags, SES_FLAG_AUTOPROMPT))
 						{
-							ses->check_output = utime() + 100000ULL;
+							strcat(ses->more_output, line);
+							ses->check_output = utime() + 500000ULL;
+							break;
 						}
 					}
 				}
@@ -493,7 +535,7 @@ void process_mud_output(struct session *ses, char *linebuf, int prompt)
 
 		strip_vt102_codes(linebuf, line);
 
-		show_info(ses, LIST_GAG, "#INFO GAG {%s}", line);
+		show_debug(ses, LIST_GAG, "#DEBUG GAG {%s}", line);
 
 		pop_call();
 		return;
@@ -518,7 +560,7 @@ void process_mud_output(struct session *ses, char *linebuf, int prompt)
 		{
 			if (!IS_SPLIT(ses))
 			{
-				gtd->input_off = 1 + strip_vt102_strlen(ses, linebuf);
+				ses->input->off = 1 + strip_vt102_strlen(ses, linebuf);
 			}
 		}
 	}

+ 8 - 1
src/parse.c

@@ -409,6 +409,13 @@ struct session *parse_tintin_command(struct session *ses, char *input)
 		}
 	}
 
+	if (*line == '!')
+	{
+		show_error(ses, LIST_COMMAND, "#!%s %s", line + 1, input);
+
+		return ses;
+	}
+
 	tintin_printf2(ses, "#ERROR: #UNKNOWN TINTIN-COMMAND '%s'.", line);
 
 	check_all_events(ses, SUB_ARG|SUB_SEC, 0, 1, "UNKNOWN COMMAND", line);
@@ -1048,7 +1055,7 @@ void do_one_line(char *line, struct session *ses)
 
 	if (!HAS_BIT(ses->list[LIST_PROMPT]->flags, LIST_FLAG_IGNORE))
 	{
-		check_all_prompts(ses, line, strip);
+		check_all_prompts(ses, line, strip, TRUE);
 	}
 
 	if (!HAS_BIT(ses->list[LIST_GAG]->flags, LIST_FLAG_IGNORE))

+ 57 - 10
src/path.c

@@ -446,7 +446,7 @@ DO_PATH(path_run)
 		if (*arg1)
 		{
 		
-			delay = (long long) get_number(ses, arg1) * 1000000LL;
+			delay = (long long) (get_number(ses, arg1) * 1000000.0);
 			total = 0;
 
 			DEL_BIT(ses->flags, SES_FLAG_PATHMAPPING);
@@ -481,7 +481,7 @@ DO_PATH(path_walk)
 
 	DEL_BIT(ses->flags, SES_FLAG_PATHMAPPING);
 
-	if (is_abbrev(arg1, "BACKWARDS"))
+	if (is_abbrev(arg1, "BACKWARDS") || is_abbrev(arg1, "-1"))
 	{
 		if (root->update == 0)
 		{
@@ -497,7 +497,7 @@ DO_PATH(path_walk)
 			}
 		}
 	}
-	else if (*arg1 == 0 || is_abbrev(arg1, "FORWARDS"))
+	else if (*arg1 == 0 || is_abbrev(arg1, "FORWARDS") || is_abbrev(arg1, "+1"))
 	{
 		if (root->update == root->used)
 		{
@@ -773,33 +773,35 @@ DO_PATH(path_move)
 	{
 		if (root->update == 0)
 		{
-			show_message(ses, LIST_COMMAND, "#PATH GOTO: ALREADY AT START OF PATH.", root->update);
+			show_message(ses, LIST_COMMAND, "#PATH GOTO: ALREADY AT START OF PATH.");
 		}
 		else
 		{
 			root->update--;
 
-			show_message(ses, LIST_COMMAND, "#PATH MOVE: POSITION SET TO %d.", root->update);
+			show_message(ses, LIST_COMMAND, "#PATH MOVE: POSITION SET TO %d.", root->update + 1);
 		}
 	}
 	else if (is_abbrev(arg1, "FORWARD"))
 	{
 		if (root->update == root->used)
 		{
-			show_message(ses, LIST_COMMAND, "#PATH MOVE: ALREADY AT END OF PATH.", root->update);
+			show_message(ses, LIST_COMMAND, "#PATH MOVE: ALREADY AT END OF PATH.");
 		}
 		else
 		{
 			root->update++;
 
-			show_message(ses, LIST_COMMAND, "#PATH MOVE: POSITION SET TO %d.", root->update);
+			show_message(ses, LIST_COMMAND, "#PATH MOVE: POSITION SET TO %d.", root->update + 1);
 		}
 	}
 	else if (is_math(ses, arg1))
 	{
+		int last = root->update;
+
 		root->update = URANGE(0, root->update + get_number(ses, arg1), root->used);
 
-		show_message(ses, LIST_COMMAND, "#PATH MOVE: POSITION SET TO %d.", root->update + 1);
+		show_message(ses, LIST_COMMAND, "#PATH MOVE: POSITION MOVED FROM %d TO %d.", last + 1, root->update + 1);
 	}
 }
 
@@ -912,9 +914,11 @@ DO_COMMAND(do_pathdir)
 			}
 			get_number_string(ses, arg3, arg3);
 		}
-		update_node_list(ses->list[LIST_PATHDIR], arg1, arg2, arg3, "");
+		node = update_node_list(ses->list[LIST_PATHDIR], arg1, arg2, arg3, "");
+
+		node->val32[0] = atoi(arg3);
 
-		show_message(ses, LIST_PATHDIR, "#OK: DIRECTION {%s} WILL BE REVERSED AS {%s} @ {%s}.", arg1, arg2, arg3);
+		show_message(ses, LIST_PATHDIR, "#OK: DIRECTION {%s} WILL BE REVERSED AS {%s} @ {%d}.", arg1, arg2, atoi(arg3));
 	}
 	return ses;
 }
@@ -942,6 +946,49 @@ DO_COMMAND(do_unpathdir)
 	return ses;
 }
 
+int exit_to_dir(struct session *ses, char *name)
+{
+	struct listnode *node;
+
+	node = search_node_list(ses->list[LIST_PATHDIR], name);
+
+	if (node)
+	{
+		return atoi(node->arg3);
+	}
+	else
+	{
+		return 0;
+	}
+}
+
+char *dir_to_exit(struct session *ses, int dir)
+{
+	struct listroot *root;
+	struct listnode *node;
+
+	if (dir <= 0 || dir >= 64)
+	{
+		return "";
+	}
+
+	root = ses->list[LIST_PATHDIR];
+
+	root->update = 0;
+
+	while (root->update < root->used)
+	{
+		node = root->list[root->update];
+
+		if (node->val32[0] == dir)
+		{
+			return node->arg1;
+		}
+		root->update++;
+	}
+	return "";
+}
+
 // Old commands, left for backward compatibility
 
 DO_PATH(path_new)

+ 1 - 1
src/regex.c

@@ -307,7 +307,7 @@ int get_regex_range(char *in, char *out, int *var, int *arg)
 	{
 		gtd->args[next_arg(*var)] = next_arg(*arg);
 	}
-	strcpy(out, in[2] == 0 ? "(.+)" : "(.+?)");
+	strcpy(out, *pti ? "(.+?)" : "(.+)");
 
 	return 0;
 }

+ 775 - 358
src/screen.c

@@ -24,6 +24,7 @@
 ******************************************************************************/
 
 #include "tintin.h"
+#include "telnet.h"
 
 void screen_osc(char *arg1, char *arg2);
 void screen_csi(char *cmd, char *arg1, char *arg2, char *arg3, char *tc);
@@ -171,16 +172,16 @@ DO_SCREEN(screen_clear)
 		arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
 		arg = sub_arg_in_braces(ses, arg, arg2, GET_ONE, SUB_VAR|SUB_FUN);
 
-		top_row = get_row_index(ses, arg1);
-		top_col = get_col_index(ses, arg2);
+		top_row = get_row_index_arg(ses, arg1);
+		top_col = get_col_index_arg(ses, arg2);
 
 //		tintin_printf2(ses, "debug: (%s) (%s) %d %d", arg1, arg2, top_row, top_col);
 
 		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);
 
-		bot_row = get_row_index(ses, arg1);
-		bot_col = get_col_index(ses, arg2);
+		bot_row = get_row_index_arg(ses, arg1);
+		bot_col = get_col_index_arg(ses, arg2);
 
 //		tintin_printf2(ses, "debug: (%s) (%s) %d %d", arg1, arg2, bot_row, bot_col);
 
@@ -218,39 +219,44 @@ DO_SCREEN(screen_fill)
 		{
 			if (ses->split->sav_top_row == 1)
 			{
-				sprintf(buf, "LINE %d %d %d %d", 1, 1, ses->split->top_row - 1, gtd->screen->cols);
+				sprintf(buf, "%s LINE %d %d %d %d", arg2, 1, 1, ses->split->top_row - 1, gtd->screen->cols);
 			}
 			else
 			{
-				sprintf(buf, "BOX %d %d %d %d {}", 1, 1, ses->split->top_row - 1, gtd->screen->cols);
+				sprintf(buf, "%s BOX %d %d %d %d {}", arg2, 1, 1, ses->split->top_row - 1, gtd->screen->cols);
 			}
 			do_draw(ses, buf);
 		}
 
+		// bottom split
+
 		if (ses->split->sav_bot_row)
 		{
-			if (ses->split->sav_bot_row == 1)
-			{
-				sprintf(buf, "LINE %d %d %d %d", ses->split->bot_row + 1, 1, gtd->screen->rows - 1, gtd->screen->cols);
-			}
-			else
+			if (ses->split->sav_bot_row - inputline_max_row() >= 0)
 			{
-				sprintf(buf, "BOX %d %d %d %d {}", ses->split->bot_row + 1, 1, gtd->screen->rows - 1, gtd->screen->cols);
+				if (ses->split->sav_bot_row - inputline_max_row() == 0)
+				{
+					sprintf(buf, "%s LINE %d %d %d %d", arg2, ses->split->bot_row + 1, 1, gtd->screen->rows - 1, gtd->screen->cols);
+				}
+				else
+				{
+					sprintf(buf, "%s BOX %d %d %d %d {}", arg2, ses->split->bot_row + 1, 1, gtd->screen->rows - inputline_max_row(), gtd->screen->cols);
+				}
+				do_draw(ses, buf);
 			}
-			do_draw(ses, buf);
 		}
 
 		if (ses->split->sav_top_row > 0)
 		{
 			if (ses->split->sav_top_col)
 			{
-				sprintf(buf, "TEED VERTICAL LINE %d %d %d %d", ses->split->top_row - 1, ses->split->top_col - 1, ses->split->bot_row + 1, ses->split->top_col - 1);
+				sprintf(buf, "%s TEED VERTICAL LINE %d %d %d %d", arg2, ses->split->top_row - 1, ses->split->top_col - 1, ses->split->bot_row + 1, ses->split->top_col - 1);
 				do_draw(ses, buf);
 			}
 
 			if (ses->split->sav_bot_col)
 			{
-				sprintf(buf, "TEED VERTICAL LINE %d %d %d %d", ses->split->top_row - 1, ses->split->bot_col + 1, ses->split->bot_row + 1, ses->split->bot_col + 1);
+				sprintf(buf, "%s TEED VERTICAL LINE %d %d %d %d", arg2, ses->split->top_row - 1, ses->split->bot_col + 1, ses->split->bot_row + 1, ses->split->bot_col + 1);
 				do_draw(ses, buf);
 			}
 		}
@@ -258,13 +264,13 @@ DO_SCREEN(screen_fill)
 		{
 			if (ses->split->sav_top_col)
 			{
-				sprintf(buf, "VERTICAL LINE %d %d %d %d", ses->split->top_row, ses->split->top_col - 1, ses->split->bot_row, ses->split->top_col - 1);
+				sprintf(buf, "%s VERTICAL LINE %d %d %d %d", arg2, ses->split->top_row, ses->split->top_col - 1, ses->split->bot_row, ses->split->top_col - 1);
 				do_draw(ses, buf);
 			}
 
 			if (ses->split->sav_bot_col)
 			{
-				sprintf(buf, "VERTICAL LINE %d %d %d %d", ses->split->top_row, ses->split->bot_col + 1, ses->split->bot_row, ses->split->bot_col + 1);
+				sprintf(buf, "%s VERTICAL LINE %d %d %d %d", arg2, ses->split->top_row, ses->split->bot_col + 1, ses->split->bot_row, ses->split->bot_col + 1);
 				do_draw(ses, buf);
 			}
 		}
@@ -472,11 +478,35 @@ DO_SCREEN(screen_move)
 
 	if (height < 0)
 	{
+		if (gtd->screen->desk_height == 0)
+		{
+			show_error(ses, LIST_COMMAND, "#ERROR: #SCREEN MOVE %d %d: USE #SCREEN RAISE DESKTOP DIMENSIONS FIRST.", height, width);
+
+			return;
+		}
+		if (gtd->screen->tot_height == 0)
+		{
+			show_error(ses, LIST_COMMAND, "#ERROR: #SCREEN MOVE %d %d: USE #SCREEN RAISE SCREEN DIMENSIONS FIRST.", height, width);
+
+			return;
+		}
 		sprintf(arg1, "%d", 1 + gtd->screen->desk_height - gtd->screen->tot_height + height);
 	}
 
 	if (width < 0)
 	{
+		if (gtd->screen->desk_width == 0)
+		{
+			show_error(ses, LIST_COMMAND, "#ERROR: #SCREEN MOVE %d %d: USE #SCREEN RAISE DESKTOP DIMENSIONS FIRST.", height, width);
+
+			return;
+		}
+		if (gtd->screen->tot_width == 0)
+		{
+			show_error(ses, LIST_COMMAND, "#ERROR: #SCREEN MOVE %d %d: USE #SCREEN RAISE SCREEN DIMENSIONS FIRST.", height, width);
+
+			return;
+		}
 		sprintf(arg2, "%d", 1 + gtd->screen->desk_width - gtd->screen->tot_width + width);
 	}
 
@@ -599,6 +629,66 @@ DO_SCREEN(screen_scrollregion)
 	return;
 }
 
+void init_inputregion(struct session *ses, int top_row, int top_col, int bot_row, int 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;
+
+	top_row = get_row_index(ses, top_row);
+	top_col = get_col_index(ses, top_col);
+	bot_row = get_row_index(ses, bot_row);
+	bot_col = get_col_index(ses, bot_col);
+
+	if ((top_row|top_col|bot_row|bot_col) == 0)
+	{
+		top_row = gtd->screen->rows;
+		top_col = 1;
+		bot_row = gtd->screen->rows;
+		bot_col = gtd->screen->cols;
+	}
+
+	ses->input->top_row = top_row;
+	ses->input->top_col = top_col;
+	ses->input->bot_row = bot_row;
+	ses->input->bot_col = bot_col;
+}
+
+DO_SCREEN(screen_inputregion)
+{
+	int top_row, top_col, bot_row, bot_col;
+
+	if ((*arg1 && !is_math(ses, arg1)) || (*arg2 && !is_math(ses, arg2)))
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN INPUT {TOP ROW} {TOP COL} {BOT ROW} {BOT COL}");
+
+		return;
+	}
+
+	top_row = get_row_index_arg(ses, arg1);
+	top_col = get_col_index_arg(ses, arg2);
+
+	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)))
+	{
+		show_error(ses, LIST_COMMAND, "#SYNTAX: #SCREEN INPUT {TOP ROW} {TOP COL} {BOT ROW} {BOT COL}");
+
+		return;
+	}
+
+	bot_row = get_row_index_arg(ses, arg1);
+	bot_col = get_col_index_arg(ses, arg2);
+
+	init_inputregion(ses, top_row, top_col, bot_row, bot_col);
+
+//	init_split(ses, ses->split->sav_top_row, ses->split->sav_top_col, ses->split->sav_bot_row, ses->split->sav_bot_col);
+
+	return;
+}
+
 DO_SCREEN(screen_load)
 {
 	if (is_abbrev(arg1, "LABEL"))
@@ -778,7 +868,7 @@ DO_SCREEN(screen_raise)
 	}
 }
 
-int get_row_index(struct session *ses, char *arg)
+int get_row_index_arg(struct session *ses, char *arg)
 {
 	int val;
 
@@ -791,6 +881,11 @@ int get_row_index(struct session *ses, char *arg)
 		val = 0;
 	}
 
+	return get_row_index(ses, val);
+}
+
+int get_row_index(struct session *ses, int val)
+{
 	if (val < 0)
 	{
 		val = 1 + gtd->screen->rows + val;
@@ -804,7 +899,8 @@ int get_row_index(struct session *ses, char *arg)
 	return val;
 }
 
-int get_col_index(struct session *ses, char *arg)
+
+int get_col_index_arg(struct session *ses, char *arg)
 {
 	int val;
 
@@ -816,7 +912,11 @@ int get_col_index(struct session *ses, char *arg)
 	{
 		val = 0;
 	}
+	return get_col_index(ses, val);
+}
 
+int get_col_index(struct session *ses, int val)
+{
 	if (val < 0)
 	{
 		val = 1 + gtd->screen->cols + val;
@@ -994,533 +1094,850 @@ void screen_csit(struct session *ses, char *arg1, char *arg2, char *arg3)
 }
 
 
-DO_SCREEN(screen_info)
-{
-	int lvl;
 
-	tintin_printf2(ses, "gtd->ses->split->sav_top_row: %4d", gtd->ses->split->sav_top_row);
-	tintin_printf2(ses, "gtd->ses->split->sav_top_col: %4d", gtd->ses->split->sav_top_col);
-	tintin_printf2(ses, "gtd->ses->split->sav_bot_row: %4d", gtd->ses->split->sav_bot_row);
-	tintin_printf2(ses, "gtd->ses->split->sav_bot_col: %4d", gtd->ses->split->sav_bot_col);
 
-	tintin_printf2(ses, "gtd->ses->split->top_row:     %4d", gtd->ses->split->top_row);
-	tintin_printf2(ses, "gtd->ses->split->top_col:     %4d", gtd->ses->split->top_col);
-	tintin_printf2(ses, "gtd->ses->split->bot_row:     %4d", gtd->ses->split->bot_row);
-	tintin_printf2(ses, "gtd->ses->split->bot_col:     %4d", gtd->ses->split->bot_col);
 
-	tintin_printf2(ses, "");
+/*
+	save cursor, goto top row, delete (bot - top) rows, restore cursor
+*/
 
-	tintin_printf2(ses, "gtd->ses->wrap:           %4d", gtd->ses->wrap);
-	tintin_printf2(ses, "gtd->ses->cur_row:        %4d", gtd->ses->cur_row);
-	tintin_printf2(ses, "gtd->ses->cur_col:        %4d", gtd->ses->cur_col);
+void erase_scroll_region(struct session *ses)
+{
+	int row;
 
-	for (lvl = 0 ; lvl < gtd->screen->sav_lev ; lvl++)
+	push_call("erase_scroll_region(%p) [%d,%d]",ses,ses->split->top_row,ses->split->bot_row);
+
+	save_pos(ses);
+
+	for (row = ses->split->top_row ; row <= ses->split->bot_row ; row++)
 	{
-		tintin_printf2(ses, "gtd->screen->sav_row[%2d]: %4d", lvl, gtd->screen->sav_row[lvl]);
-		tintin_printf2(ses, "gtd->screen->sav_col[%2d]: %4d", lvl, gtd->screen->sav_col[lvl]);
+		print_stdout("\e[%d;%dH\e[%dX", row, ses->split->top_col, ses->wrap);
 	}
+	restore_pos(ses);
 
-	tintin_printf2(ses, "");
+	pop_call();
+	return;
+}
 
-	tintin_printf2(ses, "gtd->screen->rows:        %4d", gtd->screen->rows);
-	tintin_printf2(ses, "gtd->screen->cols:        %4d", gtd->screen->cols);
-	tintin_printf2(ses, "gtd->screen->height:      %4d", gtd->screen->height);
-	tintin_printf2(ses, "gtd->screen->width:       %4d", gtd->screen->width);
-	tintin_printf2(ses, "gtd->screen->tot_height:  %4d", gtd->screen->tot_height);
-	tintin_printf2(ses, "gtd->screen->tot_width:   %4d", gtd->screen->tot_width);
+void erase_split_region(struct session *ses)
+{
+	erase_top_region(ses);
 
-	tintin_printf2(ses, "");
+	erase_bot_region(ses);
 
-	tintin_printf2(ses, "gtd->screen->top_row:     %4d", gtd->screen->top_row);
-	tintin_printf2(ses, "gtd->screen->bot_row:     %4d", gtd->screen->bot_row);
-	tintin_printf2(ses, "gtd->screen->cur_row:     %4d", gtd->screen->cur_row);
-	tintin_printf2(ses, "gtd->screen->cur_col:     %4d", gtd->screen->cur_col);
-	tintin_printf2(ses, "gtd->screen->max_row:     %4d", gtd->screen->max_row);
+	erase_left_region(ses);
 
-	tintin_printf2(ses, "");
+	erase_right_region(ses);
+}
 
-	tintin_printf2(ses, "gtd->screen->desk_rows:   %4d", gtd->screen->desk_rows);
-	tintin_printf2(ses, "gtd->screen->desk_cols:   %4d", gtd->screen->desk_cols);
-	tintin_printf2(ses, "gtd->screen->desk_height: %4d", gtd->screen->desk_height);
-	tintin_printf2(ses, "gtd->screen->desk_width:  %4d", gtd->screen->desk_width);
+void erase_top_region(struct session *ses)
+{
+	int row;
 
-	if (!HAS_BIT(ses->flags, SES_FLAG_READMUD) && IS_SPLIT(ses))
+	if (ses->split->top_row > 1)
 	{
-		tintin_printf2(ses, "SPLIT mode detected.");
+		save_pos(ses);
+		goto_pos(ses, 1, 1);
+
+		for (row = 1 ; row < ses->split->top_row ; row++)
+		{
+			print_stdout("\e[K\n");
+		}
+		restore_pos(ses);
 	}
 }
 
-/*
+void erase_bot_region(struct session *ses)
+{
+	int row;
 
-	if (gtd->screen == NULL)
+	if (ses->split->bot_row < gtd->screen->rows)
 	{
-		tintin_printf2(ses, "gtd->screen: NULL");
+		save_pos(ses);
+		goto_pos(ses, ses->split->bot_row + 1, 1);
 
-		return ses;
+		for (row = ses->split->bot_row + 1 ; row < gtd->screen->rows ; row++)
+		{
+			print_stdout("\e[K\n");
+		}
+		restore_pos(ses);
 	}
-
-	arg = get_arg_in_braces(ses, arg, arg1, GET_ONE);
-
-
-	print_screen(gts);
-
-	return ses;
 }
-*/
 
-void add_row_screen(int index)
+void erase_left_region(struct session *ses)
 {
-	gtd->screen->lines[index] = (struct row_data *) calloc(1, sizeof(struct row_data));
-	gtd->screen->lines[index]->str = strdup("");
-}
+	int row;
 
-void del_row_screen(int index)
-{
-	free(gtd->screen->lines[index]->str);
-	free(gtd->screen->lines[index]);
+	if (ses->split->top_col > 1)
+	{
+		save_pos(ses);
+
+		for (row = ses->split->top_row ; row <= ses->split->bot_row ; row++)
+		{
+			print_stdout("\e[%d;1H\e[%dX", row, ses->split->top_col - 1);
+		}
+		restore_pos(ses);
+	}
 }
 
-void init_screen(int rows, int cols, int height, int width)
+void erase_right_region(struct session *ses)
 {
-	int cnt;
-
-	gtd->screen->rows        = UMAX(1, rows);
-	gtd->screen->cols        = UMAX(1, cols);
-	gtd->screen->height      = UMAX(1, height);
-	gtd->screen->width       = UMAX(1, width);
-	gtd->screen->char_height = UMAX(1, gtd->screen->height / gtd->screen->rows);
-	gtd->screen->char_width  = UMAX(1, gtd->screen->width / gtd->screen->cols);
-
-	gtd->screen->focus  = 1;
-
-	return;
-
-//	disabled for now
-
-	push_call("init_screen(%d,%d)",rows,cols);
+	int row;
 
-	if (gtd->screen)
+	if (ses->split->bot_col < gtd->screen->cols)
 	{
-		if (gtd->screen->max_row < rows)
-		{
-			gtd->screen->lines = (struct row_data **) realloc(gtd->screen->lines, rows * sizeof(struct row_data *));
-			
-			memset(gtd->screen->lines + gtd->screen->max_row * sizeof(struct row_data *), 0, (rows - gtd->screen->max_row) * sizeof(struct row_data *));
+		save_pos(ses);
 
-			gtd->screen->max_row = rows;
+		for (row = ses->split->top_row ; row <= ses->split->bot_row ; row++)
+		{
+			print_stdout("\e[%d;%dH\e[K", row, ses->split->bot_col + 1);
 		}
+		restore_pos(ses);
 	}
-	else
-	{
-		gtd->screen = calloc(1, sizeof(struct screen_data));
-		gtd->screen->lines = (struct row_data **) calloc(rows, sizeof(struct row_data *));
+}
 
-		gtd->screen->top_row = 1;
-		gtd->screen->bot_row = rows;
 
-		gtd->screen->max_row = rows;
-	}
+void erase_square(struct session *ses, int top_row, int top_col, int bot_row, int bot_col)
+{
+	int row;
 
-	gtd->screen->rows = rows;
-	gtd->screen->cols = cols;
+	push_call("erase_square(%p,%d,%d,%d,%d)",ses,top_row,top_col,bot_row,bot_col);
 
-	gtd->screen->sav_lev = 0;
-	gtd->screen->sav_row[0] = gtd->screen->cur_row = rows;
-	gtd->screen->sav_col[0] = gtd->screen->cur_col = 0;
+	save_pos(ses);
 
-	for (cnt = 0 ; cnt < gtd->screen->max_row ; cnt++)
+	for (row = top_row ; row <= bot_row ; row++)
 	{
-		if (gtd->screen->lines[cnt] == NULL)
-		{
-			add_row_screen(cnt);
-		}
+		goto_pos(ses, row, top_col);
+		print_stdout("\e[%dX", bot_col - top_col + 1);
 	}
+	restore_pos(ses);
+
 	pop_call();
 	return;
 }
 
-void destroy_screen()
+void fill_scroll_region(struct session *ses, char *arg)
 {
-	int cnt;
-
-//	disabled for now
+	int row, col;
 
-	return;
+	save_pos(ses);
 
-	for (cnt = 0 ; cnt < gtd->screen->max_row ; cnt++)
+	for (row = ses->split->top_row ; row < ses->split->bot_row ; row++)
 	{
-		del_row_screen(cnt);
-	}
-	free(gtd->screen->lines);
-	free(gtd->screen);
+		goto_pos(ses, row, ses->split->top_col);
 
-	gtd->screen = NULL;
+		for (col = ses->split->top_col ; col < ses->split->bot_col ; col++)
+		{
+			print_stdout("%s", arg);
+		}
+		print_stdout("\n");
+	}
+	restore_pos(ses);
 }
 
-void print_screen()
+void fill_top_region(struct session *ses, char *arg)
 {
-	int cnt;
+	int row, col;
 
-	for (cnt = 0 ; cnt < gtd->screen->rows ; cnt++)
+	if (ses->split->top_row > 1)
 	{
-		print_stdout("%2d %s\n", cnt, gtd->screen->lines[cnt]->str);
-	}
-}
+		save_pos(ses);
+		goto_pos(ses, 1, 1);
 
+		for (row = 1 ; row < ses->split->top_row ; row++)
+		{
+			print_stdout("\e[0m");
 
-void add_line_screen(char *str)
-{
-	char *ptr;
-	int cnt;
-
-	// disabled for now
-
-	return;
+			for (col = 0 ; col < gtd->screen->cols ; col++)
+			{
+				print_stdout("%s", arg);
+			}
+			print_stdout("\n");
+		}
+		restore_pos(ses);
+	}
+}
 
-	push_call("add_line_screen(%p)",str);
+void fill_bot_region(struct session *ses, char *arg)
+{
+	int row, col;
 
-	if (gtd->screen == NULL)
+	if (ses->split->bot_row < gtd->screen->rows)
 	{
-		print_stdout("screen == NULL!\n");
+		save_pos(ses);
+		goto_pos(ses, ses->split->bot_row + 1, 1);
 
-		pop_call();
-		return;
+		for (row = ses->split->bot_row + 1 ; row < gtd->screen->rows ; row++)
+		{
+			print_stdout("\e[0m");
+			for (col = 0 ; col < gtd->screen->cols ; col++)
+			{
+				print_stdout("%s", arg);
+			}
+			print_stdout("\n");
+		}
+		restore_pos(ses);
 	}
+}
 
-	while (str)
-	{
-		cnt = gtd->ses->split->top_row - 1;
+void fill_left_region(struct session *ses, char *arg)
+{
+	int row, col;
 
-		free(gtd->screen->lines[cnt]->str);
+	if (ses->split->top_col > 1)
+	{
+		save_pos(ses);
 
-		while (cnt < gtd->ses->split->bot_row - 2)
+		for (row = ses->split->top_row ; row <= ses->split->bot_row ; row++)
 		{
-			gtd->screen->lines[cnt]->str = gtd->screen->lines[cnt + 1]->str;
+			print_stdout("\e[%d;1H\e[0m", row);
 
-			cnt++;
+			for (col = 0 ; col < ses->split->top_col - 1 ; col++)
+			{
+				print_stdout("%s", arg);
+			}
 		}
+		restore_pos(ses);
+	}
+}
 
-		ptr = strchr(str, '\n');
+void fill_right_region(struct session *ses, char *arg)
+{
+	int row, col;
 
-		if (ptr)
-		{
-			gtd->screen->lines[cnt]->str = strndup(str, ptr - str);
+	if (ses->split->bot_col < gtd->screen->cols)
+	{
+		save_pos(ses);
 
-			str = ptr + 1;
-		}
-		else
+		for (row = ses->split->top_row ; row <= ses->split->bot_row ; row++)
 		{
-			gtd->screen->lines[cnt]->str = strdup(str);
+			print_stdout("\e[%d;%dH\e[0m", row, ses->split->bot_col + 1);
 
-			str = NULL;
+			for (col = ses->split->bot_col + 1 ; col <= gtd->screen->cols ; col++)
+			{
+				print_stdout("%s", arg);
+			}
 		}
-//		gtd->screen->lines[cnt]->raw_len = strlen(gtd->screen->lines[cnt]->str);
-//		gtd->screen->lines[cnt]->str_len = strip_vt102_strlen(gts, gtd->screen->lines[cnt]->str);
+		restore_pos(ses);
 	}
-
-	pop_call();
-	return;
 }
 
+void fill_split_region(struct session *ses, char *arg)
+{
+	fill_top_region(ses, arg);
 
+	fill_bot_region(ses, arg);
 
-void set_line_screen(char *str, int row, int col)
+	fill_left_region(ses, arg);
+
+	fill_right_region(ses, arg);
+}
+
+// VT SCREEN TECH
+
+DO_SCREEN(screen_info)
 {
-	char buf[BUFFER_SIZE];
+	int lvl;
 
-	// disabled for now
-	
-	return;
+	tintin_printf2(ses, "gtd->ses->split->sav_top_row: %4d", gtd->ses->split->sav_top_row);
+	tintin_printf2(ses, "gtd->ses->split->sav_top_col: %4d", gtd->ses->split->sav_top_col);
+	tintin_printf2(ses, "gtd->ses->split->sav_bot_row: %4d", gtd->ses->split->sav_bot_row);
+	tintin_printf2(ses, "gtd->ses->split->sav_bot_col: %4d", gtd->ses->split->sav_bot_col);
 
-	push_call("set_line_screen(%p,%d)",str,row,col);
+	tintin_printf2(ses, "gtd->ses->split->top_row:     %4d", gtd->ses->split->top_row);
+	tintin_printf2(ses, "gtd->ses->split->top_col:     %4d", gtd->ses->split->top_col);
+	tintin_printf2(ses, "gtd->ses->split->bot_row:     %4d", gtd->ses->split->bot_row);
+	tintin_printf2(ses, "gtd->ses->split->bot_col:     %4d", gtd->ses->split->bot_col);
 
-	strcpy(buf, gtd->screen->lines[row]->str);
+	tintin_printf2(ses, "");
 
-	free(gtd->screen->lines[row]->str);
+	tintin_printf2(ses, "gtd->ses->wrap:           %4d", gtd->ses->wrap);
+	tintin_printf2(ses, "gtd->ses->cur_row:        %4d", gtd->ses->cur_row);
+	tintin_printf2(ses, "gtd->ses->cur_col:        %4d", gtd->ses->cur_col);
 
-	strcpy(&buf[col], str);
+	for (lvl = 0 ; lvl < gtd->screen->sav_lev ; lvl++)
+	{
+		tintin_printf2(ses, "gtd->screen->sav_row[%2d]: %4d", lvl, gtd->screen->sav_row[lvl]);
+		tintin_printf2(ses, "gtd->screen->sav_col[%2d]: %4d", lvl, gtd->screen->sav_col[lvl]);
+	}
 
-	gtd->screen->lines[row]->str = strdup(buf);
+	tintin_printf2(ses, "");
 
-	pop_call();
-	return;
-}
+	tintin_printf2(ses, "gtd->screen->rows:        %4d", gtd->screen->rows);
+	tintin_printf2(ses, "gtd->screen->cols:        %4d", gtd->screen->cols);
+	tintin_printf2(ses, "gtd->screen->height:      %4d", gtd->screen->height);
+	tintin_printf2(ses, "gtd->screen->width:       %4d", gtd->screen->width);
+	tintin_printf2(ses, "gtd->screen->tot_height:  %4d", gtd->screen->tot_height);
+	tintin_printf2(ses, "gtd->screen->tot_width:   %4d", gtd->screen->tot_width);
 
-/*
-	save cursor, goto top row, delete (bot - top) rows, restore cursor
-*/
+	tintin_printf2(ses, "");
 
-void erase_scroll_region(struct session *ses)
-{
-	int row;
+	tintin_printf2(ses, "gtd->screen->top_row:     %4d", gtd->screen->top_row);
+	tintin_printf2(ses, "gtd->screen->bot_row:     %4d", gtd->screen->bot_row);
+	tintin_printf2(ses, "gtd->screen->cur_row:     %4d", gtd->screen->cur_row);
+	tintin_printf2(ses, "gtd->screen->cur_col:     %4d", gtd->screen->cur_col);
+	tintin_printf2(ses, "gtd->screen->max_row:     %4d", gtd->screen->max_row);
 
-	push_call("erase_scroll_region(%p) [%d,%d]",ses,ses->split->top_row,ses->split->bot_row);
+	tintin_printf2(ses, "");
 
-	save_pos(ses);
+	tintin_printf2(ses, "gtd->screen->desk_rows:   %4d", gtd->screen->desk_rows);
+	tintin_printf2(ses, "gtd->screen->desk_cols:   %4d", gtd->screen->desk_cols);
+	tintin_printf2(ses, "gtd->screen->desk_height: %4d", gtd->screen->desk_height);
+	tintin_printf2(ses, "gtd->screen->desk_width:  %4d", gtd->screen->desk_width);
 
-	for (row = ses->split->top_row ; row <= ses->split->bot_row ; row++)
+	if (!HAS_BIT(ses->flags, SES_FLAG_READMUD) && IS_SPLIT(ses))
 	{
-		print_stdout("\e[%d;%dH\e[%dX", row, ses->split->top_col, ses->wrap);
+		tintin_printf2(ses, "SPLIT mode detected.");
+	}
+
+	if (*arg1)
+	{
+		tintin_printf2(ses, "PRINTING SCREEN");
+
+		print_screen();
 	}
-	restore_pos(ses);
 
-	pop_call();
 	return;
 }
 
-void erase_split_region(struct session *ses)
+DO_SCREEN(screen_print)
 {
-	erase_top_region(ses);
-
-	erase_bot_region(ses);
-
-	erase_left_region(ses);
-
-	erase_right_region(ses);
+	print_screen();
 }
 
-void erase_top_region(struct session *ses)
+int inside_scroll_region(struct session *ses, int row, int col)
 {
-	int row;
-
-	if (ses->split->top_row > 1)
+	if (row < ses->split->top_row)
 	{
-		save_pos(ses);
-		goto_pos(ses, 1, 1);
-
-		for (row = 1 ; row < ses->split->top_row ; row++)
-		{
-			print_stdout("\e[K\n");
-		}
-		restore_pos(ses);
+		return 0;
+	}
+	if (row > ses->split->bot_row)
+	{
+		return 0;
 	}
+	if (col < ses->split->top_col)
+	{
+		return 0;
+	}
+	if (col > ses->split->bot_col)
+	{
+		return 0;
+	}
+	return 1;
 }
 
-void erase_bot_region(struct session *ses)
+void add_row_screen(int index)
 {
-	int row;
-
-	if (ses->split->bot_row < gtd->screen->rows)
-	{
-		save_pos(ses);
-		goto_pos(ses, ses->split->bot_row + 1, 1);
+	gtd->screen->lines[index] = (struct row_data *) calloc(1, sizeof(struct row_data));
+	gtd->screen->lines[index]->str = strdup("");
+}
 
-		for (row = ses->split->bot_row + 1 ; row < gtd->screen->rows ; row++)
-		{
-			print_stdout("\e[K\n");
-		}
-		restore_pos(ses);
-	}
+void del_row_screen(int index)
+{
+	free(gtd->screen->lines[index]->str);
+	free(gtd->screen->lines[index]);
 }
 
-void erase_left_region(struct session *ses)
+void init_screen(int rows, int cols, int height, int width)
 {
-	int row;
+	int cnt;
 
-	if (ses->split->top_col > 1)
-	{
-		save_pos(ses);
+	gtd->screen->rows        = UMAX(1, rows);
+	gtd->screen->cols        = UMAX(1, cols);
+	gtd->screen->height      = UMAX(1, height);
+	gtd->screen->width       = UMAX(1, width);
+	gtd->screen->char_height = UMAX(1, gtd->screen->height / gtd->screen->rows);
+	gtd->screen->char_width  = UMAX(1, gtd->screen->width / gtd->screen->cols);
 
-		for (row = ses->split->top_row ; row <= ses->split->bot_row ; row++)
-		{
-			print_stdout("\e[%d;1H\e[%dX", row, ses->split->top_col - 1);
-		}
-		restore_pos(ses);
-	}
-}
+	gtd->screen->focus  = 1;
 
-void erase_right_region(struct session *ses)
-{
-	int row;
+	gts->input->top_row = rows;
+	gts->input->top_col = 1;
+	gts->input->bot_row = rows;
+	gts->input->bot_col = cols;
 
-	if (ses->split->bot_col < gtd->screen->cols)
+	gtd->screen->sav_lev    = 0;
+	gtd->screen->sav_row[0] = gtd->screen->cur_row = rows;
+	gtd->screen->sav_col[0] = gtd->screen->cur_col = 1;
+
+	push_call("init_screen(%d,%d)",rows,cols);
+
+	if (gtd->screen->max_row < rows)
 	{
-		save_pos(ses);
+		gtd->screen->lines = (struct row_data **) realloc(gtd->screen->lines, rows * sizeof(struct row_data *));
 
-		for (row = ses->split->top_row ; row <= ses->split->bot_row ; row++)
+		for (cnt = gtd->screen->max_row ; cnt < rows ; cnt++)
 		{
-			print_stdout("\e[%d;%dH\e[K", row, ses->split->bot_col + 1);
+			add_row_screen(cnt);
 		}
-		restore_pos(ses);
+		gtd->screen->max_row = rows;
 	}
+
+	pop_call();
+	return;
 }
 
 
-void erase_square(struct session *ses, int top_row, int top_col, int bot_row, int bot_col)
+void get_line_screen(char *result, int row)
 {
-	int row;
-
-	push_call("erase_square(%p,%d,%d,%d,%d)",ses,top_row,top_col,bot_row,bot_col);
+	strcpy(result, gtd->screen->lines[row]->str);
+}
 
-	save_pos(ses);
+void get_word_screen(char *result, int row, int col)
+{
+	char *ptr;
+	int i, j;
 
-	for (row = top_row ; row <= bot_row ; row++)
-	{
-		goto_pos(ses, row, top_col);
-		print_stdout("\e[%dX", bot_col - top_col + 1);
-	}
-	restore_pos(ses);
+	strip_vt102_codes(gtd->screen->lines[row]->str, result);
 
-	pop_call();
-	return;
-}
+	ptr = result;
 
-void fill_scroll_region(struct session *ses, char *arg)
-{
-	int row, col;
+	if (!isalnum((int) ptr[col]) && ptr[col] != '_')
+	{
+		sprintf(result, "%c", ptr[col]);
 
-	save_pos(ses);
+		return;
+	}
 
-	for (row = ses->split->top_row ; row < ses->split->bot_row ; row++)
+	for (i = col ; i >= 0 ; i--)
 	{
-		goto_pos(ses, row, ses->split->top_col);
+		if (!isalnum((int) ptr[i]) && ptr[i] != '_')
+		{
+			break;
+		}
+	}
+	i++;
 
-		for (col = ses->split->top_col ; col < ses->split->bot_col ; col++)
+	for (j = col ; ptr[j] ; j++)
+	{
+		if (!isalnum((int) ptr[j]) && ptr[j] != '_')
 		{
-			print_stdout("%s", arg);
+			break;
 		}
-		print_stdout("\n");
 	}
-	restore_pos(ses);
+
+	strncpy(result, &ptr[i], j - i);
+
+	result[j - i] = 0;
 }
 
-void fill_top_region(struct session *ses, char *arg)
+int get_link_screen(struct session *ses, char *result, int flags, int row, int col)
 {
-	int row, col;
+	char *pts, *ptl, *ptw;
+	int skip, width, len, start, opt;
 
-	if (ses->split->top_row > 1)
+	ptl     = NULL;
+	len     = 0;
+	opt     = 0;
+	*result = 0;
+
+	if (inside_scroll_region(ses, row, col))
 	{
-		save_pos(ses);
-		goto_pos(ses, 1, 1);
+		col -= ses->split->top_col;
+		pts = gtd->screen->lines[row - 1]->str;
+		ptw = pts;
+	}
+	else
+	{
+//		tintin_printf2(ses, "debug: scroll region only for now.");
 
-		for (row = 1 ; row < ses->split->top_row ; row++)
+		return 0;
+	}
+
+	while (*pts)
+	{
+		start:
+
+		if (*pts == ASCII_ESC)
 		{
-			print_stdout("\e[0m");
+//			tintin_printf2(gtd->ses, "link debug: %3d %c %c", *pts, pts[1], pts[2]);
 
-			for (col = 0 ; col < gtd->screen->cols ; col++)
+			if (pts[1] == ']' && pts[2] == '6' && pts[3] == '8' && pts[4] == ';')
 			{
-				print_stdout("%s", arg);
-			}
-			print_stdout("\n");
-		}
-		restore_pos(ses);
-	}
-}
+				char var[BUFFER_SIZE], val[BUFFER_SIZE], *pto;
+				int nest, state[100], last;
 
-void fill_bot_region(struct session *ses, char *arg)
-{
-	int row, col;
+				result[0] = var[0] = val[0] = state[0] = nest = last = opt = 0;
 
-	if (ses->split->bot_row < gtd->screen->rows)
-	{
-		save_pos(ses);
-		goto_pos(ses, ses->split->bot_row + 1, 1);
+				pts += 5;
 
-		for (row = ses->split->bot_row + 1 ; row < gtd->screen->rows ; row++)
-		{
-			print_stdout("\e[0m");
-			for (col = 0 ; col < gtd->screen->cols ; col++)
+				opt = 0;
+
+				while (isdigit(*pts))
+				{
+					opt = opt * 10 + (*pts++ - '0');
+				}
+
+				if (*pts == ';')
+				{
+					pts++;
+				}
+
+				pto = var;
+
+				while (*pts)
+				{
+					switch (*pts)
+					{
+						case MSDP_TABLE_OPEN:
+							if (last != MSDP_VAL)
+							{
+								if (nest)
+								{
+									if (last == MSDP_VAR || last == MSDP_VAL)
+									{
+										*pto++ = '}';
+									}
+									if (state[nest])
+									{
+										pto += sprintf(pto, "{%d}", state[nest]++);
+									}
+									*pto++ = '{';
+								}
+								else
+								{
+									*pto = 0;
+
+									if (last != MSDP_VAR)
+									{
+										if (!is_number(var) || (int) tintoi(var) == flags)
+										{
+											cat_sprintf(result, "{%s}{%s}",var,val);
+										}
+									}
+									pto = val;
+								}
+							}
+							nest++;
+							state[nest] = 0;
+							last = MSDP_TABLE_OPEN;
+							break;
+
+						case MSDP_TABLE_CLOSE:
+							if (nest)
+							{
+								if (last == MSDP_VAL || last == MSDP_VAR)
+								{
+									*pto++ = '}';
+								}
+								nest--;
+							}
+							if (nest)
+							{
+								*pto++ = '}';
+							}
+							last = MSDP_TABLE_CLOSE;
+							break;
+
+						case MSDP_ARRAY_OPEN:
+							if (last != MSDP_VAL)
+							{
+								if (nest)
+								{
+									if (last == MSDP_VAR || last == MSDP_VAL)
+									{
+										*pto++ = '}';
+									}
+									if (state[nest])
+									{
+										pto += sprintf(pto, "{%d}", state[nest]++);
+									}
+									*pto++ = '{';
+								}
+								else
+								{
+									*pto = 0;
+
+									if (last != MSDP_VAR)
+									{
+										if (!is_number(var) || (int) tintoi(var) == flags)
+										{
+											cat_sprintf(result, "{%s}{%s}",var,val);
+										}
+									}
+									pto = val;
+								}
+							}
+							nest++;
+							state[nest] = 1;
+							last = MSDP_ARRAY_OPEN;
+							break;
+
+						case MSDP_ARRAY_CLOSE:
+							if (nest)
+							{
+								if (last == MSDP_VAL)
+								{
+									*pto++ = '}';
+								}
+								nest--;
+							}
+							if (nest)
+							{
+								*pto++ = '}';
+							}
+							last = MSDP_ARRAY_CLOSE;
+							break;
+
+						case MSDP_VAR:
+							if (nest)
+							{
+								if (last == MSDP_VAL)
+								{
+									*pto++ = '}';
+								}
+								*pto++ = '{';
+							}
+							else
+							{
+								*pto = 0;
+
+								if (last)
+								{
+									if (!is_number(var) || (int) tintoi(var) == flags)
+									{
+										cat_sprintf(result, "{%s}{%s}",var,val);
+									}
+								}
+								pto = var;
+							}
+							last = MSDP_VAR;
+							break;
+
+						case MSDP_VAL:
+							if (nest)
+							{
+								if (last == MSDP_VAR || last == MSDP_VAL)
+								{
+									*pto++ = '}';
+								}
+								if (state[nest])
+								{
+									pto += sprintf(pto, "{%d}", state[nest]++);
+								}
+								*pto++ = '{';
+							}
+							else
+							{
+								*pto = 0;
+
+								if (last != MSDP_VAR)
+								{
+									if (!is_number(var) || (int) tintoi(var) == flags)
+									{
+										cat_sprintf(result, "{%s}{%s}",var,val);
+									}
+								}
+								pto = val;
+							}
+							last = MSDP_VAL;
+							break;
+
+						case ASCII_BEL:
+							*pto = 0;
+
+							if (last)
+							{
+								if (!is_number(var) || (int) tintoi(var) == flags)
+								{
+									cat_sprintf(result, "{%s}{%s}", var, val);
+								}
+							}
+							else
+							{
+								strcpy(result, var);
+							}
+							pts++;
+//							tintin_printf2(gtd->ses, "link debug: %s", result);
+							goto start;
+							break;
+
+						case '\r':
+							break;
+
+						case '\\':
+							*pto++ = '\\';
+							*pto++ = '\\';
+							break;
+
+						case '{':
+							*pto++ = '\\';
+							*pto++ = 'x';
+							*pto++ = '7';
+							*pto++ = 'B';
+							break;
+
+						case '}':
+							*pto++ = '\\';
+							*pto++ = 'x';
+							*pto++ = '7';
+							*pto++ = 'D';
+							break;
+
+						case COMMAND_SEPARATOR:
+							*pto++ = '\\';
+							*pto++ = COMMAND_SEPARATOR;
+							break;
+
+						default:
+							*pto++ = *pts;
+							break;
+					}
+					pts++;
+				}
+			}
+			else if (pts[1] == '[' && pts[2] == '4')
 			{
-				print_stdout("%s", arg);
+				if (pts[3] == 'm')
+				{
+					ptl   = &pts[4];
+					start = len;
+				}
+				else if (pts[3] == ';' && pts[4] == '2' && pts[5] == '4' && pts[6] == 'm')
+				{
+					ptl   = &pts[7];
+					start = len;
+				}
 			}
-			print_stdout("\n");
-		}
-		restore_pos(ses);
-	}
-}
-
-void fill_left_region(struct session *ses, char *arg)
-{
-	int row, col;
+			else if (pts[1] == '[' && pts[2] == '2' && pts[3] == '4' && pts[4] == 'm')
+			{
+				if (ptl && col >= start && col < len)
+				{
+					if (*result == 0)
+					{
+						sprintf(result, "%.*s", (int) (pts - ptl), ptl);
+					}
 
-	if (ses->split->top_col > 1)
-	{
-		save_pos(ses);
+//					tintin_printf2(gtd->ses, "\e[1;32mfound link: (%d,%d) [%s]", col, len, result);
 
-		for (row = ses->split->top_row ; row <= ses->split->bot_row ; row++)
+					return opt ? opt : TRUE;
+				}
+				else
+				{
+					ptl = NULL;
+					*result = 0;
+				}
+			}
+		}
+		else if (*pts == ' ')
 		{
-			print_stdout("\e[%d;1H\e[0m", row);
-
-			for (col = 0 ; col < ses->split->top_col - 1 ; col++)
+			if (ptl == NULL && len >= col)
 			{
-				print_stdout("%s", arg);
+				break;
 			}
+			ptw = pts;
 		}
-		restore_pos(ses);
+
+		skip = skip_one_char(gtd->ses, pts, &width);
+
+		len += width;
+		pts += skip;
 	}
+
+	sprintf(result, "%.*s", (int) (pts - ptw), ptw);
+
+	return FALSE;
 }
 
-void fill_right_region(struct session *ses, char *arg)
+void set_line_screen(char *str, int row, int col)
 {
-	int row, col;
+	char buf[BUFFER_SIZE];
 
-	if (ses->split->bot_col < gtd->screen->cols)
-	{
-		save_pos(ses);
+	push_call("set_line_screen(%p,%d)",str,row,col);
 
-		for (row = ses->split->top_row ; row <= ses->split->bot_row ; row++)
-		{
-			print_stdout("\e[%d;%dH\e[0m", row, ses->split->bot_col + 1);
+	strcpy(buf, gtd->screen->lines[row]->str);
 
-			for (col = ses->split->bot_col + 1 ; col <= gtd->screen->cols ; col++)
-			{
-				print_stdout("%s", arg);
-			}
-		}
-		restore_pos(ses);
-	}
+	free(gtd->screen->lines[row]->str);
+
+	strcpy(&buf[col], str);
+
+	gtd->screen->lines[row]->str = strdup(buf);
+
+	pop_call();
+	return;
 }
 
-void fill_split_region(struct session *ses, char *arg)
+
+void destroy_screen()
 {
-	fill_top_region(ses, arg);
+	int cnt;
 
-	fill_bot_region(ses, arg);
+//	disabled for now
 
-	fill_left_region(ses, arg);
+	return;
 
-	fill_right_region(ses, arg);
+	for (cnt = 0 ; cnt < gtd->screen->max_row ; cnt++)
+	{
+		del_row_screen(cnt);
+	}
+	free(gtd->screen->lines);
+	free(gtd->screen);
+
+	gtd->screen = NULL;
 }
 
-void get_line_screen(char *result, int row)
+void print_screen()
 {
-	strcpy(result, gtd->screen->lines[row]->str);
+	int cnt;
+
+	for (cnt = 0 ; cnt < gtd->screen->rows ; cnt++)
+	{
+		print_stdout("\e[%dH%02d%s", cnt + 1, cnt + 1, gtd->screen->lines[cnt]->str);
+	}
 }
 
-void get_word_screen(char *result, int row, int col)
+
+void add_line_screen(char *str)
 {
 	char *ptr;
-	int i, j;
-
-	strip_vt102_codes(gtd->screen->lines[row]->str, result);
+	int cnt;
 
-	ptr = result;
+	push_call("add_line_screen(%p)",str);
 
-	if (!isalnum((int) ptr[col]) && ptr[col] != '_')
+	if (gtd->screen == NULL)
 	{
-		sprintf(result, "%c", ptr[col]);
+		print_stdout("screen == NULL!\n");
 
+		pop_call();
 		return;
 	}
 
-	for (i = col ; i >= 0 ; i--)
+	while (str)
 	{
-		if (!isalnum((int) ptr[i]) && ptr[i] != '_')
+		cnt = gtd->ses->split->top_row - 1;
+
+		if (cnt < 0 || cnt >= gtd->ses->split->bot_row)
 		{
-			break;
+			tintin_printf2(gtd->ses, "add_line_screen debug: cnt = %d", cnt);
 		}
-	}
-	i++;
 
-	for (j = col ; ptr[j] ; j++)
-	{
-		if (!isalnum((int) ptr[j]) && ptr[j] != '_')
+		free(gtd->screen->lines[cnt]->str);
+
+		while (cnt < gtd->ses->split->bot_row - 2)
 		{
-			break;
+			gtd->screen->lines[cnt]->str = gtd->screen->lines[cnt + 1]->str;
+
+			cnt++;
 		}
-	}
 
-	strncpy(result, &ptr[i], j - i);
+		ptr = strchr(str, '\n');
 
-	result[j - i] = 0;
+		if (ptr)
+		{
+			gtd->screen->lines[cnt]->str = strndup(str, ptr - str);
+
+			str = ptr + 1;
+		}
+		else
+		{
+			gtd->screen->lines[cnt]->str = strdup(str);
+
+			str = NULL;
+		}
+//		gtd->screen->lines[cnt]->raw_len = strlen(gtd->screen->lines[cnt]->str);
+//		gtd->screen->lines[cnt]->str_len = strip_vt102_strlen(gts, gtd->screen->lines[cnt]->str);
+	}
+
+	pop_call();
+	return;
 }

+ 57 - 20
src/session.c

@@ -306,7 +306,10 @@ struct session *activate_session(struct session *ses)
 
 	dirty_screen(ses);
 
-	show_message(ses, LIST_COMMAND, "#SESSION '%s' ACTIVATED.", ses->name);
+	if (!check_all_events(ses, SUB_ARG, 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);
 
@@ -347,10 +350,7 @@ struct session *new_session(struct session *ses, char *name, char *arg, int desc
 
 		if (*port == 0)
 		{
-			tintin_puts(ses, "#HEY! SPECIFY A PORT NUMBER WILL YOU?");
-
-			pop_call();
-			return ses;
+			strcpy(port, "23");
 		}
 	}
 
@@ -389,7 +389,6 @@ struct session *new_session(struct session *ses, char *name, char *arg, int desc
 	newses->logline_name  = strdup("");
 	newses->rand          = utime();
 
-
 	LINK(newses, gts->next, gts->prev);
 
 	if (HAS_BIT(gtd->flags, TINTIN_FLAG_INHERITANCE))
@@ -414,25 +413,51 @@ struct session *new_session(struct session *ses, char *name, char *arg, int desc
 		}
 	}
 
-	newses->event_flags = gts->event_flags;
+	newses->event_flags   = gts->event_flags;
 
-	newses->split   = calloc(1, sizeof(struct split_data));
+	newses->split         = calloc(1, sizeof(struct split_data));
 
 	memcpy(newses->split, gts->split, sizeof(struct split_data));
 
-	newses->cur_row = gts->cur_row;
-	newses->cur_col = gts->cur_col;
+	newses->cur_row       = gts->cur_row;
+	newses->cur_col       = gts->cur_col;
 
-	newses->wrap    = gts->wrap;
+	newses->wrap          = gts->wrap;
 
-        newses->scroll = calloc(1, sizeof(struct scroll_data));
+        newses->scroll        = calloc(1, sizeof(struct scroll_data));
 	init_buffer(newses, gts->scroll->size);
 
+	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;
+
 	memcpy(&newses->cur_terminal, &gts->cur_terminal, sizeof(gts->cur_terminal));
 
 	if (desc == 0)
 	{
-		tintin_printf(ses, "#TRYING TO CONNECT '%s' TO '%s' PORT '%s'.", newses->name, newses->session_host, newses->session_port);
+		if (!check_all_events(newses, SUB_ARG, 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);
+		}
 	}
 	else if (desc == -1)
 	{
@@ -440,7 +465,10 @@ struct session *new_session(struct session *ses, char *name, char *arg, int desc
 	}
 	else
 	{
-		tintin_printf(ses, "#TRYING TO LAUNCH '%s' RUNNING '%s'.", newses->name, newses->session_host);
+		if (!check_all_events(newses, SUB_ARG, 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);
@@ -541,9 +569,10 @@ struct session *connect_session(struct session *ses)
 
 		SET_BIT(ses->flags, SES_FLAG_CONNECTED);
 
-		tintin_printf2(ses, "");
-
-		tintin_printf(ses, "#SESSION '%s' CONNECTED TO '%s' PORT '%s'", ses->name, ses->session_host, ses->session_port);
+		if (!check_all_events(ses, SUB_ARG, 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);
 
@@ -646,15 +675,23 @@ void cleanup_session(struct session *ses)
 	{
 		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))
+		{
+			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);
 
-		tintin_printf(gtd->ses, "#SESSION '%s' DIED.", ses->name);
+
 	}
 	else
 	{
-		check_all_events(ses, SUB_ARG, 0, 4, "SESSION TIMED OUT", ses->name, ses->session_host, ses->session_ip, ses->session_port);
+		if (!check_all_events(ses, SUB_ARG, 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);
+		}
 
-		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);
 	}
 
 	if (ses == gtd->ses)

+ 6 - 9
src/show.c

@@ -49,11 +49,11 @@ DO_COMMAND(do_showme)
 	{
 		DEL_BIT(ses->flags, SES_FLAG_GAG);
 
-		gtd->level->ignore++;
+//		gtd->level->ignore++;
 
-		show_info(ses, LIST_GAG, "#INFO GAG {%s}", arg1);
+		show_debug(ses, LIST_GAG, "#DEBUG GAG {%s}", arg1);
 
-		gtd->level->ignore--;
+//		gtd->level->ignore--;
 
 		return ses;
 	}
@@ -108,7 +108,7 @@ void show_message(struct session *ses, int index, char *format, ...)
 
 	root = ses->list[index];
 
-	if (gtd->level->verbose || gtd->level->debug )
+	if (gtd->level->verbose || gtd->level->debug)
 	{
 		goto display;
 	}
@@ -441,10 +441,7 @@ void tintin_puts(struct session *ses, char *string)
 
 		gtd->level->ignore++;
 
-		if (HAS_BIT(ses->list[LIST_GAG]->flags, LIST_FLAG_INFO))
-		{
-			show_info(ses, LIST_GAG, "#INFO GAG {%s}", string);
-		}
+		show_debug(ses, LIST_GAG, "#DEBUG GAG {%s}", string);
 
 		gtd->level->ignore--;
 	}
@@ -505,7 +502,7 @@ void tintin_puts3(struct session *ses, char *string)
 		}
 	}
 
-	if (!HAS_BIT(gtd->ses->flags, SES_FLAG_VERBOSE) && gtd->level->quiet && gtd->level->verbose == 0)
+	if (gtd->level->quiet && gtd->level->verbose == 0)
 	{
 		pop_call();
 		return;

+ 1483 - 0
src/sort.c

@@ -0,0 +1,1483 @@
+/******************************************************************************
+*   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"
+
+#include <assert.h>
+
+//typedef int CMPFUNC (const void *a, const void *b);
+
+void quad_sort32(int *array, int *swap, size_t nmemb, size_t block, CMPFUNC *cmp);
+
+void quad_swap32(int *array, int *swap, size_t nmemb, CMPFUNC *cmp)
+{
+	size_t offset;
+	register unsigned char loop;
+	register int *pta, *pts, *ptt, tmp;
+
+	pta = array;
+
+	for (offset = 0 ; offset + 4 <= nmemb ; offset += 4)
+	{
+		if (cmp(&pta[0], &pta[1]) > 0)
+		{
+			tmp = pta[0];
+			pta[0] = pta[1];
+			pta[1] = tmp;
+		}
+
+		if (cmp(&pta[2], &pta[3]) > 0)
+		{
+			tmp = pta[2];
+			pta[2] = pta[3];
+			pta[3] = tmp;
+		}
+
+		if (cmp(&pta[1], &pta[2]) > 0)
+		{
+			if (cmp(&pta[0], &pta[3]) > 0)
+			{
+				tmp = pta[0];
+				pta[0] = pta[2];
+				pta[2] = tmp;
+
+				tmp = pta[1];
+				pta[1] = pta[3];
+				pta[3] = tmp;
+			}
+			else if (cmp(&pta[0], &pta[2]) <= 0)
+			{
+				if (cmp(&pta[1], &pta[3]) <= 0)
+				{
+					tmp = pta[1];
+					pta[1] = pta[2];
+					pta[2] = tmp;
+				}
+				else
+				{
+					tmp = pta[1];
+					pta[1] = pta[2];
+					pta[2] = pta[3];
+					pta[3] = tmp;
+				}
+			}
+			else
+			{
+				if (cmp(&pta[1], &pta[3]) <= 0)
+				{
+					tmp = pta[0];
+					pta[0] = pta[2];
+					pta[2] = pta[1];
+					pta[1] = tmp;
+				}
+				else
+				{
+					tmp = pta[0];
+					pta[0] = pta[2];
+					pta[2] = pta[3];
+					pta[3] = pta[1];
+					pta[1] = tmp;
+				}
+			}
+		}
+		pta += 4;
+	}
+
+	switch (nmemb - offset)
+	{
+		case 0:
+		case 1:
+			break;
+		case 2:
+			if (cmp(&pta[0], &pta[1]) > 0)
+			{
+				tmp = pta[0];
+				pta[0] = pta[1];
+				pta[1] = tmp;
+			}
+			break;
+		case 3:
+			if (cmp(&pta[0], &pta[1]) > 0)
+			{
+				tmp = pta[0];
+				pta[0] = pta[1];
+				pta[1] = tmp;
+			}
+			if (cmp(&pta[1], &pta[2]) > 0)
+			{
+				tmp = pta[1];
+				pta[1] = pta[2];
+				pta[2] = tmp;
+			}
+			if (cmp(&pta[0], &pta[1]) > 0)
+			{
+				tmp = pta[0];
+				pta[0] = pta[1];
+				pta[1] = tmp;
+			}
+			break;
+		default:
+			assert(nmemb - offset > 3);
+	}
+
+	pta = array;
+
+	for (offset = 0 ; offset + 16 <= nmemb ; offset += 16)
+	{
+		if (cmp(&pta[3], &pta[4]) <= 0)
+		{
+			if (cmp(&pta[11], &pta[12]) <= 0)
+			{
+				if (cmp(&pta[7], &pta[8]) <= 0)
+				{
+					pta += 16;
+					continue;
+				}
+				pts = swap;
+
+				for (loop = 0 ; loop < 16 ; loop++)
+					*pts++ = *pta++;
+
+				goto step3;
+			}
+			pts = swap;
+
+			for (loop = 0 ; loop < 8 ; loop++)
+				*pts++ = *pta++;
+
+			goto step2;
+		}
+
+		// step1:
+
+		pts = swap;
+
+		if (cmp(&pta[3], &pta[7]) <= 0)
+		{
+			ptt = pta + 4;
+
+			for (loop = 0 ; loop < 5 ; loop++)
+				if (cmp(pta, ptt) > 0)
+					*pts++ = *ptt++;
+				else
+					*pts++ = *pta++;
+
+			while (pta < array + offset + 4)
+			{
+				*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+			}
+			while (ptt < array + offset + 8)
+			{
+				*pts++ = *ptt++;
+			}
+			pta = ptt;
+		}
+		else if (cmp(&pta[0], &pta[7]) > 0)
+		{
+			if (cmp(&pta[8], &pta[15]) > 0)
+			{
+				if (cmp(&pta[4], &pta[11]) > 0)
+				{
+					tmp = pta[0]; pta[0] = pta[12]; pta[12] = tmp;
+					tmp = pta[1]; pta[1] = pta[13];	pta[13] = tmp;
+					tmp = pta[2]; pta[2] = pta[14]; pta[14] = tmp;
+					tmp = pta[3]; pta[3] = pta[15]; pta[15] = tmp;
+					tmp = pta[4]; pta[4] = pta[8]; pta[8] = tmp;
+					tmp = pta[5]; pta[5] = pta[9]; pta[9] = tmp;
+					tmp = pta[6]; pta[6] = pta[10]; pta[10] = tmp;
+					tmp = pta[7]; pta[7] = pta[11]; pta[11] = tmp;
+
+					pta += 16;
+					continue;
+				}
+				pta += 4;
+
+				*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++;
+
+				pta -= 8;
+
+				*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; 
+
+				pta += 8;
+
+				*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++;
+
+				pta -= 8;
+
+				*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; 
+
+				pta += 4;
+
+				goto step3;
+			}
+			pta += 4;
+
+			*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++;
+
+			pta -= 8;
+
+			*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; 
+
+			pta += 4;
+		}
+		else
+		{
+			ptt = pta + 4;
+
+			for (loop = 0 ; loop < 5 ; loop++)
+				if (cmp(pta, ptt) > 0)
+					*pts++ = *ptt++;
+				else
+					*pts++ = *pta++;
+
+			while (ptt < array + offset + 8)
+			{
+				*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+			}
+			while (pta < array + offset + 4)
+			{
+				*pts++ = *pta++;
+			}
+			pta = ptt;
+		}
+
+		step2:
+
+		if (cmp(&pta[3], &pta[7]) <= 0)
+		{
+			ptt = pta + 4;
+
+			for (loop = 0 ; loop < 4 ; loop++)
+				*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+
+			while (pta < array + offset + 12)
+			{
+				*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+			}
+			while (ptt < array + offset + 16)
+			{
+				*pts++ = *ptt++;
+			}
+		}
+		else if (cmp(&pta[0], &pta[7]) > 0)
+		{
+			pta += 4;
+
+			*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++;
+
+			pta -= 8;
+
+			*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++;
+		}
+		else
+		{
+			ptt = pta + 4;
+
+			for (loop = 0 ; loop < 5 ; loop++)
+				*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+
+			while (ptt < array + offset + 16)
+			{
+				*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+			}
+			while (pta < array + offset + 12)
+			{
+				*pts++ = *pta++;
+			}
+		}
+
+		step3:
+
+		pta = array + offset;
+		pts = swap;
+
+		if (cmp(&pts[7], &pts[15]) <= 0)
+		{
+			ptt = pts + 8;
+
+			for (loop = 0 ; loop < 8 ; loop++)
+				*pta++ = cmp(pts, ptt) > 0 ? *ptt++ : *pts++;
+
+			while (pts < swap + 8)
+			{
+				*pta++ = cmp(pts, ptt) > 0 ? *ptt++ : *pts++;
+			}
+			while (ptt < swap + 16)
+			{
+				*pta++ = *ptt++;
+			}
+		}
+		else if (cmp(&pts[0], &pts[15]) > 0)
+		{
+			pts += 8;
+
+			for (loop = 0 ; loop < 8 ; loop++)
+				*pta++ = *pts++;
+
+			pts -= 16;
+
+			for (loop = 0 ; loop < 8 ; loop++)
+				*pta++ = *pts++;
+		}
+		else
+		{
+			ptt = pts + 8;
+
+			for (loop = 0 ; loop < 9 ; loop++)
+				*pta++ = cmp(pts, ptt) > 0 ? *ptt++ : *pts++;
+
+			while (ptt < swap + 16)
+			{
+				*pta++ = cmp(pts, ptt) > 0 ? *ptt++ : *pts++;
+			}
+			while (pts < swap + 8)
+			{
+				*pta++ = *pts++;
+			}
+		}
+	}
+
+	switch (nmemb - offset)
+	{
+		case 0:
+		case 1:
+		case 2:
+		case 3:
+		case 4:
+			return;
+		default:
+			quad_sort32(pta, swap, nmemb - offset, 4, cmp);
+	}
+}
+
+void quad_sort64(long long *array, long long *swap, size_t nmemb, size_t block, CMPFUNC *cmp);
+
+void quad_swap64(long long *array, long long *swap, size_t nmemb, CMPFUNC *cmp)
+{
+	size_t offset;
+	register long long *pta, *pts, *ptt, tmp;
+
+	pta = array;
+
+	for (offset = 0 ; offset + 4 <= nmemb ; offset += 4)
+	{
+		if (cmp(&pta[0], &pta[1]) > 0)
+		{
+			tmp = pta[0];
+			pta[0] = pta[1];
+			pta[1] = tmp;
+		}
+
+		if (cmp(&pta[2], &pta[3]) > 0)
+		{
+			tmp = pta[2];
+			pta[2] = pta[3];
+			pta[3] = tmp;
+		}
+
+		if (cmp(&pta[1], &pta[2]) > 0)
+		{
+			if (cmp(&pta[0], &pta[3]) > 0)
+			{
+				tmp = pta[0];
+				pta[0] = pta[2];
+				pta[2] = tmp;
+
+				tmp = pta[1];
+				pta[1] = pta[3];
+				pta[3] = tmp;
+			}
+			else if (cmp(&pta[0], &pta[2]) <= 0)
+			{
+				if (cmp(&pta[1], &pta[3]) <= 0)
+				{
+					tmp = pta[1];
+					pta[1] = pta[2];
+					pta[2] = tmp;
+				}
+				else
+				{
+					tmp = pta[1];
+					pta[1] = pta[2];
+					pta[2] = pta[3];
+					pta[3] = tmp;
+				}
+			}
+			else
+			{
+				if (cmp(&pta[1], &pta[3]) <= 0)
+				{
+					tmp = pta[0];
+					pta[0] = pta[2];
+					pta[2] = pta[1];
+					pta[1] = tmp;
+				}
+				else
+				{
+					tmp = pta[0];
+					pta[0] = pta[2];
+					pta[2] = pta[3];
+					pta[3] = pta[1];
+					pta[1] = tmp;
+				}
+			}
+		}
+		pta += 4;
+	}
+
+	switch (nmemb - offset)
+	{
+		case 0:
+		case 1:
+			break;
+		case 2:
+			if (cmp(&pta[0], &pta[1]) > 0)
+			{
+				tmp = pta[0];
+				pta[0] = pta[1];
+				pta[1] = tmp;
+			}
+			break;
+		case 3:
+			if (cmp(&pta[0], &pta[1]) > 0)
+			{
+				tmp = pta[0];
+				pta[0] = pta[1];
+				pta[1] = tmp;
+			}
+			if (cmp(&pta[1], &pta[2]) > 0)
+			{
+				tmp = pta[1];
+				pta[1] = pta[2];
+				pta[2] = tmp;
+			}
+			if (cmp(&pta[0], &pta[1]) > 0)
+			{
+				tmp = pta[0];
+				pta[0] = pta[1];
+				pta[1] = tmp;
+			}
+			break;
+		default:
+			assert(nmemb - offset > 3);
+	}
+
+	pta = array;
+
+	for (offset = 0 ; offset + 16 <= nmemb ; offset += 16)
+	{
+		if (cmp(&pta[3], &pta[4]) <= 0)
+		{
+			if (cmp(&pta[11], &pta[12]) <= 0)
+			{
+				if (cmp(&pta[7], &pta[8]) <= 0)
+				{
+					pta += 16;
+					continue;
+				}
+				pts = swap;
+
+				*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++;
+				*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++;
+				*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++;
+				*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++;
+
+				goto step3;
+			}
+			pts = swap;
+
+			*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++;
+			*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++;
+
+			goto step2;
+		}
+
+		// step1:
+
+		pts = swap;
+
+		if (cmp(&pta[3], &pta[7]) <= 0)
+		{
+			ptt = pta + 4;
+
+			*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+			*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+			*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+			*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+			*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+
+			while (pta < array + offset + 4)
+			{
+				*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+			}
+			while (ptt < array + offset + 8)
+			{
+				*pts++ = *ptt++;
+			}
+			pta = ptt;
+		}
+		else if (cmp(&pta[0], &pta[7]) > 0)
+		{
+			if (cmp(&pta[8], &pta[15]) > 0)
+			{
+				if (cmp(&pta[4], &pta[11]) > 0)
+				{
+					tmp = pta[0]; pta[0] = pta[12]; pta[12] = tmp;
+					tmp = pta[1]; pta[1] = pta[13];	pta[13] = tmp;
+					tmp = pta[2]; pta[2] = pta[14]; pta[14] = tmp;
+					tmp = pta[3]; pta[3] = pta[15]; pta[15] = tmp;
+					tmp = pta[4]; pta[4] = pta[8]; pta[8] = tmp;
+					tmp = pta[5]; pta[5] = pta[9]; pta[9] = tmp;
+					tmp = pta[6]; pta[6] = pta[10]; pta[10] = tmp;
+					tmp = pta[7]; pta[7] = pta[11]; pta[11] = tmp;
+
+					pta += 16;
+					continue;
+				}
+				pta += 4;
+
+				*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++;
+
+				pta -= 8;
+
+				*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; 
+
+				pta += 8;
+
+				*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++;
+
+				pta -= 8;
+
+				*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; 
+
+				pta += 4;
+
+				goto step3;
+			}
+			pta += 4;
+
+			*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++;
+
+			pta -= 8;
+
+			*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; 
+
+			pta += 4;
+		}
+		else
+		{
+			ptt = pta + 4;
+
+			*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+			*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+			*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+			*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+			*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+
+			while (ptt < array + offset + 8)
+			{
+				*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+			}
+			while (pta < array + offset + 4)
+			{
+				*pts++ = *pta++;
+			}
+			pta = ptt;
+		}
+
+		step2:
+
+		if (cmp(&pta[3], &pta[7]) <= 0)
+		{
+			ptt = pta + 4;
+
+			*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+			*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+			*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+			*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+//			*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+
+			while (pta < array + offset + 12)
+			{
+				*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+			}
+			while (ptt < array + offset + 16)
+			{
+				*pts++ = *ptt++;
+			}
+		}
+		else if (cmp(&pta[0], &pta[7]) > 0)
+		{
+			pta += 4;
+
+			*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++;
+
+			pta -= 8;
+
+			*pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++; *pts++ = *pta++;
+		}
+		else
+		{
+			ptt = pta + 4;
+
+			*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+			*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+			*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+			*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+			*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+
+			while (ptt < array + offset + 16)
+			{
+				*pts++ = cmp(pta, ptt) > 0 ? *ptt++ : *pta++;
+			}
+			while (pta < array + offset + 12)
+			{
+				*pts++ = *pta++;
+			}
+		}
+
+		step3:
+
+		pta = array + offset;
+		pts = swap;
+
+		if (cmp(&pts[7], &pts[15]) <= 0)
+		{
+			ptt = pts + 8;
+
+			*pta++ = cmp(pts, ptt) > 0 ? *ptt++ : *pts++;
+			*pta++ = cmp(pts, ptt) > 0 ? *ptt++ : *pts++;
+			*pta++ = cmp(pts, ptt) > 0 ? *ptt++ : *pts++;
+			*pta++ = cmp(pts, ptt) > 0 ? *ptt++ : *pts++;
+			*pta++ = cmp(pts, ptt) > 0 ? *ptt++ : *pts++;
+			*pta++ = cmp(pts, ptt) > 0 ? *ptt++ : *pts++;
+			*pta++ = cmp(pts, ptt) > 0 ? *ptt++ : *pts++;
+			*pta++ = cmp(pts, ptt) > 0 ? *ptt++ : *pts++;
+//			*pta++ = cmp(pts, ptt) > 0 ? *ptt++ : *pts++;
+
+			while (pts < swap + 8)
+			{
+				*pta++ = cmp(pts, ptt) > 0 ? *ptt++ : *pts++;
+			}
+			while (ptt < swap + 16)
+			{
+				*pta++ = *ptt++;
+			}
+		}
+		else if (cmp(&pts[0], &pts[15]) > 0)
+		{
+			pts += 8;
+
+			*pta++ = *pts++; *pta++ = *pts++; *pta++ = *pts++; *pta++ = *pts++;
+			*pta++ = *pts++; *pta++ = *pts++; *pta++ = *pts++; *pta++ = *pts++;
+
+			pts -= 16;
+
+			*pta++ = *pts++; *pta++ = *pts++; *pta++ = *pts++; *pta++ = *pts++;
+			*pta++ = *pts++; *pta++ = *pts++; *pta++ = *pts++; *pta++ = *pts++;
+		}
+		else
+		{
+			ptt = pts + 8;
+
+			*pta++ = cmp(pts, ptt) > 0 ? *ptt++ : *pts++;
+			*pta++ = cmp(pts, ptt) > 0 ? *ptt++ : *pts++;
+			*pta++ = cmp(pts, ptt) > 0 ? *ptt++ : *pts++;
+			*pta++ = cmp(pts, ptt) > 0 ? *ptt++ : *pts++;
+			*pta++ = cmp(pts, ptt) > 0 ? *ptt++ : *pts++;
+			*pta++ = cmp(pts, ptt) > 0 ? *ptt++ : *pts++;
+			*pta++ = cmp(pts, ptt) > 0 ? *ptt++ : *pts++;
+			*pta++ = cmp(pts, ptt) > 0 ? *ptt++ : *pts++;
+			*pta++ = cmp(pts, ptt) > 0 ? *ptt++ : *pts++;
+
+			while (ptt < swap + 16)
+			{
+				*pta++ = cmp(pts, ptt) > 0 ? *ptt++ : *pts++;
+			}
+			while (pts < swap + 8)
+			{
+				*pta++ = *pts++;
+			}
+		}
+	}
+
+	switch (nmemb - offset)
+	{
+		case 0:
+		case 1:
+		case 2:
+		case 3:
+		case 4:
+			return;
+		default:
+			quad_sort64(pta, swap, nmemb - offset, 4, cmp);
+	}
+}
+
+void quad_sort32(int *array, int *swap, size_t nmemb, size_t block, CMPFUNC *cmp)
+{
+	size_t offset;
+	register int *pta, *pts, *c, *c_max, *d, *d_max;
+
+	while (block < nmemb)
+	{
+		offset = 0;
+
+		while (offset + block < nmemb)
+		{
+			pta = array;
+			pta += offset;
+
+			c_max = pta + block;
+
+			if (cmp(c_max - 1, c_max) <= 0)
+			{
+				if (offset + block * 3 < nmemb)
+				{
+					c_max = pta + block * 3;
+
+					if (cmp(c_max - 1, c_max) <= 0)
+					{
+						c_max = pta + block * 2;
+
+						if (cmp(c_max - 1, c_max) <= 0)
+						{
+							offset += block * 4;
+							continue;
+						}
+						pts = swap;
+
+						c = pta;
+
+						while (c < c_max - 8)
+						{
+							*pts++ = *c++; *pts++ = *c++; *pts++ = *c++; *pts++ = *c++;
+							*pts++ = *c++; *pts++ = *c++; *pts++ = *c++; *pts++ = *c++;
+						}
+						while (c < c_max)
+							*pts++ = *c++;
+
+						c = c_max;
+						c_max = offset + block * 4 <= nmemb ? c + block * 2 : array + nmemb;
+
+						while (c < c_max - 8)
+						{
+							*pts++ = *c++; *pts++ = *c++; *pts++ = *c++; *pts++ = *c++;
+							*pts++ = *c++; *pts++ = *c++; *pts++ = *c++; *pts++ = *c++;
+						}
+						while (c < c_max)
+							*pts++ = *c++;
+
+						goto step3;
+					}
+					pts = swap;
+
+					c = pta;
+					c_max = pta + block * 2;
+
+					while (c < c_max)
+						*pts++ = *c++;
+
+					goto step2;
+				}
+				else if (offset + block * 2 < nmemb)
+				{
+					c_max = pta + block * 2;
+
+					if (cmp(c_max - 1, c_max) <= 0)
+					{
+						offset += block * 4;
+						continue;
+					}
+					pts = swap;
+
+					c = pta;
+
+					while (c < c_max - 8)
+					{
+						*pts++ = *c++; *pts++ = *c++; *pts++ = *c++; *pts++ = *c++;
+						*pts++ = *c++; *pts++ = *c++; *pts++ = *c++; *pts++ = *c++;
+					}
+					while (c < c_max)
+						*pts++ = *c++;
+
+					goto step2;
+				}
+				else
+				{
+					offset += block * 4;
+					continue;
+				}
+			}
+
+			// step1:
+
+			pts = swap;
+
+			c = pta;
+
+			d = c_max;
+			d_max = offset + block * 2 <= nmemb ? d + block : array + nmemb;
+
+			if (cmp(c_max - 1, d_max - 1) <= 0)
+			{
+				while (c < c_max)
+				{
+					while (cmp(c, d) > 0)
+					{
+						*pts++ = *d++;
+					}
+					*pts++ = *c++;
+				}
+				while (d < d_max)
+					*pts++ = *d++;
+			}
+			else if (cmp(c, d_max - 1) > 0)
+			{
+				if (offset + block * 4 <= nmemb)
+				{
+					int *e, *e_max, *f, *f_max, tmp;
+
+					e = pta + block * 2;
+					e_max = e + block;
+					f = e_max;
+					f_max = f + block;
+
+					if (cmp(e, f_max - 1) > 0)
+					{
+						if (cmp(d, f_max - 1) > 0)
+						{
+							while (c < c_max)
+							{
+								tmp = *c;
+								*c++ = *f;
+								*f++ = tmp;
+							}
+							while (d < d_max)
+							{
+								tmp = *d;
+								*d++ = *e;
+								*e++ = tmp;
+							}
+							offset += block * 4;
+							continue;
+						}
+					}
+				}
+
+				while (d < d_max - 8)
+				{
+					*pts++ = *d++; *pts++ = *d++; *pts++ = *d++; *pts++ = *d++;
+					*pts++ = *d++; *pts++ = *d++; *pts++ = *d++; *pts++ = *d++;
+				}
+				while (d < d_max)
+					*pts++ = *d++;
+
+				while (c < c_max - 8)
+				{
+					*pts++ = *c++; *pts++ = *c++; *pts++ = *c++; *pts++ = *c++;
+					*pts++ = *c++; *pts++ = *c++; *pts++ = *c++; *pts++ = *c++;
+				}
+				while (c < c_max)
+					*pts++ = *c++;
+			}
+			else
+			{
+				while (d < d_max)
+				{
+					while (cmp(c, d) <= 0)
+					{
+						*pts++ = *c++;
+					}
+					*pts++ = *d++;
+				}
+
+				while (c < c_max)
+					*pts++ = *c++;
+			}
+
+			step2:
+
+			if (offset + block * 2 < nmemb)
+			{
+				c = pta + block * 2;
+
+				if (offset + block * 3 < nmemb)
+				{
+					c_max = c + block;
+					d = c_max;
+					d_max = offset + block * 4 <= nmemb ? d + block : array + nmemb;
+
+					if (cmp(c_max - 1, d_max - 1) <= 0)
+					{
+						while (c < c_max)
+						{
+							while (cmp(c, d) > 0)
+							{
+								*pts++ = *d++;
+							}
+							*pts++ = *c++;
+						}
+
+						while (d < d_max)
+							*pts++ = *d++;
+					}
+					else if (cmp(c, d_max - 1) > 0)
+					{
+						while (d < d_max - 8)
+						{
+							*pts++ = *d++; *pts++ = *d++; *pts++ = *d++; *pts++ = *d++;
+							*pts++ = *d++; *pts++ = *d++; *pts++ = *d++; *pts++ = *d++;
+						}
+						while (d < d_max)
+							*pts++ = *d++;
+
+						while (c < c_max - 8)
+						{
+							*pts++ = *c++; *pts++ = *c++; *pts++ = *c++; *pts++ = *c++;
+							*pts++ = *c++; *pts++ = *c++; *pts++ = *c++; *pts++ = *c++;
+						}
+						while (c < c_max)
+							*pts++ = *c++;
+					}
+					else
+					{
+						while (d < d_max)
+						{
+							while (cmp(c, d) <= 0)
+							{
+								*pts++ = *c++;
+							}
+							*pts++ = *d++;
+						}
+
+						while (c < c_max)
+							*pts++ = *c++;
+					}
+				}
+				else
+				{
+					d = c;
+					d_max = array + nmemb;
+
+					pts = swap;
+					c = pts;
+					c_max = c + block * 2;
+
+					goto quickstep;
+				}
+			}
+
+			step3:
+
+			pts = swap;
+
+			c = pts;
+
+			if (offset + block * 2 < nmemb)
+			{
+				c_max = c + block * 2;
+
+				d = c_max;
+				d_max = offset + block * 4 <= nmemb ? d + block * 2 : pts + nmemb - offset;
+
+				quickstep:
+
+				if (cmp(c_max - 1, d_max - 1) <= 0)
+				{
+					while (c < c_max)
+					{
+						while (cmp(c, d) > 0)
+						{
+							*pta++ = *d++;
+						}
+						*pta++ = *c++;
+					}
+
+					while (d < d_max)
+						*pta++ = *d++;
+				}
+				else if (cmp(c, d_max - 1) > 0)
+				{
+					while (d < d_max - 16)
+					{
+						*pta++ = *d++; *pta++ = *d++; *pta++ = *d++; *pta++ = *d++;
+						*pta++ = *d++; *pta++ = *d++; *pta++ = *d++; *pta++ = *d++;
+						*pta++ = *d++; *pta++ = *d++; *pta++ = *d++; *pta++ = *d++;
+						*pta++ = *d++; *pta++ = *d++; *pta++ = *d++; *pta++ = *d++;
+					}
+					while (d < d_max)
+						*pta++ = *d++;
+
+					while (c < c_max - 16)
+					{
+						*pta++ = *c++; *pta++ = *c++; *pta++ = *c++; *pta++ = *c++;
+						*pta++ = *c++; *pta++ = *c++; *pta++ = *c++; *pta++ = *c++;
+						*pta++ = *c++; *pta++ = *c++; *pta++ = *c++; *pta++ = *c++;
+						*pta++ = *c++; *pta++ = *c++; *pta++ = *c++; *pta++ = *c++;
+					}
+					while (c < c_max)
+						*pta++ = *c++;
+				}
+				else
+				{
+					while (d < d_max)
+					{
+						while (cmp(d, c) > 0)
+						{
+							*pta++ = *c++;
+						}
+						*pta++ = *d++;
+					}
+
+					while (c < c_max)
+						*pta++ = *c++;
+				}
+			}
+			else
+			{
+				d_max = pts + nmemb - offset;
+
+				while (c < d_max - 8)
+				{
+					*pta++ = *c++; *pta++ = *c++; *pta++ = *c++; *pta++ = *c++;
+					*pta++ = *c++; *pta++ = *c++; *pta++ = *c++; *pta++ = *c++;
+				}
+				while (c < d_max)
+					*pta++ = *c++;
+			}
+			offset += block * 4;
+		}
+		block *= 4;
+	}
+}
+
+void quad_sort64(long long *array, long long *swap, size_t nmemb, size_t block, CMPFUNC *cmp)
+{
+	size_t offset;
+	register long long *pta, *pts, *c, *c_max, *d, *d_max;
+
+	while (block < nmemb)
+	{
+		offset = 0;
+
+		while (offset + block < nmemb)
+		{
+			pta = array;
+			pta += offset;
+
+			c_max = pta + block;
+
+			if (cmp(c_max - 1, c_max) <= 0)
+			{
+				if (offset + block * 3 < nmemb)
+				{
+					c_max = pta + block * 3;
+
+					if (cmp(c_max - 1, c_max) <= 0)
+					{
+						c_max = pta + block * 2;
+
+						if (cmp(c_max - 1, c_max) <= 0)
+						{
+							offset += block * 4;
+							continue;
+						}
+						pts = swap;
+
+						c = pta;
+
+						while (c < c_max - 8)
+						{
+							*pts++ = *c++; *pts++ = *c++; *pts++ = *c++; *pts++ = *c++;
+							*pts++ = *c++; *pts++ = *c++; *pts++ = *c++; *pts++ = *c++;
+						}
+						while (c < c_max)
+							*pts++ = *c++;
+
+						c = c_max;
+						c_max = offset + block * 4 <= nmemb ? c + block * 2 : array + nmemb;
+
+						while (c < c_max - 8)
+						{
+							*pts++ = *c++; *pts++ = *c++; *pts++ = *c++; *pts++ = *c++;
+							*pts++ = *c++; *pts++ = *c++; *pts++ = *c++; *pts++ = *c++;
+						}
+						while (c < c_max)
+							*pts++ = *c++;
+
+						goto step3;
+					}
+					pts = swap;
+
+					c = pta;
+					c_max = pta + block * 2;
+
+					while (c < c_max)
+						*pts++ = *c++;
+
+					goto step2;
+				}
+				else if (offset + block * 2 < nmemb)
+				{
+					c_max = pta + block * 2;
+
+					if (cmp(c_max - 1, c_max) <= 0)
+					{
+						offset += block * 4;
+						continue;
+					}
+					pts = swap;
+
+					c = pta;
+
+					while (c < c_max - 8)
+					{
+						*pts++ = *c++; *pts++ = *c++; *pts++ = *c++; *pts++ = *c++;
+						*pts++ = *c++; *pts++ = *c++; *pts++ = *c++; *pts++ = *c++;
+					}
+					while (c < c_max)
+						*pts++ = *c++;
+
+					goto step2;
+				}
+				else
+				{
+					offset += block * 4;
+					continue;
+				}
+			}
+
+			// step1:
+
+			pts = swap;
+
+			c = pta;
+
+			d = c_max;
+			d_max = offset + block * 2 <= nmemb ? d + block : array + nmemb;
+
+			if (cmp(c_max - 1, d_max - 1) <= 0)
+			{
+				while (c < c_max)
+				{
+					while (cmp(c, d) > 0)
+					{
+						*pts++ = *d++;
+					}
+					*pts++ = *c++;
+				}
+				while (d < d_max)
+					*pts++ = *d++;
+			}
+			else if (cmp(c, d_max - 1) > 0)
+			{
+				if (offset + block * 4 <= nmemb)
+				{
+					long long *e, *e_max, *f, *f_max, tmp;
+
+					e = pta + block * 2;
+					e_max = e + block;
+					f = e_max;
+					f_max = f + block;
+
+					if (cmp(e, f_max - 1) > 0)
+					{
+						if (cmp(d, f_max - 1) > 0)
+						{
+							while (c < c_max)
+							{
+								tmp = *c;
+								*c++ = *f;
+								*f++ = tmp;
+							}
+							while (d < d_max)
+							{
+								tmp = *d;
+								*d++ = *e;
+								*e++ = tmp;
+							}
+							offset += block * 4;
+							continue;
+						}
+					}
+				}
+
+				while (d < d_max - 8)
+				{
+					*pts++ = *d++; *pts++ = *d++; *pts++ = *d++; *pts++ = *d++;
+					*pts++ = *d++; *pts++ = *d++; *pts++ = *d++; *pts++ = *d++;
+				}
+				while (d < d_max)
+					*pts++ = *d++;
+
+				while (c < c_max - 8)
+				{
+					*pts++ = *c++; *pts++ = *c++; *pts++ = *c++; *pts++ = *c++;
+					*pts++ = *c++; *pts++ = *c++; *pts++ = *c++; *pts++ = *c++;
+				}
+				while (c < c_max)
+					*pts++ = *c++;
+			}
+			else
+			{
+				while (d < d_max)
+				{
+					while (cmp(c, d) <= 0)
+					{
+						*pts++ = *c++;
+					}
+					*pts++ = *d++;
+				}
+
+				while (c < c_max)
+					*pts++ = *c++;
+			}
+
+			step2:
+
+			if (offset + block * 2 < nmemb)
+			{
+				c = pta + block * 2;
+
+				if (offset + block * 3 < nmemb)
+				{
+					c_max = c + block;
+					d = c_max;
+					d_max = offset + block * 4 <= nmemb ? d + block : array + nmemb;
+
+					if (cmp(c_max - 1, d_max - 1) <= 0)
+					{
+						while (c < c_max)
+						{
+							while (cmp(c, d) > 0)
+							{
+								*pts++ = *d++;
+							}
+							*pts++ = *c++;
+						}
+
+						while (d < d_max)
+							*pts++ = *d++;
+					}
+					else if (cmp(c, d_max - 1) > 0)
+					{
+						while (d < d_max - 8)
+						{
+							*pts++ = *d++; *pts++ = *d++; *pts++ = *d++; *pts++ = *d++;
+							*pts++ = *d++; *pts++ = *d++; *pts++ = *d++; *pts++ = *d++;
+						}
+						while (d < d_max)
+							*pts++ = *d++;
+
+						while (c < c_max - 8)
+						{
+							*pts++ = *c++; *pts++ = *c++; *pts++ = *c++; *pts++ = *c++;
+							*pts++ = *c++; *pts++ = *c++; *pts++ = *c++; *pts++ = *c++;
+						}
+						while (c < c_max)
+							*pts++ = *c++;
+					}
+					else
+					{
+						while (d < d_max)
+						{
+							while (cmp(c, d) <= 0)
+							{
+								*pts++ = *c++;
+							}
+							*pts++ = *d++;
+						}
+
+						while (c < c_max)
+							*pts++ = *c++;
+					}
+				}
+				else
+				{
+					d = c;
+					d_max = array + nmemb;
+
+					pts = swap;
+					c = pts;
+					c_max = c + block * 2;
+
+					goto quickstep;
+				}
+			}
+
+			step3:
+
+			pts = swap;
+
+			c = pts;
+
+			if (offset + block * 2 < nmemb)
+			{
+				c_max = c + block * 2;
+
+				d = c_max;
+				d_max = offset + block * 4 <= nmemb ? d + block * 2 : pts + nmemb - offset;
+
+				quickstep:
+
+				if (cmp(c_max - 1, d_max - 1) <= 0)
+				{
+					while (c < c_max)
+					{
+						while (cmp(c, d) > 0)
+						{
+							*pta++ = *d++;
+						}
+						*pta++ = *c++;
+					}
+
+					while (d < d_max)
+						*pta++ = *d++;
+				}
+				else if (cmp(c, d_max - 1) > 0)
+				{
+					while (d < d_max - 16)
+					{
+						*pta++ = *d++; *pta++ = *d++; *pta++ = *d++; *pta++ = *d++;
+						*pta++ = *d++; *pta++ = *d++; *pta++ = *d++; *pta++ = *d++;
+						*pta++ = *d++; *pta++ = *d++; *pta++ = *d++; *pta++ = *d++;
+						*pta++ = *d++; *pta++ = *d++; *pta++ = *d++; *pta++ = *d++;
+					}
+					while (d < d_max)
+						*pta++ = *d++;
+
+					while (c < c_max - 16)
+					{
+						*pta++ = *c++; *pta++ = *c++; *pta++ = *c++; *pta++ = *c++;
+						*pta++ = *c++; *pta++ = *c++; *pta++ = *c++; *pta++ = *c++;
+						*pta++ = *c++; *pta++ = *c++; *pta++ = *c++; *pta++ = *c++;
+						*pta++ = *c++; *pta++ = *c++; *pta++ = *c++; *pta++ = *c++;
+					}
+					while (c < c_max)
+						*pta++ = *c++;
+				}
+				else
+				{
+					while (d < d_max)
+					{
+						while (cmp(d, c) > 0)
+						{
+							*pta++ = *c++;
+						}
+						*pta++ = *d++;
+					}
+
+					while (c < c_max)
+						*pta++ = *c++;
+				}
+			}
+			else
+			{
+				d_max = pts + nmemb - offset;
+
+				while (c < d_max - 8)
+				{
+					*pta++ = *c++; *pta++ = *c++; *pta++ = *c++; *pta++ = *c++;
+					*pta++ = *c++; *pta++ = *c++; *pta++ = *c++; *pta++ = *c++;
+				}
+				while (c < d_max)
+					*pta++ = *c++;
+			}
+			offset += block * 4;
+		}
+		block *= 4;
+	}
+}
+
+void quadsort(void *array, size_t nmemb, size_t size, CMPFUNC *cmp)
+{
+	void *swap;
+
+	swap = malloc(nmemb * size);
+
+	if (size == sizeof(int))
+	{
+		quad_swap32(array, swap, nmemb, cmp);
+		quad_sort32(array, swap, nmemb, 16, cmp);
+	}
+	else if (size == sizeof(long long))
+	{
+		quad_swap64(array, swap, nmemb, cmp);
+		quad_sort64(array, swap, nmemb, 16, cmp);
+	}
+	else
+	{
+		assert(size == 4 || size == 8);
+	}
+
+	free(swap);
+}
+
+int cmp_int(const void * a, const void * b)
+{
+	return *(int *) a - *(int *) b;
+}
+
+int cmp_str(const void * a, const void * b)
+{
+	return strcmp(*(const char **) a, *(const char **) b);
+}
+
+int cmp_float(const void * a, const void * b)
+{
+	return *(float *) a - *(float *) b;
+}
+
+int cmp_num(const void * a, const void * b)
+{
+	if (is_number(*(char **) a) && is_number(*(char **) 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;
+
+		if (num_a < num_b)
+		{
+			return -1;
+		}
+		if (num_a > num_b)
+		{
+			return 1;
+		}
+		return 0;
+	}
+	else if (is_number(*(char **) a))
+	{
+		return -1;
+	}
+	else if (is_number(*(char **) b))
+	{
+		return 1;
+	}
+	else
+	{
+		return strcmp(*(const char **) a, *(const char **) b);
+	}
+}

+ 8 - 17
src/split.c

@@ -109,6 +109,8 @@ 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);
+
 	if (!HAS_BIT(ses->flags, SES_FLAG_SPLIT))
 	{
 		ses->split->top_row = 1;
@@ -168,21 +170,9 @@ void init_split(struct session *ses, int top_row, int top_col, int bot_row, int
 
 	if (!HAS_BIT(ses->flags, SES_FLAG_SCROLLSPLIT))
 	{
-		if (gtd->level->quiet == 0)
+		if (HAS_BIT(ses->flags, SES_FLAG_VERBOSE) || gtd->level->verbose || gtd->level->quiet == 0)
 		{
-//			if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8))
-			{
-				do_screen(ses, "FILL DEFAULT");
-			}
-/*			else
-			{
-				fill_split_region(ses, "-");
-
-				erase_scroll_region(ses);
-				fill_split_region(ses, "-");
-				buffer_end(ses, "");
-
-			}*/
+			do_screen(ses, "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));
@@ -317,15 +307,16 @@ void split_show(struct session *ses, char *prompt, int row, int col)
 
 	if (row == gtd->screen->rows)
 	{
-		gtd->input_off = len + 1;
+		gtd->ses->input->off = len + 1;
 
 		goto_pos(ses, row, col);
 
-		print_stdout("%s%s", buf1, gtd->input_buf);
+		print_stdout("%s%s", buf1, gtd->ses->input->buf);
 
 		// bit of a hack
 
-		gtd->screen->sav_col[0] = inputline_cur_pos();
+		gtd->screen->sav_col[0] = inputline_cur_col();
+		gtd->screen->sav_row[0] = inputline_cur_row();
 	}
 	else
 	{

+ 91 - 31
src/tables.c

@@ -464,13 +464,15 @@ struct color_type color_table[] =
 	{    "faint",         "<288>",  5 },
 	{    "dim",           "<288>",  3 },
 	{    "dark",          "<288>",  4 },
+	{    "italic",        "<388>",  6 },
 	{    "underscore",    "<488>", 10 },
 	{    "blink",         "<588>",  5 },
 	{    "reverse",       "<788>",  7 },
 
-	{    "ununderscore", "\e[24m",13 },
-	{    "unblink",      "\e[25m", 8 },
-	{    "unreverse",    "\e[27m",10 },
+	{    "unitalic",     "\e[23m",  8 },
+	{    "ununderscore", "\e[24m", 13 },
+	{    "unblink",      "\e[25m",  8 },
+	{    "unreverse",    "\e[27m", 10 },
 
 	{    "black",         "<aaa>",  5 },
 	{    "red",           "<daa>",  4 },
@@ -535,6 +537,7 @@ struct color_type map_color_table[] =
 	{     "BACKGROUND",       ""      },
 	{     "BLOCK",            "<218>" },
 	{     "EXITS",            "<278>" },
+	{     "FOG",              "<148>" },
 	{     "HIDE",             "<168>" },
 	{     "INVISIBLE",        "<208>" },
 	{     "PATHS",            "<138>" },
@@ -644,9 +647,11 @@ struct array_type array_table[] =
 	{     "FND",              array_find,        NULL                                      },
 	{     "GET",              array_get,         "Retrieve a list item with given index"   },
 	{     "INSERT",           array_insert,      "Insert a list item at given index"       },
+	{     "ORDER",            array_order,       "Sort a list table numerically"           },
 	{     "LENGTH",           array_size,        NULL                                      },
+	{     "REVERSE",          array_reverse,     "Sort a list table in reverse order"      },
 	{     "SET",              array_set,         "Change a list item at given index"       },
-	{     "SHUFFLE",          array_shuffle,     "Sort a list table randomly"              },
+	{     "SHUFFLE",          array_shuffle,     "Sort a list table in random order"       },
 	{     "SIMPLIFY",         array_simplify,    "Turn a list table into a simple list"    },
 	{     "SIZE",             array_size,        NULL                                      },
 	{     "SORT",             array_sort,        "Sort a list table alphabetically"        },
@@ -817,7 +822,7 @@ struct cursor_type cursor_table[] =
 	{
 		"DELETE WORD RIGHT",
 		"Delete forwards till next space",
-		"",
+		"\e[3;5~",
 		CURSOR_FLAG_GET_ALL,
 		cursor_delete_word_right
 	},
@@ -1015,79 +1020,88 @@ struct cursor_type cursor_table[] =
 	},
 */
 	{
-		"", "", "\e[5~",   0, cursor_buffer_up
+		"", "", "\e[5~",     0, cursor_buffer_up
+	},
+	{
+		"", "", "\e[6~",     0, cursor_buffer_down
+	},
+	{
+		"", "", "",         0, cursor_buffer_lock
+	},
+	{
+		"","", "\e[13;2u",   0, cursor_enter
 	},
 	{
-		"", "", "\e[6~",   0, cursor_buffer_down
+		"", "", "\eOM",      0, cursor_enter
 	},
 	{
-		"", "", "",       0, cursor_buffer_lock
+		"", "", "\e[7~",     0, cursor_home
 	},
 	{
-		"","", "\e[13;2u", 0, cursor_enter
+		"", "", "\e[1~",     0, cursor_home
 	},
 	{
-		"", "", "\eOM",    0, cursor_enter
+		"", "", "\eOH",      0, cursor_home
 	},
 	{
-		"", "", "\e[7~",   0, cursor_home
+		"", "", "\e[H",      0, cursor_home
 	},
 	{
-		"", "", "\e[1~",   0, cursor_home
+		"", "", "\eOD",      0, cursor_left
 	},
 	{
-		"", "", "\eOH",    0, cursor_home
+		"", "", "\e[D",      0, cursor_left
 	},
 	{
-		"", "", "\e[H",    0, cursor_home
+		"", "", "\e[8~",     0, cursor_end
 	},
 	{
-		"", "", "\eOD",    0, cursor_left
+		"", "", "\e[4~",     0, cursor_end
 	},
 	{
-		"", "", "\e[D",    0, cursor_left
+		"", "", "\eOF",      0, cursor_end
 	},
 	{
-		"", "", "\e[8~",   0, cursor_end
+		"", "", "\e[F",      0, cursor_end
 	},
 	{
-		"", "", "\e[4~",   0, cursor_end
+		"", "", "\eOC",      0, cursor_right
 	},
 	{
-		"", "", "\eOF",    0, cursor_end
+		"", "", "\e[C",      0, cursor_right
 	},
 	{
-		"", "", "\e[F",    0, cursor_end
+		"", "", "\x7F",      0, cursor_backspace
 	},
 	{
-		"", "", "\eOC",    0, cursor_right
+		"", "", "\eOB",      0, cursor_history_next
 	},
 	{
-		"", "", "\e[C",    0, cursor_right
+		"", "", "\e[B",      0, cursor_history_next
 	},
 	{
-		"", "", "\x7F",    0, cursor_backspace
+		"", "", "\eOA",      0, cursor_history_prev
 	},
 	{
-		"", "", "\eOB",    0, cursor_history_next
+		"", "", "\e[A",      0, cursor_history_prev
 	},
 	{
-		"", "", "\e[B",    0, cursor_history_next
+		"", "", "\e[1;5D",   0, cursor_left_word
 	},
 	{
-		"", "", "\eOA",    0, cursor_history_prev
+		"", "", "\e[1;5C",   0, cursor_right_word
 	},
 	{
-		"", "", "\e[A",    0, cursor_history_prev
+		"", "", "\e[127;5u", 0, cursor_clear_line
 	},
 	{
-		"", "", "\e\x7F",  0, cursor_delete_word_left
+		"", "", "\e\x7F",    0, cursor_delete_word_left
 	},
 	{
-		"", "", "\ed",     0, cursor_delete_word_right
+		"", "", "\ed",       0, cursor_delete_word_right
 	},
 	{
-		"", "", "",        0, NULL
+		"", "", "",          0, NULL
 	}
 };
 
@@ -1217,6 +1231,15 @@ struct screen_type screen_table[] =
 		SCREEN_FLAG_CSIP,
 		screen_info
 	},
+	{
+		"INPUT",
+		"Set the input region to {square}.",
+		SCREEN_FLAG_GET_ONE,
+		SCREEN_FLAG_GET_ONE,
+		SCREEN_FLAG_CSIP,
+		screen_inputregion
+	},
+
 	{
 		"LOAD",
 		"Load screen information from memory.",
@@ -1250,6 +1273,14 @@ struct screen_type screen_table[] =
 		SCREEN_FLAG_CSIP,
 		screen_move
 	},
+	{
+		"PRINT",
+		"Print the screen dump to the screen.",
+		SCREEN_FLAG_GET_ONE,
+		SCREEN_FLAG_GET_ONE,
+		SCREEN_FLAG_CSIP,
+		screen_print
+	},
 	{
 		"RAISE",
 		"Raise a screen event.",
@@ -1352,9 +1383,12 @@ struct event_type event_table[] =
 	{    "DAY",                                    EVENT_FLAG_TIME,     "Triggers each day or given day."         },
 	{    "DOUBLE-CLICKED ",                        EVENT_FLAG_MOUSE,    "Triggers when mouse is double-clicked"   },
 	{    "END OF PATH",                            EVENT_FLAG_MAP,      "Triggers when walking the last room."    },
+	{    "GAG ",                                   EVENT_FLAG_GAG,      "Triggers on gag events."                 },
 	{    "HOUR",                                   EVENT_FLAG_TIME,     "Triggers each hour or given hour."       },
 	{    "IAC ",                                   EVENT_FLAG_TELNET,   "Triggers on telopt negotiation."         },
 	{    "LONG-CLICKED ",                          EVENT_FLAG_MOUSE,    "Triggers when mouse is long-clicked."    },
+	{    "MAP CREATE ROOM",                        EVENT_FLAG_MAP,      "Triggers when a room is created."        },
+	{    "MAP DELETE ROOM",                        EVENT_FLAG_MAP,      "Triggers when a room is deleted."        },
 	{    "MAP DOUBLE-CLICKED ",                    EVENT_FLAG_MOUSE,    "Triggers on vt map click."               },
 	{    "MAP ENTER MAP",                          EVENT_FLAG_MAP,      "Triggers when entering the map."         },
 	{    "MAP ENTER ROOM",                         EVENT_FLAG_MAP,      "Triggers when entering a map room."      },
@@ -1466,6 +1500,7 @@ struct line_type line_table[] =
 	{    "BACKGROUND",        line_background,     "Execute line without stealing session focus."   },
 	{    "BENCHMARK",         line_benchmark,      "Execute line and provide timing information."   },
 	{    "CAPTURE",           line_capture,        "Capture output in the given variable."          },
+	{    "CONVERT",           line_convert,        "Execute line in convert meta data mode."        },
 	{    "DEBUG",             line_debug,          "Execute line in debug mode."                    },
 	{    "GAG",               line_gag,            "Gag the next line."                             },
 	{    "IGNORE",            line_ignore,         "Execute line with triggers ignored."            },
@@ -2066,8 +2101,14 @@ struct stamp_type huge_stamp_table[] =
 	{ "&",  59, "  ████╗  \n ██╔═██╗ \n ╚████╔╝ \n██╔══██═╗\n╚█████╔█║\n ╚════╝╚╝" },
 	{ "%",  47, "██╗ ██╗\n╚═╝██╔╝\n  ██╔╝ \n ██╔╝  \n██╔╝██╗\n╚═╝ ╚═╝" },
 	{ "'",  23, "╗██╗\n██║\n╚═╝\n   \n   \n   " },
-
+	{ "(",  29, " ██╗\n██╔╝\n██║ \n██║ \n╚██╗\n ╚═╝" },
+	{ ")",  29, "██╗ \n╚██╗\n ██║\n ██║\n██╔╝\n╚═╝ " },
+	{ "*",  47, "▄  █  ▄\n █▄█▄█ \n  ▐█▌  \n █▀█▀█ \n▀  █  ▀\n       " },
 	{ "+",  59, "   ██╗   \n   ██║   \n████████╗\n╚══██╔══╝\n   ██║   \n   ╚═╝   " },
+// ,
+// -
+// .
+// /
 
 	{ "0",  53, " █████╗ \n██╔══██╗\n██║  ██║\n██║  ██║\n╚█████╔╝\n ╚════╝ " },
 	{ "1",  53, "  ▄██╗  \n ████║  \n ╚═██║  \n   ██║  \n ██████╗\n ╚═════╝" },
@@ -2081,7 +2122,14 @@ struct stamp_type huge_stamp_table[] =
 	{ "9",  53, " █████╗ \n██╔══██╗\n╚██████║\n ╚═══██║\n █████╔╝\n ╚════╝ " },
 
 	{ ":",  53, "        \n   ██╗  \n   ╚═╝  \n        \n   ██╗  \n   ╚═╝  " },
+// ;
+// <
+// =
+// >
+// ?
+
 
+	{ "@",  59, " ██████╗ \n██╔═══██╗\n██║██╗██║\n██║██║██║\n╚█║████╔╝\n ╚╝╚═══╝ " },
 	{ "A",  53, " █████╗ \n██╔══██╗\n███████║\n██╔══██║\n██║  ██║\n╚═╝  ╚═╝" },
 	{ "B",  53, "██████╗ \n██╔══██╗\n██████╔╝\n██╔══██╗\n██████╔╝\n╚═════╝ " },
 	{ "C",  53, " ██████╗\n██╔════╝\n██║     \n██║     \n╚██████╗\n ╚═════╝" },
@@ -2109,9 +2157,21 @@ struct stamp_type huge_stamp_table[] =
 	{ "Y",  59, "██╗   ██╗\n╚██╗ ██╔╝\n ╚████╔╝ \n  ╚██╔╝  \n   ██║   \n   ╚═╝   " },
 	{ "Z",  53, "███████╗\n╚══███╔╝\n  ███╔╝ \n ███╔╝  \n███████╗\n╚══════╝" },
 
+// [
+
+// ]
+	{ "^",  41, " ███╗ \n██╔██╗\n╚═╝╚═╝\n      \n      \n" },
+	{ "_",  53, "        \n        \n        \n        \n███████╗\n╚══════╝" },
+// `
+
 	{ "i",  23, "██╗\n╚═╝\n██╗\n██║\n██║\n╚═╝" },
 	{ "n",  47, "       \n       \n██▟███╗\n██║ ██║\n██║ ██║\n╚═╝ ╚═╝" },
 
+// {
+// }
+// ~
+// DEL
+
 	{ NULL, 0, NULL }
 };
 

+ 1 - 0
src/telopt_client.c

@@ -624,6 +624,7 @@ 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);
 
 	if (cpsrc[1] == GA)
 	{

+ 2 - 2
src/text.c

@@ -55,7 +55,7 @@ void print_line(struct session *ses, char **str, int prompt)
 
 	out = str_alloc(BUFFER_SIZE + strlen(*str));
 
-	if (HAS_BIT(ses->flags, SES_FLAG_CONVERTMETA))
+	if (HAS_BIT(ses->flags, SES_FLAG_CONVERTMETA) || gtd->level->convert)
 	{
 		convert_meta(*str, out, TRUE);
 
@@ -79,7 +79,7 @@ void print_line(struct session *ses, char **str, int prompt)
 	{
 		print_stdout("%s\n", out);
 	}
-	add_line_screen(out);
+//	add_line_screen(out);
 
 	str_free(out);
 

+ 175 - 71
src/tintin.h

@@ -172,7 +172,7 @@
 #define LIST_SIZE                        2
 
 #define CLIENT_NAME              "TinTin++"
-#define CLIENT_VERSION           "2.02.01 "
+#define CLIENT_VERSION           "2.02.02 "
 
 #define XT_E                            0x27
 #define XT_C                            0x5B
@@ -340,14 +340,17 @@ enum operators
 #define BV37 (1LL << 36)
 #define BV38 (1LL << 37)
 #define BV39 (1LL << 38)
+#define BV40 (1LL << 39)
 
-#define BUFFER_FLAG_GREP              BV01
+
+#define BUFFER_FLAG_GREP                  BV01
 
 
 #define CHARSET_FLAG_UTF8                 BV01
 #define CHARSET_FLAG_BIG5                 BV02
 #define CHARSET_FLAG_GBK1                 BV03
 
+
 #define CHARSET_FLAG_BIG5TOUTF8           BV04
 #define CHARSET_FLAG_FANSITOUTF8          BV05
 #define CHARSET_FLAG_GBK1TOUTF8           BV06
@@ -456,23 +459,25 @@ enum operators
 #define DRAW_FLAG_TUBED               BV27
 #define DRAW_FLAG_UTF8                BV28
 #define DRAW_FLAG_VER                 BV29
-
+#define DRAW_FLAG_CURSIVE             BV30
+#define DRAW_FLAG_FAT                 BV31
+#define DRAW_FLAG_SANSSERIF           BV32
 
 #define EVENT_FLAG_CATCH              BV01
 #define EVENT_FLAG_CLASS              BV02
-#define EVENT_FLAG_INPUT              BV03
-#define EVENT_FLAG_MAP                BV04
-#define EVENT_FLAG_MOUSE              BV05
-#define EVENT_FLAG_OUTPUT             BV06
-#define EVENT_FLAG_PORT               BV07
-#define EVENT_FLAG_SCAN               BV08
-#define EVENT_FLAG_SCREEN             BV09
-#define EVENT_FLAG_SESSION            BV10
-#define EVENT_FLAG_SYSTEM             BV11
-#define EVENT_FLAG_TELNET             BV12
-#define EVENT_FLAG_TIME               BV13
-#define EVENT_FLAG_VT100              BV14
-
+#define EVENT_FLAG_GAG                BV03
+#define EVENT_FLAG_INPUT              BV04
+#define EVENT_FLAG_MAP                BV05
+#define EVENT_FLAG_MOUSE              BV06
+#define EVENT_FLAG_OUTPUT             BV07
+#define EVENT_FLAG_PORT               BV08
+#define EVENT_FLAG_SCAN               BV09
+#define EVENT_FLAG_SCREEN             BV10
+#define EVENT_FLAG_SESSION            BV11
+#define EVENT_FLAG_SYSTEM             BV12
+#define EVENT_FLAG_TELNET             BV13
+#define EVENT_FLAG_TIME               BV14
+#define EVENT_FLAG_VT100              BV15
 
 
 #define PORT_FLAG_PRIVATE             BV01
@@ -555,18 +560,19 @@ enum operators
 //#define TINTIN_FLAG_RESETBUFFER       (1 <<  0)
 
 #define TINTIN_FLAG_CONVERTMETACHAR   (1 <<  1)
-#define TINTIN_FLAG_HISTORYBROWSE     (1 <<  2)
-#define TINTIN_FLAG_HISTORYSEARCH     (1 <<  3)
-#define TINTIN_FLAG_PROCESSINPUT      (1 <<  4)
-#define TINTIN_FLAG_INHERITANCE       (1 <<  5)
-#define TINTIN_FLAG_INSERTINPUT       (1 <<  6)
-#define TINTIN_FLAG_CHILDLOCK         (1 <<  7)
-#define TINTIN_FLAG_TERMINATE         (1 <<  8)
-#define TINTIN_FLAG_MOUSETRACKING     (1 <<  9)
-#define TINTIN_FLAG_FLUSH             (1 << 10)
-#define TINTIN_FLAG_DAEMONIZE         (1 << 11)
-#define TINTIN_FLAG_HIDDENCURSOR      (1 << 12)
-#define TINTIN_FLAG_LOCAL             (1 << 13)
+//#define TINTIN_FLAG_CONVERTEDMETACHAR (1 <<  2)
+#define TINTIN_FLAG_HISTORYBROWSE     (1 <<  3)
+#define TINTIN_FLAG_HISTORYSEARCH     (1 <<  4)
+#define TINTIN_FLAG_PROCESSINPUT      (1 <<  5)
+#define TINTIN_FLAG_INHERITANCE       (1 <<  6)
+#define TINTIN_FLAG_INSERTINPUT       (1 <<  7)
+#define TINTIN_FLAG_CHILDLOCK         (1 <<  8)
+#define TINTIN_FLAG_TERMINATE         (1 <<  9)
+#define TINTIN_FLAG_MOUSETRACKING     (1 << 10)
+#define TINTIN_FLAG_FLUSH             (1 << 11)
+#define TINTIN_FLAG_DAEMONIZE         (1 << 12)
+#define TINTIN_FLAG_HIDDENCURSOR      (1 << 13)
+#define TINTIN_FLAG_LOCAL             (1 << 14)
 
 #define SES_FLAG_ECHOCOMMAND          BV01
 #define SES_FLAG_SNOOP                BV02
@@ -599,6 +605,7 @@ enum operators
 #define SES_FLAG_SCROLLSPLIT          BV29
 #define SES_FLAG_MOUSEDEBUG           BV30
 #define SES_FLAG_MOUSEINFO            BV31
+#define SES_FLAG_AUTOPROMPT           BV32
 
 
 #define TELOPT_FLAG_TELNET            BV01
@@ -665,6 +672,7 @@ enum operators
 #define ROOM_FLAG_CURVED_TMP          BV14|ROOM_FLAG_CURVED
 #define ROOM_FLAG_BLOCK               BV15
 #define ROOM_FLAG_TERRAIN             BV20
+#define ROOM_FLAG_FOG                 BV21
 
 // keep synced with room flags
 
@@ -757,7 +765,7 @@ enum operators
 #define MOUSE_FLAG_MOTION              32
 #define MOUSE_FLAG_WHEEL               64
 #define MOUSE_FLAG_EXTRA              128
-#define MOUSE_FLAG_UNKNOWN            256
+#define MOUSE_FLAG_RELEASE            256
 
 #define CURSOR_FLAG_ALWAYS              1
 //#define CURSOR_FLAG_NEVER               2
@@ -769,6 +777,7 @@ enum operators
 #define STARTUP_FLAG_NORESET            4
 #define STARTUP_FLAG_ARGUMENT           8
 #define STARTUP_FLAG_NOTITLE           16
+#define STARTUP_FLAG_VERBOSE           32
 
 #define WRAP_FLAG_DISPLAY             (1 <<  0)
 #define WRAP_FLAG_WORD                (1 <<  1)
@@ -793,6 +802,7 @@ enum operators
 #define UNICODE_DIR_NE                  2
 #define UNICODE_DIR_SW                  4
 #define UNICODE_DIR_NW                  8
+
 #define UNICODE_DIR_D                  16
 #define UNICODE_DIR_N                  17
 #define UNICODE_DIR_S                  18
@@ -812,13 +822,15 @@ enum operators
 #define MAP_COLOR_BACK                  1
 #define MAP_COLOR_BLOCK                 2
 #define MAP_COLOR_EXIT                  3
-#define MAP_COLOR_HIDE                  4
-#define MAP_COLOR_INVIS                 5
-#define MAP_COLOR_PATH                  6
-#define MAP_COLOR_ROOM                  7
-#define MAP_COLOR_SYMBOL                8
-#define MAP_COLOR_USER                  9
-#define MAP_COLOR_MAX                   10
+#define MAP_COLOR_FOG                   4
+#define MAP_COLOR_HIDE                  5
+#define MAP_COLOR_INVIS                 6
+#define MAP_COLOR_PATH                  7
+#define MAP_COLOR_ROOM                  8
+#define MAP_COLOR_SYMBOL                9
+#define MAP_COLOR_USER                  10
+
+#define MAP_COLOR_MAX                   11
 
 
 /*
@@ -1046,17 +1058,17 @@ struct tintin_data
 	int                     mud_output_len;
 	unsigned char         * mccp_buf;
 	int                     mccp_len;
-	char                    input_buf[BUFFER_SIZE];
-	char                    input_tmp[BUFFER_SIZE];
+/*	char                    input_buf[BUFFER_SIZE];
+	char                    input_tmp[BUFFER_SIZE];*/
 	char                    macro_buf[BUFFER_SIZE];
 	char                    paste_buf[BUFFER_SIZE];
-	char                    is_result[NUMBER_SIZE];
-	int                     input_off;
+	char                    is_result[NUMBER_SIZE]; // not properly utilized?
+/*	int                     input_off;
 	int                     input_len;
 	int                     input_cur;
 	int                     input_pos;
 	int                     input_hid;
-	int                     input_tab;
+	int                     input_tab;*/
 	char                  * home;
 	char                  * lang;
 	char                  * os;
@@ -1071,10 +1083,11 @@ struct tintin_data
 	long long               total_io_ticks;
 	long long               total_io_exec;
 	long long               total_io_delay;
+	long long               convert_time;
 	int                     history_size;
 	int                     command_ref[26];
 	int                     msdp_table_size;
-	int                     flags;
+	long long               flags;
 	struct scriptroot     * script_stack[STACK_SIZE];
 	int                     script_index;
 	char                    tintin_char;
@@ -1097,6 +1110,7 @@ struct session
 	struct termios          cur_terminal;
 	struct scroll_data    * scroll;
 	struct split_data     * split;
+	struct input_data     * input;
 	char                  * name;
 	char                  * group;
 	FILE                  * logfile;
@@ -1142,22 +1156,24 @@ struct session
 	int                     auto_tab;
 	int                     tab_width;
 	unsigned long long      rand;
+	unsigned short          rkey;
 };
 
 
 struct level_data
 {
-	int                     background;
-	int                     debug;
-	int                     grep;
-	int                     ignore;
-	int                     info;
-	int                     input;
-	int                     oneshot;
-	int                     quiet;
-	int                     scroll;
-	int                     verbatim;
-	int                     verbose;
+	unsigned int            background;
+	unsigned int            convert;
+	unsigned int            debug;
+	unsigned int            grep;
+	unsigned int            ignore;
+	unsigned int            info;
+	unsigned int            input;
+	unsigned int            oneshot;
+	unsigned int            quiet;
+	unsigned int            scroll;
+	unsigned int            verbatim;
+	unsigned int            verbose;
 };
 
 struct split_data
@@ -1172,6 +1188,53 @@ struct split_data
 	int                     bot_col;
 };
 
+struct input_data
+{
+	int                     sav_top_row;
+	int                     sav_top_col;
+	int                     sav_bot_row;
+	int                     sav_bot_col;
+
+	int                     top_row;
+	int                     top_col;
+	int                     bot_row;
+	int                     bot_col;
+
+	int                     rel_row;
+	int                     rel_col;
+
+	int                     len;
+	int                     off;
+	int                     pos;
+	int                     cur;
+	int                     hid;
+	int                     tab;
+
+	char                   *buf;
+	char                   *tmp;
+};
+
+struct window_data
+{
+	char                    *name;
+
+	int                     top_row;
+	int                     top_col;
+	int                     bot_row;
+	int                     bot_col;
+
+	int                     off_row;
+	int                     off_col;
+
+	int                     max_row;
+	int                     max_col;
+
+	int                     pos_row;
+	int                     pos_col;
+
+	struct input_data      **buffer;
+};
+
 struct scroll_data
 {
 	struct buffer_data   ** buffer;
@@ -1185,7 +1248,6 @@ struct scroll_data
 	int                     flags;
 };
 
-
 struct buffer_data
 {
 	int                     width;
@@ -1292,7 +1354,6 @@ struct str_data
 	int                       len;
 };
 
-
 struct row_data
 {
 	char                  * str;
@@ -1321,8 +1382,6 @@ struct screen_data
 	int                     bot_row;
 	int                     cur_row;
 	int                     cur_col;
-//	int                     sav_row;
-//	int                     sav_col;
 	int                     max_row;
 	int                     sav_lev;
 	int                     sav_row[STACK_SIZE];
@@ -1333,6 +1392,7 @@ struct map_data
 {
 	struct room_data     ** room_list;
 	struct room_data     ** grid_rooms;
+	int                   * grid_vnums;
 	FILE                  * logfile;
 	struct link_data      * undo_head;
 	struct link_data      * undo_tail;
@@ -1400,7 +1460,6 @@ struct room_data
 	char                    * note;
 	char                    * symbol;
 	char                    * terrain;
-
 };
 
 struct exit_data
@@ -1440,6 +1499,8 @@ struct search_data
 	Typedefs
 */
 
+typedef int             CMPFUNC (const void *a, const void *b);
+
 typedef struct session *ARRAY   (struct session *ses, struct listnode *list, char *arg, char *var);
 typedef void            CHAT    (char *arg1, char *arg2);
 typedef struct session *CLASS   (struct session *ses, struct listnode *node, char *left, char *right);
@@ -1696,25 +1757,42 @@ extern DO_COMMAND(do_advertise);
 #define __ARRAY_H__
 
 extern DO_COMMAND(do_list);
+
 extern DO_ARRAY(array_add);
 extern DO_ARRAY(array_clear);
 extern DO_ARRAY(array_collapse);
 extern DO_ARRAY(array_create);
-extern DO_ARRAY(array_explode);
-extern DO_ARRAY(array_insert);
 extern DO_ARRAY(array_delete);
+extern DO_ARRAY(array_explode);
 extern DO_ARRAY(array_find);
 extern DO_ARRAY(array_get);
+extern DO_ARRAY(array_insert);
+extern DO_ARRAY(array_order);
+extern DO_ARRAY(array_reverse);
+extern DO_ARRAY(array_set);
 extern DO_ARRAY(array_shuffle);
 extern DO_ARRAY(array_simplify);
 extern DO_ARRAY(array_size);
-extern DO_ARRAY(array_set);
 extern DO_ARRAY(array_sort);
 extern DO_ARRAY(array_tokenize);
 
 #endif
 
 
+#ifndef __BASE_H__
+#define __BASE_H__
+
+extern int str_to_base64(char *in, char *out, size_t size);
+extern int base64_to_str(char *in, char *out, size_t size);
+
+extern int str_to_base252(char *in, char *out, size_t size);
+extern int base252_to_str(char *in, char *out, size_t size);
+
+extern void str_to_base252z(char *in, char *out, size_t size);
+extern void base252z_to_str(char *in, char *out, size_t size);
+
+#endif
+
 #ifndef __BUFFER_H__
 #define __BUFFER_H__
 
@@ -1812,7 +1890,10 @@ extern DO_CLASS(class_write);
 
 extern DO_COMMAND(do_cursor);
 
-int inputline_cur_pos(void);
+int inputline_cur_row(void);
+int inputline_cur_col(void);
+
+int inputline_max_row(void);
 
 extern DO_CURSOR(cursor_backspace);
 extern DO_CURSOR(cursor_brace_open);
@@ -2125,7 +2206,7 @@ extern DO_COMMAND(do_event);
 extern DO_COMMAND(do_unevent);
 
 extern  int check_all_events(struct session *ses, int flags, int args, int vars, char *fmt, ...);
-extern void mouse_handler(struct session *ses, int val1, int val2, int val3, char type);
+extern void mouse_handler(struct session *ses, int val1, int val2, int val3);
 
 #endif
 
@@ -2178,6 +2259,7 @@ extern DO_COMMAND(do_line);
 extern DO_LINE(line_background);
 extern DO_LINE(line_benchmark);
 extern DO_LINE(line_capture);
+extern DO_LINE(line_convert);
 extern DO_LINE(line_debug);
 extern DO_LINE(line_gag);
 extern DO_LINE(line_ignore);
@@ -2383,6 +2465,9 @@ extern DO_COMMAND(do_path);
 extern DO_COMMAND(do_pathdir);
 extern DO_COMMAND(do_unpathdir);
 
+int exit_to_dir(struct session *ses, char *name);
+char *dir_to_exit(struct session *ses, int dir);
+
 extern void check_append_path(struct session *ses, char *forward, char *backward, int follow);
 
 extern DO_PATH(path_create);
@@ -2466,10 +2551,12 @@ extern DO_SCREEN(screen_focus);
 extern DO_SCREEN(screen_fullscreen);
 extern DO_SCREEN(screen_get);
 extern DO_SCREEN(screen_info);
+extern DO_SCREEN(screen_inputregion);
 extern DO_SCREEN(screen_load);
 extern DO_SCREEN(screen_maximize);
 extern DO_SCREEN(screen_minimize);
 extern DO_SCREEN(screen_move);
+extern DO_SCREEN(screen_print);
 extern DO_SCREEN(screen_raise);
 extern DO_SCREEN(screen_refresh);
 extern DO_SCREEN(screen_resize);
@@ -2479,17 +2566,15 @@ extern DO_SCREEN(screen_scrollbar);
 extern DO_SCREEN(screen_scrollregion);
 extern DO_SCREEN(screen_set);
 
-extern  int get_row_index(struct session *ses, char *arg);
-extern  int get_col_index(struct session *ses, char *arg);
+extern void init_inputregion(struct session *ses, int top_row, int top_col, int bot_row, int bot_col);
+extern  int get_row_index(struct session *ses, int val);
+extern  int get_col_index(struct session *ses, int val);
+extern  int get_row_index_arg(struct session *ses, char *arg);
+extern  int get_col_index_arg(struct session *ses, char *arg);
 extern void csip_handler(int var1, int var2, int var3);
 extern void csit_handler(int var1, int var2, int var3);
 extern void rqlp_handler(int event, int button, int row, int col);
 extern void osc_handler(char ind, char *arg);
-extern void print_screen();
-extern void init_screen(int rows, int cols, int pix_rows, int pix_cols);
-extern void destroy_screen();
-extern void add_line_screen(char *str);
-extern void set_line_screen(char *str, int row, int col);
 extern void erase_scroll_region(struct session *ses);
 extern void erase_split_region(struct session *ses);
 extern void erase_bot_region(struct session *ses);
@@ -2502,7 +2587,15 @@ extern void fill_bot_region(struct session *ses, char *arg);
 extern void fill_left_region(struct session *ses, char *arg);
 extern void fill_right_region(struct session *ses, char *arg);
 extern void fill_split_region(struct session *ses, char *arg);
+
+extern void print_screen();
+extern void init_screen(int rows, int cols, int pix_rows, int pix_cols);
+extern void destroy_screen();
+extern int inside_scroll_region(struct session *ses, int row, int col);
+extern void add_line_screen(char *str);
+extern void set_line_screen(char *str, int row, int col);
 extern void get_line_screen(char *str, int row);
+extern  int get_link_screen(struct session *ses, char *result, int flags, int row, int col);
 extern void get_word_screen(char *str, int row, int col);
 
 #endif
@@ -2550,6 +2643,16 @@ extern void tintin_puts(struct session *ses, char *string);
 #endif
 
 
+#ifndef __SORT_H__
+#define __SORT_H__
+
+extern void quadsort(void *array, size_t nmemb, size_t size, CMPFUNC *cmp);
+extern int cmp_int(const void * a, const void * b);
+extern int cmp_str(const void * a, const void * b);
+extern int cmp_num(const void * a, const void * b);
+
+#endif
+
 #ifndef __SPLIT_H__
 #define __SPLIT_H__
 
@@ -2734,7 +2837,7 @@ extern DO_COMMAND(do_unmacro);
 
 extern DO_COMMAND(do_prompt);
 extern DO_COMMAND(do_unprompt);
-extern void check_all_prompts(struct session *ses, char *original, char *line);
+extern int check_all_prompts(struct session *ses, char *original, char *line, int check);
 
 extern DO_COMMAND(do_substitute);
 extern DO_COMMAND(do_unsubstitute);
@@ -2860,6 +2963,7 @@ extern void scroll_region(struct session *ses, int top, int bottom);
 extern void reset_scroll_region(struct session *ses);
 extern int find_color_code(char *str);
 extern int find_secure_color_code(char *str);
+extern int skip_one_char(struct session *ses, char *str, int *width);
 extern int skip_vt102_codes(char *str);
 extern int skip_vt102_codes_non_graph(char *str);
 extern void strip_vt102_codes(char *str, char *buf);

+ 15 - 7
src/trigger.c

@@ -251,6 +251,8 @@ DO_COMMAND(do_button)
 	}
 	else
 	{
+		SET_BIT(ses->event_flags, EVENT_FLAG_MOUSE);
+
 		node = update_node_list(ses->list[LIST_BUTTON], arg1, arg2, arg3, "");
 
 		show_message(ses, LIST_BUTTON, "#OK. BUTTON {%s} NOW TRIGGERS {%s} @ {%s}.", arg1, arg2, arg3);
@@ -273,11 +275,11 @@ DO_COMMAND(do_button)
 		{
 			arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
 
-			RESTRING(node->arg4, arg2);
+			str_cpy(&node->arg4, arg2);
 		}
 		else
 		{
-			RESTRING(node->arg4, "PRESSED MOUSE BUTTON ONE");
+			str_cpy(&node->arg4, "PRESSED MOUSE BUTTON ONE");
 		}
 	}
 	return ses;
@@ -514,7 +516,7 @@ void check_all_gags(struct session *ses, char *original, char *line)
 
 		if (check_one_regexp(ses, node, line, original, 0))
 		{
-			show_debug(ses, LIST_GAG, "#DEBUG GAG {%s}", node->arg1);
+//			show_debug(ses, LIST_GAG, "#DEBUG GAG {%s}", node->arg1);
 
 			if (HAS_BIT(node->flags, NODE_FLAG_ONESHOT))
 			{
@@ -746,14 +748,14 @@ DO_COMMAND(do_unprompt)
 }
 
 
-void check_all_prompts(struct session *ses, char *original, char *line)
+int check_all_prompts(struct session *ses, char *original, char *line, int check)
 {
 	struct listroot *root = ses->list[LIST_PROMPT];
 	struct listnode *node;
 
-	if (!HAS_BIT(ses->flags, SES_FLAG_SPLIT))
+	if (check && !HAS_BIT(ses->flags, SES_FLAG_SPLIT))
 	{
-		return;
+		return 0;
 	}
 
 	for (root->update = 0 ; root->update < root->used ; root->update++)
@@ -762,6 +764,11 @@ void check_all_prompts(struct session *ses, char *original, char *line)
 
 		if (check_one_regexp(ses, node, line, original, 0))
 		{
+			if (!check)
+			{
+				return TRUE;
+			}
+
 			if (*node->arg2)
 			{
 				substitute(ses, node->arg2, original, SUB_ARG);
@@ -769,7 +776,7 @@ void check_all_prompts(struct session *ses, char *original, char *line)
 			}
 
 			show_debug(ses, LIST_PROMPT, "#DEBUG PROMPT {%s}", node->arg1);
-			show_debug(ses, LIST_GAG, "#DEBUG GAG {%s}", node->arg1);
+//			show_debug(ses, LIST_GAG, "#DEBUG GAG {%s}", node->arg1);
 
 			split_show(ses, original, atoi(node->arg3), atoi(node->arg4));
 
@@ -780,6 +787,7 @@ void check_all_prompts(struct session *ses, char *original, char *line)
 			SET_BIT(ses->flags, SES_FLAG_GAG);
 		}
 	}
+	return 0;
 }
 
 

+ 15 - 2
src/utils.c

@@ -327,16 +327,29 @@ unsigned long long utime()
 void seed_rand(struct session *ses, unsigned long long seed)
 {
 	ses->rand = seed % 4294967291ULL;
+	ses->rkey = seed % 5;
 }
 
 unsigned long long generate_rand(struct session *ses)
 {
-	ses->rand = ses->rand * 279470273ULL % 4294967291ULL;
+	static unsigned long long primes[] = {26196137413795067, 1062272168593625449, 5189794811, 237506310434573, 212938855558633 };
 
+	if (ses->rkey % 3 == 1)
+	{
+		ses->rand += 316595909ULL + primes[++ses->rkey % 5];
+	}
+	else
+	{
+		ses->rand += primes[++ses->rkey % 5];
+	}
+
+	return (unsigned int) ses->rand;
+
+//	ses->rand = (ses->rand + 260854879ULL) % 4294967291ULL;
 //	return ses->rand % 1000000000ULL;
 
-	return ses->rand;
 }
+
 /*
 uint32_t lcg_rand(uint32_t *state)
 {

+ 226 - 83
src/variable.c

@@ -142,8 +142,12 @@ DO_COMMAND(do_local)
 
 		arg = sub_arg_in_braces(ses, arg, str, GET_ALL, SUB_VAR|SUB_FUN);
 
+		DEL_BIT(gtd->flags, TINTIN_FLAG_LOCAL);
+
 		node = set_nest_node(root, arg1, "%s", str);
 
+		SET_BIT(gtd->flags, TINTIN_FLAG_LOCAL);
+
 		while (*arg)
 		{
 			arg = sub_arg_in_braces(ses, arg, str, GET_ALL, SUB_VAR|SUB_FUN);
@@ -159,8 +163,6 @@ DO_COMMAND(do_local)
 		show_message(ses, LIST_VARIABLE, "#OK. LOCAL VARIABLE {%s} HAS BEEN SET TO {%s}.", arg1, str);
 
 		str_free(str);
-
-		SET_BIT(gtd->flags, TINTIN_FLAG_LOCAL);
 	}
 	return ses;
 }
@@ -315,6 +317,114 @@ int valid_variable(struct session *ses, char *arg)
 	support routines for #format
 */
 
+void stringtobase(char *str, char *base)
+{
+	char *buf;
+
+	push_call("stringtobase(%p,%p)",str,base);
+
+	buf = strdup(str);
+
+	switch (atoi(base))
+	{
+		case 64:
+			str_to_base64(buf, str, strlen(str));
+			break;
+
+		case 252:
+			str_to_base252(buf, str, strlen(str));
+			break;
+
+		default:
+			tintin_printf2(gtd->ses, "#FORMAT: Unknown base conversion {%s}.", base);
+			break;
+	}
+	free(buf);
+
+	pop_call();
+	return;
+}
+
+void basetostring(char *str, char *base)
+{
+	char *buf;
+
+	push_call("basetostring(%p,%p)",str,base);
+
+	buf = strdup(str);
+
+	switch (atoi(base))
+	{
+		case 64:
+			base64_to_str(buf, str, strlen(str));
+			break;
+
+		case 252:
+			base252_to_str(buf, str, strlen(str));
+			break;
+
+		default:
+			tintin_printf2(gtd->ses, "#FORMAT: Unknown base conversion {%s}.", base);
+			break;
+	}
+	pop_call();
+	return;
+}
+
+void stringtobasez(char *str, char *base)
+{
+	char *buf;
+
+	push_call("stringtobase(%p,%p)",str,base);
+
+	buf = strdup(str);
+
+	switch (atoi(base))
+	{
+		case 64:
+			str_to_base64(buf, str, strlen(str));
+			break;
+
+		case 252:
+			str_to_base252z(buf, str, strlen(str));
+			break;
+
+		default:
+			tintin_printf2(gtd->ses, "#FORMAT: Unknown base conversion {%s}.", base);
+			break;
+	}
+	free(buf);
+
+	pop_call();
+	return;
+}
+
+void basetostringz(char *str, char *base)
+{
+	char *buf;
+
+	push_call("basetostring(%p,%p)",str,base);
+
+	buf = strdup(str);
+
+	switch (atoi(base))
+	{
+		case 64:
+			base64_to_str(buf, str, strlen(str));
+			break;
+
+		case 252:
+			base252z_to_str(buf, str, strlen(str));
+			break;
+
+		default:
+			tintin_printf2(gtd->ses, "#FORMAT: Unknown base conversion {%s}.", base);
+			break;
+	}
+	pop_call();
+	return;
+}
+
 unsigned long long generate_hash_key(char *str)
 {
 	unsigned long long len, h = 4321;
@@ -956,7 +1066,18 @@ int string_str_raw_len(struct session *ses, char *str, int start, int end)
 			continue;
 		}
 
-		if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&str[raw_cnt]))
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, &str[raw_cnt]))
+		{
+			tmp_cnt = get_euc_width(ses, &str[raw_cnt], &width);
+
+			if (str_cnt >= start)
+			{
+				ret_cnt += tmp_cnt;
+			}
+			raw_cnt += tmp_cnt;
+			str_cnt += width;
+		}
+		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(&str[raw_cnt]))
 		{
 			tmp_cnt = get_utf8_width(&str[raw_cnt], &width);
 
@@ -1022,13 +1143,13 @@ int string_raw_str_len(struct session *ses, char *str, int raw_start, int raw_en
 			continue;
 		}
 
-		if (HAS_BIT(gtd->ses->charset, CHARSET_FLAG_EUC)  && is_euc_head(ses, &str[raw_cnt]))
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC)  && is_euc_head(ses, &str[raw_cnt]))
 		{
 			raw_cnt += get_euc_width(ses, &str[raw_cnt], &width);
 
 			ret_cnt += width;
 		}
-		else if (HAS_BIT(gtd->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]))
 		{
 			raw_cnt += get_utf8_width(&str[raw_cnt], &width);
 
@@ -1144,85 +1265,93 @@ void format_string(struct session *ses, char *format, char *arg, char *out)
 
 				*ptn = 0;
 
-				if (*ptf == 0)
-				{
-					show_error(ses, LIST_VARIABLE, "#FORMAT STRING: UNKNOWN ARGUMENT {%s}.", pts);
-					continue;
-				}
-
-				if (*ptf == 'd' || *ptf == 'f' || *ptf == 'X')
-				{
-					strcpy(argformat, pts);
-
-					ptn = pts + 1;
-					*ptn = 0;
-				}
-				else if (*ptf == 'w')
-				{
-					strcpy(argformat, pts+1);
-					ptn = pts + 1;
-					*ptn = 0;
-				}
-				else if (pts[1])
+				switch (*ptf)
 				{
-					char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
+					case 0:
+						show_error(ses, LIST_VARIABLE, "#FORMAT STRING: UNKNOWN ARGUMENT {%s}.", pts);
+						continue;
 
-					ptt = arg1;
-					ptn = pts + 1;
-
-					while (*ptn && *ptn != '.')
-					{
-						*ptt++ = *ptn++;
-					}
-
-					*ptt = 0;
-
-					if (*ptn == 0)
-					{
-						if (atoi(arg1) < 0)
-						{
-							sprintf(argformat, "%%%d", atoi(arg1) - ((int) strlen(arglist[i]) - string_raw_str_len(ses, arglist[i], 0, BUFFER_SIZE)));
-						}
-						else
-						{
-							sprintf(argformat, "%%%d", atoi(arg1) + ((int) strlen(arglist[i]) - string_raw_str_len(ses, arglist[i], 0, BUFFER_SIZE)));
-						}
-					}
-					else
-					{
-						ptt = arg2;
-						ptn = ptn + 1;
+					case 'd':
+					case 'f':
+					case 'X':
+						strcpy(argformat, pts);
 
-						while (*ptn)
-						{
-							*ptt++ = *ptn++;
-						}
+						ptn = pts + 1;
+						*ptn = 0;
+						break;
 
-						*ptt = 0;
+					case 'w':
+					case 'b':
+					case 'B':
+					case 'z':
+					case 'Z':
+						strcpy(argformat, pts+1);
+						ptn = pts + 1;
+						*ptn = 0;
+						break;
 
-						if (atoi(arg1) < 0)
-						{
-							sprintf(argformat, "%%%d.%d",
-								atoi(arg1) - ((int) strlen(arglist[i]) - string_raw_str_len(ses, arglist[i], 0, BUFFER_SIZE)),
-								string_str_raw_len(ses, arglist[i], 0, atoi(arg2)));
-						}
-						else
+					default:
+						if (pts[1])
 						{
-							sprintf(argformat, "%%%d.%d",
-								atoi(arg1) + ((int) strlen(arglist[i]) - string_raw_str_len(ses, arglist[i], 0, BUFFER_SIZE)),
-								string_str_raw_len(ses, arglist[i], 0, atoi(arg2)));
+							char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
+
+							ptt = arg1;
+							ptn = pts + 1;
+
+							while (*ptn && *ptn != '.')
+							{
+								*ptt++ = *ptn++;
+							}
+
+							*ptt = 0;
+
+							if (*ptn == 0)
+							{
+								if (atoi(arg1) < 0)
+								{
+									sprintf(argformat, "%%%d", atoi(arg1) - ((int) strlen(arglist[i]) - string_raw_str_len(ses, arglist[i], 0, BUFFER_SIZE)));
+								}
+								else
+								{
+									sprintf(argformat, "%%%d", atoi(arg1) + ((int) strlen(arglist[i]) - string_raw_str_len(ses, arglist[i], 0, BUFFER_SIZE)));
+								}
+							}
+							else
+							{
+								ptt = arg2;
+								ptn = ptn + 1;
+		
+								while (*ptn)
+								{
+									*ptt++ = *ptn++;
+								}
+		
+								*ptt = 0;
+		
+								if (atoi(arg1) < 0)
+								{
+									sprintf(argformat, "%%%d.%d",
+										atoi(arg1) - ((int) strlen(arglist[i]) - string_raw_str_len(ses, arglist[i], 0, BUFFER_SIZE)),
+										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)),
+										string_str_raw_len(ses, arglist[i], 0, atoi(arg2)));
+								}
+							}
+		
+							ptt = argformat;
+							ptn = pts;
+		
+							while (*ptt)
+							{
+								*ptn++ = *ptt++;
+							}
+		
+							*ptn = 0;
 						}
-					}
-
-					ptt = argformat;
-					ptn = pts;
-
-					while (*ptt)
-					{
-						*ptn++ = *ptt++;
-					}
-
-					*ptn = 0;
 				}
 
 				switch (*ptf)
@@ -1232,6 +1361,11 @@ void format_string(struct session *ses, char *format, char *arg, char *out)
 //						sprintf(arglist[i], "%c", (char) get_number(ses, arglist[i]));
 						break;
 
+					case 'b':
+						substitute(ses, arglist[i], arglist[i], SUB_VAR|SUB_FUN);
+						stringtobase(arglist[i], argformat);
+						break;
+
 					case 'c':
 						colorstring(ses, arglist[i]);
 						break;
@@ -1294,10 +1428,20 @@ void format_string(struct session *ses, char *format, char *arg, char *out)
 						hexstring(arglist[i]);
 						break;
 
+					case 'z':
+						substitute(ses, arglist[i], arglist[i], SUB_VAR|SUB_FUN);
+						stringtobasez(arglist[i], argformat);
+						break;
+
 					case 'A':
 						charactertonumber(ses, arglist[i]);
 						break;
 
+					case 'B':
+						substitute(ses, arglist[i], arglist[i], SUB_VAR|SUB_FUN);
+						basetostring(arglist[i], argformat);
+						break;
+
 					case 'C':
 						chronosgroupingstring(ses, arglist[i]);
 						break;
@@ -1307,12 +1451,6 @@ void format_string(struct session *ses, char *format, char *arg, char *out)
 
 						break;
 
-/*					case 'D':
-						timeval_t  = (time_t) *arglist[i] ? atoll(arglist[i]) : gtd->time;
-						timeval_tm = *localtime(&timeval_t);
-						strftime(arglist[i], BUFFER_SIZE, "%d", &timeval_tm);
-						break;
-*/
 					case 'G':
 						thousandgroupingstring(ses, arglist[i]);
 						break;
@@ -1359,6 +1497,11 @@ void format_string(struct session *ses, char *format, char *arg, char *out)
 						strftime(arglist[i], BUFFER_SIZE, "%Y", &timeval_tm);
 						break;
 
+					case 'Z':
+						substitute(ses, arglist[i], arglist[i], SUB_VAR|SUB_FUN);
+						basetostringz(arglist[i], argformat);
+						break;
+
 					default:
 						show_error(ses, LIST_VARIABLE, "#FORMAT STRING: UNKNOWN ARGUMENT {%s%c}.", pts, *ptf);
 						break;

+ 58 - 18
src/vt102.c

@@ -77,9 +77,9 @@ void restore_pos(struct session *ses)
 		syserr_printf(ses, "sav_lev-- below 0.");
 	}
 
-	if (gtd->screen->sav_row[gtd->screen->sav_lev] == gtd->screen->rows)
+	if (gtd->screen->sav_lev == 1 /* gtd->screen->sav_row[gtd->screen->sav_lev] == inputline_cur_row()*/ /*gtd->screen->rows*/)
 	{
-		goto_pos(ses, gtd->screen->rows, inputline_cur_pos());
+		goto_pos(ses, inputline_cur_row(), inputline_cur_col());
 	}
 	else
 	{
@@ -263,6 +263,15 @@ int skip_vt102_codes(char *str)
 				case 'R':
 					pop_call();
 					return str[3] ? 3 : 2;
+
+				default:
+					for (skip = 2 ; str[skip] ; skip++)
+					{
+						if (str[skip] == '\a' || (str[skip] == '\e' && str[skip+1] == '\\'))
+						{
+							return skip + 1;
+						}
+					}
 			}
 			pop_call();
 			return 2;
@@ -296,6 +305,37 @@ int skip_vt102_codes(char *str)
 	return skip;
 }
 
+int skip_one_char(struct session *ses, char *str, int *width)
+{
+	int skip;
+
+	*width = 0;
+
+	if (*str)
+	{
+		skip = skip_vt102_codes(str);
+
+		if (skip)
+		{
+			return skip;
+		}
+
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC) && is_euc_head(ses, str))
+		{
+			return get_euc_width(ses, str, width);
+		}
+
+		if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8) && is_utf8_head(str))
+		{
+			return get_utf8_width(str, width);
+		}
+
+		*width = 1;
+		return 1;
+	}
+	return 0;
+}
+
 int find_color_code(char *str)
 {
 	int skip;
@@ -402,23 +442,23 @@ int skip_vt102_codes_non_graph(char *str)
 
 	switch (str[skip])
 	{
-		case   7:   /* BEL */
-	/*	case   8: *//* BS  */
-	/*	case   9: *//* HT  */
-	/*	case  10: *//* LF  */
-		case  11:   /* VT  */
-		case  12:   /* FF  */
-		case  13:   /* CR  */
-		case  14:   /* SO  */
-		case  15:   /* SI  */
-		case  17:   /* DC1 */
-		case  19:   /* DC3 */
-		case  24:   /* CAN */
-		case  26:   /* SUB */
-		case 127:   /* DEL */
+		case   7:   // BEL
+//		case   8:   // BS  
+//		case   9:   // HT  
+//		case  10:   // LF  
+		case  11:   // VT  
+		case  12:   // FF  
+		case  13:   // CR  
+		case  14:   // SO  
+		case  15:   // SI  
+		case  17:   // DC1 
+		case  19:   // DC3 
+		case  24:   // CAN 
+		case  26:   // SUB 
+		case 127:   // DEL 
 			return 1;
 
-		case  27:   /* ESC */
+		case  27:   // ESC 
 			break;
 
 		default:
@@ -463,7 +503,7 @@ int skip_vt102_codes_non_graph(char *str)
 				case 'R':
 					return 3;
 			}
-			return 2;
+			return 0;
 
 		case '[':
 			break;

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff