# -*- text -*-
#
#  $Id$

#
#  This module performs mathematical calculations:
#
#	Attribute-Name = "%{expr:2 + 3 + &NAS-Port}"
#
#  It supports the following operators (in order of precedence)
#
#	&	binary AND
#	|	binary OR
#	<<	left shift
#	>>	right shift
#	+	addition
#	-	subtraction
#	*	multiply
#	/	divide
#	%%	remainder
#	^	exponentiation
#	(...)	sub-expression
#
#  Operator precedence follows the normal rules.
#  Division by zero means that the entire expression is invalid.
#
#  Note that in versions before 3.0.5, the expression
#  was parsed strictly left to right, and ignored operator
#  precedence.
#
#  It also allows unary negation:	-1
#  And twos complement:			~1
#
#  All calculations are done on signed 63-bit integers.
#  e.g. int64_t.  This should be sufficient for all normal
#  purposes.
#
#  Hex numbers are supported:		0xabcdef
#
#  As with all string expansions, you can nest the expansions:
#
#	%{expr: %{NAS-Port} + 1}
#	%{expr: %{sql:SELECT ... } + 1}
#
#  Attribute references are supported for integer attributes.
#  e.g. &NAS-Port.  The benefit of using attribute references
#  is that the expression is calculated directly on the
#  attribute.  It skips the step of "print to string, and then
#  parse to number".  This means it's a little faster.
#
#  Otherwise, all numbers are decimal.
#

#
#  The module also registers a few paircompare functions, and
#  many string manipulation functions, including:
#
#  rand		get random number from 0 to n-1
#		"%{rand:10}" == "9"
#
#  randstr	get random string built from character classes:
#			c lowercase letters
#			C uppercase letters
#			n numbers
#			a alphanumeric
#			! punctuation
#			. alphanumeric + punctuation
#			s alphanumeric + "./"
#			o characters suitable for OTP (easily confused removed)
#			h binary data as lowercase hex
#			H binary data as uppercase hex
#
#		"%{randstr:CCCC!!cccnnn}" == "IPFL>{saf874"
#		"%{randstr:oooooooo}" == "rfVzyA4y"
#		"%{randstr:hhhh}" == "68d60de3"
#
#  urlquote	quote special characters in URI
#		"%{urlquote:http://example.org/}" == "http%3A%47%47example.org%47"
#
#  urlunquote	unquote URL special characters
#		"%{urlunquote:http%%3A%%47%%47example.org%%47}" == "http://example.org/"
#
#  escape	escape string similar to rlm_sql safe_characters
#		"%{escape:<img>foo.jpg</img>}" == "=60img=62foo.jpg=60/img=62" 
#
#  unescape	reverse of escape
#		"%{unescape:=60img=62foo.jpg=60/img=62}" == "<img>foo.jpg</img>"
#
#  tolower	convert to lowercase
#		"%{tolower:Bar}" == "bar"
#
#  toupper	convert to uppercase
#		"%{toupper:Foo}" == "FOO"
#
#  md5		get md5sum hash
#		"%{md5:foo}" == "acbd18db4cc2f85cedef654fccc4a4d8"
#		
#  sha1		get sha1 hash
#		"%{sha1:foo}" == "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"
#
#  sha256	get sha256 hash
#		"%{sha256:foo}" == "2c26b46b68ffc68ff99b453c1d30413413422d706..."
#
#  sha512	get sha512 hash
#		"%{sha512:foo}" == "f7fbba6e0636f890e56fbbf3283e524c6fa3204ae29838..."
#
#  hmacmd5	generate HMAC-MD5 of string
#		"%{hmacmd5:foo bar}" == "31b6db9e5eb4addb42f1a6ca07367adc"
#
#  hmacsha1	generate HMAC-SHA1 of string
#		"%{hmacsha1:foo bar}" == "85d155c55ed286a300bd1cf124de08d87e914f3a"
#
#  crypt	encrypt with a salt: %{crypt:salt:password}
#		"%{crypt:aa:foo}" == "aaKNIEDOaueR6"
#		"%{crypt:$1$abcdefgh:foo}" == "$1$abcdefgh$XxzGe9Muun7wTYbZO4sdr0"
#		"%{crypt:$5$%{randstr:aaaaaaaaaaaaaaaa}:foo}" == "$1$fu4P2fcAdo9gM..."
#
#  pairs	serialize attributes as comma-delimited string
#		"%{pairs:request:}" == "User-Name = 'foo', User-Password = 'bar', ..."
#
#  base64	encode string as base64
#		"%{base64:foo}" == "Zm9v"
#
#  base64tohex	convert base64 to hex
#		"%{base64tohex:Zm9v}" == "666f6f"
#
#  explode	split an attribute into multiple new attributes based on a delimiter
#		"%{explode:&ref <delim>}"
#
#  nexttime	calculate number of seconds until next n hour(s), day(s), week(s), year(s)
#		if it were 16:18, %{nexttime:1h} would expand to 2520
#
#  lasttime	calculate number of seconds until last n hour(s), day(s), week(s), year(s)
#		if it were 16:18, %{lasttime:1h} would expand to 4680
#
#  lpad		left-pad a string
#		if User-Name is "foo": "%{lpad:&User-Name 6 x}" == "xxxfoo"
#
#  rpad		right-pad a string
#		if User-Name is "foo": "%{rpad:&User-Name 5 -}" == "foo--"
#
#  concat 	concatenate a set of attributes, separated by a character.
#		"%{concat:foo[*] ;}"
#

expr {
	#
	# Characters that will not be encoded by the %{escape}
	# xlat function.
	#
	safe_characters = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /äéöüàâæçèéêëîïôœùûüaÿÄÉÖÜßÀÂÆÇÈÉÊËÎÏÔŒÙÛÜŸ"
}
