Rolled from #448.
NNN_OPTS to specify binary options to nnns in status bar to indicate selection in progressO_NOMOUSE to disable mouse supportNNN_TRASH and -Q always, do not store in config/sessionvidir-like functionality (@KlzXS)nnn.vim plugin to show a persistent bar (https://github.com/mcchrish/nnn.vim/issues/46)nnn pluginsAnything else which would add value (please discuss in this thread).
Filtering is case insensitive for english names, but case sensitive for russian.
β> ls
test Test ΡΠ΅ΡΡ Π’Π΅ΡΡ
"te" selects both "Test" and "test", while "ΡΠ΅" selects only "ΡΠ΅ΡΡ" missing "Π’Π΅ΡΡ".
It's expected to be case insensitive not depending on language.
Tested on latest master.
By default, we do use setlocale() and REG_ICASE (or PCRE_CASELESS).
I think the issue may be with UTF8. As per the following man page: http://man7.org/linux/man-pages/man3/pcreposix.3.html REG_UTF8 is not POSIX. Can you try the PCRE version with the following patch:
diff --git a/src/nnn.c b/src/nnn.c
index a31b30e..571530e 100644
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -2059,7 +2059,7 @@ static char xchartohex(char c)
static char * (*fnstrstr)(const char *haystack, const char *needle) = &strcasestr;
#ifdef PCRE
static const unsigned char *tables;
-static int pcreflags = PCRE_NO_AUTO_CAPTURE | PCRE_EXTENDED | PCRE_CASELESS;
+static int pcreflags = PCRE_NO_AUTO_CAPTURE | PCRE_EXTENDED | PCRE_CASELESS | PCRE_UTF8;
#else
static int regflags = REG_NOSUB | REG_EXTENDED | REG_ICASE;
#endif
To compile with PCRE, run:
sudo make O_PCRE=1 strip install
β> git diff
diff --git a/src/nnn.c b/src/nnn.c
index a31b30e..571530e 100644
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -2059,7 +2059,7 @@ static char xchartohex(char c)
static char * (*fnstrstr)(const char *haystack, const char *needle) = &strcasestr;
#ifdef PCRE
static const unsigned char *tables;
-static int pcreflags = PCRE_NO_AUTO_CAPTURE | PCRE_EXTENDED | PCRE_CASELESS;
+static int pcreflags = PCRE_NO_AUTO_CAPTURE | PCRE_EXTENDED | PCRE_CASELESS | PCRE_UTF8;
#else
static int regflags = REG_NOSUB | REG_EXTENDED | REG_ICASE;
#endif
β> make O_PCRE=1 strip
cc -DPCRE -Wall -Wextra -O3 -D_GNU_SOURCE -D_DEFAULT_SOURCE -o nnn src/nnn.c -lreadline -lpcre -lncursesw
strip nnn
md5-726e18c43362c59fe9107c8d840e68a5
β> ./nnn
same behavior.
I think either the library is not working correctly OR we need to do something extra that I am not aware of. I don't know Russian. Please raise a defect on libpcre and see what they have to say.
Hm, I just retested, and if I filter by using regex (by doing // - the \ in prompt) it filters correctly, while when doing string filtering (when / in prompt) the problem shows.
So, when doing the regex filtering (\ in prompt) the patch helps (I checked without it to confirm).
At the filter prompt:
/ to toggle string and regex: to toggle case-sensitivityWhen the prompt shows /, it's string. When it shows \, it's regex.
Try this without the patch:
Start in string filter mode (default), press : and see if case-insensitive search works.
Testing without patch: in string search mode (/ in prompt):
started:
[1 2 3 4] /test
test
Test
ΡΠ΅ΡΡ
Π’Π΅ΡΡ
str [/], ic [:]
/
search for "te" with default mode, shows both "test" and "Test" as expected:
[1 2 3 4] /test
test
Test
str [/], ic [:]
/te
searching for "te" in case sensitive mode ("noic") shows only "test" as expected:
[1 2 3 4] /test
test
str [/], noic [:]
/te
searching for "ΡΠ΅" in default mode shows only "ΡΠ΅ΡΡ", and not shows "Π’Π΅ΡΡ":
[1 2 3 4] /test
ΡΠ΅ΡΡ
str [/], ic [:]
/ΡΠ΅
searching for "ΡΠ΅" in case insensitive mode ("noic") shows only "ΡΠ΅ΡΡ" as expected:
[1 2 3 4] /test
ΡΠ΅ΡΡ
str [/], noic [:]
/ΡΠ΅
searching for regex "te":
[1 2 3 4] /test
test
Test
regex [/], ic [:]
\te
searching for regex "ΡΠ΅" (without patch):
[1 2 3 4] /test
ΡΠ΅ΡΡ
regex [/], ic [:]
\ΡΠ΅
note, that is tested on latest master. I have 2.9 version installed in system, and surprisingly, regex searching in it works correct:
[1 2 3 4] /test
ΡΠ΅ΡΡ
Π’Π΅ΡΡ
regex [/], ic [:]
\ΡΠ΅
Did you build master with PCRE or without PCRE?
make O_PCRE=1 clean strip
OK. I compiled master without PCRE (and without patch):
sudo make strip install
And here's what I see:
[1 2 3 4] /home/vaio/GitHub/nnn/test
ΡΠ΅ΡΡ
Π’Π΅ΡΡ
regex [/], ic [:]
\ΡΠ΅
Which I think is expected.
My locale output:
$ locale
LANG=en_US.UTF-8
LANGUAGE=en_US:en
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC=en_IN.UTF-8
LC_TIME=en_IN.UTF-8
LC_COLLATE="en_US.UTF-8"
LC_MONETARY=en_IN.UTF-8
LC_MESSAGES="en_US.UTF-8"
LC_PAPER=en_IN.UTF-8
LC_NAME=en_IN.UTF-8
LC_ADDRESS=en_IN.UTF-8
LC_TELEPHONE=en_IN.UTF-8
LC_MEASUREMENT=en_IN.UTF-8
LC_IDENTIFICATION=en_IN.UTF-8
LC_ALL=
For regex that's expected, yes. But string search gives different result.
And yes, when I compile with PCRE (without the pacth), I do see the issue in regex. I think we need the patch for regex.
I can repro the issue with string search with the above examples. In this case regex does not take effect as well.
Also, with string search the issue exists in v2.9 as well.
I think the problem is with using strcasestr. noic (strstr() works fine).
If I see the man page of strstr or strcasestr:
For an explanation of the terms used in this section, see attributes(7).
βββββββββββββββ¬ββββββββββββββββ¬βββββββββββββββββ
βInterface β Attribute β Value β
βββββββββββββββΌββββββββββββββββΌβββββββββββββββββ€
βstrstr() β Thread safety β MT-Safe β
βββββββββββββββΌββββββββββββββββΌβββββββββββββββββ€
βstrcasestr() β Thread safety β MT-Safe locale β
βββββββββββββββ΄ββββββββββββββββ΄βββββββββββββββββ
which essentially tells me strcasestr depends on the locale. @KlzXS @annagrram are you aware of any locale independent api that can do this? Otherwise I think we will have to convert both the strings to lowercase and do the comparison.
converting to lowercase is also locale dependent, so it will not help.
Iirc, normalizing UTF-8 strings is going to require a huge external library to help with normalizing it, and afaik it's not 100% foolproof.
Btw, I would propose that regex keeps the / symbol, and another symbol is found for regular text search. The reason I propose this is because then at least you can copy paste the line and not have to worry that \ will escape something if you paste it into grep or other utilities.
I'm not in sync with master since december since there were some changes that are huge merge conflict for me, so I'm way behind atm, until I can find the time to correct the merge conflicts.
Iirc, normalizing UTF-8 strings is going to require a huge external library to help with normalizing it, and afaik it's not 100% foolproof.
Yes, I think it's not simple to achieve this.
@alosich with the PCRE fix in, I would suggest you use regex (POSIX or PCRE) for this use case. We can document this limitation.
The reason I propose this is because then at least you can copy paste the line and not have to worry that will escape something if you paste it into grep or other utilities.
Hey, it looks cool and is easy to figure. Copy/paste carefully all the time. ;)
I would suggest you use regex (POSIX or PCRE) for this use case. We can document this limitation.
works for me.
I have updated the documentation here: https://github.com/jarun/nnn/wiki#limitation
@KlzXS @0xACE @maximbaz
I have a question on the cfg.trash variable. As it is in the cfg it's saved in sessions. Say at some point the user didn't have NNN_TRASH set and he saved a session. Later he wanted to trash and set NNN_TRASH. However, when he loads the session, cfg.trash would be lost and when he deletes a file it would be unrecoverable.
I think when we say, NNN_TRASH determines the behaviour we should honor the runtime env var instead of the config retrieved from the stored session. So I think we should not save it in the config. What do you guys think?
Implemented at commit ca257e6016c272e2ddb415a0f6427d49d305b354 as I had some time. But this is still open for discussion,
I agree with what you did π
BTW, I am enjoying v3.0 (+ O_NOMOUSE) thoroughly. 3.0 feels like an achievement.
Me too!
+ O_NOMOUSE
Huh, I didn't realize until now that mouse _is_ supported, I never even thought to try to use mouse in nnn before π
I used to realize it now and then when clicking to bring the terminal above other windows.
It reduces memory usage and binary size. On my system I have O_NORL + O_NOMOUSE and the size is 70.1KiB.
If you filter in a context, the filter will be gone when you return to that context after switching away. This was pretty annoying for some work I was doing.
I tried to fix this but ran into a deadlock. It shows the correct results on the screen but stops responding to input :(
diff --git a/src/nnn.c b/src/nnn.c
index 3e161db..9c6a3ba 100644
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -4966,6 +4966,7 @@ begin:
blk_shift = BLK_SHIFT_512;
presel = CONTROL('L');
}
+ matches(g_ctx[cfg.curctx].c_fltr + 1);
#ifdef LINUX_INOTIFY
if (presel != FILTER && inotify_wd == -1)
From what I read, when you change contexts, there's a switch-statement in browse() that has a case for SEL_CTX* and then it jumps to the begin: label and repopulates the directory entry array. I tried adding a call to matches() after this point, but it causes a deadlock whenever you return to a context that was filtered.
Also I now realize that the UI could use work. It's not obvious when you return to a filtered context that you are seeing a subset of directory entries. You can press ^L to remove the filter, but maybe there should be something obvious to warn the user that a filter is in place.
In which version are you? These are all fixed. In v3.0 the filter is retained and applied when you return to a context. And obviously the filter is shown in the filter prompt.
In which version are you?
git master
These are all fixed. In v3.0 the filter is retained and applied when you return to a context. And obviously the filter is shown in the filter prompt.
No it is not.
/ and type a filter queryESC to finalize the filter so you can actually navigate in the context and do things with the files2 to go second context and then press 1 return to first oneThis is what I mean
https://asciinema.org/a/ot4QfHGAl4t9lHPYlUduYkzov
OK. I got the difference between your your use case and mine. I am in _nav-as-you-type_ mode, you are not.
~Commit 3d5391cb53a935ae57775eb7ab8a7cf881e6fee1 should fix this.~
@JustAPerson please test with commit f0f8008014a39e3a849a8b51b709afca90205525. The previous one was not to my liking.
When the below directory in an ext4 partition is entered and the du is toggled
with td, nnn exits with segmentation fault:
File: /home/lo/Desktop/Apollo - loc analysis
Size: 4096 Blocks: 8 IO Block: 4096 directory
Device: 821h/2081d Inode: 21634578 Links: 3
However, when the same directory is copied to another ext4 partition with both
less capacity and less disk usage, the du toggle works fine:
File: /home/Apollo - loc analysis
Size: 4096 Blocks: 8 IO Block: 4096 directory
Device: 803h/2051d Inode: 1845697 Links: 3
@lawnowner I think it's obvious I can't repro it on my system. Please enable debug logs and get your hands dirty.
Also,
@lawnowner another option would be to compile in debug mode and run in gdb. When you get the segfault run bt full to get the line number in which the crash occurred.
Segv happens at the line 710 of nnn.c: *m |= 1 << (nr & 63); . Apparently the issue is introduced with the commint 4a91df950b26660a9d6918cf97ab3f1f9cf7b97b, where the 24-bit hash bitmap that is defined for in-memory hard link detection may not be enough for larger inode numbers: #define HASH_BITS (0xFFFFFF). Using a 32-bit constant prevents the segmentations fault, while also accounting for the maximum number inodes in ext4.
Got it! A 32-bit HASH_BITS will increase the virtual memory usage drastically. So we need to figure a more efficient algo.
@lawnowner ~can you please confirm if the following patch works:~
diff --git a/src/nnn.c b/src/nnn.c
index ea37f2b..3dcf76b 100644
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -702,6 +702,7 @@ static char *xitoa(uint val)
*/
static bool test_set_bit(ull nr)
{
+ nr = nr & HASH_BITS;
ull *m = ((ull *)ihashbmp) + (nr >> 6);
if (*m & (1 << (nr & 63)))
@@ -4179,7 +4180,7 @@ static void launch_app(const char *path, char *newpath)
static int sum_bsize(const char *UNUSED(fpath), const struct stat *sb, int typeflag, struct FTW *UNUSED(ftwbuf))
{
if (sb->st_blocks && (typeflag == FTW_F || typeflag == FTW_D)
- && (sb->st_nlink <= 1 || test_set_bit((ull)sb->st_ino)))
+ && (sb->st_nlink <= 1 || test_set_bit((ull)sb->st_ino + (ull)sb->st_size)))
ent_blocks += sb->st_blocks;
++num_files;
@@ -4189,7 +4190,7 @@ static int sum_bsize(const char *UNUSED(fpath), const struct stat *sb, int typef
static int sum_asize(const char *UNUSED(fpath), const struct stat *sb, int typeflag, struct FTW *UNUSED(ftwbuf))
{
if (sb->st_size && (typeflag == FTW_F || typeflag == FTW_D)
- && (sb->st_nlink <= 1 || test_set_bit((ull)sb->st_ino)))
+ && (sb->st_nlink <= 1 || test_set_bit((ull)sb->st_ino + (ull)sb->st_size)))
ent_blocks += sb->st_size;
++num_files;
@@ -4309,7 +4310,8 @@ static int dentfill(char *path, struct entry **dents)
}
} else {
/* Do not recount hard links */
- if (sb.st_nlink <= 1 || test_set_bit((ull)sb.st_ino))
+ if (sb.st_nlink <= 1
+ || test_set_bit((ull)sb.st_ino + (ull)sb.st_size))
dir_blocks += (cfg.apparentsz ? sb.st_size : sb.st_blocks);
++num_files;
}
@@ -4406,7 +4408,8 @@ static int dentfill(char *path, struct entry **dents)
} else {
dentp->blocks = (cfg.apparentsz ? sb.st_size : sb.st_blocks);
/* Do not recount hard links */
- if (sb.st_nlink <= 1 || test_set_bit((ull)sb.st_ino))
+ if (sb.st_nlink <= 1
+ || test_set_bit((ull)sb.st_ino + (ull)sb.st_size))
dir_blocks += dentp->blocks;
++num_files;
}
@lawnowner ignore the previous patch. Try the following (I have reduced the hash bits further):
diff --git a/src/nnn.c b/src/nnn.c
index ea37f2b..24fe374 100644
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -165,7 +165,7 @@
#define BLK_SHIFT_512 9
/* Detect hardlinks in du */
-#define HASH_BITS (0xFFFFFF)
+#define HASH_BITS (0xFFFF)
#define HASH_OCTETS (HASH_BITS >> 6) /* 2^6 = 64 */
/* Program return codes */
@@ -702,6 +702,7 @@ static char *xitoa(uint val)
*/
static bool test_set_bit(ull nr)
{
+ nr = nr & HASH_BITS;
ull *m = ((ull *)ihashbmp) + (nr >> 6);
if (*m & (1 << (nr & 63)))
@@ -4179,7 +4180,7 @@ static void launch_app(const char *path, char *newpath)
static int sum_bsize(const char *UNUSED(fpath), const struct stat *sb, int typeflag, struct FTW *UNUSED(ftwbuf))
{
if (sb->st_blocks && (typeflag == FTW_F || typeflag == FTW_D)
- && (sb->st_nlink <= 1 || test_set_bit((ull)sb->st_ino)))
+ && (sb->st_nlink <= 1 || test_set_bit((ull)sb->st_ino + (ull)sb->st_size)))
ent_blocks += sb->st_blocks;
++num_files;
@@ -4189,7 +4190,7 @@ static int sum_bsize(const char *UNUSED(fpath), const struct stat *sb, int typef
static int sum_asize(const char *UNUSED(fpath), const struct stat *sb, int typeflag, struct FTW *UNUSED(ftwbuf))
{
if (sb->st_size && (typeflag == FTW_F || typeflag == FTW_D)
- && (sb->st_nlink <= 1 || test_set_bit((ull)sb->st_ino)))
+ && (sb->st_nlink <= 1 || test_set_bit((ull)sb->st_ino + (ull)sb->st_size)))
ent_blocks += sb->st_size;
++num_files;
@@ -4309,7 +4310,8 @@ static int dentfill(char *path, struct entry **dents)
}
} else {
/* Do not recount hard links */
- if (sb.st_nlink <= 1 || test_set_bit((ull)sb.st_ino))
+ if (sb.st_nlink <= 1
+ || test_set_bit((ull)sb.st_ino + (ull)sb.st_size))
dir_blocks += (cfg.apparentsz ? sb.st_size : sb.st_blocks);
++num_files;
}
@@ -4406,7 +4408,8 @@ static int dentfill(char *path, struct entry **dents)
} else {
dentp->blocks = (cfg.apparentsz ? sb.st_size : sb.st_blocks);
/* Do not recount hard links */
- if (sb.st_nlink <= 1 || test_set_bit((ull)sb.st_ino))
+ if (sb.st_nlink <= 1
+ || test_set_bit((ull)sb.st_ino + (ull)sb.st_size))
dir_blocks += dentp->blocks;
++num_files;
}
The segmentation fault returns after decreasing the variable width from ull to ulong at the commit c6cc8a5181c991ccfd7786deb6365cbb7fa95cb8.
You can reproduce the issue with test_set_bit() by setting the nr value in gdb regardless of whether your file system naturally produces it or not, but now the segv occurs even in the system directories (e.g. /usr) when the du toggle is switched.
Yes, I have to reduce the width as well. I had to leave after the change. I'll fix it and update you to confirm.
@lawnowner please confirm with commit 95356681ffc24987daeda46c8fb3fb5b04d9952f. I think it's fixed now.
@jarun I noticed that if you remove a file in nnn with x, the selection goes to the previous file (line above) and not to the next file (line below). This is inconsistent with how text editors like vim work (when you dd a line, your cursor will go the next line), and also this makes it a bit more annoying when you want to delete 3 files, you must click xjxjx or <space><space><space>xs instead of simply xxx.
Do you know if this is something that can be easily done? I tried to look into the code but it's not immediately obvious to me where this selection happens after you delete a file.
@maximbaz I think it can be done easily. I'll make the change.
@maximbaz this should be fixed at commit 76cf0c65d433f5c694ea2fb4c4edb183f7518e58. Please confirm.
@JustAPerson please test with commit f0f8008. The previous one was not to my liking.
This works somewhat.
When you return to a context, now the filter is active (and you can edit the filter), but I see two problems.
ESC to do things with the files in the context again. To have left this context in the first place, we already hit ESC once before we could hit 2 to go to a new context (otherwise the 2 would've become part of the filter). On one hand, this informs the user that there is an active filter but on the other, it's kind of annoying. I'm not sure this is a good UX. I don't think we should leave it like this. RET causes a bug where nnn enters a weird state. It seems to ignore lots of keypresses randomly.Valgrind says this is because of uninitalized memory (these line numbers are f0f80080):
==16737== Memcheck, a memory error detector
==16737== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==16737== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==16737== Command: ./nnn
==16737==
==16737== Conditional jump or move depends on uninitialised value(s)
==16737== at 0x566DE77: __wcsnlen_avx2 (strlen-avx2.S:261)
==16737== by 0x559BEC1: wcsrtombs (wcsrtombs.c:104)
==16737== by 0x5521B20: wcstombs (wcstombs.c:34)
==16737== by 0x110375: filterentries (nnn.c:2541)
==16737== by 0x1186F7: browse (nnn.c:5415)
==16737== by 0x11CAEF: main (nnn.c:6808)
I first noticed this bug on f0f8008014a39e3a849a8b51b709afca90205525 but it occurs on the commit before and also master.
I can find even more undefined behavior on master (these line numbers are from 76cf0c65d433f5c694ea2fb4c4edb183f7518e58):
==17387== Conditional jump or move depends on uninitialised value(s)
==17387== at 0x5505458: internal_utf8_loop (loop.c:298)
==17387== by 0x5505458: __gconv_transform_internal_utf8 (skeleton.c:609)
==17387== by 0x559BEF4: wcsrtombs (wcsrtombs.c:110)
==17387== by 0x5521B20: wcstombs (wcstombs.c:34)
==17387== by 0x110368: filterentries (nnn.c:2563)
==17387== by 0x1187DE: browse (nnn.c:5454)
==17387== by 0x11CBF1: main (nnn.c:6851)
==17387==
==17387== Conditional jump or move depends on uninitialised value(s)
==17387== at 0x566DE77: __wcsnlen_avx2 (strlen-avx2.S:261)
==17387== by 0x559BEC1: wcsrtombs (wcsrtombs.c:104)
==17387== by 0x5521B20: wcstombs (wcstombs.c:34)
==17387== by 0x1100A9: filterentries (nnn.c:2470)
==17387== by 0x1187DE: browse (nnn.c:5454)
==17387== by 0x11CBF1: main (nnn.c:6851)
==17387== Use of uninitialised value of size 8
==17387== at 0x560E6AE: __lll_lock_wait_private (lowlevellock.S:96)
==17387== by 0x55DF6F6: regexec@@GLIBC_2.3.4 (regexec.c:215)
==17387== by 0x10F375: visible_re (nnn.c:2143)
==17387== by 0x10FD0D: fill (nnn.c:2383)
==17387== by 0x10FDC7: matches (nnn.c:2416)
==17387== by 0x110374: filterentries (nnn.c:2570)
==17387== by 0x1187DE: browse (nnn.c:5454)
==17387== by 0x11CBF1: main (nnn.c:6851)
==17387==
==17387== Syscall param futex(futex) contains uninitialised byte(s)
==17387== at 0x560E6AC: __lll_lock_wait_private (lowlevellock.S:95)
==17387== by 0x55DF6F6: regexec@@GLIBC_2.3.4 (regexec.c:215)
==17387== by 0x10F375: visible_re (nnn.c:2143)
==17387== by 0x10FD0D: fill (nnn.c:2383)
==17387== by 0x10FDC7: matches (nnn.c:2416)
==17387== by 0x110374: filterentries (nnn.c:2570)
==17387== by 0x1187DE: browse (nnn.c:5454)
==17387== by 0x11CBF1: main (nnn.c:6851)
I also found a segfault at one point doing some random stuff but that one is harder to replicated.
@maximbaz this should be fixed at commit 76cf0c6. Please confirm.
Confirmed, thanks a lot! π
@JustAPerson
this informs the user that there is an active filter
That's the intention. With different filters applied and 4 contexts open, this is indeed helpful. What problem are you facing? Despite the filter showing there, up, down, enter. control keypresses work seamlessly. You do not need to clear the filter with Esc beforehand.
Once the filter is editable after returning a context, pressing RET causes a bug where nnn enters a weird state. It seems to ignore lots of keypresses randomly.
I can't reproduce this! More detailed steps please. Are you restoring from a session? When you press RET are you hovering on a dir or a file? For me if it's a file, the file is opened, if it's a dir, it's entered.
~I can repro it now.~
@JustAPerson in filterentries() can you uncomment the following 2 lines:
//DPRINTF_D(*ch);
//DPRINTF_S(keyname(*ch));
and see what keypress you get when you press Enter? For me it's 'r` (and ^M).
On 76cf0c65d433f5c694ea2fb4c4edb183f7518e58
ln 2453: *ch=13
ln 2454: keyname(*ch)=^M
*ch=13 is carriage return \r.
I definitely think you should pursue fixing any undefined behavior in nnn, which it seems like there might be a fair bit of. Try exploring -fsanitize.
I will not be responding to this issue further.
@JustAPerson nnn uses a shortcut to remember the last filter in-place in ln. The NULL terminator is also stored in-place however the start of the filter is hidden away. I am not sure your tool sees through that. That's the reason I wanted to concentrate on the issue you see. Anyway, I'm sure someone else will see it and report if you don't have the time.