1 Support for parallel decompression. |
1 Support for parallel decompression. |
2 Written by Mihael Gerdts <[email protected]> |
2 Written by Mihael Gerdts <[email protected]> |
3 |
3 |
4 These changes should be sent upstream. |
4 These changes have been sent upstream. |
5 |
5 |
6 --- pigz-2.3.3/Makefile.orig 2016-09-26 11:06:54.000000000 +0000 |
6 --- pigz-2.3.4/Makefile.orig 2017-03-02 13:32:39.612576924 +0000 |
7 +++ pigz-2.3.3/Makefile 2016-09-26 13:16:05.000000000 +0000 |
7 +++ pigz-2.3.4/Makefile 2017-03-02 13:32:51.018629392 +0000 |
8 @@ -70,6 +70,15 @@ |
8 @@ -71,6 +71,15 @@ |
9 compress -f < pigz.c | ./unpigz | cmp - pigz.c ;\ |
9 compress -f < pigz.c | ./unpigz | cmp - pigz.c ;\ |
10 fi |
10 fi |
11 @rm -f pigz.c.gz pigz.c.zz pigz.c.zip |
11 @rm -f pigz.c.gz pigz.c.zz pigz.c.zip |
12 + @rm -rf d/1 d/2 |
12 + @rm -rf d/1 d/2 |
13 + (mkdir -p d/1; cd d/1; tar xzf ../../../../pigz-2.3.3.tar.gz; \ |
13 + (mkdir -p d/1; cd d/1; tar xzf ../../../../pigz-2.3.3.tar.gz; \ |
19 + ../pigz -dzrp 4 -X %f.idx 1; diff -r 1 2) |
19 + ../pigz -dzrp 4 -X %f.idx 1; diff -r 1 2) |
20 + @rm -rf d/1 d/2 |
20 + @rm -rf d/1 d/2 |
21 |
21 |
22 tests: dev test |
22 tests: dev test |
23 ./pigzn -kf pigz.c ; ./pigz -t pigz.c.gz |
23 ./pigzn -kf pigz.c ; ./pigz -t pigz.c.gz |
24 --- pigz-2.3.3/pigz.1.orig 2016-09-26 11:07:52.000000000 +0000 |
24 --- pigz-2.3.4/pigz.1.orig 2017-03-02 13:33:31.420259920 +0000 |
25 +++ pigz-2.3.3/pigz.1 2016-09-26 11:12:03.000000000 +0000 |
25 +++ pigz-2.3.4/pigz.1 2017-03-02 13:33:41.537522623 +0000 |
26 @@ -185,6 +185,14 @@ |
26 @@ -188,6 +188,14 @@ |
27 .B -V --version |
27 .B -V --version |
28 Show the version of pigz. |
28 Show the version of pigz. -vV also shows the zlib version. |
29 .TP |
29 .TP |
30 +.B -X --index file |
30 +.B -X --index file |
31 +During compression, create an index that can be used for parallel |
31 +During compression, create an index that can be used for parallel |
32 +decompression. During decompression, use the specified index file for parallel |
32 +decompression. During decompression, use the specified index file for parallel |
33 +decompression. Each occurrence of %f and %z are replaced by the uncompressed |
33 +decompression. Each occurrence of %f and %z are replaced by the uncompressed |
36 +compressed file. |
36 +compressed file. |
37 +.TP |
37 +.TP |
38 .B -z --zlib |
38 .B -z --zlib |
39 Compress to zlib (.zz) instead of gzip format. |
39 Compress to zlib (.zz) instead of gzip format. |
40 .TP |
40 .TP |
41 --- pigz-2.3.3/pigz.c.orig 2016-09-26 11:07:43.000000000 +0000 |
41 --- pigz-2.3.4/pigz.c.orig 2017-03-02 13:26:45.154085766 +0000 |
42 +++ pigz-2.3.3/pigz.c 2016-09-27 08:09:45.122201079 +0000 |
42 +++ pigz-2.3.4/pigz.c 2017-03-02 13:29:35.979415416 +0000 |
43 @@ -218,14 +218,27 @@ |
43 @@ -224,14 +224,27 @@ |
44 the --independent or -i option, so that the blocks can be decompressed |
44 the --independent or -i option, so that the blocks can be decompressed |
45 independently for partial error recovery or for random access. |
45 independently for partial error recovery or for random access. |
46 |
46 |
47 - Decompression can't be parallelized over an arbitrary number of processors |
47 - Decompression can't be parallelized over an arbitrary number of processors |
48 - like compression can be, at least not without specially prepared deflate |
48 - like compression can be, at least not without specially prepared deflate |
71 + per-file checksum is compared to the checksum in the stream's trailer. |
71 + per-file checksum is compared to the checksum in the stream's trailer. |
72 + |
72 + |
73 pigz requires zlib 1.2.1 or later to allow setting the dictionary when doing |
73 pigz requires zlib 1.2.1 or later to allow setting the dictionary when doing |
74 raw deflate. Since zlib 1.2.3 corrects security vulnerabilities in zlib |
74 raw deflate. Since zlib 1.2.3 corrects security vulnerabilities in zlib |
75 version 1.2.1 and 1.2.2, conditionals check for zlib 1.2.3 or later during |
75 version 1.2.1 and 1.2.2, conditionals check for zlib 1.2.3 or later during |
76 @@ -260,7 +273,7 @@ |
76 @@ -266,7 +279,7 @@ |
77 jobs until instructed to return. When a job is pulled, the dictionary, if |
77 jobs until instructed to return. When a job is pulled, the dictionary, if |
78 provided, will be loaded into the deflate engine and then that input buffer |
78 provided, will be loaded into the deflate engine and then that input buffer |
79 is dropped for reuse. Then the input data is compressed into an output |
79 is dropped for reuse. Then the input data is compressed into an output |
80 - buffer that grows in size if necessary to hold the compressed data. The job |
80 - buffer that grows in size if necessary to hold the compressed data. The job |
81 + buffer that grows in size if necessary to hold the compressed data. The job |
81 + buffer that grows in size if necessary to hold the compressed data. The job |
82 is then put into the write job list, sorted by the sequence number. The |
82 is then put into the write job list, sorted by the sequence number. The |
83 compress thread however continues to calculate the check value on the input |
83 compress thread however continues to calculate the check value on the input |
84 data, either a CRC-32 or Adler-32, possibly in parallel with the write |
84 data, either a CRC-32 or Adler-32, possibly in parallel with the write |
85 @@ -286,13 +299,14 @@ |
85 @@ -292,13 +305,14 @@ |
86 can't get way ahead of the write thread and build up a large backlog of |
86 can't get way ahead of the write thread and build up a large backlog of |
87 unwritten compressed data. The write thread will write the compressed data, |
87 unwritten compressed data. The write thread will write the compressed data, |
88 drop the output buffer, and then wait for the check value to be unlocked |
88 drop the output buffer, and then wait for the check value to be unlocked |
89 - by the compress thread. Then the write thread combines the check value for |
89 - by the compress thread. Then the write thread combines the check value for |
90 - this chunk with the total check value for eventual use in the trailer. If |
90 - this chunk with the total check value for eventual use in the trailer. If |
102 + write thread writes the appropriate header and trailer around the compressed |
102 + write thread writes the appropriate header and trailer around the compressed |
103 + data. |
103 + data. |
104 |
104 |
105 The input and output buffers are reused through their collection in pools. |
105 The input and output buffers are reused through their collection in pools. |
106 Each buffer has a use count, which when decremented to zero returns the |
106 Each buffer has a use count, which when decremented to zero returns the |
107 @@ -341,6 +355,9 @@ |
107 @@ -347,6 +361,9 @@ |
108 #if __STDC_VERSION__-0 >= 199901L || __GNUC__-0 >= 3 |
108 #if __STDC_VERSION__-0 >= 199901L || __GNUC__-0 >= 3 |
109 # include <inttypes.h> /* intmax_t */ |
109 # include <inttypes.h> /* intmax_t */ |
110 #endif |
110 #endif |
111 +#include <stddef.h> /* offsetof() */ |
111 +#include <stddef.h> /* offsetof() */ |
112 +#include <sys/mman.h> /* mmap() */ |
112 +#include <sys/mman.h> /* mmap() */ |
113 +#include <netinet/in.h> /* htonl() */ |
113 +#include <netinet/in.h> /* htonl() */ |
114 |
114 |
115 #ifdef DEBUG |
115 #ifdef PIGZ_DEBUG |
116 # if defined(__APPLE__) |
116 # if defined(__APPLE__) |
117 @@ -473,9 +490,11 @@ |
117 @@ -490,9 +507,11 @@ |
118 char *prog; /* name by which pigz was invoked */ |
118 char *prog; /* name by which pigz was invoked */ |
119 int ind; /* input file descriptor */ |
119 int ind; /* input file descriptor */ |
120 int outd; /* output file descriptor */ |
120 int outd; /* output file descriptor */ |
121 + int idxd; /* index file descriptor */ |
121 + int idxd; /* index file descriptor */ |
122 char *inf; /* input file name (allocated) */ |
122 char *inf; /* input file name (allocated) */ |
124 char *outf; /* output file name (allocated) */ |
124 char *outf; /* output file name (allocated) */ |
125 + char *index; /* index file name template (may have %f, %z) */ |
125 + char *index; /* index file name template (may have %f, %z) */ |
126 int verbosity; /* 0 = quiet, 1 = normal, 2 = verbose, 3 = trace */ |
126 int verbosity; /* 0 = quiet, 1 = normal, 2 = verbose, 3 = trace */ |
127 int headis; /* 1 to store name, 2 to store date, 3 both */ |
127 int headis; /* 1 to store name, 2 to store date, 3 both */ |
128 int pipeout; /* write output to stdout even if file */ |
128 int pipeout; /* write output to stdout even if file */ |
129 @@ -620,7 +639,7 @@ |
129 @@ -837,12 +856,15 @@ |
130 |
|
131 local void yarn_free(void *ptr) |
|
132 { |
|
133 - return free_track(&mem_track, ptr); |
|
134 + free_track(&mem_track, ptr); |
|
135 } |
|
136 #endif |
|
137 |
|
138 @@ -820,12 +839,15 @@ |
|
139 |
130 |
140 #endif |
131 #endif |
141 |
132 |
142 +local void idx_abort(void); |
133 +local void idx_abort(void); |
143 + |
134 + |
174 + |
165 + |
175 + |
166 + |
176 /* write a gzip, zlib, or zip header using the information in the globals */ |
167 /* write a gzip, zlib, or zip header using the information in the globals */ |
177 local unsigned long put_header(void) |
168 local unsigned long put_header(void) |
178 { |
169 { |
179 @@ -1253,7 +1287,7 @@ |
170 @@ -1272,7 +1306,7 @@ |
180 |
171 |
181 /* get a space from a pool -- the use count is initially set to one, so there |
172 /* get a space from a pool -- the use count is initially set to one, so there |
182 is no need to call use_space() for the first use */ |
173 is no need to call use_space() for the first use */ |
183 -local struct space *get_space(struct pool *pool) |
174 -local struct space *get_space(struct pool *pool) |
184 +local struct space *get_space_size(struct pool *pool, size_t size) |
175 +local struct space *get_space_size(struct pool *pool, size_t size) |
185 { |
176 { |
186 struct space *space; |
177 struct space *space; |
187 |
178 |
188 @@ -1266,6 +1300,15 @@ |
179 @@ -1285,6 +1319,15 @@ |
189 if (pool->head != NULL) { |
180 if (pool->head != NULL) { |
190 space = pool->head; |
181 space = pool->head; |
191 possess(space->use); |
182 possess(space->use); |
192 + /* If there's not enough space, free and malloc rather than realloc to |
183 + /* If there's not enough space, free and malloc rather than realloc to |
193 + avoid the potential of an unnecessary memory copy. */ |
184 + avoid the potential of an unnecessary memory copy. */ |
199 + space->size = size; |
190 + space->size = size; |
200 + } |
191 + } |
201 pool->head = space->next; |
192 pool->head = space->next; |
202 twist(pool->have, BY, -1); /* one less in pool */ |
193 twist(pool->have, BY, -1); /* one less in pool */ |
203 twist(space->use, TO, 1); /* initially one user */ |
194 twist(space->use, TO, 1); /* initially one user */ |
204 @@ -1281,13 +1324,18 @@ |
195 @@ -1300,13 +1343,18 @@ |
205 release(pool->have); |
196 release(pool->have); |
206 space = alloc(NULL, sizeof(struct space)); |
197 space = alloc(NULL, sizeof(struct space)); |
207 space->use = new_lock(1); /* initially one user */ |
198 space->use = new_lock(1); /* initially one user */ |
208 - space->buf = alloc(NULL, pool->size); |
199 - space->buf = alloc(NULL, pool->size); |
209 - space->size = pool->size; |
200 - space->size = pool->size; |
257 + this is the last chunk, which after writing tells compress_write_thread to |
248 + this is the last chunk, which after writing tells compress_write_thread to |
258 + return */ |
249 + return */ |
259 struct job { |
250 struct job { |
260 long seq; /* sequence number */ |
251 long seq; /* sequence number */ |
261 int more; /* true if this is not the last chunk */ |
252 int more; /* true if this is not the last chunk */ |
262 @@ -1411,6 +1477,7 @@ |
253 @@ -1430,6 +1496,7 @@ |
263 new_pool(&out_pool, OUTPOOL(g.block), -1); |
254 new_pool(&out_pool, OUTPOOL(g.block), -1); |
264 new_pool(&dict_pool, DICT, -1); |
255 new_pool(&dict_pool, DICT, -1); |
265 new_pool(&lens_pool, g.block >> (RSYNCBITS - 1), -1); |
256 new_pool(&lens_pool, g.block >> (RSYNCBITS - 1), -1); |
266 + new_pool(&idx_pool, 1, -1); |
257 + new_pool(&idx_pool, 1, -1); |
267 } |
258 } |
268 |
259 |
269 /* command the compress threads to all return, then join them all (call from |
260 /* command the compress threads to all return, then join them all (call from |
270 @@ -1447,6 +1514,8 @@ |
261 @@ -1466,6 +1533,8 @@ |
271 Trace(("-- freed %d output buffers", caught)); |
262 Trace(("-- freed %d output buffers", caught)); |
272 caught = free_pool(&in_pool); |
263 caught = free_pool(&in_pool); |
273 Trace(("-- freed %d input buffers", caught)); |
264 Trace(("-- freed %d input buffers", caught)); |
274 + caught = free_pool(&idx_pool); |
265 + caught = free_pool(&idx_pool); |
275 + Trace(("-- freed %d index buffers", caught)); |
266 + Trace(("-- freed %d index buffers", caught)); |
276 free_lock(write_first); |
267 free_lock(write_first); |
277 free_lock(compress_have); |
268 free_lock(compress_have); |
278 compress_have = NULL; |
269 compress_have = NULL; |
279 @@ -1710,18 +1779,483 @@ |
270 @@ -1738,18 +1807,483 @@ |
280 } |
271 } |
281 } |
272 } |
282 |
273 |
283 +/* Block Index |
274 +/* Block Index |
284 + |
275 + |
760 - unsigned long clen; /* total compressed size (overflow ok) */ |
751 - unsigned long clen; /* total compressed size (overflow ok) */ |
761 + size_t clen; /* total compressed size */ |
752 + size_t clen; /* total compressed size */ |
762 unsigned long check; /* check value of uncompressed data */ |
753 unsigned long check; /* check value of uncompressed data */ |
763 ball_t err; /* error information from throw() */ |
754 ball_t err; /* error information from throw() */ |
764 |
755 |
765 @@ -1747,23 +2281,27 @@ |
756 @@ -1775,23 +2309,27 @@ |
766 /* update lengths, save uncompressed length for COMB */ |
757 /* update lengths, save uncompressed length for COMB */ |
767 more = job->more; |
758 more = job->more; |
768 len = job->in->len; |
759 len = job->in->len; |
769 + olen = job->out->len; |
760 + olen = job->out->len; |
770 drop_space(job->in); |
761 drop_space(job->in); |
792 + idx_add(len, olen, job->check); |
783 + idx_add(len, olen, job->check); |
793 + |
784 + |
794 /* free the job */ |
785 /* free the job */ |
795 free_lock(job->calc); |
786 free_lock(job->calc); |
796 FREE(job); |
787 FREE(job); |
797 @@ -1845,7 +2383,7 @@ |
788 @@ -1873,7 +2411,7 @@ |
798 setup_jobs(); |
789 setup_jobs(); |
799 |
790 |
800 /* start write thread */ |
791 /* start write thread */ |
801 - writeth = launch(write_thread, NULL); |
792 - writeth = launch(write_thread, NULL); |
802 + writeth = launch(compress_write_thread, NULL); |
793 + writeth = launch(compress_write_thread, NULL); |
803 |
794 |
804 /* read from input and start compress threads (write thread will pick up |
795 /* read from input and start compress threads (write thread will pick up |
805 the output of the compress threads) */ |
796 the output of the compress threads) */ |
806 @@ -2303,7 +2841,7 @@ |
797 @@ -2336,7 +2874,7 @@ |
807 #ifndef NOTHREAD |
798 #ifndef NOTHREAD |
808 /* if first time in or procs == 1, read a buffer to have something to |
799 /* if first time in or procs == 1, read a buffer to have something to |
809 return, otherwise wait for the previous read job to complete */ |
800 return, otherwise wait for the previous read job to complete */ |
810 - if (g.procs > 1) { |
801 - if (g.procs > 1) { |
811 + if (g.procs > 1 && g.index == NULL && !ind_has_index()) { |
802 + if (g.procs > 1 && g.index == NULL && !ind_has_index()) { |
812 /* if first time, fire up the read thread, ask for a read */ |
803 /* if first time, fire up the read thread, ask for a read */ |
813 if (g.in_which == -1) { |
804 if (g.in_which == -1) { |
814 g.in_which = 1; |
805 g.in_which = 1; |
815 @@ -2404,12 +2942,6 @@ |
806 @@ -2437,12 +2975,6 @@ |
816 g.in_next += togo; \ |
807 g.in_next += togo; \ |
817 } while (0) |
808 } while (0) |
818 |
809 |
819 -/* pull LSB order or MSB order integers from an unsigned char buffer */ |
810 -/* pull LSB order or MSB order integers from an unsigned char buffer */ |
820 -#define PULL2L(p) ((p)[0] + ((unsigned)((p)[1]) << 8)) |
811 -#define PULL2L(p) ((p)[0] + ((unsigned)((p)[1]) << 8)) |
897 +} |
888 +} |
898 + |
889 + |
899 /* inflate for decompression or testing -- decompress from ind to outd unless |
890 /* inflate for decompression or testing -- decompress from ind to outd unless |
900 decode != 1, in which case just test ind, and then also list if list != 0; |
891 decode != 1, in which case just test ind, and then also list if list != 0; |
901 look for and decode multiple, concatenated gzip and/or zlib streams; |
892 look for and decode multiple, concatenated gzip and/or zlib streams; |
902 @@ -3040,10 +3639,8 @@ |
893 @@ -3073,10 +3672,8 @@ |
903 local void infchk(void) |
894 local void infchk(void) |
904 { |
895 { |
905 int ret, cont, was; |
896 int ret, cont, was; |
906 - unsigned long check, len; |
897 - unsigned long check, len; |
907 + unsigned long check; |
898 + unsigned long check; |
1215 +} |
1206 +} |
1216 + |
1207 + |
1217 /* --- decompress Unix compress (LZW) input --- */ |
1208 /* --- decompress Unix compress (LZW) input --- */ |
1218 |
1209 |
1219 /* Type for accumulating bits. 23 bits will be used to accumulate up to 16-bit |
1210 /* Type for accumulating bits. 23 bits will be used to accumulate up to 16-bit |
1220 @@ -3576,7 +4333,7 @@ |
1211 @@ -3614,7 +4371,7 @@ |
1221 if (g.decode == 2) { |
1212 if (g.decode == 2) { |
1222 try { |
1213 try { |
1223 if (method == 8) |
1214 if (method == 8) |
1224 - infchk(); |
1215 - infchk(); |
1225 + best_infchk(); |
1216 + best_infchk(); |
1226 else { |
1217 else { |
1227 unlzw(); |
1218 unlzw(); |
1228 if (g.list) { |
1219 if (g.list) { |
1229 @@ -3649,19 +4406,8 @@ |
1220 @@ -3687,19 +4444,8 @@ |
1230 |
1221 |
1231 /* if exists and not -f, give user a chance to overwrite */ |
1222 /* if exists and not -f, give user a chance to overwrite */ |
1232 if (g.outd < 0 && errno == EEXIST && isatty(0) && g.verbosity) { |
1223 if (g.outd < 0 && errno == EEXIST && isatty(0) && g.verbosity) { |
1233 - int ch, reply; |
1224 - int ch, reply; |
1234 - |
1225 - |
1246 + if (allow_overwrite(g.outf)) |
1237 + if (allow_overwrite(g.outf)) |
1247 + g.outd = open(g.outf, O_CREAT | O_TRUNC | O_WRONLY, 0600); |
1238 + g.outd = open(g.outf, O_CREAT | O_TRUNC | O_WRONLY, 0600); |
1248 } |
1239 } |
1249 |
1240 |
1250 /* if exists and no overwrite, report and go on to next */ |
1241 /* if exists and no overwrite, report and go on to next */ |
1251 @@ -3684,10 +4430,11 @@ |
1242 @@ -3722,10 +4468,11 @@ |
1252 /* process ind to outd */ |
1243 /* process ind to outd */ |
1253 if (g.verbosity > 1) |
1244 if (g.verbosity > 1) |
1254 fprintf(stderr, "%s to %s ", g.inf, g.outf); |
1245 fprintf(stderr, "%s to %s ", g.inf, g.outf); |
1255 + |
1246 + |
1256 if (g.decode) { |
1247 if (g.decode) { |
1275 + parallel_compress(); |
1266 + parallel_compress(); |
1276 + } |
1267 + } |
1277 #endif |
1268 #endif |
1278 else |
1269 else |
1279 single_compress(0); |
1270 single_compress(0); |
1280 @@ -3718,6 +4471,10 @@ |
1271 @@ -3756,6 +4509,10 @@ |
1281 fflush(stderr); |
1272 fflush(stderr); |
1282 } |
1273 } |
1283 |
1274 |
1284 + /* close index file - this may append the index to outd */ |
1275 + /* close index file - this may append the index to outd */ |
1285 + if (idx.valid) |
1276 + if (idx.valid) |
1286 + idx_close(); |
1277 + idx_close(); |
1287 + |
1278 + |
1288 /* finish up, copy attributes, set times, delete original */ |
1279 /* finish up, copy attributes, set times, delete original */ |
1289 if (g.ind != 0) |
1280 if (g.ind != 0) |
1290 close(g.ind); |
1281 close(g.ind); |
1291 @@ -3781,6 +4538,9 @@ |
1282 @@ -3819,6 +4576,9 @@ |
1292 " -v, --verbose Provide more verbose output", |
1283 " -v, --verbose Provide more verbose output", |
1293 #endif |
1284 #endif |
1294 " -V --version Show the version of pigz", |
1285 " -V --version Show the version of pigz", |
1295 +" -X --index file Create or use parallel uncompression index file.", |
1286 +" -X --index file Create or use parallel uncompression index file.", |
1296 +" %f and %z are replaced by uncompressed and compressed", |
1287 +" %f and %z are replaced by uncompressed and compressed", |
1297 +" file names", |
1288 +" file names", |
1298 " -z, --zlib Compress to zlib (.zz) instead of gzip format", |
1289 " -z, --zlib Compress to zlib (.zz) instead of gzip format", |
1299 " -- All arguments after \"--\" are treated as files" |
1290 " -- All arguments after \"--\" are treated as files" |
1300 }; |
1291 }; |
1301 @@ -3859,11 +4619,11 @@ |
1292 @@ -3897,11 +4657,11 @@ |
1302 {"LZW", "Z"}, {"ascii", "a"}, {"best", "9"}, {"bits", "Z"}, |
1293 {"LZW", "Z"}, {"ascii", "a"}, {"best", "9"}, {"bits", "Z"}, |
1303 {"blocksize", "b"}, {"decompress", "d"}, {"fast", "1"}, {"first", "F"}, |
1294 {"blocksize", "b"}, {"decompress", "d"}, {"fast", "1"}, {"first", "F"}, |
1304 {"force", "f"}, {"help", "h"}, {"independent", "i"}, {"iterations", "I"}, |
1295 {"force", "f"}, {"help", "h"}, {"independent", "i"}, {"iterations", "I"}, |
1305 - {"keep", "k"}, {"license", "L"}, {"list", "l"}, {"maxsplits", "M"}, |
1296 - {"keep", "k"}, {"license", "L"}, {"list", "l"}, {"maxsplits", "M"}, |
1306 - {"name", "N"}, {"no-name", "n"}, {"no-time", "T"}, {"oneblock", "O"}, |
1297 - {"name", "N"}, {"no-name", "n"}, {"no-time", "T"}, {"oneblock", "O"}, |
1313 + {"rsyncable", "R"}, {"silent", "q"}, {"stdout", "c"}, {"suffix", "S"}, |
1304 + {"rsyncable", "R"}, {"silent", "q"}, {"stdout", "c"}, {"suffix", "S"}, |
1314 + {"test", "t"}, {"to-stdout", "c"}, {"uncompress", "d"}, {"verbose", "v"}, |
1305 + {"test", "t"}, {"to-stdout", "c"}, {"uncompress", "d"}, {"verbose", "v"}, |
1315 {"version", "V"}, {"zip", "K"}, {"zlib", "z"}}; |
1306 {"version", "V"}, {"zip", "K"}, {"zlib", "z"}}; |
1316 #define NLOPTS (sizeof(longopts) / (sizeof(char *) << 1)) |
1307 #define NLOPTS (sizeof(longopts) / (sizeof(char *) << 1)) |
1317 |
1308 |
1318 @@ -3903,7 +4663,7 @@ |
1309 @@ -3941,7 +4701,7 @@ |
1319 |
1310 |
1320 /* if no argument or dash option, check status of get */ |
1311 /* if no argument or dash option, check status of get */ |
1321 if (get && (arg == NULL || *arg == '-')) { |
1312 if (get && (arg == NULL || *arg == '-')) { |
1322 - bad[1] = "bpSIM"[get - 1]; |
1313 - bad[1] = "bpSIM"[get - 1]; |
1323 + bad[1] = "bpSIMX"[get - 1]; |
1314 + bad[1] = "bpSIMX"[get - 1]; |
1324 throw(EINVAL, "missing parameter after %s", bad); |
1315 throw(EINVAL, "missing parameter after %s", bad); |
1325 } |
1316 } |
1326 if (arg == NULL) |
1317 if (arg == NULL) |
1327 @@ -3972,6 +4732,7 @@ |
1318 @@ -4014,6 +4774,7 @@ |
1328 case 'S': get = 3; break; |
1319 if (g.verbosity > 1) |
1329 case 'T': g.headis &= ~0xa; break; |
1320 fprintf(stderr, "zlib %s\n", zlibVersion()); |
1330 case 'V': fputs(VERSION, stderr); exit(0); |
1321 exit(0); |
1331 + case 'X': g.setdict = 0; get = 6; break; |
1322 + case 'X': g.setdict = 0; get = 6; break; |
1332 case 'Z': |
1323 case 'Z': |
1333 throw(EINVAL, "invalid option: LZW output not supported: %s", |
1324 throw(EINVAL, "invalid option: LZW output not supported: %s", |
1334 bad); |
1325 bad); |
1335 @@ -4001,7 +4762,7 @@ |
1326 @@ -4043,7 +4804,7 @@ |
1336 return 0; |
1327 return 0; |
1337 } |
1328 } |
1338 |
1329 |
1339 - /* process option parameter for -b, -p, -S, -I, or -M */ |
1330 - /* process option parameter for -b, -p, -S, -I, or -M */ |
1340 + /* process option parameter for -b, -p, -S, -I, -M or -X */ |
1331 + /* process option parameter for -b, -p, -S, -I, -M or -X */ |
1341 if (get) { |
1332 if (get) { |
1342 size_t n; |
1333 size_t n; |
1343 |
1334 |
1344 @@ -4036,6 +4797,8 @@ |
1335 @@ -4078,6 +4839,8 @@ |
1345 g.zopts.numiterations = num(arg); /* optimization iterations */ |
1336 g.zopts.numiterations = num(arg); /* optimization iterations */ |
1346 else if (get == 5) |
1337 else if (get == 5) |
1347 g.zopts.blocksplittingmax = num(arg); /* max block splits */ |
1338 g.zopts.blocksplittingmax = num(arg); /* max block splits */ |
1348 + else if (get == 6) |
1339 + else if (get == 6) |
1349 + g.index = arg; /* index file */ |
1340 + g.index = arg; /* index file */ |