Template language: Add strcat and strlen builtin functions. Fixes #821935 ([enhancement] priority rule for tailoring too-long filenames)

This commit is contained in:
Kovid Goyal 2011-08-06 10:38:36 -06:00
commit c8011b48c7
2 changed files with 55 additions and 4 deletions

View File

@ -273,7 +273,9 @@ The following functions are available in addition to those described in single-f
* ``print(a, b, ...)`` -- prints the arguments to standard output. Unless you start calibre from the command line (``calibre-debug -g``), the output will go to a black hole. * ``print(a, b, ...)`` -- prints the arguments to standard output. Unless you start calibre from the command line (``calibre-debug -g``), the output will go to a black hole.
* ``raw_field(name)`` -- returns the metadata field named by name without applying any formatting. * ``raw_field(name)`` -- returns the metadata field named by name without applying any formatting.
* ``strcat(a, b, ...)`` -- can take any number of arguments. Returns a string formed by concatenating all the arguments. * ``strcat(a, b, ...)`` -- can take any number of arguments. Returns a string formed by concatenating all the arguments.
* ``strcat_max(max, string1, prefix2, string2, ...)`` -- Returns a string formed by concatenating the arguments. The returned value is initialized to string1. `Prefix, string` pairs are added to the end of the value as long as the resulting string length is less than `max`. String1 is returned even if string1 is longer than max. You can pass as many `prefix, string` pairs as you wish.
* ``strcmp(x, y, lt, eq, gt)`` -- does a case-insensitive comparison x and y as strings. Returns ``lt`` if x < y. Returns ``eq`` if x == y. Otherwise returns ``gt``. * ``strcmp(x, y, lt, eq, gt)`` -- does a case-insensitive comparison x and y as strings. Returns ``lt`` if x < y. Returns ``eq`` if x == y. Otherwise returns ``gt``.
* ``strlen(a)`` -- Returns the length of the string passed as the argument.
* ``substr(str, start, end)`` -- returns the ``start``'th through the ``end``'th characters of ``str``. The first character in ``str`` is the zero'th character. If end is negative, then it indicates that many characters counting from the right. If end is zero, then it indicates the last character. For example, ``substr('12345', 1, 0)`` returns ``'2345'``, and ``substr('12345', 1, -1)`` returns ``'234'``. * ``substr(str, start, end)`` -- returns the ``start``'th through the ``end``'th characters of ``str``. The first character in ``str`` is the zero'th character. If end is negative, then it indicates that many characters counting from the right. If end is zero, then it indicates the last character. For example, ``substr('12345', 1, 0)`` returns ``'2345'``, and ``substr('12345', 1, -1)`` returns ``'234'``.
* ``subtract(x, y)`` -- returns x - y. Throws an exception if either x or y are not numbers. * ``subtract(x, y)`` -- returns x - y. Throws an exception if either x or y are not numbers.
* ``today()`` -- return a date string for today. This value is designed for use in format_date or days_between, but can be manipulated like any other string. The date is in ISO format. * ``today()`` -- return a date string for today. This value is designed for use in format_date or days_between, but can be manipulated like any other string. The date is in ISO format.

View File

@ -136,6 +136,19 @@ class BuiltinStrcat(BuiltinFormatterFunction):
res += args[i] res += args[i]
return res return res
class BuiltinStrlen(BuiltinFormatterFunction):
name = 'strlen'
arg_count = 1
category = 'String Manipulation'
__doc__ = doc = _('strlen(a) -- Returns the length of the string passed as '
'the argument')
def evaluate(self, formatter, kwargs, mi, locals, a):
try:
return len(a)
except:
return -1
class BuiltinAdd(BuiltinFormatterFunction): class BuiltinAdd(BuiltinFormatterFunction):
name = 'add' name = 'add'
arg_count = 2 arg_count = 2
@ -345,6 +358,40 @@ class BuiltinSwitch(BuiltinFormatterFunction):
return args[i+1] return args[i+1]
i += 2 i += 2
class BuiltinStrcatMax(BuiltinFormatterFunction):
name = 'strcat_max'
arg_count = -1
category = 'String Manipulation'
__doc__ = doc = _('strcat_max(max, string1, prefix2, string2, ...) -- '
'Returns a string formed by concatenating the arguments. The '
'returned value is initialized to string1. `Prefix, string` '
'pairs are added to the end of the value as long as the '
'resulting string length is less than `max`. String1 is returned '
'even if string1 is longer than max. You can pass as many '
'`prefix, string` pairs as you wish.')
def evaluate(self, formatter, kwargs, mi, locals, *args):
if len(args) < 2:
raise ValueError(_('strcat_max requires 2 or more arguments'))
if (len(args) % 2) != 0:
raise ValueError(_('strcat_max requires an even number of arguments'))
try:
max = int(args[0])
except:
raise ValueError(_('first argument to strcat_max must be an integer'))
i = 2
result = args[1]
try:
while i < len(args):
if (len(result) + len(args[i]) + len(args[i+1])) > max:
break
result = result + args[i] + args[i+1]
i += 2
except:
pass
return result.strip()
class BuiltinInList(BuiltinFormatterFunction): class BuiltinInList(BuiltinFormatterFunction):
name = 'in_list' name = 'in_list'
arg_count = 5 arg_count = 5
@ -432,7 +479,7 @@ class BuiltinSwapAroundComma(BuiltinFormatterFunction):
'returns val unchanged') 'returns val unchanged')
def evaluate(self, formatter, kwargs, mi, locals, val): def evaluate(self, formatter, kwargs, mi, locals, val):
return re.sub(r'^(.*?),(.*$)', r'\2 \1', val, flags=re.I) return re.sub(r'^(.*?),\s*(.*$)', r'\2 \1', val, flags=re.I).strip()
class BuiltinIfempty(BuiltinFormatterFunction): class BuiltinIfempty(BuiltinFormatterFunction):
name = 'ifempty' name = 'ifempty'
@ -502,7 +549,7 @@ class BuiltinListitem(BuiltinFormatterFunction):
index = int(index) index = int(index)
val = val.split(sep) val = val.split(sep)
try: try:
return val[index] return val[index].strip()
except: except:
return '' return ''
@ -620,7 +667,8 @@ class BuiltinSublist(BuiltinFormatterFunction):
return '' return ''
si = int(start_index) si = int(start_index)
ei = int(end_index) ei = int(end_index)
val = val.split(sep) # allow empty list items so counts are what the user expects
val = [v.strip() for v in val.split(sep)]
try: try:
if ei == 0: if ei == 0:
return sep.join(val[si:]) return sep.join(val[si:])
@ -955,7 +1003,8 @@ _formatter_builtins = [
BuiltinLowercase(), BuiltinMultiply(), BuiltinNot(), BuiltinLowercase(), BuiltinMultiply(), BuiltinNot(),
BuiltinOndevice(), BuiltinOr(), BuiltinPrint(), BuiltinRawField(), BuiltinOndevice(), BuiltinOr(), BuiltinPrint(), BuiltinRawField(),
BuiltinRe(), BuiltinSelect(), BuiltinShorten(), BuiltinStrcat(), BuiltinRe(), BuiltinSelect(), BuiltinShorten(), BuiltinStrcat(),
BuiltinStrcmp(), BuiltinStrInList(), BuiltinSubitems(), BuiltinStrcatMax(),
BuiltinStrcmp(), BuiltinStrInList(), BuiltinStrlen(), BuiltinSubitems(),
BuiltinSublist(),BuiltinSubstr(), BuiltinSubtract(), BuiltinSwapAroundComma(), BuiltinSublist(),BuiltinSubstr(), BuiltinSubtract(), BuiltinSwapAroundComma(),
BuiltinSwitch(), BuiltinTemplate(), BuiltinTest(), BuiltinTitlecase(), BuiltinSwitch(), BuiltinTemplate(), BuiltinTest(), BuiltinTitlecase(),
BuiltinToday(), BuiltinUppercase(), BuiltinToday(), BuiltinUppercase(),