ObjFW  Check-in [fed68f8fd5]

Overview
Comment:OFZIP: Add a mode for printing files
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: fed68f8fd5a974809eaf861bac078231b6c2ab82d98e64976c17a4962ac86505
User & Date: js on 2016-05-16 13:44:55
Other Links: manifest | tags
Context
2016-05-16
13:47
OFZIP: Do not try to open archive if path is nil check-in: 4ac59d558b user: js tags: trunk
13:44
OFZIP: Add a mode for printing files check-in: fed68f8fd5 user: js tags: trunk
11:45
OFZIP: Accept .GZ (uppercase) files check-in: 0909bbc678 user: js tags: trunk
Changes

Modified utils/ofzip/Archive.h from [138de6bf97] to [9e6c49c585].

19
20
21
22
23
24
25

26
#import "OFArray.h"

@protocol Archive <OFObject>
+ (instancetype)archiveWithFile: (OFFile*)file;
- initWithFile: (OFFile*)file;
- (void)listFiles;
- (void)extractFiles: (OFArray OF_GENERIC(OFString*)*)files;

@end







>

19
20
21
22
23
24
25
26
27
#import "OFArray.h"

@protocol Archive <OFObject>
+ (instancetype)archiveWithFile: (OFFile*)file;
- initWithFile: (OFFile*)file;
- (void)listFiles;
- (void)extractFiles: (OFArray OF_GENERIC(OFString*)*)files;
- (void)printFiles: (OFArray OF_GENERIC(OFString*)*)files;
@end

Modified utils/ofzip/GZIPArchive.m from [7bb45e0fc2] to [1fc9513872].

113
114
115
116
117
118
119
























120
			return;
		}
	}

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
























@end







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

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
			return;
		}
	}

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

- (void)printFiles: (OFArray OF_GENERIC(OFString*)*)files
{
	OFString *fileName = [[app->_archivePath lastPathComponent]
	    stringByDeletingPathExtension];

	if ([files count] > 0) {
		[of_stderr writeLine:
		    @"Cannot specify a file to print for .gz archives!"];
		app->_exitStatus = 1;
		return;
	}

	while (![_stream isAtEndOfStream]) {
		ssize_t length = [app copyBlockFromStream: _stream
						 toStream: of_stdout
						 fileName: fileName];

		if (length < 0) {
			app->_exitStatus = 1;
			return;
		}
	}
}
@end

Modified utils/ofzip/OFZIP.m from [5ee35aa87f] to [c9180070ce].

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

OF_APPLICATION_DELEGATE(OFZIP)

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

	if (full)
		[stream writeString:
		    @"\nOptions:\n"
		    @"    -f  --force      Force / overwrite files\n"
		    @"    -h  --help       Show this help\n"
		    @"    -l  --list       List all files in the archive\n"
		    @"    -n  --no-clober  Never overwrite files\n"


		    @"    -q  --quiet      Quiet mode (no output, except "
		    @"errors)\n"
		    @"    -v  --verbose    Verbose output for file list\n"
		    @"    -x  --extract    Extract files\n"];

	[OFApplication terminateWithStatus: status];
}

static void
mutuallyExclusiveError(of_unichar_t shortOption1, OFString *longOption1,
    of_unichar_t shortOption2, OFString *longOption2)
{
	[of_stderr writeFormat:
	    @"Error: -%C / --%@ and -%C / --%@ are mutually exclusive!\n",
	    shortOption1, longOption1, shortOption2, longOption2];
	[OFApplication terminateWithStatus: 1];
}













@implementation OFZIP
- (void)applicationDidFinishLaunching
{
	const of_options_parser_option_t options[] = {
		{ 'f', @"force", 0, NULL, NULL },
		{ 'h', @"help", 0, NULL, NULL },
		{ 'l', @"list", 0, NULL, NULL },
		{ 'n', @"no-clobber", 0, NULL, NULL },

		{ 'q', @"quiet", 0, NULL, NULL },
		{ 'v', @"verbose", 0, NULL, NULL },
		{ 'x', @"extract", 0, NULL, NULL },
		{ '\0', nil, 0, NULL, NULL }
	};
	OFOptionsParser *optionsParser =
	    [OFOptionsParser parserWithOptions: options];







|









>
>

















>
>
>
>
>
>
>
>
>
>
>
>









>







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
97
98
99
100
101
102
103

OF_APPLICATION_DELEGATE(OFZIP)

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

	if (full)
		[stream writeString:
		    @"\nOptions:\n"
		    @"    -f  --force      Force / overwrite files\n"
		    @"    -h  --help       Show this help\n"
		    @"    -l  --list       List all files in the archive\n"
		    @"    -n  --no-clober  Never overwrite files\n"
		    @"    -p  --print      Print one or more files from the "
		    @"archive\n"
		    @"    -q  --quiet      Quiet mode (no output, except "
		    @"errors)\n"
		    @"    -v  --verbose    Verbose output for file list\n"
		    @"    -x  --extract    Extract files\n"];

	[OFApplication terminateWithStatus: status];
}

static void
mutuallyExclusiveError(of_unichar_t shortOption1, OFString *longOption1,
    of_unichar_t shortOption2, OFString *longOption2)
{
	[of_stderr writeFormat:
	    @"Error: -%C / --%@ and -%C / --%@ are mutually exclusive!\n",
	    shortOption1, longOption1, shortOption2, longOption2];
	[OFApplication terminateWithStatus: 1];
}

static void
mutuallyExclusiveError3(of_unichar_t shortOption1, OFString *longOption1,
    of_unichar_t shortOption2, OFString *longOption2,
    of_unichar_t shortOption3, OFString *longOption3)
{
	[of_stderr writeFormat:
	    @"Error: -%C / --%@, -%C / --%@ and -%C / --%@ are mutually "
	    @"exclusive!\n", shortOption1, longOption1, shortOption2,
	    longOption2, shortOption3, longOption3];
	[OFApplication terminateWithStatus: 1];
}

@implementation OFZIP
- (void)applicationDidFinishLaunching
{
	const of_options_parser_option_t options[] = {
		{ 'f', @"force", 0, NULL, NULL },
		{ 'h', @"help", 0, NULL, NULL },
		{ 'l', @"list", 0, NULL, NULL },
		{ 'n', @"no-clobber", 0, NULL, NULL },
		{ 'p', @"print", 0, NULL, NULL },
		{ 'q', @"quiet", 0, NULL, NULL },
		{ 'v', @"verbose", 0, NULL, NULL },
		{ 'x', @"extract", 0, NULL, NULL },
		{ '\0', nil, 0, NULL, NULL }
	};
	OFOptionsParser *optionsParser =
	    [OFOptionsParser parserWithOptions: options];
118
119
120
121
122
123
124

125
126
127

128
129
130
131
132
133
134
				mutuallyExclusiveError(
				    'q', @"quiet", 'v', @"verbose");

			_outputLevel--;
			break;
		case 'l':
		case 'x':

			if (mode != '\0')
				mutuallyExclusiveError(
				    'l', @"list", 'x', @"extract");


			mode = option;
			break;
		case 'h':
			help(of_stdout, true, 0);
			break;
		case '=':







>

|
|
>







133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
				mutuallyExclusiveError(
				    'q', @"quiet", 'v', @"verbose");

			_outputLevel--;
			break;
		case 'l':
		case 'x':
		case 'p':
			if (mode != '\0')
				mutuallyExclusiveError3(
				    'l', @"list", 'x', @"extract",
				    'p', @"print");

			mode = option;
			break;
		case 'h':
			help(of_stdout, true, 0);
			break;
		case '=':
183
184
185
186
187
188
189









190
191
192
193
194
195
196
			[of_stderr writeFormat:
			    @"\rFailed to open file %@: %s\n",
			    [e path], strerror([e errNo])];
			_exitStatus = 1;
		}

		break;









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

	[OFApplication terminateWithStatus: _exitStatus];
}







>
>
>
>
>
>
>
>
>







200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
			[of_stderr writeFormat:
			    @"\rFailed to open file %@: %s\n",
			    [e path], strerror([e errNo])];
			_exitStatus = 1;
		}

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

		files = [remainingArguments objectsInRange:
		    of_range(1, [remainingArguments count] - 1)];

		[archive printFiles: files];
		break;
	default:
		help(of_stderr, true, 1);
		break;
	}

	[OFApplication terminateWithStatus: _exitStatus];
}

Modified utils/ofzip/ZIPArchive.m from [03760bd752] to [71fb0eed5b].

12
13
14
15
16
17
18


19
20
21
22
23
24
25
26
27
28

29
30
31
32
33
34
35
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"



#import "OFDate.h"
#import "OFSet.h"
#import "OFApplication.h"
#import "OFFileManager.h"
#import "OFStdIOStream.h"

#import "ZIPArchive.h"
#import "OFZIP.h"

#import "OFInvalidFormatException.h"


#ifndef S_IRWXG
# define S_IRWXG 0
#endif
#ifndef S_IRWXO
# define S_IRWXO 0
#endif







>
>










>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <errno.h>

#import "OFDate.h"
#import "OFSet.h"
#import "OFApplication.h"
#import "OFFileManager.h"
#import "OFStdIOStream.h"

#import "ZIPArchive.h"
#import "OFZIP.h"

#import "OFInvalidFormatException.h"
#import "OFOpenItemFailedException.h"

#ifndef S_IRWXG
# define S_IRWXG 0
#endif
#ifndef S_IRWXO
# define S_IRWXO 0
#endif
254
255
256
257
258
259
260








































261
		for (OFString *file in missing)
			[of_stderr writeFormat:
			    @"File %@ is not in the archive!\n", file];

		app->_exitStatus = 1;
	}
}








































@end







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
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
298
299
300
301
302
303
304
		for (OFString *file in missing)
			[of_stderr writeFormat:
			    @"File %@ is not in the archive!\n", file];

		app->_exitStatus = 1;
	}
}

- (void)printFiles: (OFArray OF_GENERIC(OFString*)*)files
{
	OFStream *stream;

	if ([files count] < 1) {
		[of_stderr writeLine: @"Need one or more files to print!"];
		app->_exitStatus = 1;
		return;
	}

	for (OFString *path in files) {
		@try {
			stream = [_archive streamForReadingFile: path];
		} @catch (OFOpenItemFailedException *e) {
			if ([e errNo] == ENOENT) {
				[of_stderr writeFormat:
				    @"File %@ is not in the archive!\n",
				    [e path]];
				app->_exitStatus = 1;
				continue;
			}

			@throw e;
		}

		while (![stream isAtEndOfStream]) {
			ssize_t length = [app copyBlockFromStream: stream
							 toStream: of_stdout
							 fileName: path];

			if (length < 0) {
				app->_exitStatus = 1;
				return;
			}
		}

		[stream close];
	}
}
@end