blob: dc670dbd1489be2b52c1a80a49983fc02ab25da9 [file] [log] [blame]
Bram Moolenaara5792f52005-11-23 21:25:05 +00001" tar.vim: Handles browsing tarfiles
2" AUTOLOAD PORTION
Bram Moolenaarff034192013-04-24 18:51:19 +02003" Date: Apr 17, 2013
4" Version: 29
5" Maintainer: Charles E Campbell <NdrOchip@ScampbellPfamily.AbizM-NOSPAM>
Bram Moolenaara5792f52005-11-23 21:25:05 +00006" License: Vim License (see vim's :help license)
Bram Moolenaar87e25fd2005-07-27 21:13:01 +00007"
Bram Moolenaara5792f52005-11-23 21:25:05 +00008" Contains many ideas from Michael Toren's <tar.vim>
Bram Moolenaar87e25fd2005-07-27 21:13:01 +00009"
Bram Moolenaarff034192013-04-24 18:51:19 +020010" Copyright: Copyright (C) 2005-2011 Charles E. Campbell {{{1
Bram Moolenaara5792f52005-11-23 21:25:05 +000011" Permission is hereby granted to use and distribute this code,
12" with or without modifications, provided that this copyright
13" notice is copied with it. Like anything else that's free,
Bram Moolenaar8c8de832008-06-24 22:58:06 +000014" tar.vim and tarPlugin.vim are provided *as is* and comes
15" with no warranty of any kind, either expressed or implied.
16" By using this plugin, you agree that in no event will the
17" copyright holder be liable for any damages resulting from
18" the use of this software.
Bram Moolenaar5c736222010-01-06 20:54:52 +010019" call inputsave()|call input("Press <cr> to continue")|call inputrestore()
Bram Moolenaarab194812005-09-14 21:40:12 +000020" ---------------------------------------------------------------------
Bram Moolenaarc81e5e72007-05-05 18:24:42 +000021" Load Once: {{{1
Bram Moolenaar5c736222010-01-06 20:54:52 +010022if &cp || exists("g:loaded_tar")
Bram Moolenaara5792f52005-11-23 21:25:05 +000023 finish
24endif
Bram Moolenaarff034192013-04-24 18:51:19 +020025let g:loaded_tar= "v29"
Bram Moolenaar5c736222010-01-06 20:54:52 +010026if v:version < 702
27 echohl WarningMsg
28 echo "***warning*** this version of tar needs vim 7.2"
29 echohl Normal
30 finish
Bram Moolenaar8c8de832008-06-24 22:58:06 +000031endif
Bram Moolenaar5c736222010-01-06 20:54:52 +010032let s:keepcpo= &cpo
33set cpo&vim
Bram Moolenaarff034192013-04-24 18:51:19 +020034"DechoTabOn
Bram Moolenaar5c736222010-01-06 20:54:52 +010035"call Decho("loading autoload/tar.vim")
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000036
Bram Moolenaara5792f52005-11-23 21:25:05 +000037" ---------------------------------------------------------------------
38" Default Settings: {{{1
39if !exists("g:tar_browseoptions")
40 let g:tar_browseoptions= "Ptf"
41endif
42if !exists("g:tar_readoptions")
43 let g:tar_readoptions= "OPxf"
44endif
Bram Moolenaar910f66f2006-04-05 20:41:53 +000045if !exists("g:tar_cmd")
46 let g:tar_cmd= "tar"
47endif
Bram Moolenaara5792f52005-11-23 21:25:05 +000048if !exists("g:tar_writeoptions")
49 let g:tar_writeoptions= "uf"
50endif
Bram Moolenaar251e1912011-06-19 05:09:16 +020051if !exists("g:netrw_cygwin")
52 if has("win32") || has("win95") || has("win64") || has("win16")
53 if &shell =~ '\%(\<bash\>\|\<zsh\>\)\%(\.exe\)\=$'
54 let g:netrw_cygwin= 1
55 else
56 let g:netrw_cygwin= 0
57 endif
58 else
59 let g:netrw_cygwin= 0
60 endif
61endif
Bram Moolenaar5c736222010-01-06 20:54:52 +010062if !exists("g:tar_copycmd")
63 if !exists("g:netrw_localcopycmd")
64 if has("win32") || has("win95") || has("win64") || has("win16")
65 if g:netrw_cygwin
66 let g:netrw_localcopycmd= "cp"
67 else
68 let g:netrw_localcopycmd= "copy"
69 endif
70 elseif has("unix") || has("macunix")
71 let g:netrw_localcopycmd= "cp"
72 else
73 let g:netrw_localcopycmd= ""
74 endif
75 endif
76 let g:tar_copycmd= g:netrw_localcopycmd
77endif
Bram Moolenaar5c736222010-01-06 20:54:52 +010078if !exists("g:tar_extractcmd")
79 let g:tar_extractcmd= "tar -xf"
80endif
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000081
Bram Moolenaar8c8de832008-06-24 22:58:06 +000082" set up shell quoting character
83if !exists("g:tar_shq")
Bram Moolenaarff034192013-04-24 18:51:19 +020084 if exists("+shq") && exists("&shq") && &shq != ""
Bram Moolenaar8c8de832008-06-24 22:58:06 +000085 let g:tar_shq= &shq
86 elseif has("win32") || has("win95") || has("win64") || has("win16")
87 if exists("g:netrw_cygwin") && g:netrw_cygwin
88 let g:tar_shq= "'"
89 else
90 let g:tar_shq= '"'
91 endif
92 else
93 let g:tar_shq= "'"
94 endif
95" call Decho("g:tar_shq<".g:tar_shq.">")
96endif
97
Bram Moolenaara5792f52005-11-23 21:25:05 +000098" ----------------
99" Functions: {{{1
100" ----------------
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000101
Bram Moolenaara5792f52005-11-23 21:25:05 +0000102" ---------------------------------------------------------------------
103" tar#Browse: {{{2
104fun! tar#Browse(tarfile)
105" call Dfunc("tar#Browse(tarfile<".a:tarfile.">)")
Bram Moolenaarbba577a2005-11-28 23:05:55 +0000106 let repkeep= &report
107 set report=10
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000108
Bram Moolenaara5792f52005-11-23 21:25:05 +0000109 " sanity checks
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000110 if !executable(g:tar_cmd)
Bram Moolenaarc81e5e72007-05-05 18:24:42 +0000111 redraw!
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000112 echohl Error | echo '***error*** (tar#Browse) "'.g:tar_cmd.'" not available on your system'
Bram Moolenaarbba577a2005-11-28 23:05:55 +0000113 let &report= repkeep
Bram Moolenaara5792f52005-11-23 21:25:05 +0000114" call Dret("tar#Browse")
115 return
116 endif
117 if !filereadable(a:tarfile)
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000118" call Decho('a:tarfile<'.a:tarfile.'> not filereadable')
Bram Moolenaara5792f52005-11-23 21:25:05 +0000119 if a:tarfile !~# '^\a\+://'
Bram Moolenaar3e496b02016-09-25 22:11:48 +0200120 " if it's an url, don't complain, let url-handlers such as vim do its thing
Bram Moolenaarc81e5e72007-05-05 18:24:42 +0000121 redraw!
Bram Moolenaara5792f52005-11-23 21:25:05 +0000122 echohl Error | echo "***error*** (tar#Browse) File not readable<".a:tarfile.">" | echohl None
Bram Moolenaara5792f52005-11-23 21:25:05 +0000123 endif
Bram Moolenaarbba577a2005-11-28 23:05:55 +0000124 let &report= repkeep
Bram Moolenaara5792f52005-11-23 21:25:05 +0000125" call Dret("tar#Browse : file<".a:tarfile."> not readable")
126 return
127 endif
128 if &ma != 1
129 set ma
130 endif
Bram Moolenaar7fc0c062010-08-10 21:43:35 +0200131 let b:tarfile= a:tarfile
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000132
Bram Moolenaara5792f52005-11-23 21:25:05 +0000133 setlocal noswapfile
134 setlocal buftype=nofile
135 setlocal bufhidden=hide
136 setlocal nobuflisted
137 setlocal nowrap
138 set ft=tar
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000139
Bram Moolenaara5792f52005-11-23 21:25:05 +0000140 " give header
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000141" call Decho("printing header")
Bram Moolenaar8c8de832008-06-24 22:58:06 +0000142 let lastline= line("$")
143 call setline(lastline+1,'" tar.vim version '.g:loaded_tar)
144 call setline(lastline+2,'" Browsing tarfile '.a:tarfile)
145 call setline(lastline+3,'" Select a file with cursor and press ENTER')
Bram Moolenaar251e1912011-06-19 05:09:16 +0200146 keepj $put =''
Bram Moolenaar6be7f872012-01-20 21:08:56 +0100147 keepj sil! 0d
Bram Moolenaar251e1912011-06-19 05:09:16 +0200148 keepj $
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000149
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000150 let tarfile= a:tarfile
Bram Moolenaarff034192013-04-24 18:51:19 +0200151 if has("win32unix") && executable("cygpath")
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000152 " assuming cygwin
Bram Moolenaar5c736222010-01-06 20:54:52 +0100153 let tarfile=substitute(system("cygpath -u ".shellescape(tarfile,0)),'\n$','','e')
Bram Moolenaara5792f52005-11-23 21:25:05 +0000154 endif
Bram Moolenaar20aac6c2018-09-02 21:07:30 +0200155
Bram Moolenaard68071d2006-05-02 22:08:30 +0000156 let curlast= line("$")
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000157 if tarfile =~# '\.\(gz\|tgz\)$'
Bram Moolenaard4a1aab2018-09-08 15:10:34 +0200158 let gzip_command = s:get_gzip_command(tarfile)
Bram Moolenaar5c736222010-01-06 20:54:52 +0100159" call Decho("1: exe silent r! gzip -d -c -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - ")
Bram Moolenaar20aac6c2018-09-02 21:07:30 +0200160 exe "sil! r! " . gzip_command . " -d -c -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
Bram Moolenaar8c8de832008-06-24 22:58:06 +0000161 elseif tarfile =~# '\.lrp'
Bram Moolenaar5c736222010-01-06 20:54:52 +0100162" call Decho("2: exe silent r! cat -- ".shellescape(tarfile,1)."|gzip -d -c -|".g:tar_cmd." -".g:tar_browseoptions." - ")
Bram Moolenaard4a1aab2018-09-08 15:10:34 +0200163 exe "sil! r! cat -- ".shellescape(tarfile,1)."|gzip -d -c -|".g:tar_cmd." -".g:tar_browseoptions." - "
Bram Moolenaar6be7f872012-01-20 21:08:56 +0100164 elseif tarfile =~# '\.\(bz2\|tbz\|tb2\)$'
Bram Moolenaar5c736222010-01-06 20:54:52 +0100165" call Decho("3: exe silent r! bzip2 -d -c -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - ")
Bram Moolenaar251e1912011-06-19 05:09:16 +0200166 exe "sil! r! bzip2 -d -c -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
Bram Moolenaar6be7f872012-01-20 21:08:56 +0100167 elseif tarfile =~# '\.\(lzma\|tlz\)$'
Bram Moolenaar5c736222010-01-06 20:54:52 +0100168" call Decho("3: exe silent r! lzma -d -c -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - ")
Bram Moolenaar251e1912011-06-19 05:09:16 +0200169 exe "sil! r! lzma -d -c -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
Bram Moolenaar477db062010-07-28 18:17:41 +0200170 elseif tarfile =~# '\.\(xz\|txz\)$'
171" call Decho("3: exe silent r! xz --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - ")
Bram Moolenaar251e1912011-06-19 05:09:16 +0200172 exe "sil! r! xz --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_browseoptions." - "
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000173 else
Bram Moolenaared39e1d2008-08-09 17:55:22 +0000174 if tarfile =~ '^\s*-'
Bram Moolenaar5c736222010-01-06 20:54:52 +0100175 " A file name starting with a dash is taken as an option. Prepend ./ to avoid that.
Bram Moolenaared39e1d2008-08-09 17:55:22 +0000176 let tarfile = substitute(tarfile, '-', './-', '')
177 endif
Bram Moolenaar5c736222010-01-06 20:54:52 +0100178" call Decho("4: exe silent r! ".g:tar_cmd." -".g:tar_browseoptions." ".shellescape(tarfile,0))
Bram Moolenaar251e1912011-06-19 05:09:16 +0200179 exe "sil! r! ".g:tar_cmd." -".g:tar_browseoptions." ".shellescape(tarfile,1)
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000180 endif
181 if v:shell_error != 0
Bram Moolenaarc81e5e72007-05-05 18:24:42 +0000182 redraw!
Bram Moolenaard68071d2006-05-02 22:08:30 +0000183 echohl WarningMsg | echo "***warning*** (tar#Browse) please check your g:tar_browseoptions<".g:tar_browseoptions.">"
Bram Moolenaard68071d2006-05-02 22:08:30 +0000184" call Dret("tar#Browse : a:tarfile<".a:tarfile.">")
Bram Moolenaard68071d2006-05-02 22:08:30 +0000185 return
186 endif
Bram Moolenaarc81e5e72007-05-05 18:24:42 +0000187 if line("$") == curlast || ( line("$") == (curlast + 1) && getline("$") =~ '\c\%(warning\|error\|inappropriate\|unrecognized\)')
188 redraw!
Bram Moolenaard68071d2006-05-02 22:08:30 +0000189 echohl WarningMsg | echo "***warning*** (tar#Browse) ".a:tarfile." doesn't appear to be a tar file" | echohl None
Bram Moolenaar251e1912011-06-19 05:09:16 +0200190 keepj sil! %d
Bram Moolenaard68071d2006-05-02 22:08:30 +0000191 let eikeep= &ei
192 set ei=BufReadCmd,FileReadCmd
Bram Moolenaarc236c162008-07-13 17:41:49 +0000193 exe "r ".fnameescape(a:tarfile)
Bram Moolenaard68071d2006-05-02 22:08:30 +0000194 let &ei= eikeep
Bram Moolenaar251e1912011-06-19 05:09:16 +0200195 keepj sil! 1d
Bram Moolenaard68071d2006-05-02 22:08:30 +0000196" call Dret("tar#Browse : a:tarfile<".a:tarfile.">")
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000197 return
198 endif
Bram Moolenaara5792f52005-11-23 21:25:05 +0000199
200 setlocal noma nomod ro
201 noremap <silent> <buffer> <cr> :call <SID>TarBrowseSelect()<cr>
202
Bram Moolenaarbba577a2005-11-28 23:05:55 +0000203 let &report= repkeep
Bram Moolenaar7fc0c062010-08-10 21:43:35 +0200204" call Dret("tar#Browse : b:tarfile<".b:tarfile.">")
Bram Moolenaarab194812005-09-14 21:40:12 +0000205endfun
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000206
Bram Moolenaarab194812005-09-14 21:40:12 +0000207" ---------------------------------------------------------------------
Bram Moolenaara5792f52005-11-23 21:25:05 +0000208" TarBrowseSelect: {{{2
209fun! s:TarBrowseSelect()
Bram Moolenaar7fc0c062010-08-10 21:43:35 +0200210" call Dfunc("TarBrowseSelect() b:tarfile<".b:tarfile."> curfile<".expand("%").">")
Bram Moolenaarbba577a2005-11-28 23:05:55 +0000211 let repkeep= &report
212 set report=10
Bram Moolenaara5792f52005-11-23 21:25:05 +0000213 let fname= getline(".")
214" call Decho("fname<".fname.">")
215
Bram Moolenaared39e1d2008-08-09 17:55:22 +0000216 if !exists("g:tar_secure") && fname =~ '^\s*-\|\s\+-'
217 redraw!
Bram Moolenaar5c736222010-01-06 20:54:52 +0100218 echohl WarningMsg | echo '***warning*** (tar#BrowseSelect) rejecting tarfile member<'.fname.'> because of embedded "-"'
Bram Moolenaared39e1d2008-08-09 17:55:22 +0000219" call Dret('tar#BrowseSelect : rejecting tarfile member<'.fname.'> because of embedded "-"')
220 return
221 endif
222
Bram Moolenaara5792f52005-11-23 21:25:05 +0000223 " sanity check
224 if fname =~ '^"'
Bram Moolenaarbba577a2005-11-28 23:05:55 +0000225 let &report= repkeep
Bram Moolenaara5792f52005-11-23 21:25:05 +0000226" call Dret("TarBrowseSelect")
227 return
228 endif
229
Bram Moolenaar7fc0c062010-08-10 21:43:35 +0200230 " about to make a new window, need to use b:tarfile
231 let tarfile= b:tarfile
Bram Moolenaara5792f52005-11-23 21:25:05 +0000232 let curfile= expand("%")
Bram Moolenaarff034192013-04-24 18:51:19 +0200233 if has("win32unix") && executable("cygpath")
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000234 " assuming cygwin
Bram Moolenaar5c736222010-01-06 20:54:52 +0100235 let tarfile=substitute(system("cygpath -u ".shellescape(tarfile,0)),'\n$','','e')
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000236 endif
Bram Moolenaara5792f52005-11-23 21:25:05 +0000237
238 new
Bram Moolenaar8c8de832008-06-24 22:58:06 +0000239 if !exists("g:tar_nomax") || g:tar_nomax == 0
240 wincmd _
241 endif
Bram Moolenaara5792f52005-11-23 21:25:05 +0000242 let s:tblfile_{winnr()}= curfile
Bram Moolenaar8c8de832008-06-24 22:58:06 +0000243 call tar#Read("tarfile:".tarfile.'::'.fname,1)
Bram Moolenaara5792f52005-11-23 21:25:05 +0000244 filetype detect
Bram Moolenaarff034192013-04-24 18:51:19 +0200245 set nomod
246 exe 'com! -buffer -nargs=? -complete=file TarDiff :call tar#Diff(<q-args>,"'.fnameescape(fname).'")'
Bram Moolenaara5792f52005-11-23 21:25:05 +0000247
Bram Moolenaarbba577a2005-11-28 23:05:55 +0000248 let &report= repkeep
Bram Moolenaara5792f52005-11-23 21:25:05 +0000249" call Dret("TarBrowseSelect : s:tblfile_".winnr()."<".s:tblfile_{winnr()}.">")
250endfun
251
252" ---------------------------------------------------------------------
253" tar#Read: {{{2
254fun! tar#Read(fname,mode)
255" call Dfunc("tar#Read(fname<".a:fname.">,mode=".a:mode.")")
Bram Moolenaarbba577a2005-11-28 23:05:55 +0000256 let repkeep= &report
257 set report=10
Bram Moolenaar8c8de832008-06-24 22:58:06 +0000258 let tarfile = substitute(a:fname,'tarfile:\(.\{-}\)::.*$','\1','')
259 let fname = substitute(a:fname,'tarfile:.\{-}::\(.*\)$','\1','')
Bram Moolenaarff034192013-04-24 18:51:19 +0200260 if has("win32unix") && executable("cygpath")
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000261 " assuming cygwin
Bram Moolenaar5c736222010-01-06 20:54:52 +0100262 let tarfile=substitute(system("cygpath -u ".shellescape(tarfile,0)),'\n$','','e')
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000263 endif
264" call Decho("tarfile<".tarfile.">")
265" call Decho("fname<".fname.">")
Bram Moolenaara5792f52005-11-23 21:25:05 +0000266
Bram Moolenaar5c736222010-01-06 20:54:52 +0100267 if fname =~ '\.bz2$' && executable("bzcat")
268 let decmp= "|bzcat"
269 let doro = 1
270 elseif fname =~ '\.gz$' && executable("zcat")
Bram Moolenaar8c8de832008-06-24 22:58:06 +0000271 let decmp= "|zcat"
272 let doro = 1
Bram Moolenaar5c736222010-01-06 20:54:52 +0100273 elseif fname =~ '\.lzma$' && executable("lzcat")
274 let decmp= "|lzcat"
Bram Moolenaar8c8de832008-06-24 22:58:06 +0000275 let doro = 1
Bram Moolenaar477db062010-07-28 18:17:41 +0200276 elseif fname =~ '\.xz$' && executable("xzcat")
277 let decmp= "|xzcat"
278 let doro = 1
Bram Moolenaara5792f52005-11-23 21:25:05 +0000279 else
Bram Moolenaar8c8de832008-06-24 22:58:06 +0000280 let decmp=""
281 let doro = 0
Bram Moolenaar477db062010-07-28 18:17:41 +0200282 if fname =~ '\.bz2$\|\.gz$\|\.lzma$\|\.xz$\|\.zip$\|\.Z$'
Bram Moolenaar8c8de832008-06-24 22:58:06 +0000283 setlocal bin
284 endif
Bram Moolenaara5792f52005-11-23 21:25:05 +0000285 endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +0000286
Bram Moolenaared39e1d2008-08-09 17:55:22 +0000287 if exists("g:tar_secure")
288 let tar_secure= " -- "
Bram Moolenaar8c8de832008-06-24 22:58:06 +0000289 else
Bram Moolenaared39e1d2008-08-09 17:55:22 +0000290 let tar_secure= " "
291 endif
Bram Moolenaar20aac6c2018-09-02 21:07:30 +0200292
Bram Moolenaar5c736222010-01-06 20:54:52 +0100293 if tarfile =~# '\.bz2$'
294" call Decho("7: exe silent r! bzip2 -d -c ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp)
Bram Moolenaar251e1912011-06-19 05:09:16 +0200295 exe "sil! r! bzip2 -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
Bram Moolenaar5c736222010-01-06 20:54:52 +0100296 elseif tarfile =~# '\.\(gz\|tgz\)$'
Bram Moolenaard4a1aab2018-09-08 15:10:34 +0200297 let gzip_command = s:get_gzip_command(tarfile)
Bram Moolenaar5c736222010-01-06 20:54:52 +0100298" call Decho("5: exe silent r! gzip -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd.' -'.g:tar_readoptions.' - '.tar_secure.shellescape(fname,1))
Bram Moolenaar20aac6c2018-09-02 21:07:30 +0200299 exe "sil! r! " . gzip_command . " -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
Bram Moolenaared39e1d2008-08-09 17:55:22 +0000300 elseif tarfile =~# '\.lrp$'
Bram Moolenaar5c736222010-01-06 20:54:52 +0100301" call Decho("6: exe silent r! cat ".shellescape(tarfile,1)." | gzip -d -c - | ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp)
Bram Moolenaard4a1aab2018-09-08 15:10:34 +0200302 exe "sil! r! cat -- ".shellescape(tarfile,1)." | gzip -d -c - | ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
Bram Moolenaar5c736222010-01-06 20:54:52 +0100303 elseif tarfile =~# '\.lzma$'
304" call Decho("7: exe silent r! lzma -d -c ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp)
Bram Moolenaar251e1912011-06-19 05:09:16 +0200305 exe "sil! r! lzma -d -c -- ".shellescape(tarfile,1)."| ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
Bram Moolenaar477db062010-07-28 18:17:41 +0200306 elseif tarfile =~# '\.\(xz\|txz\)$'
307" call Decho("3: exe silent r! xz --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp)
Bram Moolenaar251e1912011-06-19 05:09:16 +0200308 exe "sil! r! xz --decompress --stdout -- ".shellescape(tarfile,1)." | ".g:tar_cmd." -".g:tar_readoptions." - ".tar_secure.shellescape(fname,1).decmp
Bram Moolenaared39e1d2008-08-09 17:55:22 +0000309 else
310 if tarfile =~ '^\s*-'
Bram Moolenaar5c736222010-01-06 20:54:52 +0100311 " A file name starting with a dash is taken as an option. Prepend ./ to avoid that.
Bram Moolenaared39e1d2008-08-09 17:55:22 +0000312 let tarfile = substitute(tarfile, '-', './-', '')
313 endif
Bram Moolenaar5c736222010-01-06 20:54:52 +0100314" call Decho("8: exe silent r! ".g:tar_cmd." -".g:tar_readoptions.tar_secure.shellescape(tarfile,1)." ".shellescape(fname,1).decmp)
315 exe "silent r! ".g:tar_cmd." -".g:tar_readoptions.shellescape(tarfile,1)." ".tar_secure.shellescape(fname,1).decmp
Bram Moolenaar8c8de832008-06-24 22:58:06 +0000316 endif
317
318 if doro
319 " because the reverse process of compressing changed files back into the tarball is not currently supported
320 setlocal ro
321 endif
322
Bram Moolenaar7fc0c062010-08-10 21:43:35 +0200323 let b:tarfile= a:fname
Bram Moolenaarc236c162008-07-13 17:41:49 +0000324 exe "file tarfile::".fnameescape(fname)
Bram Moolenaara5792f52005-11-23 21:25:05 +0000325
326 " cleanup
Bram Moolenaar251e1912011-06-19 05:09:16 +0200327 keepj sil! 0d
Bram Moolenaara5792f52005-11-23 21:25:05 +0000328 set nomod
329
Bram Moolenaarbba577a2005-11-28 23:05:55 +0000330 let &report= repkeep
Bram Moolenaar7fc0c062010-08-10 21:43:35 +0200331" call Dret("tar#Read : b:tarfile<".b:tarfile.">")
Bram Moolenaara5792f52005-11-23 21:25:05 +0000332endfun
333
334" ---------------------------------------------------------------------
335" tar#Write: {{{2
336fun! tar#Write(fname)
Bram Moolenaar7fc0c062010-08-10 21:43:35 +0200337" call Dfunc("tar#Write(fname<".a:fname.">) b:tarfile<".b:tarfile."> tblfile_".winnr()."<".s:tblfile_{winnr()}.">")
Bram Moolenaarbba577a2005-11-28 23:05:55 +0000338 let repkeep= &report
339 set report=10
Bram Moolenaara5792f52005-11-23 21:25:05 +0000340
Bram Moolenaared39e1d2008-08-09 17:55:22 +0000341 if !exists("g:tar_secure") && a:fname =~ '^\s*-\|\s\+-'
342 redraw!
Bram Moolenaar5c736222010-01-06 20:54:52 +0100343 echohl WarningMsg | echo '***warning*** (tar#Write) rejecting tarfile member<'.a:fname.'> because of embedded "-"'
Bram Moolenaared39e1d2008-08-09 17:55:22 +0000344" call Dret('tar#Write : rejecting tarfile member<'.fname.'> because of embedded "-"')
345 return
346 endif
347
Bram Moolenaarab194812005-09-14 21:40:12 +0000348 " sanity checks
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000349 if !executable(g:tar_cmd)
Bram Moolenaarc81e5e72007-05-05 18:24:42 +0000350 redraw!
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000351 echohl Error | echo '***error*** (tar#Browse) "'.g:tar_cmd.'" not available on your system'
Bram Moolenaarbba577a2005-11-28 23:05:55 +0000352 let &report= repkeep
Bram Moolenaarab194812005-09-14 21:40:12 +0000353" call Dret("tar#Write")
354 return
355 endif
356 if !exists("*mkdir")
Bram Moolenaarc81e5e72007-05-05 18:24:42 +0000357 redraw!
Bram Moolenaara5792f52005-11-23 21:25:05 +0000358 echohl Error | echo "***error*** (tar#Write) sorry, mkdir() doesn't work on your system" | echohl None
Bram Moolenaarbba577a2005-11-28 23:05:55 +0000359 let &report= repkeep
Bram Moolenaarab194812005-09-14 21:40:12 +0000360" call Dret("tar#Write")
361 return
362 endif
363
364 let curdir= getcwd()
365 let tmpdir= tempname()
366" call Decho("orig tempname<".tmpdir.">")
367 if tmpdir =~ '\.'
368 let tmpdir= substitute(tmpdir,'\.[^.]*$','','e')
369 endif
370" call Decho("tmpdir<".tmpdir.">")
371 call mkdir(tmpdir,"p")
372
373 " attempt to change to the indicated directory
374 try
Bram Moolenaar8c8de832008-06-24 22:58:06 +0000375 exe "cd ".fnameescape(tmpdir)
Bram Moolenaarab194812005-09-14 21:40:12 +0000376 catch /^Vim\%((\a\+)\)\=:E344/
Bram Moolenaarc81e5e72007-05-05 18:24:42 +0000377 redraw!
Bram Moolenaara5792f52005-11-23 21:25:05 +0000378 echohl Error | echo "***error*** (tar#Write) cannot cd to temporary directory" | Echohl None
Bram Moolenaarbba577a2005-11-28 23:05:55 +0000379 let &report= repkeep
Bram Moolenaarab194812005-09-14 21:40:12 +0000380" call Dret("tar#Write")
381 return
382 endtry
383" call Decho("current directory now: ".getcwd())
384
Bram Moolenaara5792f52005-11-23 21:25:05 +0000385 " place temporary files under .../_ZIPVIM_/
386 if isdirectory("_ZIPVIM_")
387 call s:Rmdir("_ZIPVIM_")
Bram Moolenaarab194812005-09-14 21:40:12 +0000388 endif
Bram Moolenaara5792f52005-11-23 21:25:05 +0000389 call mkdir("_ZIPVIM_")
390 cd _ZIPVIM_
Bram Moolenaarab194812005-09-14 21:40:12 +0000391" call Decho("current directory now: ".getcwd())
392
Bram Moolenaar7fc0c062010-08-10 21:43:35 +0200393 let tarfile = substitute(b:tarfile,'tarfile:\(.\{-}\)::.*$','\1','')
394 let fname = substitute(b:tarfile,'tarfile:.\{-}::\(.*\)$','\1','')
Bram Moolenaara5792f52005-11-23 21:25:05 +0000395
Bram Moolenaar20aac6c2018-09-02 21:07:30 +0200396 let gzip_command = s:get_gzip_command(tarfile)
397
Bram Moolenaara5792f52005-11-23 21:25:05 +0000398 " handle compressed archives
Bram Moolenaar5c736222010-01-06 20:54:52 +0100399 if tarfile =~# '\.bz2'
400 call system("bzip2 -d -- ".shellescape(tarfile,0))
401 let tarfile = substitute(tarfile,'\.bz2','','e')
402 let compress= "bzip2 -- ".shellescape(tarfile,0)
403" call Decho("compress<".compress.">")
404 elseif tarfile =~# '\.gz'
Bram Moolenaar20aac6c2018-09-02 21:07:30 +0200405 call system(gzip_command . " -d -- ".shellescape(tarfile,0))
Bram Moolenaara5792f52005-11-23 21:25:05 +0000406 let tarfile = substitute(tarfile,'\.gz','','e')
Bram Moolenaar5c736222010-01-06 20:54:52 +0100407 let compress= "gzip -- ".shellescape(tarfile,0)
408" call Decho("compress<".compress.">")
Bram Moolenaara5792f52005-11-23 21:25:05 +0000409 elseif tarfile =~# '\.tgz'
Bram Moolenaar20aac6c2018-09-02 21:07:30 +0200410 call system(gzip_command . " -d -- ".shellescape(tarfile,0))
Bram Moolenaara5792f52005-11-23 21:25:05 +0000411 let tarfile = substitute(tarfile,'\.tgz','.tar','e')
Bram Moolenaar5c736222010-01-06 20:54:52 +0100412 let compress= "gzip -- ".shellescape(tarfile,0)
Bram Moolenaara5792f52005-11-23 21:25:05 +0000413 let tgz = 1
Bram Moolenaared39e1d2008-08-09 17:55:22 +0000414" call Decho("compress<".compress.">")
Bram Moolenaar477db062010-07-28 18:17:41 +0200415 elseif tarfile =~# '\.xz'
416 call system("xz -d -- ".shellescape(tarfile,0))
417 let tarfile = substitute(tarfile,'\.xz','','e')
418 let compress= "xz -- ".shellescape(tarfile,0)
419" call Decho("compress<".compress.">")
420 elseif tarfile =~# '\.lzma'
421 call system("lzma -d -- ".shellescape(tarfile,0))
422 let tarfile = substitute(tarfile,'\.lzma','','e')
423 let compress= "lzma -- ".shellescape(tarfile,0)
424" call Decho("compress<".compress.">")
Bram Moolenaarab194812005-09-14 21:40:12 +0000425 endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +0000426" call Decho("tarfile<".tarfile.">")
Bram Moolenaarab194812005-09-14 21:40:12 +0000427
Bram Moolenaarab194812005-09-14 21:40:12 +0000428 if v:shell_error != 0
Bram Moolenaarc81e5e72007-05-05 18:24:42 +0000429 redraw!
Bram Moolenaara5792f52005-11-23 21:25:05 +0000430 echohl Error | echo "***error*** (tar#Write) sorry, unable to update ".tarfile." with ".fname | echohl None
Bram Moolenaarab194812005-09-14 21:40:12 +0000431 else
Bram Moolenaara5792f52005-11-23 21:25:05 +0000432
433" call Decho("tarfile<".tarfile."> fname<".fname.">")
434
Bram Moolenaar1cbe5f72005-12-29 22:51:09 +0000435 if fname =~ '/'
436 let dirpath = substitute(fname,'/[^/]\+$','','e')
Bram Moolenaarff034192013-04-24 18:51:19 +0200437 if has("win32unix") && executable("cygpath")
Bram Moolenaar5c736222010-01-06 20:54:52 +0100438 let dirpath = substitute(system("cygpath ".shellescape(dirpath, 0)),'\n','','e')
Bram Moolenaar1cbe5f72005-12-29 22:51:09 +0000439 endif
440 call mkdir(dirpath,"p")
441 endif
Bram Moolenaara5792f52005-11-23 21:25:05 +0000442 if tarfile !~ '/'
443 let tarfile= curdir.'/'.tarfile
444 endif
Bram Moolenaared39e1d2008-08-09 17:55:22 +0000445 if tarfile =~ '^\s*-'
446 " A file name starting with a dash may be taken as an option. Prepend ./ to avoid that.
447 let tarfile = substitute(tarfile, '-', './-', '')
448 endif
Bram Moolenaara5792f52005-11-23 21:25:05 +0000449" call Decho("tarfile<".tarfile."> fname<".fname.">")
450
Bram Moolenaared39e1d2008-08-09 17:55:22 +0000451 if exists("g:tar_secure")
452 let tar_secure= " -- "
453 else
454 let tar_secure= " "
455 endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +0000456 exe "w! ".fnameescape(fname)
Bram Moolenaarff034192013-04-24 18:51:19 +0200457 if has("win32unix") && executable("cygpath")
Bram Moolenaar5c736222010-01-06 20:54:52 +0100458 let tarfile = substitute(system("cygpath ".shellescape(tarfile,0)),'\n','','e')
Bram Moolenaara5792f52005-11-23 21:25:05 +0000459 endif
460
461 " delete old file from tarfile
Bram Moolenaar5c736222010-01-06 20:54:52 +0100462" call Decho("system(".g:tar_cmd." --delete -f ".shellescape(tarfile,0)." -- ".shellescape(fname,0).")")
463 call system(g:tar_cmd." --delete -f ".shellescape(tarfile,0).tar_secure.shellescape(fname,0))
Bram Moolenaara5792f52005-11-23 21:25:05 +0000464 if v:shell_error != 0
Bram Moolenaarc81e5e72007-05-05 18:24:42 +0000465 redraw!
Bram Moolenaar8c8de832008-06-24 22:58:06 +0000466 echohl Error | echo "***error*** (tar#Write) sorry, unable to update ".fnameescape(tarfile)." with ".fnameescape(fname) | echohl None
Bram Moolenaara5792f52005-11-23 21:25:05 +0000467 else
468
469 " update tarfile with new file
Bram Moolenaar5c736222010-01-06 20:54:52 +0100470" call Decho(g:tar_cmd." -".g:tar_writeoptions." ".shellescape(tarfile,0).tar_secure.shellescape(fname,0))
471 call system(g:tar_cmd." -".g:tar_writeoptions." ".shellescape(tarfile,0).tar_secure.shellescape(fname,0))
Bram Moolenaara5792f52005-11-23 21:25:05 +0000472 if v:shell_error != 0
Bram Moolenaarc81e5e72007-05-05 18:24:42 +0000473 redraw!
Bram Moolenaar8c8de832008-06-24 22:58:06 +0000474 echohl Error | echo "***error*** (tar#Write) sorry, unable to update ".fnameescape(tarfile)." with ".fnameescape(fname) | echohl None
Bram Moolenaara5792f52005-11-23 21:25:05 +0000475 elseif exists("compress")
476" call Decho("call system(".compress.")")
477 call system(compress)
478 if exists("tgz")
479" call Decho("rename(".tarfile.".gz,".substitute(tarfile,'\.tar$','.tgz','e').")")
480 call rename(tarfile.".gz",substitute(tarfile,'\.tar$','.tgz','e'))
481 endif
482 endif
483 endif
484
485 " support writing tarfiles across a network
486 if s:tblfile_{winnr()} =~ '^\a\+://'
487" call Decho("handle writing <".tarfile."> across network to <".s:tblfile_{winnr()}.">")
488 let tblfile= s:tblfile_{winnr()}
489 1split|enew
Bram Moolenaar5c736222010-01-06 20:54:52 +0100490 let binkeep= &l:binary
Bram Moolenaara5792f52005-11-23 21:25:05 +0000491 let eikeep = &ei
492 set binary ei=all
Bram Moolenaarc236c162008-07-13 17:41:49 +0000493 exe "e! ".fnameescape(tarfile)
Bram Moolenaara5792f52005-11-23 21:25:05 +0000494 call netrw#NetWrite(tblfile)
Bram Moolenaar5c736222010-01-06 20:54:52 +0100495 let &ei = eikeep
496 let &l:binary = binkeep
Bram Moolenaara5792f52005-11-23 21:25:05 +0000497 q!
498 unlet s:tblfile_{winnr()}
499 endif
Bram Moolenaarab194812005-09-14 21:40:12 +0000500 endif
501
502 " cleanup and restore current directory
503 cd ..
Bram Moolenaara5792f52005-11-23 21:25:05 +0000504 call s:Rmdir("_ZIPVIM_")
Bram Moolenaarc236c162008-07-13 17:41:49 +0000505 exe "cd ".fnameescape(curdir)
Bram Moolenaarab194812005-09-14 21:40:12 +0000506 setlocal nomod
507
Bram Moolenaarbba577a2005-11-28 23:05:55 +0000508 let &report= repkeep
Bram Moolenaarab194812005-09-14 21:40:12 +0000509" call Dret("tar#Write")
510endfun
511
512" ---------------------------------------------------------------------
Bram Moolenaarff034192013-04-24 18:51:19 +0200513" tar#Diff: {{{2
514fun! tar#Diff(userfname,fname)
515" call Dfunc("tar#Diff(userfname<".a:userfname."> fname<".a:fname.")")
516 let fname= a:fname
517 if a:userfname != ""
518 let fname= a:userfname
519 endif
520 if filereadable(fname)
521 " sets current file (from tarball) for diff'ing
522 " splits window vertically
523 " opens original file, sets it for diff'ing
524 " sets up b:tardiff_otherbuf variables so each buffer knows about the other (for closing purposes)
525 diffthis
526 wincmd v
527 exe "e ".fnameescape(fname)
528 diffthis
529 else
530 redraw!
531 echo "***warning*** unable to read file<".fname.">"
532 endif
533" call Dret("tar#Diff")
534endfun
535
536" ---------------------------------------------------------------------
Bram Moolenaar5c736222010-01-06 20:54:52 +0100537" s:Rmdir: {{{2
Bram Moolenaarab194812005-09-14 21:40:12 +0000538fun! s:Rmdir(fname)
539" call Dfunc("Rmdir(fname<".a:fname.">)")
540 if has("unix")
Bram Moolenaar5c736222010-01-06 20:54:52 +0100541 call system("/bin/rm -rf -- ".shellescape(a:fname,0))
Bram Moolenaarab194812005-09-14 21:40:12 +0000542 elseif has("win32") || has("win95") || has("win64") || has("win16")
543 if &shell =~? "sh$"
Bram Moolenaar5c736222010-01-06 20:54:52 +0100544 call system("/bin/rm -rf -- ".shellescape(a:fname,0))
Bram Moolenaarab194812005-09-14 21:40:12 +0000545 else
Bram Moolenaar5c736222010-01-06 20:54:52 +0100546 call system("del /S ".shellescape(a:fname,0))
Bram Moolenaarab194812005-09-14 21:40:12 +0000547 endif
548 endif
549" call Dret("Rmdir")
550endfun
551
Bram Moolenaar8c8de832008-06-24 22:58:06 +0000552" ---------------------------------------------------------------------
Bram Moolenaar5c736222010-01-06 20:54:52 +0100553" tar#Vimuntar: installs a tarball in the user's .vim / vimfiles directory {{{2
554fun! tar#Vimuntar(...)
555" call Dfunc("tar#Vimuntar() a:0=".a:0." a:1<".(exists("a:1")? a:1 : "-n/a-").">")
556 let tarball = expand("%")
557" call Decho("tarball<".tarball.">")
558 let tarbase = substitute(tarball,'\..*$','','')
559" call Decho("tarbase<".tarbase.">")
560 let tarhome = expand("%:p")
561 if has("win32") || has("win95") || has("win64") || has("win16")
562 let tarhome= substitute(tarhome,'\\','/','g')
563 endif
564 let tarhome= substitute(tarhome,'/[^/]*$','','')
565" call Decho("tarhome<".tarhome.">")
566 let tartail = expand("%:t")
567" call Decho("tartail<".tartail.">")
568 let curdir = getcwd()
569" call Decho("curdir <".curdir.">")
570 " set up vimhome
571 if a:0 > 0 && a:1 != ""
572 let vimhome= a:1
573 else
574 let vimhome= vimball#VimballHome()
575 endif
576" call Decho("vimhome<".vimhome.">")
577
578" call Decho("curdir<".curdir."> vimhome<".vimhome.">")
579 if simplify(curdir) != simplify(vimhome)
580 " copy (possibly compressed) tarball to .vim/vimfiles
581" call Decho(netrw#WinPath(g:tar_copycmd)." ".shellescape(tartail)." ".shellescape(vimhome))
582 call system(netrw#WinPath(g:tar_copycmd)." ".shellescape(tartail)." ".shellescape(vimhome))
583" call Decho("exe cd ".fnameescape(vimhome))
584 exe "cd ".fnameescape(vimhome)
585 endif
586" call Decho("getcwd<".getcwd().">")
587
588 " if necessary, decompress the tarball; then, extract it
589 if tartail =~ '\.tgz'
Bram Moolenaard4a1aab2018-09-08 15:10:34 +0200590 let gzip_command = s:get_gzip_command(tarfile)
591 if executable(gzip_command)
592 silent exe "!" . gzip_command . " -d ".shellescape(tartail)
Bram Moolenaar20aac6c2018-09-02 21:07:30 +0200593 elseif executable("gunzip")
Bram Moolenaar5c736222010-01-06 20:54:52 +0100594 silent exe "!gunzip ".shellescape(tartail)
595 elseif executable("gzip")
596 silent exe "!gzip -d ".shellescape(tartail)
Bram Moolenaarc236c162008-07-13 17:41:49 +0000597 else
Bram Moolenaar5c736222010-01-06 20:54:52 +0100598 echoerr "unable to decompress<".tartail."> on this sytem"
599 if simplify(curdir) != simplify(tarhome)
600 " remove decompressed tarball, restore directory
601" call Decho("delete(".tartail.".tar)")
602 call delete(tartail.".tar")
603" call Decho("exe cd ".fnameescape(curdir))
604 exe "cd ".fnameescape(curdir)
605 endif
606" call Dret("tar#Vimuntar")
607 return
Bram Moolenaarc236c162008-07-13 17:41:49 +0000608 endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +0000609 else
Bram Moolenaar5c736222010-01-06 20:54:52 +0100610 call vimball#Decompress(tartail,0)
Bram Moolenaar8c8de832008-06-24 22:58:06 +0000611 endif
Bram Moolenaar5c736222010-01-06 20:54:52 +0100612 let extractcmd= netrw#WinPath(g:tar_extractcmd)
613" call Decho("system(".extractcmd." ".shellescape(tarbase.".tar").")")
614 call system(extractcmd." ".shellescape(tarbase.".tar"))
615
616 " set up help
617 if filereadable("doc/".tarbase.".txt")
618" call Decho("exe helptags ".getcwd()."/doc")
619 exe "helptags ".getcwd()."/doc"
620 endif
621
622 if simplify(tarhome) != simplify(vimhome)
623 " remove decompressed tarball, restore directory
624 call delete(vimhome."/".tarbase.".tar")
625 exe "cd ".fnameescape(curdir)
626 endif
627
628" call Dret("tar#Vimuntar")
Bram Moolenaar8c8de832008-06-24 22:58:06 +0000629endfun
630
Bram Moolenaar20aac6c2018-09-02 21:07:30 +0200631func s:get_gzip_command(file)
Bram Moolenaard4a1aab2018-09-08 15:10:34 +0200632 " Try using the "file" command to get the actual compression type, since
633 " there is no standard way for the naming: ".tgz", ".tbz", ".txz", etc.
634 " If the "file" command doesn't work fall back to just using the file name.
635 if a:file =~# 'z$'
636 let filetype = system('file ' . a:file)
637 if filetype =~ 'bzip2 compressed' && executable('bzip2')
638 return 'bzip2'
639 endif
640 if filetype =~ 'XZ compressed' && executable('xz')
641 return 'xz'
642 endif
643 endif
644 if a:file =~# 'bz2$'
Bram Moolenaar20aac6c2018-09-02 21:07:30 +0200645 return 'bzip2'
646 endif
Bram Moolenaard4a1aab2018-09-08 15:10:34 +0200647 if a:file =~# 'xz$'
648 return 'xz'
649 endif
Bram Moolenaar20aac6c2018-09-02 21:07:30 +0200650 return 'gzip'
651endfunc
652
Bram Moolenaar5c736222010-01-06 20:54:52 +0100653" =====================================================================
Bram Moolenaara5792f52005-11-23 21:25:05 +0000654" Modelines And Restoration: {{{1
655let &cpo= s:keepcpo
656unlet s:keepcpo
Bram Moolenaar8c8de832008-06-24 22:58:06 +0000657" vim:ts=8 fdm=marker