ObjFW  Check-in [8e35da9d61]

Overview
Comment:OFZIP: Add quiet mode.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 8e35da9d61e0fb8363c70bdaa909878d8c561072304bb4e87cb340b79087afda
User & Date: js on 2013-12-21 01:10:35
Other Links: manifest | tags
Context
2013-12-21
01:12
OFZIP: Keep going after non-fatal errors. check-in: 7e6942f348 user: js tags: trunk
01:10
OFZIP: Add quiet mode. check-in: 8e35da9d61 user: js tags: trunk
2013-12-20
00:20
Fix make recursion for bridge. check-in: 3f3151bd81 user: js tags: trunk
Changes

Modified utils/OFZIP.m from [7be8bd0d44] to [6b66318439].

27
28
29
30
31
32
33




34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

52
53
54
55

56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83


84

85
86
87
88
89
90
91

#import "autorelease.h"
#import "macros.h"

#define BUFFER_SIZE 4096

@interface OFZIP: OFObject




- (void)listFilesInArchive: (OFZIPArchive*)archive
		   verbose: (bool)verbose;
- (void)extractFiles: (OFArray*)files
	 fromArchive: (OFZIPArchive*)archive
	    override: (int_fast8_t)override;
@end

OF_APPLICATION_DELEGATE(OFZIP)

static void
help(OFStream *stream, bool full, int status)
{
	[stream writeFormat:
	    @"Usage: %@ -[flnvx] archive.zip [file1 file2 ...]\n",
	    [OFApplication programName]];

	if (full) {
		[stream writeString: @"\nOptions:\n"

				     @"    -f  Force / override files\n"
				     @"    -h  Show this help\n"
				     @"    -l  List all files in the archive\n"
				     @"    -n  Never override files\n"

				     @"    -v  Verbose output for file list\n"
				     @"    -x  Extract files\n"];
	}

	[OFApplication terminateWithStatus: status];
}

@implementation OFZIP
- (void)applicationDidFinishLaunching
{
	OFOptionsParser *optionsParser =
	    [OFOptionsParser parserWithOptions: @"fhlnvx"];
	of_unichar_t option, mode = '\0';
	int_fast8_t override = 0;
	bool verbose = false;
	OFArray *remainingArguments;
	OFZIPArchive *archive;
	OFArray *files;

	while ((option = [optionsParser nextOption]) != '\0') {
		switch (option) {
		case 'f':
			override = 1;
			break;
		case 'n':
			override = -1;
			break;
		case 'v':


			verbose = true;

			break;
		case 'l':
		case 'x':
			if (mode != '\0')
				help(of_stdout, false, 1);

			mode = option;







>
>
>
>
|
<

|
<












|
>
|
|
|
|
>
|
|









|

<
<







|


|


>
>
|
>







27
28
29
30
31
32
33
34
35
36
37
38

39
40

41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72


73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

#import "autorelease.h"
#import "macros.h"

#define BUFFER_SIZE 4096

@interface OFZIP: OFObject
{
	int_fast8_t _override, _outputLevel;
}

- (void)listFilesInArchive: (OFZIPArchive*)archive;

- (void)extractFiles: (OFArray*)files
	 fromArchive: (OFZIPArchive*)archive;

@end

OF_APPLICATION_DELEGATE(OFZIP)

static void
help(OFStream *stream, bool full, int status)
{
	[stream writeFormat:
	    @"Usage: %@ -[flnvx] archive.zip [file1 file2 ...]\n",
	    [OFApplication programName]];

	if (full) {
		[stream writeString:
		    @"\nOptions:\n"
		    @"    -f  Force / override files\n"
		    @"    -h  Show this help\n"
		    @"    -l  List all files in the archive\n"
		    @"    -n  Never override files\n"
		    @"    -q  Quiet mode (no output, except errors)\n"
		    @"    -v  Verbose output for file list\n"
		    @"    -x  Extract files\n"];
	}

	[OFApplication terminateWithStatus: status];
}

@implementation OFZIP
- (void)applicationDidFinishLaunching
{
	OFOptionsParser *optionsParser =
	    [OFOptionsParser parserWithOptions: @"fhlnqvx"];
	of_unichar_t option, mode = '\0';


	OFArray *remainingArguments;
	OFZIPArchive *archive;
	OFArray *files;

	while ((option = [optionsParser nextOption]) != '\0') {
		switch (option) {
		case 'f':
			_override = 1;
			break;
		case 'n':
			_override = -1;
			break;
		case 'v':
			_outputLevel = 1;
			break;
		case 'q':
			_outputLevel = -1;
			break;
		case 'l':
		case 'x':
			if (mode != '\0')
				help(of_stdout, false, 1);

			mode = option;
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
	case 'l':
		if ([remainingArguments count] != 1)
			help(of_stderr, false, 1);

		archive = [OFZIPArchive archiveWithPath:
		    [remainingArguments firstObject]];

		[self listFilesInArchive: archive
				 verbose: verbose];
		break;
	case 'x':
		if ([remainingArguments count] < 1)
			help(of_stderr, false, 1);

		files = [remainingArguments objectsInRange:
		    of_range(1, [remainingArguments count] - 1)];
		archive = [OFZIPArchive archiveWithPath:
		    [remainingArguments firstObject]];

		[self extractFiles: files
		       fromArchive: archive
			  override: override];
		break;
	default:
		help(of_stderr, true, 1);
		break;
	}

	[OFApplication terminate];
}

- (void)listFilesInArchive: (OFZIPArchive*)archive
		   verbose: (bool)verbose
{
	OFEnumerator *enumerator = [[archive entries] objectEnumerator];
	OFZIPArchiveEntry *entry;

	while ((entry = [enumerator nextObject]) != nil) {
		void *pool = objc_autoreleasePoolPush();

		if (verbose) {
			OFString *date = [[entry modificationDate]
			    localDateStringWithFormat: @"%Y-%m-%d %H:%M:%S"];

			[of_stdout writeFormat:
			    @"%@: %" PRIu64 @" (%" PRIu64 @") bytes; %08X; %@; "
			    @"%@\n", [entry fileName], [entry uncompressedSize],
			    [entry compressedSize], [entry CRC32], date,
			    [entry fileComment]];
		} else
			[of_stdout writeLine: [entry fileName]];

		objc_autoreleasePoolPop(pool);
	}
}

- (void)extractFiles: (OFArray*)files
	 fromArchive: (OFZIPArchive*)archive
	    override: (int_fast8_t)override
{
	OFEnumerator *enumerator = [[archive entries] objectEnumerator];
	OFZIPArchiveEntry *entry;
	bool all = ([files count] == 0);
	OFMutableSet *missing = [OFMutableSet setWithArray: files];

	while ((entry = [enumerator nextObject]) != nil) {







|
<











|
<










<







|

















<







112
113
114
115
116
117
118
119

120
121
122
123
124
125
126
127
128
129
130
131

132
133
134
135
136
137
138
139
140
141

142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166

167
168
169
170
171
172
173
	case 'l':
		if ([remainingArguments count] != 1)
			help(of_stderr, false, 1);

		archive = [OFZIPArchive archiveWithPath:
		    [remainingArguments firstObject]];

		[self listFilesInArchive: archive];

		break;
	case 'x':
		if ([remainingArguments count] < 1)
			help(of_stderr, false, 1);

		files = [remainingArguments objectsInRange:
		    of_range(1, [remainingArguments count] - 1)];
		archive = [OFZIPArchive archiveWithPath:
		    [remainingArguments firstObject]];

		[self extractFiles: files
		       fromArchive: archive];

		break;
	default:
		help(of_stderr, true, 1);
		break;
	}

	[OFApplication terminate];
}

- (void)listFilesInArchive: (OFZIPArchive*)archive

{
	OFEnumerator *enumerator = [[archive entries] objectEnumerator];
	OFZIPArchiveEntry *entry;

	while ((entry = [enumerator nextObject]) != nil) {
		void *pool = objc_autoreleasePoolPush();

		if (_outputLevel > 0) {
			OFString *date = [[entry modificationDate]
			    localDateStringWithFormat: @"%Y-%m-%d %H:%M:%S"];

			[of_stdout writeFormat:
			    @"%@: %" PRIu64 @" (%" PRIu64 @") bytes; %08X; %@; "
			    @"%@\n", [entry fileName], [entry uncompressedSize],
			    [entry compressedSize], [entry CRC32], date,
			    [entry fileComment]];
		} else
			[of_stdout writeLine: [entry fileName]];

		objc_autoreleasePoolPop(pool);
	}
}

- (void)extractFiles: (OFArray*)files
	 fromArchive: (OFZIPArchive*)archive

{
	OFEnumerator *enumerator = [[archive entries] objectEnumerator];
	OFZIPArchiveEntry *entry;
	bool all = ([files count] == 0);
	OFMutableSet *missing = [OFMutableSet setWithArray: files];

	while ((entry = [enumerator nextObject]) != nil) {
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209

210
211
212
213
214

215
216
217
218
219
220
221
222
223
224
225
226
227

228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257

#ifndef _WIN32
		if ([outFileName hasPrefix: @"/"]) {
#else
		if ([outFileName hasPrefix: @"/"] ||
		    [outFileName containsString: @":"]) {
#endif
			[of_stdout writeFormat: @"Refusing to extract %@!\n",
						fileName];
			[OFApplication terminateWithStatus: 1];
		}

		componentEnumerator =
		    [[outFileName pathComponents] objectEnumerator];
		while ((component = [componentEnumerator nextObject]) != nil) {
			if ([component isEqual: OF_PATH_PARENT_DIRECTORY]) {
				[of_stdout writeFormat:
				    @"Refusing to extract %@!\n", fileName];
				[OFApplication terminateWithStatus: 1];
			}
		}


		[of_stdout writeFormat: @"Extracting %@...", fileName];

		if ([fileName hasSuffix: @"/"]) {
			[OFFile createDirectoryAtPath: outFileName
					createParents: true];

			[of_stdout writeLine: @" done"];
			continue;
		}

		directory = [outFileName stringByDeletingLastPathComponent];
		if (![OFFile directoryExistsAtPath: directory])
			[OFFile createDirectoryAtPath: directory
					createParents: true];

		if ([OFFile fileExistsAtPath: outFileName] && override != 1) {
			OFString *line;

			if (override == -1) {

				[of_stdout writeLine: @" skipped"];
				continue;
			}

			do {
				[of_stderr writeFormat:
				    @"\rOverride %@? [ynAN?] ", fileName];

				line = [of_stdin readLine];

				if ([line isEqual: @"?"])
					[of_stderr writeString: @" y: yes\n"
								@" n: no\n"
								@" A: always\n"
								@" N: never\n"];
			} while (![line isEqual: @"y"] &&
			    ![line isEqual: @"n"] && ![line isEqual: @"N"] &&
			    ![line isEqual: @"A"]);

			if ([line isEqual: @"A"])
				override = 1;
			else if ([line isEqual: @"N"])
				override = -1;

			if ([line isEqual: @"n"] || [line isEqual: @"N"]) {
				[of_stdout writeFormat: @"Skipping %@...\n",
							fileName];
				continue;
			}








|








|





>
|




>
|








|


|
>
|



















|

|







189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261

#ifndef _WIN32
		if ([outFileName hasPrefix: @"/"]) {
#else
		if ([outFileName hasPrefix: @"/"] ||
		    [outFileName containsString: @":"]) {
#endif
			[of_stderr writeFormat: @"Refusing to extract %@!\n",
						fileName];
			[OFApplication terminateWithStatus: 1];
		}

		componentEnumerator =
		    [[outFileName pathComponents] objectEnumerator];
		while ((component = [componentEnumerator nextObject]) != nil) {
			if ([component isEqual: OF_PATH_PARENT_DIRECTORY]) {
				[of_stderr writeFormat:
				    @"Refusing to extract %@!\n", fileName];
				[OFApplication terminateWithStatus: 1];
			}
		}

		if (_outputLevel > -1)
			[of_stdout writeFormat: @"Extracting %@...", fileName];

		if ([fileName hasSuffix: @"/"]) {
			[OFFile createDirectoryAtPath: outFileName
					createParents: true];
			if (_outputLevel > -1)
				[of_stdout writeLine: @" done"];
			continue;
		}

		directory = [outFileName stringByDeletingLastPathComponent];
		if (![OFFile directoryExistsAtPath: directory])
			[OFFile createDirectoryAtPath: directory
					createParents: true];

		if ([OFFile fileExistsAtPath: outFileName] && _override != 1) {
			OFString *line;

			if (_override == -1) {
				if (_outputLevel > -1)
					[of_stdout writeLine: @" skipped"];
				continue;
			}

			do {
				[of_stderr writeFormat:
				    @"\rOverride %@? [ynAN?] ", fileName];

				line = [of_stdin readLine];

				if ([line isEqual: @"?"])
					[of_stderr writeString: @" y: yes\n"
								@" n: no\n"
								@" A: always\n"
								@" N: never\n"];
			} while (![line isEqual: @"y"] &&
			    ![line isEqual: @"n"] && ![line isEqual: @"N"] &&
			    ![line isEqual: @"A"]);

			if ([line isEqual: @"A"])
				_override = 1;
			else if ([line isEqual: @"N"])
				_override = -1;

			if ([line isEqual: @"n"] || [line isEqual: @"N"]) {
				[of_stdout writeFormat: @"Skipping %@...\n",
							fileName];
				continue;
			}

268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283

284

285
286
287
288
289
290
291
			[output writeBuffer: buffer
				     length: length];

			written += length;
			newPercent = (written == size
			    ? 100 : (int_fast8_t)(written * 100 / size));

			if (percent != newPercent) {
				percent = newPercent;

				[of_stdout writeFormat:
				    @"\rExtracting %@... %3u%%",
				    fileName, percent];
			}
		}


		[of_stdout writeFormat: @"\rExtracting %@... done\n", fileName];


		objc_autoreleasePoolPop(pool);
	}

	if ([missing count] > 0) {
		OFString *file;








|








>
|
>







272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
			[output writeBuffer: buffer
				     length: length];

			written += length;
			newPercent = (written == size
			    ? 100 : (int_fast8_t)(written * 100 / size));

			if (_outputLevel > -1 && percent != newPercent) {
				percent = newPercent;

				[of_stdout writeFormat:
				    @"\rExtracting %@... %3u%%",
				    fileName, percent];
			}
		}

		if (_outputLevel > -1)
			[of_stdout writeFormat: @"\rExtracting %@... done\n",
						fileName];

		objc_autoreleasePoolPop(pool);
	}

	if ([missing count] > 0) {
		OFString *file;