diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 9d856deb3d..5b0d76706d 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -3043,6 +3043,20 @@
*: "Numeric"
+
+ id: LANG_DISPLAY_SPECIAL_CHARACTER
+ desc: Special character (japanese, accents, etc)
+ user: core
+
+ *: "Special character"
+
+
+ *: "Special character"
+
+
+ *: "Special character"
+
+
id: LANG_PM_MENU
desc: in the display menu
diff --git a/apps/lang/francais.lang b/apps/lang/francais.lang
index be68a68903..0277129a01 100644
--- a/apps/lang/francais.lang
+++ b/apps/lang/francais.lang
@@ -2971,6 +2971,20 @@
*: "Numérique"
+
+ id: LANG_DISPLAY_SPECIAL_CHARACTER
+ desc: Special character (japanese, accents, etc)
+ user: core
+
+ *: "Special character"
+
+
+ *: "Caractère spécial"
+
+
+ *: "Caractère spécial"
+
+
id: LANG_PM_MENU
desc: in the display menu
diff --git a/apps/tagcache.c b/apps/tagcache.c
index 5ee9ff4f9c..fd61d4bc90 100644
--- a/apps/tagcache.c
+++ b/apps/tagcache.c
@@ -234,6 +234,9 @@ static const char * const tag_type_str[] = {
[clause_oneof] = "clause_oneof",
[clause_begins_oneof] = "clause_begins_oneof",
[clause_ends_oneof] = "clause_ends_oneof",
+ [clause_not_oneof] = "clause_not_oneof",
+ [clause_not_begins_oneof] = "clause_not_begins_oneof",
+ [clause_not_ends_oneof] = "clause_not_ends_oneof",
[clause_logical_or] = "clause_logical_or"
};
#define logf_clauses logf
@@ -1441,11 +1444,18 @@ static bool check_against_clause(long numeric, const char *str,
return !str_ends_with(str, clause->str);
case clause_oneof:
return str_oneof(str, clause->str);
+ case clause_not_oneof:
+ return !str_oneof(str, clause->str);
case clause_ends_oneof:
/* Fall-Through */
case clause_begins_oneof:
return str_begins_ends_oneof(str, clause->str,
clause->type == clause_begins_oneof);
+ case clause_not_ends_oneof:
+ /* Fall-Through */
+ case clause_not_begins_oneof:
+ return !str_begins_ends_oneof(str, clause->str,
+ clause->type == clause_not_begins_oneof);
default:
logf("Incorrect tag: %d", clause->type);
}
diff --git a/apps/tagcache.h b/apps/tagcache.h
index a20a13900a..5c510e02e6 100644
--- a/apps/tagcache.h
+++ b/apps/tagcache.h
@@ -74,7 +74,8 @@ enum clause { clause_none, clause_is, clause_is_not, clause_gt, clause_gteq,
clause_lt, clause_lteq, clause_contains, clause_not_contains,
clause_begins_with, clause_not_begins_with, clause_ends_with,
clause_not_ends_with, clause_oneof,
- clause_begins_oneof, clause_ends_oneof,
+ clause_begins_oneof, clause_ends_oneof, clause_not_oneof,
+ clause_not_begins_oneof, clause_not_ends_oneof,
clause_logical_or };
struct tagcache_stat {
diff --git a/apps/tagtree.c b/apps/tagtree.c
index 67abc4e9b8..f414cf3dd4 100644
--- a/apps/tagtree.c
+++ b/apps/tagtree.c
@@ -479,6 +479,9 @@ static int get_clause(int *condition)
CLAUSE('@', '^', clause_begins_oneof),
CLAUSE('@', '$', clause_ends_oneof),
CLAUSE('@', ' ', clause_oneof),
+ CLAUSE('*', '^', clause_not_begins_oneof),
+ CLAUSE('*', '$', clause_not_ends_oneof),
+ CLAUSE('!', '@', clause_not_oneof),
CLAUSE(0, 0, 0) /* sentinel */
};
@@ -1121,9 +1124,9 @@ static void build_firstletter_menu(char *buf, size_t bufsz)
const char * const showsub = /* album subitem for canonicalartist */
((strcasestr(subitem, "artist") == NULL) ? "title" : "album -> title");
- /* Numeric ex: "Numeric" -> album ? album < "A" -> title = "fmt_title" */
- snprintf(buf, bufsz, fmt,
- str(LANG_DISPLAY_NUMERIC), subitem, subitem,'<', 'A', showsub);
+ const char * fmt_numeric ="\"%s\"-> %s ? %s @^ \"0|1|2|3|4|5|6|7|8|9\" -> %s =\"fmt_title\"";
+ snprintf(buf, bufsz, fmt_numeric,
+ str(LANG_DISPLAY_NUMERIC), subitem, subitem, showsub);
if (!alloc_menu_parse_buf(buf, menu_byfirstletter))
{
@@ -1140,6 +1143,16 @@ static void build_firstletter_menu(char *buf, size_t bufsz)
return;
}
}
+
+ const char * fmt_special ="\"%s\"-> %s ? %s *^ \"0|1|2|3|4|5|6|7|8|9\" & "\
+ "%s *^ \"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\" -> %s =\"fmt_title\"";
+ snprintf(buf, bufsz, fmt_special,
+ str(LANG_DISPLAY_SPECIAL_CHARACTER), subitem, subitem, subitem, showsub);
+
+ if (!alloc_menu_parse_buf(buf, menu_byfirstletter))
+ {
+ return;
+ }
}
static bool parse_menu(const char *filename);