-- Copyright (C) 2002-2003 David Roundy---- This program is free software; you can redistribute it and/or modify-- it under the terms of the GNU General Public License as published by-- the Free Software Foundation; either version 2, or (at your option)-- any later version.---- This program is distributed in the hope that it will be useful,-- but WITHOUT ANY WARRANTY; without even the implied warranty of-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-- GNU General Public License for more details.---- You should have received a copy of the GNU General Public License-- along with this program; see the file COPYING. If not, write to-- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,-- Boston, MA 02110-1301, USA.-- | FileName is an abstract type intended to facilitate the input and output of-- unicode filenames.moduleDarcs.Patch.FileName(FileName(),fp2fn,fn2fp,fn2ps,ps2fn,niceps2fn,fn2niceps,break_on_dir,norm_path,own_name,superName,movedirfilename,encode_white,decode_white,(///),breakup)whereimportSystem.IOimportData.Char(isSpace,chr,ord)importqualifiedCodec.Binary.UTF8.StringasUTF8(encode)importCodec.Binary.UTF8.Generic(toString)importData.Word(Word8())importqualifiedData.ByteString.Char8asBC(unpack,pack)importqualifiedData.ByteStringasB(ByteString,pack)newtypeFileName=FNFilePathderiving(Eq,Ord)encode::[Char]->[Word8]encode=UTF8.encodeinstanceShowFileNamewhereshowsPrecd(FNfp)=showParen(d>app_prec)$showString"fp2fn ".showsPrec(app_prec+1)fpwhereapp_prec=10{-# INLINE fp2fn #-}fp2fn::FilePath->FileNamefp2fnfp=FNfp{-# INLINE fn2fp #-}fn2fp::FileName->FilePathfn2fp(FNfp)=fp{-# INLINE niceps2fn #-}niceps2fn::B.ByteString->FileNameniceps2fn=FN.decode_white.BC.unpack{-# INLINE fn2niceps #-}fn2niceps::FileName->B.ByteStringfn2niceps(FNfp)=BC.pack$encode_whitefp{-# INLINE fn2ps #-}fn2ps::FileName->B.ByteStringfn2ps(FNfp)=B.pack$encode$encode_whitefp{-# INLINE ps2fn #-}ps2fn::B.ByteString->FileNameps2fnps=FN$decode_white$toStringps-- | 'encode_white' translates whitespace in filenames to a darcs-specific-- format (backslash followed by numerical representation according to 'ord').-- Note that backslashes are also escaped since they are used in the encoding.---- > encode_white "hello there" == "hello\32there"-- > encode_white "hello\there" == "hello\\there"encode_white::FilePath->Stringencode_white(c:cs)|isSpacec||c=='\\'='\\':(show$ordc)++"\\"++encode_whitecsencode_white(c:cs)=c:encode_whitecsencode_white[]=[]-- | 'decode_white' interprets the Darcs-specific \"encoded\" filenames-- produced by 'encode_white'---- > decode_white "hello\32there" == "hello there"-- > decode_white "hello\\there" == "hello\there"-- > decode_white "hello\there" == error "malformed filename"decode_white::String->FilePathdecode_white('\\':cs)=casebreak(=='\\')csof(theord,'\\':rest)->chr(readtheord):decode_whiterest_->error"malformed filename"decode_white(c:cs)=c:decode_whitecsdecode_white""=""own_name::FileName->FileNameown_name(FNf)=casebreakLast'/'fofNothing->FNfJust(_,f')->FNf'superName::FileName->FileNamesuperNamefn=casenorm_pathfnofFNf->casebreakLast'/'fofNothing->FN"."Just(d,_)->FNdbreak_on_dir::FileName->Maybe(FileName,FileName)break_on_dir(FNp)=casebreakFirst'/'pofNothing->NothingJust(d,f)|d=="."->break_on_dir$FNf|otherwise->Just(FNd,FNf)norm_path::FileName->FileName-- remove "./"norm_path(FNp)=FN$repath$drop_dotdot$breakupprepath::[String]->Stringrepath[]=""repath[f]=frepath(d:p)=d++"/"++repathpdrop_dotdot::[String]->[String]drop_dotdot("":p)=drop_dotdotpdrop_dotdot(".":p)=drop_dotdotpdrop_dotdot("..":p)="..":(drop_dotdotp)drop_dotdot(_:"..":p)=drop_dotdotpdrop_dotdot(d:p)=casedrop_dotdotpof("..":p')->p'p'->d:p'drop_dotdot[]=[]-- | Split a file path at the slashesbreakup::String->[String]breakupp=casebreak(=='/')pof(d,"")->[d](d,p')->d:breakup(tailp')breakFirst::Char->String->Maybe(String,String)breakFirstcl=bf[]lwherebfa(r:rs)|r==c=Just(reversea,rs)|otherwise=bf(r:a)rsbf_[]=NothingbreakLast::Char->String->Maybe(String,String)breakLastcl=casebreakFirstc(reversel)ofNothing->NothingJust(a,b)->Just(reverseb,reversea)(///)::FileName->FileName->FileName(FN"")///b=norm_pathba///b=norm_path$fp2fn$fn2fpa++"/"++fn2fpbmovedirfilename::FileName->FileName->FileName->FileNamemovedirfilenameoldnewname=ifname'==old'thennewelseiflengthname'>lengthold'&&take(lengthold'+1)name'==old'++"/"thenfp2fn("./"++new'++drop(lengthold')name')elsenamewhereold'=fn2fp$norm_patholdnew'=fn2fp$norm_pathnewname'=fn2fp$norm_pathname