Commit 65e164f8 authored by Guido van Rossum's avatar Guido van Rossum

Removing the BeOS specific 'ar' utility -- no longer needed,

says Chris Herborth.
parent 030d2ec1
######################################################################
# Makefile for ar
#
# Dec. 14, 1997 Chris Herborth (chrish@kagi.com)
#
# $Id$
######################################################################
AR_VERSION=1.1
# Make variables
CC=mwcc
LD=mwcc
CFLAGS=-w9 -rostr -O3 -g
CFLAGS_O=-w9 -rostr -O7 -opt schedule604
LDFLAGS=-g -map ar.xMAP
LDFLAGS_O=
INSTALL=install -m 755
DESTINATION=/boot/home/config/bin
PARTS=main.o mwlib.o commands.o copy_attrs.o
all: ar
nodebug:
-rm -f ar $(PARTS) ar.dbg ar.xSYM
$(MAKE) CFLAGS="$(CFLAGS_O) -DNO_DEBUG" LDFLAGS="$(LDFLAGS_O)" ar
ar: $(PARTS)
$(LD) $(LDFLAGS) -o $@ $(PARTS)
install: ar
$(INSTALL) ar $(DESTINATION)
ln -sf $(DESTINATION)/ar $(DESTINATION)/ar-posix
clean:
-rm -f $(PARTS) ar ar.dbg ar.xSYM
zip:
(cd .. ; zip -9ry ar-$(AR_VERSION).zip ar-$(AR_VERSION) \
-x ar-$(AR_VERSION)/RCS -x ar-$(AR_VERSION)/docs/RCS \
-x ar-$(AR_VERSION)/RCS/\* -x ar-$(AR_VERSION)/docs/RCS/\*)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
docs/ar.html
\ No newline at end of file
ar - POSIX 1003.2 interface to library files
Here's the source and PowerPC binary for a POSIX 1003.2 interface "ar"
command; this is extremely useful when you're porting complex UNIX/POSIX
software to BeOS for PowerPC (I originally wrote it to support my Python
port).
To build/install ar, do this in a Terminal:
make nodebug install
This will create ar and ar-posix (a symlink to ar) in ~/config/bin. The
ar-posix symlink is to make things a little easier if you happen to
have GeekGadgets (see www.ninemoons.com) installed; it comes with an
ar that only works on objects/libraries produced by GNU C for BeOS.
To use the POSIX ar with your port, do something like this:
AR=ar-posix ./configure ... normal configure arguments ...
and then:
make AR=ar-posix
You may need to check the Makefiles; people seem to be quite sloppy about
using just plain "ar cr libfoo.a ..." instead of "$(AR) cr libfoo.a ...".
- Chris Herborth, April 18, 1998
(chrish@kagi.com)
This diff is collapsed.
This diff is collapsed.
/*
** commands.h - POSIX 1003.2 "ar" command
**
** $Id$
**
** 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 <be/support/SupportDefs.h>
status_t do_delete( const char *archive_name, char **files, int verbose );
status_t do_print( const char *archive_name, char **files, int verbose );
status_t do_replace( const char *archive_name, char **files, int verbose,
int create, int update );
status_t do_table( const char *archive_name, char **files, int verbose );
status_t do_extract( const char *archive_name, char **files, int verobse );
/*
** copy_attrs.h - copy BeFS attributes from one file to another
**
** Jan. 11, 1998 Chris Herborth (chrish@qnx.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.
*/
#include <support/Errors.h>
#ifndef NO_DEBUG
#include <assert.h>
#define ASSERT(cond) assert(cond)
#else
#define ASSERT(cond) ((void)0)
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>
#include <errno.h>
#include <kernel/fs_attr.h>
#include <fcntl.h>
#include "copy_attrs.h"
static const char *rcs_version_id = "$Id$";
/* ----------------------------------------------------------------------
** Copy file attributes from src_file to dst_file.
*/
status_t copy_attrs( const char *dst_file, const char *src_file )
{
int dst_fd, src_fd;
status_t retval = B_OK;
DIR *fa_dir = NULL;
struct dirent *fa_ent = NULL;
char *buff = NULL;
struct attr_info fa_info;
off_t read_bytes, wrote_bytes;
ASSERT( dst_file != NULL );
ASSERT( src_file != NULL );
/* Attempt to open the files.
*/
src_fd = open( src_file, O_RDONLY );
if( src_fd < 0 ) {
return B_FILE_NOT_FOUND;
}
dst_fd = open( dst_file, O_WRONLY );
if( dst_fd < 0 ) {
close( src_fd );
return B_FILE_NOT_FOUND;
}
/* Read the attributes, and write them to the destination file.
*/
fa_dir = fs_fopen_attr_dir( src_fd );
if( fa_dir == NULL ) {
retval = B_IO_ERROR;
goto close_return;
}
fa_ent = fs_read_attr_dir( fa_dir );
while( fa_ent != NULL ) {
retval = fs_stat_attr( src_fd, fa_ent->d_name, &fa_info );
if( retval != B_OK ) {
/* TODO: Print warning message?
*/
goto read_next_attr;
}
if( fa_info.size > (off_t)UINT_MAX ) {
/* TODO: That's too big. Print a warning message? You could
** copy it in chunks...
*/
goto read_next_attr;
}
if( fa_info.size > (off_t)0 ) {
buff = malloc( (size_t)fa_info.size );
if( buff == NULL ) {
/* TODO: Can't allocate memory for this attribute. Warning?
*/
goto read_next_attr;
}
read_bytes = fs_read_attr( src_fd, fa_ent->d_name, fa_info.type,
0, buff, fa_info.size );
if( read_bytes != fa_info.size ) {
/* TODO: Couldn't read entire attribute. Warning?
*/
goto free_attr_buff;
}
wrote_bytes = fs_write_attr( dst_fd, fa_ent->d_name, fa_info.type,
0, buff, fa_info.size );
if( wrote_bytes != fa_info.size ) {
/* TODO: Couldn't write entire attribute. Warning?
*/
;
}
free_attr_buff:
free( buff );
retval = B_OK;
}
/* Read the next entry.
*/
read_next_attr:
fa_ent = fs_read_attr_dir( fa_dir );
}
close_return:
close( dst_fd );
close( src_fd );
return retval;
}
/*
** copy_attrs.h - copy BeFS attributes from one file to another
**
** $Id$
**
** Jan. 11, 1998 Chris Herborth (chrish@qnx.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.
*/
/* ----------------------------------------------------------------------
** Function prototypes
**
** copy_attrs() - copy BeFS attributes from one file to another
**
** Returns:
** B_OK - all is well
** B_FILE_NOT_FOUND - can't open one of the named files
** B_IO_ERROR - can't read/write some of the file attributes
** B_NO_MEMORY - unable to allocate a buffer for the attribute data
*/
status_t copy_attrs( const char *dest_file, const char *src_file );
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML3.2//EN">
<!-- $Id$ -->
<html> <head>
<title>ar - create and maintain library archives</title>
</head>
<body bgcolor="#ffffcb">
<h1>ar</h1>
<h4 align="right">create and maintain library archives</h4>
<h2>Synopsis</h2>
<pre>
ar [-][dprtx][cuv] <i>archive</i> [<i>file</i> ...]
</pre>
<h2>Options</h2>
<table>
<tr>
<td valign="top"><b>-</b></td>
<td valign="top">
The <b>-</b> is optional for introducing <tt>ar</tt> command-line
arguments; this is a POSIX requirement, and I've never seen anyone
use it.</td>
</tr>
<tr>
<td valign="top"><b>c</b></td>
<td valign="top">
Don't print a diagnostic message to <i>stderr</i> when
<i>archive</i> is created.</td>
</tr>
<tr>
<td valign="top"><b>d</b></td>
<td valign="top">
Delete <i>file(s)</i> from <i>archive</i>.</td>
</tr>
<tr>
<td valign="top"><b>p</b></td>
<td valign="top">
Write the contents of the named <i>file(s)</i> to <i>stdout</i>.
If no <i>file(s)</i> are specified, all of the files in
<i>archive</i> are written in the order of the archive.</td>
</tr>
<tr>
<td valign="top"><b>r</b></td>
<td valign="top">
Replace or add <i>file(s)</i> to the <i>archive</i>. This will
create <i>archive</i> if it doesn't already exist.</td>
</tr>
<tr>
<td valign="top"><b>t</b></td>
<td valign="top">
Write the table of contents of <i>archive</i> to <i>stdout</i>.
If not <i>file(s)</i> are specified, list all of the files,
otherwise only list the specified files.</td>
</tr>
<tr>
<td valign="top"><b>u</b></td>
<td valign="top">
Update older files. When used with the <b>r</b> option, files
within the archive are only replaced if <i>file</i> has a
modification date at least as new as the <i>file</i> already in
the archive.</td>
</tr>
<tr>
<td valign="top"><b>v</b></td>
<td valign="top">Give verbose output.</td>
</tr>
<tr>
<td valign="top"><b>x</b></td>
<td valign="top">
Extract <i>file(s)</i> from the <i>archive</i>. If no
<i>file(s)</i> are specified, all of the files in <i>archive</i>
are extracted.</td>
</tr>
<tr>
<td valign="top"><i>archive</i></td>
<td valign="top">
The pathname of an archive file.</td>
</tr>
<tr>
<td valign="top"><i>file</i></td>
<td valign="top">
One more more pathnames of object files; only the file name is
used when comparing against the names of files in the
archive.</td>
</tr>
</table>
<h2>Description</h2>
<p>The <tt>ar</tt> utility creates and maintains groups of files
combined into a library. Once a library has been created, you can
add new files, and extract, delete, or replace existing files.</p>
<h2>Exit status</h2>
<p><tt>ar</tt> exits with one of the following values:</p>
<table>
<tr><td valign="top">0</td>
<td valign="top">Successful completion.</td></tr>
<tr><td valign="top">&gt; 0</td>
<td>An error occurred.</td></tr>
</table>
<h2>Bugs</h2>
<p>No known bugs, but <em>please</em> read the comments in the code if
you want to use it in another application.</p>
<h2>Comments</h2>
<p>This is a POSIX 1003.2-1992 based <tt>ar</tt> command; it's not
100% POSIX 1003.2 because POSIX specifies a file format for
<tt>ar</tt> archives. The BeOS <tt>ar</tt> produces library files
compatible (at least in theory <tt>:-)</tt>) with Metrowerks
CodeWarrior for PowerPC.</p>
<p>This <tt>ar</tt> and its source code were written as a service to
the Be developer community, to make it easier for us to port UNIX
applications and libraries. The code was written from scratch, after
reverse-engineering the Metrowerks library and object file format
(mostly because the library/object file format documentation was
incorrect).</p>
<p>If you find this useful, please
<a href="mailto:chrish@kagi.com">let me know</a>, and tell me what
you're working on. Be sure to include a URL for your homepage or your
product homepages for my
<a href="http://www.qnx.com/~chrish/Be/community/">Be Community</a>
pages.</p>
<p>If you find any bugs, please try to fix them, and send me a context
diff (use <tt>diff -c original_file fixed_file</tt>) so I can include
your fixes in the next update. I <i>have</i> tested this, but these
things have a way of slipping though.</p>
<p>If you'd like to know what other things I'm working on, take a look
at my <a href="http://www.qnx.com/~chrish/Be/software/">Be
Software</a> pages, and my
<a href="http://www.qnx.com/~chrish/Be/">Be Happy!</a> pages.</p>
<h2>License</h2>
<p>This program binary and its source code have been donated to the
BeOS Developer Community by Arcane Dragon Software free of charge.
You can do whatever you want with it.</p>
<p>If you <em>really</em> want to show your appreciation, you could
always send me a gift of some sort; cool software you wrote, nice
pictures for my desktop, ZIP drive disks, RAM, hard drives, post
cards, a pointer to a really cool/useful/interesting web site,
an MPEG audio file of an interesting band (make sure you can give me
enough information to track down their CDs if I like it!), <i>etc.</i>
Send me some <a href="mailto:chrish@kagi.com">email</a> and I'll let you
know where to send it.</p>
<p>But you don't have to do anything. Just write good BeOS software.
But you're already doing that, right?</p>
<h2>Disclaimer</h2>
<p>You use this at your own risk. I've tried to ensure that the code
is correct, but software usually has bugs. If <tt>ar</tt> destroys
your valuable data, formats your hard drive, kicks your cat, and lets
the air out of your tires, I'm not responsible for it. The code is
here, so you should feel fairly safe that there's nothing evil going
on.</p>
<p>And, as I learned once again in December 1997, you really should
keep backups of everything. I only lost a day's work, but it was
still annoying, and it could've been much, much worse.</p>
<h3>A word about the code</h3>
<p>This code isn't meant to be the ultimate in efficiency or speed,
it's intended to be fairly easy to understand and maintain
(hopefully). I was also quite keen on having something that was
correct, without jumping through a lot of unnecessary hoops.</p>
<p>If you think this code sucks, don't use it. You're already applying
this to your choice of operating system! <tt>:-)</tt></p>
<h2>Versions</h2>
<dl compact>
<dt><strong>1.1 (April 18, 1998)</strong></dt>
<dd>Changes include:
<ul>
<li>Extract option (<b>x</b>) will preserve a file's mode bits
when overwriting an existing file (this may go away if it's
not POSIX behaviour).</li>
<li>Extracted files will now have the proper file type.</li>
<li>Removed attempt to use <i>umask()</i> to set newly created
archive's mode bits; apparently, I'm not sure how it
works and my POSIX manual isn't helping.</li>
<li>Should be 100% endian-neutral now; using this on BeOS for
x86 is only useful if you're manipulating <em>PowerPC</em>
objects though. The <tt>ar</tt> in
<a href="http://www.ninemoons.com/GG/index.html">GeekGadgets</a>
should work fine for x86 objects/libraries.</li>
<li>Updated the <tt>README.txt</tt> file; now it's got useful
information about building/using the POSIX ar.</li>
</ul></dd>
<dt><strong>1.0 (January 13, 1998)</strong></dt>
<dd>Initial release.</dd>
</dl>
<hr>
<p>Chris Herborth (<a href="mailto:chrish@qnx.com">chrish@qnx.com</a>)</p>
<!-- hhmts start -->
Last modified: $Date$
<!-- hhmts end -->
</body> </html>
#! /bin/env python
""" Dump data about a Metrowerks archive file.
$Id$
Based on reverse-engineering the library file format.
Copyright (C) 1997 Chris Herborth (chrish@qnx.com)
"""
# ----------------------------------------------------------------------
# Standard modules
import sys
import getopt
import string
import time
# ----------------------------------------------------------------------
def usage():
""" Display a usage message and exit.
"""
print "dumpar [-v] library1 [library2 ... libraryn]"
print
print "Attempt to display some useful information about the contents"
print "of the given Metrowerks library file(s)."
print
print "-v Be verbose (displays offsets along with the data)"
raise SystemExit
# ----------------------------------------------------------------------
def mk_long( str ):
""" convert a 4-byte string into a number
Assumes big-endian!
"""
if len( str ) < 4:
raise ValueError, "str must be 4 bytes long"
num = ord( str[3] )
num = num + ord( str[2] ) * 0x100
num = num + ord( str[1] ) * 0x10000
num = num + ord( str[0] ) * 0x1000000
return num
# ----------------------------------------------------------------------
def str2hex( str ):
""" convert a string into a string of hex numbers
"""
ret = []
for c in str:
h = hex( ord( c ) )
ret.append( string.zfill( "%s" % ( h[2:] ), 2 ) )
return string.join( ret )
# ----------------------------------------------------------------------
def print_offset( offset ):
""" print the offset nicely
"""
# Turn the offset into a hex number and strip off the leading "0x".
val = "%s" % ( hex( offset ) )
val = val[2:]
out = "0x" + string.zfill( val, 8 )
print out,
# ----------------------------------------------------------------------
def get_string( data ):
""" dig a C string out of a data stream
returns the string
"""
len = 0
while data[len] != '\0':
len = len + 1
return data[:len]
# ----------------------------------------------------------------------
def dump_lib( file, verbose ):
""" dump information about a Metrowerks library file
"""
offset = 0
print "Dumping library:", file
# Attempt to read the data.
try:
data = open( file ).read()
except IOError, retval:
print "*** Unable to open file %s: %s" % ( file, retval[1] )
return
# Check the magic number.
if verbose:
print_offset( offset )
print "Magic:",
magic = data[offset:offset + 8]
print "'%s'" % ( magic )
if magic != "MWOBPPC ":
print "*** Invalid magic number!"
return
offset = offset + 8
# File flags
if verbose:
print_offset( offset )
print "file flags:",
print mk_long( data[offset:offset + 4] )
offset = offset + 4
if verbose:
print_offset( offset )
print "file version:",
print mk_long( data[offset:offset + 4] )
offset = offset + 4
# code size
if verbose:
print_offset( offset )
print "code size:", mk_long( data[offset:offset + 4] )
offset = offset + 4
# data size
if verbose:
print_offset( offset )
print "data size:", mk_long( data[offset:offset + 4] )
offset = offset + 4
# number of objects
if verbose:
print_offset( offset )
print "number of objects:",
num_objs = mk_long( data[offset:offset + 4] )
print num_objs
offset = offset + 4
print
# Now loop through the objects.
obj_sizes = [ 0, ] * num_objs
obj_data_offsets = [ 0, ] * num_objs
for obj in range( num_objs ):
# Magic?
if verbose:
print_offset( offset )
print "modification time:",
modtime = mk_long( data[offset:offset + 4] )
print "[%s]" % ( ( time.localtime( modtime ), ) )
offset = offset + 4
# Offsets?
if verbose:
print_offset( offset )
print "file name offset 1:",
file_offset1 = mk_long( data[offset:offset + 4] )
unknown = "%s" % ( hex( file_offset1 ) )
print "%s (%s)" % ( unknown, str2hex( data[offset:offset + 4] ) )
offset = offset + 4
if verbose:
print_offset( offset )
print "file name offset 2:",
file_offset2 = mk_long( data[offset:offset + 4] )
unknown = "%s" % ( hex( file_offset2 ) )
print "%s (%s)" % ( unknown, str2hex( data[offset:offset + 4] ) )
offset = offset + 4
# Extra -1 for NUL character.
print " >>>> File name should be %s characters." % \
( file_offset2 - file_offset1 - 1)
if verbose:
print_offset( offset )
print "object data offset:",
file_data_offset = mk_long( data[offset:offset + 4] )
unknown = "%s" % ( hex( file_data_offset ) )
print "%s (%s)" % ( unknown, str2hex( data[offset:offset + 4] ) )
obj_data_offsets[obj] = file_data_offset
offset = offset + 4
# object size
if verbose:
print_offset( offset )
print "object size:",
obj_sizes[obj] = mk_long( data[offset:offset + 4] )
print "%s bytes" % ( obj_sizes[obj] )
offset = offset + 4
print
# Now loop through the object names.
for obj in range( num_objs ):
# First name
if verbose:
print_offset( offset )
print "object",
print obj,
print "name 1:",
name1 = get_string( data[offset:] )
print "[%s] %s chars" % ( name1, len( name1 ) )
offset = offset + len( name1 ) + 1
# Second name
if verbose:
print_offset( offset )
print "object",
print obj,
print "name 2:",
name2 = get_string( data[offset:] )
print "[%s] %s chars" % ( name2, len( name1 ) )
offset = offset + len( name2 ) + 1
# See if we've got a magic cookie in the object data
if verbose:
print_offset( obj_data_offsets[obj] )
cookie = data[obj_data_offsets[obj]:obj_data_offsets[obj] + 8]
print "object",
print obj,
print "cookie: '%s'" % ( cookie )
print
# Now loop through the data and check for magic numbers there.
return
# ----------------------------------------------------------------------
def main():
""" mainline
"""
# Set up some defaults
be_verbose = 0
# First, check the command-line arguments
try:
opt, args = getopt.getopt( sys.argv[1:], "vh?" )
except getopt.error:
print "*** Error parsing command-line options!"
usage()
for o in opt:
if o[0] == "-h" or o[0] == "-?":
usage()
elif o[0] == "-v":
be_verbose = 1
else:
print "*** Unknown command-line option!"
usage()
# Now we can attempt to dump info about the arguments.
for lib in args:
dump_lib( lib, be_verbose )
if __name__ == "__main__":
main()
#! /bin/env python
""" Dump data about a Metrowerks object file.
Based on reverse-engineering the library file format, since the docs are
wrong.
Copyright (C) 1997 Chris Herborth (chrish@qnx.com)
"""
# ----------------------------------------------------------------------
# Standard modules
import sys, getopt, string, time
# ----------------------------------------------------------------------
# Extra goodies
from dumpar import mk_long, str2hex, print_offset, get_string
# ----------------------------------------------------------------------
def mk_short( str ):
""" convert a 2-byte string into a number
Assumes big-endian!
"""
if len( str ) < 2:
raise ValueError, "str must be 2 bytes long"
num = ord( str[1] )
num = num + ord( str[0] ) * 0x100
return num
# ----------------------------------------------------------------------
def usage():
""" Display a usage message and exit.
"""
print "dumpo [-v] object1 [object2 ... objectn]"
print
print "Attempt to display some useful information about the contents"
print "of the given Metrowerks object file(s)."
print
print "-v Be verbose (displays offsets along with the data)"
raise SystemExit
# ----------------------------------------------------------------------
def dump_o( file, verbose ):
""" dump information about a Metrowerks object file
Note that there is more info there, 6 more quads before the file name.
"""
offset = 0
print "Dumping object:", file
# Attempt to read the data.
try:
data = open( file ).read()
except IOError, retval:
print "*** Unable to open file %s: %s" % ( file, retval[1] )
return
# Check the magic number.
if verbose:
print_offset( offset )
print "Magic:",
magic = data[offset:offset + 8]
print "'%s'" % ( magic )
if magic != "MWOBPPC ":
print "*** Invalid magic number!"
return
offset = offset + 8
# version
if verbose:
print_offset( offset )
print "version:", mk_long( data[offset:offset + 4] )
offset = offset + 4
# flags
if verbose:
print_offset( offset )
print "flags:", str2hex( data[offset:offset + 4] )
offset = offset + 4
# code size
if verbose:
print_offset( offset )
print "code size:", mk_long( data[offset:offset + 4] )
offset = offset + 4
# data size
if verbose:
print_offset( offset )
print "data size:", mk_long( data[offset:offset + 4] )
offset = offset + 4
# ----------------------------------------------------------------------
def main():
""" mainline
"""
# Set up some defaults
be_verbose = 0
# First, check the command-line arguments
try:
opt, args = getopt.getopt( sys.argv[1:], "vh?" )
except getopt.error:
print "*** Error parsing command-line options!"
usage()
for o in opt:
if o[0] == "-h" or o[0] == "-?":
usage()
elif o[0] == "-v":
be_verbose = 1
else:
print "*** Unknown command-line option!"
usage()
# Now we can attempt to dump info about the arguments.
for obj in args:
dump_o( obj, be_verbose )
if __name__ == "__main__":
main()
MW library layout:
header
magic word, magic processor flag ('MWOBPPC ') - 2x 4 bytes
magic flags, version (file format version?) - 2x 4 bytes
code size - 4 bytes
data size - 4 bytes
# of objects - 4 bytes
header for file 1 - 20 bytes
- modification time - 4 bytes
- offset to filename - 4 bytes
- offset to full path - 4 bytes (NOTE: NOT a full path in reality!)
- offset to object data - 4 bytes
- size of object data - 4 bytes
...
header for file n - 20 bytes
file 1 name + NUL - variable
file 1 name + NUL - variable
file 2 name + NUL - variable
file 2 name + NUL - variable
...
file n name + NUL - variable
file n name + NUL - variable
padding to multiple of 4 bytes - 0 - 3 bytes
file 1 data - variable (padded to 4-byte boundary)
file 2 data - variable (padded to 4-byte boundary)
...
file n data - variable (padded to 4-byte boundary)
/*
** 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;
}
This diff is collapsed.
/*
** mwlib.h - POSIX 1003.2 "ar" command
**
** $Id$
**
** 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@qnx.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 <support/SupportDefs.h>
#include <time.h>
/* ----------------------------------------------------------------------
** Constants
**
*/
#define MWLIB_MAGIC_WORD 'MWOB'
#define MWLIB_MAGIC_PROC 'PPC '
/* ----------------------------------------------------------------------
** Structures
**
** This is based on the "Metrowerks CodeWarrior Library Reference
** Specification", which isn't 100% accurate for BeOS.
*/
typedef struct MWLibHeader {
uint32 magicword;
uint32 magicproc;
uint32 magicflags;
uint32 version;
uint32 code_size;
uint32 data_size;
uint32 num_objects;
} MWLibHeader;
typedef struct MWLibFile {
time_t m_time;
uint32 off_filename;
uint32 off_fullpath;
uint32 off_object;
uint32 object_size;
} MWLibFile;
typedef struct MWLib {
MWLibHeader header;
MWLibFile *files;
char **names;
char **data;
} MWLib;
/* This bears no resemblance to what's in the Metrowerks docs.
**
** Note that this is incomplete; this is all the info I needed for
** ar though.
*/
typedef struct MWObject {
uint32 magic_word; /* 'MWOB' */
uint32 arch; /* 'PPC '; this isn't in the docs */
uint32 version;
uint32 flags;
uint32 code_size;
uint32 data_size;
} MWObject;
/* ----------------------------------------------------------------------
** Function prototypes
**
** load_MW_lib() - load a Metrowerks library
**
** Returns:
** B_OK - all is well
** B_FILE_NOT_FOUND - can't open the given file
** B_IO_ERROR - can't read from the given file
** B_BAD_VALUE - invalid magic word in the file
** B_MISMATCHED_VALUES - invalid processor value (ie, not a PowerPC lib),
** or the magicflags member is not 0, or the file
** version number isn't 1.
** B_NO_MEMORY - unable to allocate memory while loading the lib
**
** write_MW_lib() - write a Metrowerks library
**
** Returns:
** B_OK - all is well
**
** write_MW_lib() - write a Metrowerks library file
**
** Returns:
** B_OK - all is well; doesn't necessarily mean the file was written
** properly, just that you didn't lose any data
** B_NO_MEMORY - unable to allocate offset buffers
** B_ERROR - problem with backup file (can't rename existing file)
**
** Note:
** If you use this in a long-lived program, it leaks memory; the MWLib
** contents are never free()'d.
*/
status_t load_MW_lib( MWLib *lib, const char *filename );
status_t write_MW_lib( MWLib *lib, const char *filename );
void setfiletype( const char *filename, const char *type );
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment