cvsserver: define a tag name character escape mechanism
CVS tags are officially only allowed to use [-_0-9A-Za-f]. Git refs commonly uses other characters, especially [./]. Such characters need to be escaped from CVS in order to be referenced. This just defines functions to escape/unescape names. The functions are not used yet. Signed-off-by: Matthew Ogilvie <mmogilvi_git@miniinfo.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Matthew Ogilvie committed
Oct 13, 2012 at 23:42 UTC
51a7e6dbc9b871ddfd73752e1a1b254e38e4336b
1 file changed
+91
git-cvsserver.perl
+91
@@ -3807,6 +3807,97 @@ sub gethistorydense
3807
return $result;
3808
}
3809
3810
+=head2 escapeRefName
3811
+
3812
+Apply an escape mechanism to compensate for characters that
3813
+git ref names can have that CVS tags can not.
3814
+
3815
+=cut
3816
+sub escapeRefName
3817
+{
3818
+ my($self,$refName)=@_;
3819
+
3820
+ # CVS officially only allows [-_A-Za-z0-9] in tag names (or in
3821
+ # many contexts it can also be a CVS revision number).
3822
+ #
3823
+ # Git tags commonly use '/' and '.' as well, but also handle
3824
+ # anything else just in case:
3825
+ #
3826
+ # = "_-s-" For '/'.
3827
+ # = "_-p-" For '.'.
3828
+ # = "_-u-" For underscore, in case someone wants a literal "_-" in
3829
+ # a tag name.
3830
+ # = "_-xx-" Where "xx" is the hexadecimal representation of the
3831
+ # desired ASCII character byte. (for anything else)
3832
+
3833
+ if(! $refName=~/^[1-9][0-9]*(\.[1-9][0-9]*)*$/)
3834
+ {
3835
+ $refName=~s/_-/_-u--/g;
3836
+ $refName=~s/\./_-p-/g;
3837
+ $refName=~s%/%_-s-%g;
3838
+ $refName=~s/[^-_a-zA-Z0-9]/sprintf("_-%02x-",$1)/eg;
3839
+ }
3840
+}
3841
+
3842
+=head2 unescapeRefName
3843
+
3844
+Undo an escape mechanism to compensate for characters that
3845
+git ref names can have that CVS tags can not.
3846
+
3847
+=cut
3848
+sub unescapeRefName
3849
+{
3850
+ my($self,$refName)=@_;
3851
+
3852
+ # see escapeRefName() for description of escape mechanism.
3853
+
3854
+ $refName=~s/_-([spu]|[0-9a-f][0-9a-f])-/unescapeRefNameChar($1)/eg;
3855
+
3856
+ # allowed tag names
3857
+ # TODO: Perhaps use git check-ref-format, with an in-process cache of
3858
+ # validated names?
3859
+ if( !( $refName=~m%^[^-][-a-zA-Z0-9_/.]*$% ) ||
3860
+ ( $refName=~m%[/.]$% ) ||
3861
+ ( $refName=~/\.lock$/ ) ||
3862
+ ( $refName=~m%\.\.|/\.|[[\\:?*~]|\@\{% ) ) # matching }
3863
+ {
3864
+ # Error:
3865
+ $log->warn("illegal refName: $refName");
3866
+ $refName=undef;
3867
+ }
3868
+ return $refName;
3869
+}
3870
+
3871
+sub unescapeRefNameChar
3872
+{
3873
+ my($char)=@_;
3874
+
3875
+ if($char eq "s")
3876
+ {
3877
+ $char="/";
3878
+ }
3879
+ elsif($char eq "p")
3880
+ {
3881
+ $char=".";
3882
+ }
3883
+ elsif($char eq "u")
3884
+ {
3885
+ $char="_";
3886
+ }
3887
+ elsif($char=~/^[0-9a-f][0-9a-f]$/)
3888
+ {
3889
+ $char=chr(hex($char));
3890
+ }
3891
+ else
3892
+ {
3893
+ # Error case: Maybe it has come straight from user, and
3894
+ # wasn't supposed to be escaped? Restore it the way we got it:
3895
+ $char="_-$char-";
3896
+ }
3897
+
3898
+ return $char;
3899
+}
3900
+
3901
=head2 in_array()
3902
3903
from Array::PAT - mimics the in_array() function