blob: a6467b8f6d804584b314764e645c818934433e36 [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>
3" Last Change: 2005 Jul 26
4
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"
71 execute "silent '[,']w " . tmpe
72 " uncompress the temp file: call system("gzip -dn tmp.gz")
73 call system(a:cmd . " " . tmpe)
74 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"
87 setlocal nobin
88 if exists(":lockmarks")
89 execute "silent lockmarks " . l . "r " . tmp
90 else
91 execute "silent " . l . "r " . tmp
92 endif
93
94 " if buffer became empty, delete trailing blank line
95 if empty
96 silent $delete _
97 1
98 endif
99 " delete the temp file and the used buffers
100 call delete(tmp)
101 silent! exe "bwipe " . tmp
102 silent! exe "bwipe " . tmpe
103 let &pm = pm_save
104 let &cpo = cpo_save
105 let &l:ma = ma_save
106 " When uncompressed the whole buffer, do autocommands
107 if empty
108 if &verbose >= 8
109 execute "doau BufReadPost " . expand("%:r")
110 else
111 execute "silent! doau BufReadPost " . expand("%:r")
112 endif
113 endif
114endfun
115
116" After writing compressed file: Compress written file with "cmd"
117fun gzip#write(cmd)
118 " don't do anything if the cmd is not supported
119 if s:check(a:cmd)
120 " Rename the file before compressing it.
121 let nm = resolve(expand("<afile>"))
122 let nmt = s:tempname(nm)
123 if rename(nm, nmt) == 0
124 if exists("b:gzip_comp_arg")
125 call system(a:cmd . " " . b:gzip_comp_arg . " " . nmt)
126 else
127 call system(a:cmd . " " . nmt)
128 endif
129 call rename(nmt . "." . expand("<afile>:e"), nm)
130 endif
131 endif
132endfun
133
134" Before appending to compressed file: Uncompress file with "cmd"
135fun gzip#appre(cmd)
136 " don't do anything if the cmd is not supported
137 if s:check(a:cmd)
138 let nm = expand("<afile>")
139
140 " for gzip check current compression level and set b:gzip_comp_arg.
141 silent! unlet b:gzip_comp_arg
142 if a:cmd[0] == 'g'
143 call s:set_compression(readfile(nm, "b", 1)[0])
144 endif
145
146 " Rename to a weird name to avoid the risk of overwriting another file
147 let nmt = expand("<afile>:p:h") . "/X~=@l9q5"
148 let nmte = nmt . "." . expand("<afile>:e")
149 if rename(nm, nmte) == 0
150 if &patchmode != "" && getfsize(nm . &patchmode) == -1
151 " Create patchmode file by creating the decompressed file new
152 call system(a:cmd . " -c " . nmte . " > " . nmt)
153 call rename(nmte, nm . &patchmode)
154 else
155 call system(a:cmd . " " . nmte)
156 endif
157 call rename(nmt, nm)
158 endif
159 endif
160endfun
161
162" find a file name for the file to be compressed. Use "name" without an
163" extension if possible. Otherwise use a weird name to avoid overwriting an
164" existing file.
165fun s:tempname(name)
166 let fn = fnamemodify(a:name, ":r")
167 if !filereadable(fn) && !isdirectory(fn)
168 return fn
169 endif
170 return fnamemodify(a:name, ":p:h") . "/X~=@l9q5"
171endfun
172
173" vim: set sw=2 :