| /* |
| ** main.c - POSIX 1003.2 "ar" command |
| ** |
| ** This isn't a pure POSIX 1003.2 ar; it only manipulates Metrowerks |
| ** Library files, not general-purpose POSIX 1003.2 format archives. |
| ** |
| ** Dec. 14, 1997 Chris Herborth (chrish@kagi.com) |
| ** |
| ** This code is donated to the PUBLIC DOMAIN. You can use, abuse, modify, |
| ** redistribute, steal, or otherwise manipulate this code. No restrictions |
| ** at all. If you laugh at this code, you can't use it. |
| ** |
| ** This "ar" was implemented using IEEE Std 1003.2-1992 as the basis for |
| ** the interface, and Metrowerk's published docs detailing their library |
| ** format. Look inside for clues about how reality differs from MW's |
| ** documentation on BeOS... |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <getopt.h> |
| |
| #include "commands.h" |
| |
| static const char *rcs_version_id = "$Id$"; |
| static const char *ar_version_id = "1.0 " __DATE__; |
| |
| /* ---------------------------------------------------------------------- */ |
| typedef enum { |
| delete_cmd, |
| print_cmd, |
| replace_cmd, |
| table_cmd, |
| extract_cmd, |
| no_cmd = -1 } command; |
| |
| /* ---------------------------------------------------------------------- |
| ** Prototypes |
| */ |
| void usage( void ); |
| void version( void ); |
| void check_command( command *cmd, int arg ); |
| |
| /* ---------------------------------------------------------------------- |
| ** Print a usage message and exit. |
| */ |
| void usage( void ) |
| { |
| printf( "ar [dprtx][cuv] archive [file ...]\n" ); |
| |
| exit( EXIT_FAILURE ); |
| } |
| |
| /* ---------------------------------------------------------------------- |
| ** Print a version message and exit. |
| */ |
| void version( void ) |
| { |
| printf( "ar (POSIX 1003.2-1992), version %s\n", ar_version_id ); |
| printf( "by Chris Herborth (chrish@qnx.com)\n" ); |
| printf( "This code has been donated to the BeOS developer community.\n" ); |
| |
| return; |
| } |
| |
| /* ---------------------------------------------------------------------- |
| ** Set *cmd to the appropriate command enum if it isn't already set. |
| */ |
| void check_command( command *cmd, int arg ) |
| { |
| if( *cmd == no_cmd ) { |
| switch( arg ) { |
| case 'd': |
| *cmd = delete_cmd; |
| break; |
| case 'p': |
| *cmd = print_cmd; |
| break; |
| case 'r': |
| *cmd = replace_cmd; |
| break; |
| case 't': |
| *cmd = table_cmd; |
| break; |
| case 'x': |
| *cmd = extract_cmd; |
| break; |
| } |
| } else { |
| printf( "ar: you can only specify one command at a time\n" ); |
| usage(); |
| } |
| } |
| |
| /* ---------------------------------------------------------------------- |
| ** Mainline |
| */ |
| int main( int argc, char **argv ) |
| { |
| command cmd = no_cmd; |
| int verbose_flag = 0; |
| int create_flag = 0; /* these two only apply to replace_cmd */ |
| int update_flag = 0; |
| int c = 0; |
| |
| char *archive_name; |
| char **files_list; |
| int num_files; |
| |
| int idx; |
| status_t retval; |
| |
| /* The argument parsing is a little hairier than usual; the idea is |
| ** to support the POSIX 1003.2 style of arguments, and the much more |
| ** common traditional argument style. |
| */ |
| if( argc < 3 ) { |
| printf( "ar: invalid number of arguments\n" ); |
| usage(); |
| } |
| |
| /* Do we have traditional or POSIX-style args? */ |
| if( argv[1][0] == '-' ) { |
| while( ( c = getopt( argc, argv, "dprtxcuvV" ) ) != EOF ) { |
| switch( c ) { |
| case 'd': /* fall-through */ |
| case 'p': /* fall-through */ |
| case 'r': /* fall-through */ |
| case 't': /* fall-through */ |
| case 'x': /* fall-through */ |
| check_command( &cmd, c ); |
| break; |
| |
| case 'v': |
| verbose_flag = 1; |
| break; |
| |
| case 'c': |
| if( cmd != no_cmd && cmd != replace_cmd ) { |
| printf( "ar: invalid option, -c\n" ); |
| usage(); |
| } else { |
| create_flag = 1; |
| } |
| break; |
| |
| case 'u': |
| if( cmd != no_cmd && cmd != replace_cmd ) { |
| printf( "ar: invalid option, -u\n" ); |
| usage(); |
| } else { |
| update_flag = 1; |
| } |
| break; |
| |
| case 'V': |
| version(); |
| break; |
| |
| default: |
| printf( "ar: invalid option, -%c\n", c ); |
| usage(); |
| break; |
| } |
| |
| idx = optind; |
| } |
| } else { |
| /* In the traditional way, arguments ar: |
| ** |
| ** argv[1] = [dprtx][cuv] |
| ** argv[2] = archive |
| ** argv[...] = file ... |
| **/ |
| char *ptr; |
| |
| idx = 1; |
| |
| ptr = argv[idx++]; |
| |
| while( *ptr != '\0' ) { |
| switch( *ptr ) { |
| case 'd': /* fall-through */ |
| case 'p': /* fall-through */ |
| case 'r': /* fall-through */ |
| case 't': /* fall-through */ |
| case 'x': /* fall-through */ |
| check_command( &cmd, *ptr ); |
| break; |
| |
| case 'v': |
| verbose_flag = 1; |
| break; |
| |
| case 'c': |
| if( cmd != no_cmd && cmd != replace_cmd ) { |
| printf( "ar: invalid option, -c\n" ); |
| usage(); |
| } else { |
| create_flag = 1; |
| } |
| break; |
| |
| case 'u': |
| if( cmd != no_cmd && cmd != replace_cmd ) { |
| printf( "ar: invalid option, -u\n" ); |
| usage(); |
| } else { |
| update_flag = 1; |
| } |
| break; |
| |
| case 'V': |
| version(); |
| break; |
| |
| default: |
| printf( "ar: invalid option, -%c\n", c ); |
| usage(); |
| break; |
| } |
| |
| ptr++; |
| } |
| } |
| |
| /* Next arg is the archive. */ |
| archive_name = argv[idx++]; |
| |
| /* Next are the files. */ |
| num_files = argc - idx; |
| |
| if( num_files == 0 ) { |
| files_list = NULL; |
| } else { |
| int ctr = 0; |
| |
| files_list = (char **)malloc( ( num_files + 1 ) * sizeof( char * ) ); |
| |
| while( idx < argc ) { |
| files_list[ctr++] = argv[idx++]; |
| } |
| |
| files_list[idx] = NULL; |
| } |
| |
| /* Now we can attempt to manipulate the archive. */ |
| switch( cmd ) { |
| case delete_cmd: |
| retval = do_delete( archive_name, files_list, verbose_flag ); |
| break; |
| |
| case print_cmd: |
| retval = do_print( archive_name, files_list, verbose_flag ); |
| break; |
| |
| case replace_cmd: |
| retval = do_replace( archive_name, files_list, verbose_flag, |
| create_flag, update_flag ); |
| break; |
| |
| case table_cmd: |
| retval = do_table( archive_name, files_list, verbose_flag ); |
| break; |
| |
| case extract_cmd: |
| retval = do_extract( archive_name, files_list, verbose_flag ); |
| break; |
| |
| default: |
| printf( "ar: you must specify a command\n" ); |
| usage(); |
| break; |
| } |
| |
| /* Check the return value. |
| */ |
| switch( retval ) { |
| case B_OK: |
| break; |
| case B_FILE_NOT_FOUND: |
| printf( "can't open the file %s\n", archive_name ); |
| return EXIT_FAILURE; |
| break; |
| case B_IO_ERROR: |
| printf( "can't read from %s\n", archive_name ); |
| return EXIT_FAILURE; |
| break; |
| case B_BAD_VALUE: |
| printf( "invalid magic word\n" ); |
| return EXIT_FAILURE; |
| break; |
| case B_MISMATCHED_VALUES: |
| printf( "invalid processor value, or magicflags, or version\n" ); |
| return EXIT_FAILURE; |
| break; |
| case B_NO_MEMORY: |
| printf( "unable to allocate memory\n" ); |
| return EXIT_FAILURE; |
| break; |
| case B_ERROR: |
| printf( "error during processing\n" ); |
| return EXIT_FAILURE; |
| default: |
| printf( "unknown error: %ld\n", retval ); |
| return EXIT_FAILURE; |
| break; |
| } |
| |
| return EXIT_SUCCESS; |
| } |