blob: 933d83d090fdf975d82b08befb4a5b3163cd774e [file] [log] [blame]
Bram Moolenaar87e25fd2005-07-27 21:13:01 +00001" Vim autoload file for editing compressed files.
2" Maintainer: Bram Moolenaar <Bram@vim.org>
Bram Moolenaar60a495f2006-10-03 12:44:42 +00003" Last Change: 2006 Oct 03
Bram Moolenaar87e25fd2005-07-27 21:13:01 +00004
5" These functions are used by the gzip plugin.
6
7" Function to check that executing "cmd [-f]" works.
8" The result is cached in s:have_"cmd" for speed.
9fun s:check(cmd)
10 let name = substitute(a:cmd, '\(\S*\).*', '\1', '')
11 if !exists("s:have_" . name)
12 let e = executable(name)
13 if e < 0
14 let r = system(name . " --version")
15 let e = (r !~ "not found" && r != "")
16 endif
17 exe "let s:have_" . name . "=" . e
18 endif
19 exe "return s:have_" . name
20endfun
21
22" Set b:gzip_comp_arg to the gzip argument to be used for compression, based on
23" the flags in the compressed file.
24" The only compression methods that can be detected are max speed (-1) and max
25" compression (-9).
26fun s:set_compression(line)
27 " get the Compression Method
28 let l:cm = char2nr(a:line[2])
29 " if it's 8 (DEFLATE), we can check for the compression level
30 if l:cm == 8
31 " get the eXtra FLags
32 let l:xfl = char2nr(a:line[8])
33 " max compression
34 if l:xfl == 2
35 let b:gzip_comp_arg = "-9"
36 " min compression
37 elseif l:xfl == 4
38 let b:gzip_comp_arg = "-1"
39 endif
40 endif
41endfun
42
43
44" After reading compressed file: Uncompress text in buffer with "cmd"
45fun gzip#read(cmd)
46 " don't do anything if the cmd is not supported
47 if !s:check(a:cmd)
48 return
49 endif
50
51 " for gzip check current compression level and set b:gzip_comp_arg.
52 silent! unlet b:gzip_comp_arg
53 if a:cmd[0] == 'g'
54 call s:set_compression(getline(1))
55 endif
56
57 " make 'patchmode' empty, we don't want a copy of the written file
58 let pm_save = &pm
59 set pm=
60 " remove 'a' and 'A' from 'cpo' to avoid the alternate file changes
61 let cpo_save = &cpo
62 set cpo-=a cpo-=A
63 " set 'modifiable'
64 let ma_save = &ma
65 setlocal ma
66 " when filtering the whole buffer, it will become empty
67 let empty = line("'[") == 1 && line("']") == line("$")
68 let tmp = tempname()
69 let tmpe = tmp . "." . expand("<afile>:e")
70 " write the just read lines to a temp file "'[,']w tmp.gz"
Bram Moolenaar60a495f2006-10-03 12:44:42 +000071 execute "silent '[,']w " . escape(tmpe, ' ')
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000072 " uncompress the temp file: call system("gzip -dn tmp.gz")
Bram Moolenaar60a495f2006-10-03 12:44:42 +000073 call system(a:cmd . " " . s:escape(tmpe))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000074 if !filereadable(tmp)
75 " uncompress didn't work! Keep the compressed file then.
76 echoerr "Error: Could not read uncompressed file"
77 return
78 endif
79 " delete the compressed lines; remember the line number
80 let l = line("'[") - 1
81 if exists(":lockmarks")
82 lockmarks '[,']d _
83 else
84 '[,']d _
85 endif
86 " read in the uncompressed lines "'[-1r tmp"
Bram Moolenaar910f66f2006-04-05 20:41:53 +000087 " Use ++edit if the buffer was empty, keep the 'ff' and 'fenc' options.
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000088 setlocal nobin
89 if exists(":lockmarks")
Bram Moolenaar910f66f2006-04-05 20:41:53 +000090 if empty
91 execute "silent lockmarks " . l . "r ++edit " . tmp
92 else
93 execute "silent lockmarks " . l . "r " . tmp
94 endif
Bram Moolenaar87e25fd2005-07-27 21:13:01 +000095 else
96 execute "silent " . l . "r " . tmp
97 endif
98
99 " if buffer became empty, delete trailing blank line
100 if empty
101 silent $delete _
102 1
103 endif
104 " delete the temp file and the used buffers
105 call delete(tmp)
106 silent! exe "bwipe " . tmp
107 silent! exe "bwipe " . tmpe
108 let &pm = pm_save
109 let &cpo = cpo_save
110 let &l:ma = ma_save
111 " When uncompressed the whole buffer, do autocommands
112 if empty
113 if &verbose >= 8
114 execute "doau BufReadPost " . expand("%:r")
115 else
116 execute "silent! doau BufReadPost " . expand("%:r")
117 endif
118 endif
119endfun
120
121" After writing compressed file: Compress written file with "cmd"
122fun gzip#write(cmd)
123 " don't do anything if the cmd is not supported
124 if s:check(a:cmd)
125 " Rename the file before compressing it.
126 let nm = resolve(expand("<afile>"))
127 let nmt = s:tempname(nm)
128 if rename(nm, nmt) == 0
129 if exists("b:gzip_comp_arg")
Bram Moolenaar60a495f2006-10-03 12:44:42 +0000130 call system(a:cmd . " " . b:gzip_comp_arg . " " . s:escape(nmt))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000131 else
Bram Moolenaar60a495f2006-10-03 12:44:42 +0000132 call system(a:cmd . " " . s:escape(nmt))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000133 endif
134 call rename(nmt . "." . expand("<afile>:e"), nm)
135 endif
136 endif
137endfun
138
139" Before appending to compressed file: Uncompress file with "cmd"
140fun gzip#appre(cmd)
141 " don't do anything if the cmd is not supported
142 if s:check(a:cmd)
143 let nm = expand("<afile>")
144
145 " for gzip check current compression level and set b:gzip_comp_arg.
146 silent! unlet b:gzip_comp_arg
147 if a:cmd[0] == 'g'
148 call s:set_compression(readfile(nm, "b", 1)[0])
149 endif
150
151 " Rename to a weird name to avoid the risk of overwriting another file
152 let nmt = expand("<afile>:p:h") . "/X~=@l9q5"
153 let nmte = nmt . "." . expand("<afile>:e")
154 if rename(nm, nmte) == 0
155 if &patchmode != "" && getfsize(nm . &patchmode) == -1
156 " Create patchmode file by creating the decompressed file new
Bram Moolenaar60a495f2006-10-03 12:44:42 +0000157 call system(a:cmd . " -c " . s:escape(nmte) . " > " . s:escape(nmt))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000158 call rename(nmte, nm . &patchmode)
159 else
Bram Moolenaar60a495f2006-10-03 12:44:42 +0000160 call system(a:cmd . " " . s:escape(nmte))
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000161 endif
162 call rename(nmt, nm)
163 endif
164 endif
165endfun
166
167" find a file name for the file to be compressed. Use "name" without an
168" extension if possible. Otherwise use a weird name to avoid overwriting an
169" existing file.
170fun s:tempname(name)
171 let fn = fnamemodify(a:name, ":r")
172 if !filereadable(fn) && !isdirectory(fn)
173 return fn
174 endif
175 return fnamemodify(a:name, ":p:h") . "/X~=@l9q5"
176endfun
177
Bram Moolenaar60a495f2006-10-03 12:44:42 +0000178fun s:escape(name)
179 " shellescape() was added by patch 7.0.111
180 if v:version > 700 || (v:version == 700 && has('patch111'))
181 return shellescape(a:name)
182 endif
183 return "'" . a:name . "'"
184endfun
185
Bram Moolenaar87e25fd2005-07-27 21:13:01 +0000186" vim: set sw=2 :