+define(nsc_norm_v6, `nsc_norm_v6_z(dnl
+ifelse(regexp($1,`::.*::'),-1,`ifelse(index($1,::),-1,`nsc_norm_v6_nn($1)',`nsc_norm_v6_cc($1)')',`nsc_bad_v6($1)'))')
+# If there is no ::, check the number of :'s
+define(nsc_norm_v6_nn, `ifelse(nsc_extract_colons($1),:::::::,$1,`nsc_bad_v6($1)')')
+# Replace :: by the right number of :'s to get 8 (possibly empty) components
+define(nsc_norm_v6_cc, `regexp($1,`\(.*\)::\(.*\)',`\1'nsc_n_times(eval(9-len(nsc_extract_colons($1))),:)`\2')')
+# Delete everything except colons
+define(nsc_extract_colons, `ifelse(index($1,:),-1,,`:nsc_extract_colons(regexp($1,`\(.*\):\(.*\)',`\1\2'))')')
+# Repeat a given string N times
+define(nsc_n_times, `ifelse($1,0,,`$2`'nsc_n_times(eval($1-1),`$2')')')
+# Pad each component to 4 hex digits and convert them to lowercase
+define(nsc_norm_v6_z, `nsc_norm_v6_digs(translit($1,:,`,'))')
+define(nsc_norm_v6_digs, `nsc_norm_v6_dig($1)`'ifelse($#,1,,:`nsc_norm_v6_digs(shift($@))')')
+define(nsc_norm_v6_dig, `ifelse(eval(len($1) > 4),1,`nsc_bad_v6($1)',`nsc_n_times(eval(4-len($1)),0)`'translit($1,A-F,a-f)')')
+# Report a fatal error in IPv6 address
+define(nsc_bad_v6, `nsc_fatal_error(`Invalid IPv6 address: '$1)')
+
+# Reverse an IPv6 address or block
+
+define(nsc_revaddr6, `substr(nsc_do_revaddr6(nsc_norm_v6($1)),1)')
+define(nsc_do_revaddr6, `ifelse($1,,,substr($1,0,1),:,`nsc_do_revaddr6(substr($1,1))',`nsc_do_revaddr6(substr($1,2)).substr($1,1,1).substr($1,0,1)')')
+define(nsc_revblock6, `nsc_do_revblock6(translit($1,/,`,'))')
+define(nsc_do_revblock6, `substr(nsc_revaddr6($1),dnl
+ifelse(eval($2%4),0,`eval(64-$2/2)',`nsc_fatal_error(`Prefixes must respect hex digit boundary')'))')