blob: 225ee628dd252dfabfad34b46ff08f814448848b [file] [log] [blame]
Guido van Rossumd8eb2111998-08-04 17:57:28 +00001/*
2** main.c - POSIX 1003.2 "ar" command
3**
4** This isn't a pure POSIX 1003.2 ar; it only manipulates Metrowerks
5** Library files, not general-purpose POSIX 1003.2 format archives.
6**
7** Dec. 14, 1997 Chris Herborth (chrish@kagi.com)
8**
9** This code is donated to the PUBLIC DOMAIN. You can use, abuse, modify,
10** redistribute, steal, or otherwise manipulate this code. No restrictions
11** at all. If you laugh at this code, you can't use it.
12**
13** This "ar" was implemented using IEEE Std 1003.2-1992 as the basis for
14** the interface, and Metrowerk's published docs detailing their library
15** format. Look inside for clues about how reality differs from MW's
16** documentation on BeOS...
17*/
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <unistd.h>
22#include <getopt.h>
23
24#include "commands.h"
25
26static const char *rcs_version_id = "$Id$";
27static const char *ar_version_id = "1.0 " __DATE__;
28
29/* ---------------------------------------------------------------------- */
30typedef enum {
31 delete_cmd,
32 print_cmd,
33 replace_cmd,
34 table_cmd,
35 extract_cmd,
36 no_cmd = -1 } command;
37
38/* ----------------------------------------------------------------------
39** Prototypes
40*/
41void usage( void );
42void version( void );
43void check_command( command *cmd, int arg );
44
45/* ----------------------------------------------------------------------
46** Print a usage message and exit.
47*/
48void usage( void )
49{
50 printf( "ar [dprtx][cuv] archive [file ...]\n" );
51
52 exit( EXIT_FAILURE );
53}
54
55/* ----------------------------------------------------------------------
56** Print a version message and exit.
57*/
58void version( void )
59{
60 printf( "ar (POSIX 1003.2-1992), version %s\n", ar_version_id );
61 printf( "by Chris Herborth (chrish@qnx.com)\n" );
62 printf( "This code has been donated to the BeOS developer community.\n" );
63
64 return;
65}
66
67/* ----------------------------------------------------------------------
68** Set *cmd to the appropriate command enum if it isn't already set.
69*/
70void check_command( command *cmd, int arg )
71{
72 if( *cmd == no_cmd ) {
73 switch( arg ) {
74 case 'd':
75 *cmd = delete_cmd;
76 break;
77 case 'p':
78 *cmd = print_cmd;
79 break;
80 case 'r':
81 *cmd = replace_cmd;
82 break;
83 case 't':
84 *cmd = table_cmd;
85 break;
86 case 'x':
87 *cmd = extract_cmd;
88 break;
89 }
90 } else {
91 printf( "ar: you can only specify one command at a time\n" );
92 usage();
93 }
94}
95
96/* ----------------------------------------------------------------------
97** Mainline
98*/
99int main( int argc, char **argv )
100{
101 command cmd = no_cmd;
102 int verbose_flag = 0;
103 int create_flag = 0; /* these two only apply to replace_cmd */
104 int update_flag = 0;
105 int c = 0;
106
107 char *archive_name;
108 char **files_list;
109 int num_files;
110
111 int idx;
112 status_t retval;
113
114 /* The argument parsing is a little hairier than usual; the idea is
115 ** to support the POSIX 1003.2 style of arguments, and the much more
116 ** common traditional argument style.
117 */
118 if( argc < 3 ) {
119 printf( "ar: invalid number of arguments\n" );
120 usage();
121 }
122
123 /* Do we have traditional or POSIX-style args? */
124 if( argv[1][0] == '-' ) {
125 while( ( c = getopt( argc, argv, "dprtxcuvV" ) ) != EOF ) {
126 switch( c ) {
127 case 'd': /* fall-through */
128 case 'p': /* fall-through */
129 case 'r': /* fall-through */
130 case 't': /* fall-through */
131 case 'x': /* fall-through */
132 check_command( &cmd, c );
133 break;
134
135 case 'v':
136 verbose_flag = 1;
137 break;
138
139 case 'c':
140 if( cmd != no_cmd && cmd != replace_cmd ) {
141 printf( "ar: invalid option, -c\n" );
142 usage();
143 } else {
144 create_flag = 1;
145 }
146 break;
147
148 case 'u':
149 if( cmd != no_cmd && cmd != replace_cmd ) {
150 printf( "ar: invalid option, -u\n" );
151 usage();
152 } else {
153 update_flag = 1;
154 }
155 break;
156
157 case 'V':
158 version();
159 break;
160
161 default:
162 printf( "ar: invalid option, -%c\n", c );
163 usage();
164 break;
165 }
166
167 idx = optind;
168 }
169 } else {
170 /* In the traditional way, arguments ar:
171 **
172 ** argv[1] = [dprtx][cuv]
173 ** argv[2] = archive
174 ** argv[...] = file ...
175 **/
176 char *ptr;
177
178 idx = 1;
179
180 ptr = argv[idx++];
181
182 while( *ptr != '\0' ) {
183 switch( *ptr ) {
184 case 'd': /* fall-through */
185 case 'p': /* fall-through */
186 case 'r': /* fall-through */
187 case 't': /* fall-through */
188 case 'x': /* fall-through */
189 check_command( &cmd, *ptr );
190 break;
191
192 case 'v':
193 verbose_flag = 1;
194 break;
195
196 case 'c':
197 if( cmd != no_cmd && cmd != replace_cmd ) {
198 printf( "ar: invalid option, -c\n" );
199 usage();
200 } else {
201 create_flag = 1;
202 }
203 break;
204
205 case 'u':
206 if( cmd != no_cmd && cmd != replace_cmd ) {
207 printf( "ar: invalid option, -u\n" );
208 usage();
209 } else {
210 update_flag = 1;
211 }
212 break;
213
214 case 'V':
215 version();
216 break;
217
218 default:
219 printf( "ar: invalid option, -%c\n", c );
220 usage();
221 break;
222 }
223
224 ptr++;
225 }
226 }
227
228 /* Next arg is the archive. */
229 archive_name = argv[idx++];
230
231 /* Next are the files. */
232 num_files = argc - idx;
233
234 if( num_files == 0 ) {
235 files_list = NULL;
236 } else {
237 int ctr = 0;
238
239 files_list = (char **)malloc( ( num_files + 1 ) * sizeof( char * ) );
240
241 while( idx < argc ) {
242 files_list[ctr++] = argv[idx++];
243 }
244
245 files_list[idx] = NULL;
246 }
247
248 /* Now we can attempt to manipulate the archive. */
249 switch( cmd ) {
250 case delete_cmd:
251 retval = do_delete( archive_name, files_list, verbose_flag );
252 break;
253
254 case print_cmd:
255 retval = do_print( archive_name, files_list, verbose_flag );
256 break;
257
258 case replace_cmd:
259 retval = do_replace( archive_name, files_list, verbose_flag,
260 create_flag, update_flag );
261 break;
262
263 case table_cmd:
264 retval = do_table( archive_name, files_list, verbose_flag );
265 break;
266
267 case extract_cmd:
268 retval = do_extract( archive_name, files_list, verbose_flag );
269 break;
270
271 default:
272 printf( "ar: you must specify a command\n" );
273 usage();
274 break;
275 }
276
277 /* Check the return value.
278 */
279 switch( retval ) {
280 case B_OK:
281 break;
282 case B_FILE_NOT_FOUND:
283 printf( "can't open the file %s\n", archive_name );
284 return EXIT_FAILURE;
285 break;
286 case B_IO_ERROR:
287 printf( "can't read from %s\n", archive_name );
288 return EXIT_FAILURE;
289 break;
290 case B_BAD_VALUE:
291 printf( "invalid magic word\n" );
292 return EXIT_FAILURE;
293 break;
294 case B_MISMATCHED_VALUES:
295 printf( "invalid processor value, or magicflags, or version\n" );
296 return EXIT_FAILURE;
297 break;
298 case B_NO_MEMORY:
299 printf( "unable to allocate memory\n" );
300 return EXIT_FAILURE;
301 break;
302 case B_ERROR:
303 printf( "error during processing\n" );
304 return EXIT_FAILURE;
305 default:
306 printf( "unknown error: %ld\n", retval );
307 return EXIT_FAILURE;
308 break;
309 }
310
311 return EXIT_SUCCESS;
312}