mirror of https://github.com/python/cpython
Adding the BeOS port. More checkins to follow.
This commit is contained in:
parent
3f7b6fcea0
commit
d8eb2119b5
|
@ -0,0 +1,47 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>PyImport_BeImageID()</title>
|
||||
</head>
|
||||
<body text="#000000" bgcolor="#ffffff">
|
||||
|
||||
<h1>PyImport_BeImageID()</h1>
|
||||
|
||||
<dl compact>
|
||||
|
||||
<dt><strong>NOTE:</strong><dt>
|
||||
|
||||
<dd>This is documentation for the BeOS-specific
|
||||
<code>PyImport_BeImageID()</code> function defined in
|
||||
<tt>Python/importdl.c</tt>; it should be merged with the
|
||||
<cite>Importing Modules</cite> section of the <cite>Python/C API</cite>
|
||||
reference (or it should be the first member of a BeOS-specific
|
||||
document in the <tt>BeOS</tt> directory).</dd>
|
||||
|
||||
</dl>
|
||||
|
||||
<dl compact
|
||||
|
||||
<dt><code>image_id <b>PyImport_BeImageID</b>( char *<i>name</i> )</code></dt>
|
||||
|
||||
<dd>Return the BeOS image ID (see the
|
||||
<a href="file:///boot/beos/documentation/Be%20Book/The%20Kernel%20Kit/Images.html">Images</a>
|
||||
section in the
|
||||
<a href="file:///boot/beos/documentation/Be%20Book/The%20Kernel%20Kit/index.html">Kernel
|
||||
Kit</a>) for the module object corresponding to a module <i>name</i>.
|
||||
If the specified module is not dynamically loaded,
|
||||
<code>PyImport_BeImageID()</code> will return <code>B_ERROR</code>,
|
||||
otherwise it will return a valid <code>image_id</code>.
|
||||
|
||||
<p>Using <code>PyImport_BeImageID()</code> outside of a BeOS-specific
|
||||
module is probably a very bad idea.</p></dd>
|
||||
|
||||
</dl>
|
||||
|
||||
<hr>
|
||||
<p>Function added by Donn Cave
|
||||
(<a href="mailto:donn@u.washington.edu"><tt>donn@u.washington.edu</tt></a>),
|
||||
documented by Chris Herborth
|
||||
(<a href="mailto:chrish@qnx.com"><tt>chrish@qnx.com</tt></a>).</p>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,140 @@
|
|||
Python 1.5.1 for BeOS
|
||||
|
||||
This directory contains several useful things to help you build your own
|
||||
version of Python for BeOS.
|
||||
|
||||
At this time, Python only supports BeOS on the PowerPC platform; if you'd
|
||||
like to help me port it to the x86 platform, please let me know (I only
|
||||
have limited access to BeOS on an x86 system). If you'd like to lend
|
||||
me an x86 laptop running BeOS to do the port, _definitely_ let me know! :-)
|
||||
I'll even give it back when I'm done.
|
||||
|
||||
What's Here?
|
||||
|
||||
ar-1.1 - An "ar" command with a POSIX 1003.2 interface; you'll need
|
||||
this for building the Python libraries under BeOS
|
||||
(/bin/ar just won't cut it).
|
||||
|
||||
linkcc - A shell script used by the build process to build the Python
|
||||
shared library.
|
||||
|
||||
linkmodule - A shell script used by the build process to build the
|
||||
shared library versions of the standard modules; you'll
|
||||
probably need this if you want to build dynamically loaded
|
||||
modules from the Python archives.
|
||||
|
||||
PyImport_BeImageID.html - Documentation for a function added to the
|
||||
Python interpreter under BeOS; not interesting
|
||||
unless you're writing your own BeOS-specific
|
||||
modules for dealing with dynamically-loaded
|
||||
Python modules.
|
||||
|
||||
README - This file (obviously!).
|
||||
|
||||
README.readline-2.2 - Instructions for compiling/installing GNU readline 2.2.
|
||||
You'll have to grab the GNU readline source code from
|
||||
prep.ai.mit.edu:/pub/GNU or any other GNU mirror.
|
||||
|
||||
The Python interpreter is much nicer to work with
|
||||
interactively if you've got readline installed. Highly
|
||||
recommended.
|
||||
|
||||
Compiling Your Own Version
|
||||
|
||||
To compile your own version of Python 1.5.1 for BeOS (with any luck,
|
||||
Python 1.6 will compile "out of the box" on BeOS), try this:
|
||||
|
||||
1) Get the Python 1.5.1 source code from ftp.python.org.
|
||||
|
||||
2) Get the Python 1.5.1 diffs from my web pages
|
||||
(http://www.qnx.com/~chrish/Be/software/); if you can't get them through
|
||||
a web browser, send me email and I'll mail them back to you. These
|
||||
diffs should also be available at ftp.python.org along with the BeOS
|
||||
binary archive.
|
||||
|
||||
Run autoconf. If you don't have autoconf, you can get a precompiled
|
||||
version from GeekGadgets (ftp://ftp.ninemoons.com/pub/geekgadgets/...).
|
||||
|
||||
3) Compile and install the POSIX ar from the ar-1.1 directory; see the
|
||||
README in there for details.
|
||||
|
||||
4) Configure with:
|
||||
|
||||
AR=ar-posix RANLIB=: ./configure --verbose --without-gcc \
|
||||
--prefix=/boot/home/config --with-thread
|
||||
|
||||
The only strange thing that happens during the configure is that
|
||||
we fail the "genuine getopt()" test; this is odd because we've got
|
||||
a real live GNU getopt() in the system libs. Other packages built
|
||||
using configure (such as all of the goodies in GeekGadgets) suffer
|
||||
the same fate though, so it's not a Python problem.
|
||||
|
||||
5) Copy Modules/Setup.in to Modules/Setup.
|
||||
|
||||
6) Edit Modules/Setup to turn on all the modules you want built. I've
|
||||
personally built the following modules:
|
||||
|
||||
array, audioop, binascii, cPickle, cStringIO, cmath, crypt, curses,
|
||||
errno, fcntl, gdbm, grp, imageop, math, md5, new, operator, parser,
|
||||
pcre, posix, pwd, readline, regex, reop, rgbimg, rotor, select,
|
||||
signal, socket, soundex, strop, struct, syslog, termios, thread,
|
||||
time, timing, zlib
|
||||
|
||||
Newly compiled/tested with 1.5.1:
|
||||
|
||||
_locale
|
||||
|
||||
You can get precompiled gdbm, ncurses, and zlib libraries from the
|
||||
GeekGadgets repository (ftp://ftp.ninemoons.com/pub/geekgadgets/...).
|
||||
|
||||
Make sure you use _socket instead of socket for the name of the
|
||||
socketmodule on BeOS.
|
||||
|
||||
7) Make:
|
||||
|
||||
make
|
||||
|
||||
or, if you feel the need for speed:
|
||||
|
||||
make OPT="-O7 -opt schedule604"
|
||||
|
||||
You can safely ignore any warnings you see during the build (and you'll
|
||||
see several if you use full warnings; I compiled the distribution with
|
||||
-w9 -ansi strict and cleaned up any errors...).
|
||||
|
||||
8) Test:
|
||||
|
||||
make test
|
||||
|
||||
Expect the following errors:
|
||||
|
||||
test_builtin failed -- round(1000000000.0)
|
||||
test_fcntl skipped -- an optional feature could not be imported
|
||||
test_grp crashed -- exceptions.KeyError : getgrnam(): name not found
|
||||
test_pwd failed -- Writing: 'fakename', expected: 'caught e'
|
||||
test_socket crashed -- exceptions.AttributeError : SOCK_RAW
|
||||
|
||||
These are all due to either partial support for certain things (like
|
||||
sockets), or valid differences between systems (like the round()
|
||||
error; different CPUs represent floating point numbers differently,
|
||||
which can cause minor rounding errors).
|
||||
|
||||
9) Install:
|
||||
|
||||
make install
|
||||
|
||||
10) Enjoy!
|
||||
|
||||
NOTE
|
||||
|
||||
If you're going to build your own C/C++-based Python modules, link them
|
||||
against the libpython1.5.so shared library (in /boot/home/config/lib)
|
||||
instead of the libpython1.5.a (in /boot/home/config/lib/python1.5/config),
|
||||
unless you're building a statically-linked python interpreter (then you
|
||||
could try linking against _APP_ instead).
|
||||
|
||||
Mixing modules linked against the shared library with a statically-linked
|
||||
interpreter is a bad idea (and it'll fail in _interesting_ ways).
|
||||
|
||||
- Chris Herborth (chrish@qnx.com)
|
||||
April 25, 1998
|
|
@ -0,0 +1,56 @@
|
|||
GNU readline 2.2 for BeOS
|
||||
|
||||
You can get the original GNU readline 2.2 source code from your favourite
|
||||
GNU software repository, such as ftp://prep.ai.mit.edu/pub/gnu/.
|
||||
|
||||
You can get the only-slightly-modified-for-BeOS version of GNU readline 2.2
|
||||
from the GeekGadgets repository; ftp://ftp.ninemoons.com/pub/geekgadgets/.
|
||||
|
||||
BUILDING libreadline for BeOS hosts
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Note that we don't build a shared library version of libreadline and
|
||||
libhistory. That's left as an exercise for the reader.
|
||||
|
||||
You won't be able to link against libreadline.a using the limited linker.
|
||||
|
||||
1) If you're on a PowerPC system, install the POSIX ar from
|
||||
http://www.qnx.com/~chrish/Be/software/index.html#programming
|
||||
(note that it's currently packaged with Python, in the BeOS/ar-1.1
|
||||
directory).
|
||||
|
||||
If you're on an x86 system, you can leave out the "AR=ar-posix" part
|
||||
of the following instructions. In fact, you'll have to...
|
||||
|
||||
2) For PowerPC, configure with:
|
||||
|
||||
CC=mwcc CFLAGS="-O7 -i- -I." AR=ar-posix RANLIB=: ./configure --verbose \
|
||||
--without-gcc --prefix=/boot/home/config powerpc-*-beos
|
||||
|
||||
For x86, configure with:
|
||||
|
||||
CC=mwcc CFLAGS="-O2 -i- -I." RANLIB=: ./configure --verbose \
|
||||
--without-gcc --prefix=/boot/home/config x86-*-beos
|
||||
|
||||
Don't worry about the warnings/errors configure spews for
|
||||
powerpc-*-beos or x86-*-beos; readline doesn't actually use this host
|
||||
information for anything, although configure will die if you don't
|
||||
specify it.
|
||||
|
||||
3) Edit config.h to comment out "#define HAVE_SELECT 1"; select() on
|
||||
BeOS doesn't work on file descriptors (such as stdin).
|
||||
|
||||
4) For PowerPC, make with:
|
||||
|
||||
make AR=ar-posix
|
||||
|
||||
For x86, make with:
|
||||
|
||||
make
|
||||
|
||||
5) Install with:
|
||||
|
||||
make install
|
||||
|
||||
- Chris Herborth (chrish@qnx.com)
|
||||
April 21, 1998
|
|
@ -0,0 +1,48 @@
|
|||
######################################################################
|
||||
# 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 $@
|
|
@ -0,0 +1 @@
|
|||
docs/ar.html
|
|
@ -0,0 +1,29 @@
|
|||
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)
|
Binary file not shown.
|
@ -0,0 +1,461 @@
|
|||
File: 0 "/boot/src/ar-1.0/main.c"
|
||||
File: 1 "/boot/src/ar-1.0/mwlib.c"
|
||||
File: 2 "/boot/src/ar-1.0/commands.c"
|
||||
File: 3 "/boot/src/ar-1.0/copy_attrs.c"
|
||||
File: 5 "/boot/rel/src/kit/glue/common/global_destructor_chain.c"
|
||||
File: 6 "/boot/rel/src/kit/glue/ppc/runtime.c"
|
||||
File: 9 "/boot/rel/src/kit/glue/common/init_term_dyn.c"
|
||||
File: 10 "/boot/rel/src/kit/glue/common/start_dyn.c"
|
||||
File: 11 "/boot/develop/lib/ppc/libroot.so"
|
||||
|
||||
Files that were not referenced:
|
||||
"libbe.so"
|
||||
"libtracker.so"
|
||||
"libmedia.so"
|
||||
"libnet.so"
|
||||
"libnetdev.so"
|
||||
"libdevice.so"
|
||||
"libmidi.so"
|
||||
"libgame.so"
|
||||
"libatalk.so"
|
||||
"libmail.so"
|
||||
|
||||
Code section, size = 16672 bytes
|
||||
000000 PR .__sinit file = "*Linker-Generated*"
|
||||
00001C PR .usage file = "main.c"
|
||||
000050 PR .version
|
||||
000094 PR .check_command
|
||||
000128 PR .main
|
||||
0005A0 PR .load_MW_lib file = "mwlib.c"
|
||||
000A1C PR .load_MWLibFile
|
||||
000BAC PR .fwrite_big32
|
||||
000C10 PR .fwrite_big32_seek
|
||||
000CA4 PR .add_object_sizes
|
||||
000DA4 PR .setfiletype
|
||||
000EA8 PR .write_MW_lib
|
||||
001850 PR .do_match file = "commands.c"
|
||||
001958 PR .do_delete
|
||||
001A84 PR .delete_lib_entry
|
||||
001C5C PR .do_print
|
||||
001D98 PR .print_lib_entry
|
||||
001E90 PR .load_lib_file
|
||||
0020F4 PR .do_replace
|
||||
0023B8 PR .add_lib_entry
|
||||
00256C PR .replace_lib_entry
|
||||
00272C PR .do_table
|
||||
002868 PR .table_lib_entry
|
||||
0029E8 PR .do_extract
|
||||
002B24 PR .extract_lib_entry
|
||||
002E20 PR .copy_attrs file = "copy_attrs.c"
|
||||
00306C PR .__destroy_global_chain file = "global_destructor_chain.c"
|
||||
0030C0 PR .__RTOC file = "init_term_dyn.c"
|
||||
0030C8 PR ._init_routine_
|
||||
003118 PR ._term_routine_
|
||||
003148 PR .__start file = "start_dyn.c"
|
||||
003204 GL .__register_fragment file = "*Linker-Generated*"
|
||||
00321C GL .find_thread
|
||||
003234 GL .memcpy
|
||||
00324C GL ._call_init_routines_
|
||||
003264 GL .printf
|
||||
00327C GL .exit
|
||||
003294 GL .getopt
|
||||
0032AC GL .malloc
|
||||
0032C4 GL .__assertion_failed
|
||||
0032DC GL .fprintf
|
||||
0032F4 GL .fopen
|
||||
00330C GL .fread
|
||||
003324 GL .fseek
|
||||
00333C GL .fgets
|
||||
003354 GL .strdup
|
||||
00336C GL .fclose
|
||||
003384 GL .strrchr
|
||||
00339C GL .strcmp
|
||||
0033B4 GL .free
|
||||
0033CC GL .memset
|
||||
0033E4 GL .access
|
||||
0033FC GL .stat
|
||||
003414 GL ._errnop
|
||||
00342C GL .strerror
|
||||
003444 GL .strlen
|
||||
00345C GL .sprintf
|
||||
003474 GL .unlink
|
||||
00348C GL .rename
|
||||
0034A4 GL .fwrite
|
||||
0034BC GL .ftell
|
||||
0034D4 GL .chmod
|
||||
0034EC GL .open
|
||||
003504 GL .close
|
||||
00351C GL .fs_fopen_attr_dir
|
||||
003534 GL .fs_read_attr_dir
|
||||
00354C GL .fs_stat_attr
|
||||
003564 GL .fs_read_attr
|
||||
00357C GL .fs_write_attr
|
||||
003594 GL .fflush
|
||||
0035AC GL .realloc
|
||||
0035C4 GL .localtime
|
||||
0035DC GL .strftime
|
||||
0035F4 GL .getgid
|
||||
00360C GL .getuid
|
||||
003624 GL .utime
|
||||
00363C GL ._thread_do_exit_notification
|
||||
003654 GL .__unregister_fragment
|
||||
00366C GL .__ptr_glue file = "runtime.c"
|
||||
003680 RO @10 file = "main.c"
|
||||
003690 RO @13
|
||||
0036B4 RO @16
|
||||
0036D8 RO @17
|
||||
0036FC RO @18
|
||||
003739 RO @30
|
||||
003769 RO @109
|
||||
00378A RO @110
|
||||
0037A2 RO @111
|
||||
0037BA RO @112
|
||||
0037D3 RO @113
|
||||
0037DD RO @114
|
||||
0037FD RO @115
|
||||
003815 RO @116
|
||||
003829 RO @117
|
||||
00383D RO @118
|
||||
003871 RO @119
|
||||
00388C RO @120
|
||||
0038A5 RO @121
|
||||
0038B9 RO @78 file = "mwlib.c"
|
||||
0038C3 RO @79
|
||||
0038CB RO @80
|
||||
0038DA RO @81
|
||||
0038DC RO @98
|
||||
0038E7 RO @99
|
||||
0038F5 RO @104
|
||||
0038FE RO @122
|
||||
003908 RO @123
|
||||
003913 RO @124
|
||||
00391E RO @133
|
||||
003947 RO @134
|
||||
003951 RO @135
|
||||
00397B RO @235
|
||||
003980 RO @236
|
||||
0039AC RO @237
|
||||
0039C3 RO @238
|
||||
0039F5 RO @239
|
||||
0039F9 RO @240
|
||||
003A12 RO @241
|
||||
003A33 RO @242
|
||||
003A35 RO @243
|
||||
003A56 RO @244
|
||||
003A7B RO @245
|
||||
003AA7 RO @246
|
||||
003AD1 RO @247
|
||||
003AF0 RO @248
|
||||
003B14 RO @249
|
||||
003B3D RO @250
|
||||
003B69 RO @251
|
||||
003B90 RO @252
|
||||
003BBB RO @253
|
||||
003BD8 RO @254
|
||||
003BF1 RO @255
|
||||
003C11 RO @29 file = "commands.c"
|
||||
003C1B RO @30
|
||||
003C26 RO @31
|
||||
003C31 RO @32
|
||||
003C3B RO @53
|
||||
003C4E RO @54
|
||||
003C65 RO @55
|
||||
003C7D RO @81
|
||||
003C9E RO @82
|
||||
003CA6 RO @120
|
||||
003CAE RO @121
|
||||
003CC5 RO @142
|
||||
003CD4 RO @143
|
||||
003CDF RO @144
|
||||
003CF6 RO @145
|
||||
003D0C RO @146
|
||||
003D2E RO @147
|
||||
003D30 RO @148
|
||||
003D47 RO @149
|
||||
003D5E RO @198
|
||||
003D6F RO @199
|
||||
003D89 RO @200
|
||||
003DAA RO @222
|
||||
003DCF RO @223
|
||||
003DE8 RO @224
|
||||
003E12 RO @225
|
||||
003E1A RO @242
|
||||
003E39 RO @243
|
||||
003E65 RO @244
|
||||
003E6D RO @284
|
||||
003E85 RO @285
|
||||
003E88 RO @286
|
||||
003E9F RO @287
|
||||
003EBE RO @288
|
||||
003EC9 RO @289
|
||||
003ECD RO @343
|
||||
003EE6 RO @344
|
||||
003EEE RO @345
|
||||
003EF0 RO @346
|
||||
003F11 RO @347
|
||||
003F27 RO @348
|
||||
003F53 RO @349
|
||||
003F7E RO @350
|
||||
003F97 RO @43 file = "copy_attrs.c"
|
||||
003FA6 RO @44
|
||||
003FB3 RO @45
|
||||
003FC4 TI @14 file = "main.c"
|
||||
003FD0 TI @19
|
||||
003FDC TI @32
|
||||
003FE8 TI @124
|
||||
003FF4 TI @82 file = "mwlib.c"
|
||||
004000 TI @100
|
||||
00400C TI @105
|
||||
004018 TI @111
|
||||
004024 TI @125
|
||||
004030 TI @136
|
||||
00403C TI @256
|
||||
004048 TI @33 file = "commands.c"
|
||||
004054 TI @56
|
||||
004060 TI @83
|
||||
00406C TI @110
|
||||
004078 TI @122
|
||||
004084 TI @150
|
||||
004090 TI @201
|
||||
00409C TI @226
|
||||
0040A8 TI @245
|
||||
0040B4 TI @272
|
||||
0040C0 TI @290
|
||||
0040CC TI @317
|
||||
0040D8 TI @351
|
||||
0040E4 TI @46 file = "copy_attrs.c"
|
||||
0040F0 TI @7 file = "global_destructor_chain.c"
|
||||
0040FC TI @2 file = "init_term_dyn.c"
|
||||
004108 TI @4
|
||||
004114 TI @17 file = "start_dyn.c"
|
||||
|
||||
Data section, size = 1084 bytes (TOC anchor = 000000)
|
||||
000000 TC fs_write_attr file = "*Linker-Generated*"
|
||||
000004 TC strftime
|
||||
000008 TC fwrite
|
||||
00000C TC sprintf
|
||||
000010 TC open
|
||||
000014 TC fread
|
||||
000018 TC fs_fopen_attr_dir
|
||||
00001C TC fseek
|
||||
000020 TC strrchr
|
||||
000024 TC free
|
||||
000028 TC printf
|
||||
00002C TC ftell
|
||||
000030 TC exit
|
||||
000034 TC strerror
|
||||
000038 TC __register_fragment
|
||||
00003C TC memcpy
|
||||
000040 TC strcmp
|
||||
000044 TC strlen
|
||||
000048 TC _call_init_routines_
|
||||
00004C TC strdup
|
||||
000050 TC _files
|
||||
000054 TC fgets
|
||||
000058 TC malloc
|
||||
00005C TC find_thread
|
||||
000060 TC close
|
||||
000064 TC memset
|
||||
000068 TC chmod
|
||||
00006C TC fopen
|
||||
000070 TC stat
|
||||
000074 TC fs_read_attr
|
||||
000078 TC access
|
||||
00007C TC fs_read_attr_dir
|
||||
000080 TC unlink
|
||||
000084 TC getopt
|
||||
000088 TC getgid
|
||||
00008C TC __unregister_fragment
|
||||
000090 TC _errnop
|
||||
000094 TC fprintf
|
||||
000098 TC optind
|
||||
00009C TC __assertion_failed
|
||||
0000A0 TC rename
|
||||
0000A4 TC utime
|
||||
0000A8 TC getuid
|
||||
0000AC TC fs_stat_attr
|
||||
0000B0 TC fflush
|
||||
0000B4 TC _thread_do_exit_notification
|
||||
0000B8 TC fclose
|
||||
0000BC TC localtime
|
||||
0000C0 TC realloc
|
||||
0000C4 TC __global_destructor_chain
|
||||
0000C8 TC __exception_table_end__
|
||||
0000CC TC __exception_table_start__
|
||||
0000D0 TC __data_end__
|
||||
0000D4 TC __data_start__
|
||||
0000D8 TC __code_end__
|
||||
0000DC TC __code_start__
|
||||
0000E0 TC __main_thread_id
|
||||
0000E4 TC environ
|
||||
0000E8 TC argv_save
|
||||
0000EC TC @123 file = "main.c"
|
||||
0000F0 TC @122
|
||||
0000F4 TC @121
|
||||
0000F8 TC @120
|
||||
0000FC TC @119
|
||||
000100 TC @118
|
||||
000104 TC @117
|
||||
000108 TC @116
|
||||
00010C TC @115
|
||||
000110 TC @114
|
||||
000114 TC @113
|
||||
000118 TC @112
|
||||
00011C TC @111
|
||||
000120 TC @110
|
||||
000124 TC @109
|
||||
000128 TC @31
|
||||
00012C TC @30
|
||||
000130 TC @18
|
||||
000134 TC @17
|
||||
000138 TC @16
|
||||
00013C TC @13
|
||||
000140 TC @255 file = "mwlib.c"
|
||||
000144 TC @254
|
||||
000148 TC @253
|
||||
00014C TC @252
|
||||
000150 TC @251
|
||||
000154 TC @250
|
||||
000158 TC @249
|
||||
00015C TC @248
|
||||
000160 TC @247
|
||||
000164 TC @246
|
||||
000168 TC @245
|
||||
00016C TC @244
|
||||
000170 TC @243
|
||||
000174 TC @242
|
||||
000178 TC @241
|
||||
00017C TC @240
|
||||
000180 TC @239
|
||||
000184 TC @238
|
||||
000188 TC @237
|
||||
00018C TC @236
|
||||
000190 TC @235
|
||||
000194 TC @135
|
||||
000198 TC @134
|
||||
00019C TC @133
|
||||
0001A0 TC @124
|
||||
0001A4 TC @123
|
||||
0001A8 TC @122
|
||||
0001AC TC @104
|
||||
0001B0 TC @99
|
||||
0001B4 TC @98
|
||||
0001B8 TC @81
|
||||
0001BC TC @80
|
||||
0001C0 TC @79
|
||||
0001C4 TC @78
|
||||
0001C8 TC @350 file = "commands.c"
|
||||
0001CC TC @349
|
||||
0001D0 TC @348
|
||||
0001D4 TC @347
|
||||
0001D8 TC @346
|
||||
0001DC TC @345
|
||||
0001E0 TC @344
|
||||
0001E4 TC @343
|
||||
0001E8 TC @289
|
||||
0001EC TC @288
|
||||
0001F0 TC @287
|
||||
0001F4 TC @286
|
||||
0001F8 TC @285
|
||||
0001FC TC @284
|
||||
000200 TC @244
|
||||
000204 TC @243
|
||||
000208 TC @242
|
||||
00020C TC @225
|
||||
000210 TC @224
|
||||
000214 TC @223
|
||||
000218 TC @222
|
||||
00021C TC @200
|
||||
000220 TC @199
|
||||
000224 TC @198
|
||||
000228 TC @149
|
||||
00022C TC @148
|
||||
000230 TC @147
|
||||
000234 TC @146
|
||||
000238 TC @145
|
||||
00023C TC @144
|
||||
000240 TC @143
|
||||
000244 TC @142
|
||||
000248 TC @121
|
||||
00024C TC @120
|
||||
000250 TC @82
|
||||
000254 TC @81
|
||||
000258 TC @55
|
||||
00025C TC @54
|
||||
000260 TC @53
|
||||
000264 TC @32
|
||||
000268 TC @31
|
||||
00026C TC @30
|
||||
000270 TC @29
|
||||
000274 TC @45 file = "copy_attrs.c"
|
||||
000278 TC @44
|
||||
00027C TC @43
|
||||
000280 TC magic_template file = "start_dyn.c"
|
||||
000284 TC default_environ
|
||||
000288 TD ar_version_id file = "main.c"
|
||||
00028C TD fragmentID file = "init_term_dyn.c"
|
||||
000290 DS _term_routine_ file = "init_term_dyn.c"
|
||||
000298 DS _init_routine_
|
||||
0002A0 DS __start file = "start_dyn.c"
|
||||
0002A8 RW @31 file = "main.c"
|
||||
0002FC RW @123
|
||||
000388 RW @122
|
||||
000414 RW magic_template file = "start_dyn.c"
|
||||
00041C RW @13
|
||||
00042C RW default_environ
|
||||
000434 RW __global_destructor_chain file = "global_destructor_chain.c"
|
||||
|
||||
Import container "libroot.so"
|
||||
Current Version = 00000000, Old Implementation = 00000000
|
||||
000000 DS fs_write_attr
|
||||
000001 DS strftime
|
||||
000002 DS fwrite
|
||||
000003 DS sprintf
|
||||
000004 DS open
|
||||
000005 DS fread
|
||||
000006 DS fs_fopen_attr_dir
|
||||
000007 DS fseek
|
||||
000008 DS strrchr
|
||||
000009 DS free
|
||||
00000A RW environ
|
||||
00000B DS printf
|
||||
00000C DS ftell
|
||||
00000D DS exit
|
||||
00000E DS strerror
|
||||
00000F DS __register_fragment
|
||||
000010 DS memcpy
|
||||
000011 DS strcmp
|
||||
000012 DS strlen
|
||||
000013 DS _call_init_routines_
|
||||
000014 DS strdup
|
||||
000015 RW argv_save
|
||||
000016 RW _files
|
||||
000017 DS fgets
|
||||
000018 DS malloc
|
||||
000019 DS find_thread
|
||||
00001A DS close
|
||||
00001B DS memset
|
||||
00001C DS chmod
|
||||
00001D DS fopen
|
||||
00001E DS stat
|
||||
00001F DS fs_read_attr
|
||||
000020 DS access
|
||||
000021 DS fs_read_attr_dir
|
||||
000022 DS unlink
|
||||
000023 DS getopt
|
||||
000024 DS getgid
|
||||
000025 DS __unregister_fragment
|
||||
000026 DS _errnop
|
||||
000027 DS fprintf
|
||||
000028 RW optind
|
||||
000029 DS __assertion_failed
|
||||
00002A DS rename
|
||||
00002B DS utime
|
||||
00002C RW __main_thread_id
|
||||
00002D DS getuid
|
||||
00002E DS fs_stat_attr
|
||||
00002F DS fflush
|
||||
000030 DS _thread_do_exit_notification
|
||||
000031 DS fclose
|
||||
000032 DS localtime
|
||||
000033 DS realloc
|
|
@ -0,0 +1,809 @@
|
|||
/*
|
||||
** commands.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 <support/Errors.h>
|
||||
#include <support/byteorder.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 <utime.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "mwlib.h"
|
||||
#include "commands.h"
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE (0)
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
#define TRUE (!FALSE)
|
||||
#endif
|
||||
|
||||
static const char *rcs_version_id = "$Id$";
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
** Local functions
|
||||
**
|
||||
** do_match() - find the index of the file, if it's in the archive; return
|
||||
** TRUE if found, else FALSE
|
||||
**/
|
||||
static int do_match( MWLib *lib, const char *file, int *idx );
|
||||
|
||||
static int do_match( MWLib *lib, const char *file, int *idx )
|
||||
{
|
||||
int which = 0;
|
||||
char *name_ptr;
|
||||
|
||||
ASSERT( lib != NULL );
|
||||
ASSERT( file != NULL );
|
||||
ASSERT( idx != NULL );
|
||||
|
||||
/* Skip over the path, if any, so we can compare just the file name.
|
||||
*/
|
||||
name_ptr = strrchr( file, '/' );
|
||||
if( name_ptr == NULL ) {
|
||||
name_ptr = (char *)file;
|
||||
} else {
|
||||
name_ptr++;
|
||||
}
|
||||
|
||||
for( which = 0; which < lib->header.num_objects; which++ ) {
|
||||
if( !strcmp( name_ptr, lib->names[which] ) ) {
|
||||
*idx = which;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
** Delete an archive member.
|
||||
**
|
||||
** This isn't really optimal; you could make a more efficient version
|
||||
** using a linked list instead of arrays for the data. This was easier
|
||||
** to write, and speed shouldn't be that big a deal here... you're not
|
||||
** likely to be dealing with thousands of files.
|
||||
*/
|
||||
static status_t delete_lib_entry( MWLib *lib, int idx, int verbose );
|
||||
|
||||
status_t do_delete( const char *archive_name, char **files, int verbose )
|
||||
{
|
||||
status_t retval = B_OK;
|
||||
MWLib lib;
|
||||
int idx = 0;
|
||||
int which = 0;
|
||||
|
||||
ASSERT( archive_name != NULL );
|
||||
|
||||
if( files == NULL ) {
|
||||
fprintf( stderr, "ar: %s, nothing to do\n", archive_name );
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
retval = load_MW_lib( &lib, archive_name );
|
||||
if( retval != B_OK ) {
|
||||
switch( retval ) {
|
||||
case B_FILE_NOT_FOUND:
|
||||
fprintf( stderr, "ar: %s, file not found\n", archive_name );
|
||||
return retval;
|
||||
break;
|
||||
|
||||
default:
|
||||
return retval;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete the specified files.
|
||||
*/
|
||||
for( idx = 0; files[idx] != NULL; idx++ ) {
|
||||
if( do_match( &lib, files[idx], &which ) ) {
|
||||
retval = delete_lib_entry( &lib, which, verbose );
|
||||
}
|
||||
which = 0;
|
||||
}
|
||||
|
||||
/* Write the new file.
|
||||
*/
|
||||
retval = write_MW_lib( &lib, archive_name );
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static status_t delete_lib_entry( MWLib *lib, int which, int verbose )
|
||||
{
|
||||
uint32 new_num;
|
||||
MWLibFile *new_files = NULL;
|
||||
char **new_names = NULL;
|
||||
char **new_data = NULL;
|
||||
int ctr = 0;
|
||||
int idx = 0;
|
||||
|
||||
ASSERT( lib != NULL );
|
||||
ASSERT( which <= lib->header.num_objects );
|
||||
|
||||
new_num = lib->header.num_objects - 1;
|
||||
|
||||
new_files = (MWLibFile *)malloc( new_num * ( sizeof( MWLibFile ) ) );
|
||||
new_names = (char **)malloc( new_num * ( sizeof( char * ) ) );
|
||||
new_data = (char **)malloc( new_num * ( sizeof( char * ) ) );
|
||||
if( new_files == NULL || new_names == NULL || new_data == NULL ) {
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
/* Copy the contents of the old lib to the new lib, skipping the one
|
||||
** we want to delete.
|
||||
*/
|
||||
for( ctr = 0; ctr < lib->header.num_objects; ctr++ ) {
|
||||
if( ctr != which ) {
|
||||
memcpy( &(new_files[idx]), &(lib->files[ctr]),
|
||||
sizeof( MWLibFile ) );
|
||||
new_names[idx] = lib->names[ctr];
|
||||
new_data[idx] = lib->data[ctr];
|
||||
|
||||
idx++;
|
||||
} else {
|
||||
/* Free up the name and data.
|
||||
*/
|
||||
if( verbose ) {
|
||||
printf( "d - %s\n", lib->names[ctr] );
|
||||
}
|
||||
|
||||
free( lib->names[idx] );
|
||||
lib->names[idx] = NULL;
|
||||
free( lib->data[idx] );
|
||||
lib->data[idx] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free up the old lib's data.
|
||||
*/
|
||||
free( lib->files );
|
||||
free( lib->names );
|
||||
free( lib->data );
|
||||
|
||||
lib->files = new_files;
|
||||
lib->names = new_names;
|
||||
lib->data = new_data;
|
||||
|
||||
lib->header.num_objects = new_num;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
** Print an archive member to stdout.
|
||||
*/
|
||||
static status_t print_lib_entry( MWLib *lib, int idx, int verbose );
|
||||
|
||||
status_t do_print( const char *archive_name, char **files, int verbose )
|
||||
{
|
||||
status_t retval = B_OK;
|
||||
MWLib lib;
|
||||
int idx = 0;
|
||||
|
||||
ASSERT( archive_name != NULL );
|
||||
|
||||
retval = load_MW_lib( &lib, archive_name );
|
||||
if( retval != B_OK ) {
|
||||
switch( retval ) {
|
||||
case B_FILE_NOT_FOUND:
|
||||
fprintf( stderr, "ar: %s, file not found\n", archive_name );
|
||||
return retval;
|
||||
break;
|
||||
|
||||
default:
|
||||
return retval;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( files == NULL ) {
|
||||
/* Then we print the entire archive.
|
||||
*/
|
||||
for( idx = 0; idx < lib.header.num_objects; idx++ ) {
|
||||
retval = print_lib_entry( &lib, idx, verbose );
|
||||
}
|
||||
} else {
|
||||
/* Then we print the specified files.
|
||||
*/
|
||||
int which = 0;
|
||||
|
||||
for( idx = 0; files[idx] != NULL; idx++ ) {
|
||||
if( do_match( &lib, files[idx], &which ) ) {
|
||||
retval = print_lib_entry( &lib, which, verbose );
|
||||
}
|
||||
which = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static status_t print_lib_entry( MWLib *lib, int idx, int verbose )
|
||||
{
|
||||
int recs;
|
||||
|
||||
ASSERT( lib != NULL );
|
||||
|
||||
if( verbose ) {
|
||||
printf( "\n<%s>\n\n", lib->names[idx] );
|
||||
}
|
||||
|
||||
recs = fwrite( lib->data[idx], lib->files[idx].object_size, 1, stdout );
|
||||
fflush( stdout );
|
||||
if( recs != 1 ) {
|
||||
fprintf( stderr, "error printing %s, %s\n", lib->names[idx],
|
||||
strerror( errno ) );
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
** Add/replace/update files in an archive.
|
||||
*/
|
||||
static status_t add_lib_entry( MWLib *lib, const char *filename, int verbose );
|
||||
static status_t replace_lib_entry( MWLib *lib, const char *filename,
|
||||
int idx, int verbose );
|
||||
static status_t load_lib_file( const char *filename,
|
||||
char **data, MWLibFile *info );
|
||||
|
||||
static status_t load_lib_file( const char *filename,
|
||||
char **data, MWLibFile *info )
|
||||
{
|
||||
status_t retval = B_OK;
|
||||
struct stat s;
|
||||
FILE *fp;
|
||||
uint32 recs;
|
||||
|
||||
ASSERT( filename != NULL );
|
||||
ASSERT( info != NULL );
|
||||
|
||||
/* Initialize the info area.
|
||||
*/
|
||||
info->m_time = (time_t)0; /* Only this... */
|
||||
info->off_filename = 0;
|
||||
info->off_fullpath = 0;
|
||||
info->off_object = 0;
|
||||
info->object_size = 0; /* ... and this will actually be updated. */
|
||||
|
||||
/* stat() the file to get the info we need.
|
||||
*/
|
||||
retval = stat( filename, &s );
|
||||
if( retval != 0 ) {
|
||||
fprintf( stderr, "ar: can't stat %s, %s\n", filename,
|
||||
strerror( errno ) );
|
||||
return B_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* Possible errors here; if you have an object that's larger
|
||||
** than a size_t can hold (malloc() can only allocate a size_t size,
|
||||
** not a full off_t)...
|
||||
*/
|
||||
if( s.st_size > (off_t)ULONG_MAX ) {
|
||||
fprintf( stderr, "ar: %s is too large!\n", filename );
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
/* Allocate enough memory to hold the file data.
|
||||
*/
|
||||
*data = (char *)malloc( (size_t)s.st_size );
|
||||
if( *data == NULL ) {
|
||||
fprintf( stderr, "ar: can't allocate memory for %s\n", filename );
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
/* Read the file's data.
|
||||
*/
|
||||
fp = fopen( filename, "r" );
|
||||
if( fp == NULL ) {
|
||||
fprintf( stderr, "ar: can't open %s, %s\n", filename,
|
||||
strerror( errno ) );
|
||||
retval = B_FILE_NOT_FOUND;
|
||||
goto free_data_return;
|
||||
}
|
||||
|
||||
recs = fread( *data, (size_t)s.st_size, 1, fp );
|
||||
if( recs != 1 ) {
|
||||
fprintf( stderr, "ar: can't read %s, %s\n", filename,
|
||||
strerror( errno ) );
|
||||
retval = B_IO_ERROR;
|
||||
goto close_fp_return;
|
||||
}
|
||||
|
||||
fclose( fp );
|
||||
|
||||
/* Now that all the stuff that can fail has succeeded, fill in the info
|
||||
** we need.
|
||||
*/
|
||||
info->m_time = s.st_mtime;
|
||||
info->object_size = (uint32)s.st_size;
|
||||
|
||||
return B_OK;
|
||||
|
||||
/* How we should return if an error occurred.
|
||||
*/
|
||||
close_fp_return:
|
||||
fclose( fp );
|
||||
|
||||
free_data_return:
|
||||
free( *data );
|
||||
*data = NULL;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
status_t do_replace( const char *archive_name, char **files, int verbose,
|
||||
int create, int update )
|
||||
{
|
||||
status_t retval = B_OK;
|
||||
MWLib lib;
|
||||
int idx = 0;
|
||||
int which = 0;
|
||||
|
||||
ASSERT( archive_name != NULL );
|
||||
|
||||
memset( &lib, 0, sizeof( MWLib ) );
|
||||
|
||||
if( files == NULL ) {
|
||||
fprintf( stderr, "ar: %s, nothing to do\n", archive_name );
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
retval = load_MW_lib( &lib, archive_name );
|
||||
if( retval != B_OK ) {
|
||||
switch( retval ) {
|
||||
case B_FILE_NOT_FOUND:
|
||||
lib.header.magicword = 'MWOB';
|
||||
lib.header.magicproc = 'PPC ';
|
||||
lib.header.magicflags = 0;
|
||||
lib.header.version = 1;
|
||||
|
||||
if( lib.files != NULL ) {
|
||||
free( lib.files );
|
||||
lib.files = NULL;
|
||||
}
|
||||
|
||||
if( lib.names != NULL ) {
|
||||
free( lib.names );
|
||||
lib.names = NULL;
|
||||
}
|
||||
|
||||
if( lib.data != NULL ) {
|
||||
lib.data = NULL;
|
||||
}
|
||||
|
||||
if( !create ) {
|
||||
fprintf( stderr, "ar: creating %s\n", archive_name );
|
||||
}
|
||||
|
||||
if( update ) {
|
||||
fprintf( stderr, "ar: nothing to do for %s\n", archive_name );
|
||||
return retval;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return retval;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for( idx = 0; files[idx] != NULL; idx++ ) {
|
||||
if( do_match( &lib, files[idx], &which ) ) {
|
||||
/* Then the file exists, and we need to replace it or update it.
|
||||
*/
|
||||
if( update ) {
|
||||
/* Compare m_times
|
||||
** then replace this entry
|
||||
*/
|
||||
struct stat s;
|
||||
|
||||
retval = stat( files[idx], &s );
|
||||
if( retval != 0 ) {
|
||||
fprintf( stderr, "ar: can't stat %s, %s\n", files[idx],
|
||||
strerror( errno ) );
|
||||
}
|
||||
|
||||
if( s.st_mtime >= lib.files[which].m_time ) {
|
||||
retval = replace_lib_entry( &lib, files[idx], which,
|
||||
verbose );
|
||||
} else {
|
||||
fprintf( stderr, "ar: a newer %s is already in %s\n",
|
||||
files[idx], archive_name );
|
||||
}
|
||||
} else {
|
||||
/* replace this entry
|
||||
*/
|
||||
retval = replace_lib_entry( &lib, files[idx], which, verbose );
|
||||
}
|
||||
} else {
|
||||
/* add this entry
|
||||
*/
|
||||
retval = add_lib_entry( &lib, files[idx], verbose );
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the new file.
|
||||
*/
|
||||
retval = write_MW_lib( &lib, archive_name );
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static status_t add_lib_entry( MWLib *lib, const char *filename, int verbose )
|
||||
{
|
||||
status_t retval = B_OK;
|
||||
uint32 new_num_objects;
|
||||
uint32 idx;
|
||||
|
||||
ASSERT( lib != NULL );
|
||||
ASSERT( filename != NULL );
|
||||
|
||||
/* Find out how many objects we'll have after we add this one.
|
||||
*/
|
||||
new_num_objects = lib->header.num_objects + 1;
|
||||
idx = lib->header.num_objects;
|
||||
|
||||
/* Attempt to reallocate the MWLib's buffers. If one of these fails,
|
||||
** we could leak a little memory, but it shouldn't be a big deal in
|
||||
** a short-lived app like this.
|
||||
*/
|
||||
lib->files = (MWLibFile *)realloc( lib->files,
|
||||
sizeof(MWLibFile) * new_num_objects );
|
||||
lib->names = (char **)realloc( lib->names,
|
||||
sizeof(char *) * new_num_objects );
|
||||
lib->data = (char **)realloc( lib->data,
|
||||
sizeof(char *) * new_num_objects );
|
||||
if( lib->files == NULL || lib->names == NULL || lib->data == NULL ) {
|
||||
fprintf( stderr, "ar: can't allocate memory to add %s\n", filename );
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
/* Load the file's data and info into the MWLib structure.
|
||||
*/
|
||||
retval = load_lib_file( filename, &(lib->data[idx]), &(lib->files[idx]) );
|
||||
if( retval != B_OK ) {
|
||||
fprintf( stderr, "ar: error adding %s, %s\n", filename,
|
||||
strerror( errno ) );
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Save a copy of the filename. This is where we leak
|
||||
** sizeof(MWLibFile) + 2 * sizeof(char *) bytes because we don't
|
||||
** shrink lib->files, lib->names, and lib->data.
|
||||
*/
|
||||
lib->names[idx] = strdup( filename );
|
||||
if( lib->names == NULL ) {
|
||||
fprintf( stderr, "ar: error allocating memory for filename\n" );
|
||||
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
/* Now that everything's OK, we can update the MWLib header.
|
||||
*/
|
||||
lib->header.num_objects++;
|
||||
|
||||
/* Give a little feedback.
|
||||
*/
|
||||
if( verbose ) {
|
||||
printf( "a - %s\n", filename );
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
static status_t replace_lib_entry( MWLib *lib, const char *filename,
|
||||
int idx, int verbose )
|
||||
{
|
||||
char *buff;
|
||||
MWLibFile info;
|
||||
char *dup_name;
|
||||
|
||||
status_t retval = B_OK;
|
||||
|
||||
ASSERT( lib != NULL );
|
||||
ASSERT( filename != NULL );
|
||||
ASSERT( idx <= lib->header.num_objects );
|
||||
|
||||
/* Load the file's data and info into the MWLib structure.
|
||||
**
|
||||
** We'll do it safely so we don't end up writing a bogus library in
|
||||
** the event of failure.
|
||||
*/
|
||||
retval = load_lib_file( filename, &buff, &info );
|
||||
if( retval != B_OK ) {
|
||||
fprintf( stderr, "ar: error adding %s, %s\n", filename,
|
||||
strerror( errno ) );
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Attempt to allocate memory for a duplicate of the file name.
|
||||
*/
|
||||
dup_name = strdup( filename );
|
||||
if( dup_name == NULL ) {
|
||||
fprintf( stderr, "ar: unable to allocate memory for filename\n",
|
||||
filename );
|
||||
|
||||
free( buff );
|
||||
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
/* All is well, so let's update the MWLib object appropriately.
|
||||
*/
|
||||
lib->files[idx].m_time = info.m_time;
|
||||
lib->files[idx].off_filename = 0;
|
||||
lib->files[idx].off_fullpath = 0;
|
||||
lib->files[idx].off_object = 0;
|
||||
lib->files[idx].object_size = info.object_size;
|
||||
|
||||
lib->data[idx] = buff;
|
||||
|
||||
free( lib->names[idx] );
|
||||
lib->names[idx] = dup_name;
|
||||
|
||||
/* Give a little feedback.
|
||||
*/
|
||||
if( verbose ) {
|
||||
printf( "r - %s\n", filename );
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
** Print the table for an archive.
|
||||
*/
|
||||
static status_t table_lib_entry( MWLib *lib, int idx, int verbose );
|
||||
|
||||
status_t do_table( const char *archive_name, char **files, int verbose )
|
||||
{
|
||||
status_t retval = B_OK;
|
||||
MWLib lib;
|
||||
int idx = 0;
|
||||
|
||||
ASSERT( archive_name != NULL );
|
||||
|
||||
retval = load_MW_lib( &lib, archive_name );
|
||||
if( retval != B_OK ) {
|
||||
switch( retval ) {
|
||||
case B_FILE_NOT_FOUND:
|
||||
fprintf( stderr, "ar: %s, file not found\n", archive_name );
|
||||
return retval;
|
||||
break;
|
||||
|
||||
default:
|
||||
return retval;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( files == NULL ) {
|
||||
/* Then we print the table for the entire archive.
|
||||
*/
|
||||
for( idx = 0; idx < lib.header.num_objects; idx++ ) {
|
||||
retval = table_lib_entry( &lib, idx, verbose );
|
||||
}
|
||||
} else {
|
||||
/* Then we print the table for the specified files.
|
||||
*/
|
||||
int which = 0;
|
||||
|
||||
for( idx = 0; files[idx] != NULL; idx++ ) {
|
||||
if( do_match( &lib, files[idx], &which ) ) {
|
||||
retval = table_lib_entry( &lib, which, verbose );
|
||||
}
|
||||
which = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static status_t table_lib_entry( MWLib *lib, int idx, int verbose )
|
||||
{
|
||||
struct tm *t;
|
||||
char month_buff[4];
|
||||
|
||||
ASSERT( lib != NULL );
|
||||
|
||||
if( verbose ) {
|
||||
t = localtime( &(lib->files[idx].m_time) );
|
||||
if( t == NULL ) {
|
||||
fprintf( stderr, "localtime() failed, %s\n",
|
||||
strerror( errno ) );
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
if( strftime( month_buff, sizeof( month_buff ),
|
||||
"%b", t ) == 0 ) {
|
||||
/* TODO: error message */
|
||||
fprintf( stderr, "strftime() failed, %s\n",
|
||||
strerror( errno ) );
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/* I wish POSIX allowed for a nicer format; even using tabs
|
||||
* between some entries would be better.
|
||||
*/
|
||||
printf( "%s %u/%u %u %s %d %d:%d %d %s\n",
|
||||
"-rw-r--r--", /* simulated mode */
|
||||
getuid(), getgid(), /* simulated uid & gid */
|
||||
lib->files[idx].object_size,
|
||||
month_buff, /* abbreviated month */
|
||||
t->tm_mon, /* day of month */
|
||||
t->tm_hour, /* hour */
|
||||
t->tm_min, /* minute */
|
||||
t->tm_year, /* year */
|
||||
lib->names[idx] );
|
||||
} else {
|
||||
printf( "%s\n", lib->names[idx] );
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
** Extract one or more files from the archive.
|
||||
*/
|
||||
static status_t extract_lib_entry( MWLib *lib, int idx, int verbose );
|
||||
|
||||
status_t do_extract( const char *archive_name, char **files, int verbose )
|
||||
{
|
||||
status_t retval = B_OK;
|
||||
MWLib lib;
|
||||
int idx = 0;
|
||||
|
||||
ASSERT( archive_name != NULL );
|
||||
|
||||
retval = load_MW_lib( &lib, archive_name );
|
||||
if( retval != B_OK ) {
|
||||
switch( retval ) {
|
||||
case B_FILE_NOT_FOUND:
|
||||
fprintf( stderr, "ar: %s, file not found\n", archive_name );
|
||||
return retval;
|
||||
break;
|
||||
|
||||
default:
|
||||
return retval;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( files == NULL ) {
|
||||
/* Then we extract all the files.
|
||||
*/
|
||||
for( idx = 0; idx < lib.header.num_objects; idx++ ) {
|
||||
retval = extract_lib_entry( &lib, idx, verbose );
|
||||
}
|
||||
} else {
|
||||
/* Then we extract the specified files.
|
||||
*/
|
||||
int which = 0;
|
||||
|
||||
for( idx = 0; files[idx] != NULL; idx++ ) {
|
||||
if( do_match( &lib, files[idx], &which ) ) {
|
||||
retval = extract_lib_entry( &lib, which, verbose );
|
||||
}
|
||||
which = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static status_t extract_lib_entry( MWLib *lib, int idx, int verbose )
|
||||
{
|
||||
FILE *fp;
|
||||
int recs;
|
||||
status_t retval = B_OK;
|
||||
struct stat s;
|
||||
mode_t mode_bits = 0666; /* TODO: use user's umask() instead */
|
||||
|
||||
ASSERT( lib != NULL );
|
||||
|
||||
/* Delete the file if it already exists.
|
||||
*/
|
||||
retval = access( lib->names[idx], F_OK );
|
||||
if( retval == 0 ) {
|
||||
retval = stat( lib->names[idx], &s );
|
||||
if( retval != 0 ) {
|
||||
fprintf( stderr, "ar: can't stat %s, %s\n", lib->names[idx],
|
||||
strerror( errno ) );
|
||||
} else {
|
||||
mode_bits = s.st_mode;
|
||||
}
|
||||
retval = unlink( lib->names[idx] );
|
||||
if( retval != 0 ) {
|
||||
fprintf( stderr, "ar: can't unlink %s, %s\n", lib->names[idx],
|
||||
strerror( retval ) );
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the file.
|
||||
*/
|
||||
if( verbose ) {
|
||||
printf( "x - %s\n", lib->names[idx] );
|
||||
}
|
||||
|
||||
fp = fopen( lib->names[idx], "w" );
|
||||
if( fp == NULL ) {
|
||||
fprintf( stderr, "ar: can't open %s for write, %s\n", lib->names[idx],
|
||||
strerror( errno ) );
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
recs = fwrite( lib->data[idx], lib->files[idx].object_size, 1, fp );
|
||||
if( recs != 1 ) {
|
||||
fprintf( stderr, "error writing %s, %s\n", lib->names[idx],
|
||||
strerror( errno ) );
|
||||
}
|
||||
|
||||
retval = fclose( fp );
|
||||
|
||||
/* Set the newly extracted file's modification time to the time
|
||||
** stored in the archive.
|
||||
*/
|
||||
retval = stat( lib->names[idx], &s );
|
||||
if( retval != 0 ) {
|
||||
fprintf( stderr, "ar: can't stat %s, %s\n", lib->names[idx],
|
||||
strerror( errno ) );
|
||||
} else {
|
||||
struct utimbuf new_times;
|
||||
|
||||
new_times.actime = s.st_atime;
|
||||
new_times.modtime = lib->files[idx].m_time;
|
||||
|
||||
retval = utime( lib->names[idx], &new_times );
|
||||
if( retval != 0 ) {
|
||||
fprintf( stderr, "ar: can't set modification time for %s, %s\n",
|
||||
lib->names[idx], strerror( retval ) );
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the newly extracted file's mode.
|
||||
*/
|
||||
retval = chmod( lib->names[idx], mode_bits );
|
||||
if( retval != 0 ) {
|
||||
fprintf( stderr, "ar: unable to change file mode for %s, %s\n",
|
||||
lib->names[idx], strerror( errno ) );
|
||||
}
|
||||
|
||||
/* Set the newly extracted file's type.
|
||||
*/
|
||||
setfiletype( lib->names[idx], "application/x-mw-library" );
|
||||
|
||||
return B_OK;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
** 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 );
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
** 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;
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
** 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 );
|
|
@ -0,0 +1,234 @@
|
|||
<!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">> 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>
|
|
@ -0,0 +1,271 @@
|
|||
#! /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()
|
Binary file not shown.
|
@ -0,0 +1,126 @@
|
|||
#! /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()
|
|
@ -0,0 +1,34 @@
|
|||
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)
|
|
@ -0,0 +1,312 @@
|
|||
/*
|
||||
** 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;
|
||||
}
|
|
@ -0,0 +1,711 @@
|
|||
/*
|
||||
** mwlib.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 <support/Errors.h>
|
||||
#include <support/byteorder.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> /* is open() really here?!? sheesh... */
|
||||
#include <storage/Mime.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "mwlib.h"
|
||||
#include "copy_attrs.h"
|
||||
|
||||
static const char *rcs_version_id = "$Id$";
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
** Local prototypes
|
||||
*/
|
||||
static status_t load_MWLibFile( FILE *file, MWLibFile *libfile );
|
||||
static size_t fwrite_big32( uint32 x, FILE *fp );
|
||||
static size_t fwrite_big32_seek( uint32 x, long offset, FILE *fp );
|
||||
static status_t add_object_sizes( MWObject *obj, uint32 *code, uint32 *data );
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
** Load a Metrowerks library file into the given MWLib object.
|
||||
**
|
||||
** 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
|
||||
*/
|
||||
status_t load_MW_lib( MWLib *lib, const char *filename )
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
size_t recs = 0;
|
||||
status_t retval = B_OK;
|
||||
uint32 tmp32 = 0;
|
||||
uint32 idx = 0;
|
||||
char obj_name[PATH_MAX];
|
||||
|
||||
ASSERT( lib != NULL );
|
||||
ASSERT( filename != NULL );
|
||||
|
||||
fp = fopen( filename, "r" );
|
||||
if( !fp ) {
|
||||
return B_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* Read and check the magic number.
|
||||
*/
|
||||
recs = fread( &tmp32, sizeof( uint32 ), 1, fp );
|
||||
lib->header.magicword = B_BENDIAN_TO_HOST_INT32( tmp32 );
|
||||
if( recs != 1 ) {
|
||||
retval = B_IO_ERROR;
|
||||
goto close_return;
|
||||
} else if( lib->header.magicword != MWLIB_MAGIC_WORD ) {
|
||||
retval = B_BAD_VALUE;
|
||||
goto close_return;
|
||||
}
|
||||
|
||||
/* Read and check the processor.
|
||||
*/
|
||||
recs = fread( &tmp32, sizeof( uint32 ), 1, fp );
|
||||
lib->header.magicproc = B_BENDIAN_TO_HOST_INT32( tmp32 );
|
||||
if( recs != 1 ) {
|
||||
retval = B_IO_ERROR;
|
||||
goto close_return;
|
||||
} else if( lib->header.magicproc != MWLIB_MAGIC_PROC ) {
|
||||
retval = B_MISMATCHED_VALUES;
|
||||
goto close_return;
|
||||
}
|
||||
|
||||
/* Read and check the flags.
|
||||
*/
|
||||
recs = fread( &tmp32, sizeof( uint32 ), 1, fp );
|
||||
lib->header.magicflags = B_BENDIAN_TO_HOST_INT32( tmp32 );
|
||||
if( recs != 1 ) {
|
||||
retval = B_IO_ERROR;
|
||||
goto close_return;
|
||||
} else if( lib->header.magicflags != 0 ) {
|
||||
retval = B_MISMATCHED_VALUES;
|
||||
goto close_return;
|
||||
}
|
||||
|
||||
/* Read and check the file version.
|
||||
*/
|
||||
recs = fread( &tmp32, sizeof( uint32 ), 1, fp );
|
||||
lib->header.version = B_BENDIAN_TO_HOST_INT32( tmp32 );
|
||||
if( recs != 1 ) {
|
||||
retval = B_IO_ERROR;
|
||||
goto close_return;
|
||||
} else if( lib->header.version != 1 ) {
|
||||
retval = B_MISMATCHED_VALUES;
|
||||
goto close_return;
|
||||
}
|
||||
|
||||
/* Read the code size, data size, and number of objects.
|
||||
*/
|
||||
recs = fread( &tmp32, sizeof( uint32 ), 1, fp );
|
||||
lib->header.code_size = B_BENDIAN_TO_HOST_INT32( tmp32 );
|
||||
if( recs != 1 ) {
|
||||
retval = B_IO_ERROR;
|
||||
goto close_return;
|
||||
}
|
||||
|
||||
recs = fread( &tmp32, sizeof( uint32 ), 1, fp );
|
||||
lib->header.data_size = B_BENDIAN_TO_HOST_INT32( tmp32 );
|
||||
if( recs != 1 ) {
|
||||
retval = B_IO_ERROR;
|
||||
goto close_return;
|
||||
}
|
||||
|
||||
recs = fread( &tmp32, sizeof( uint32 ), 1, fp );
|
||||
lib->header.num_objects = B_BENDIAN_TO_HOST_INT32( tmp32 );
|
||||
if( recs != 1 ) {
|
||||
retval = B_IO_ERROR;
|
||||
goto close_return;
|
||||
}
|
||||
|
||||
/* Load the MWLibFile objects from the lib.
|
||||
*/
|
||||
lib->files = (MWLibFile *)malloc( lib->header.num_objects * sizeof( MWLibFile ) );
|
||||
if( lib->files == NULL ) {
|
||||
retval = B_NO_MEMORY;
|
||||
goto close_return;
|
||||
}
|
||||
|
||||
for( idx = 0; idx < lib->header.num_objects; idx++ ) {
|
||||
retval = load_MWLibFile( fp, &(lib->files[idx]) );
|
||||
if( retval != B_OK ) {
|
||||
goto close_return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Load the file names and object data.
|
||||
**
|
||||
** The file name actually appears twice in the library file; according
|
||||
** to the docs, one is the file name, the other is the "full path name".
|
||||
** In all of the libraries on my system, they're the same.
|
||||
*/
|
||||
lib->names = (char **)malloc( lib->header.num_objects * sizeof( char * ) );
|
||||
lib->data = (char **)malloc( lib->header.num_objects * sizeof( char * ) );
|
||||
if( lib->names == NULL || lib->data == NULL ) {
|
||||
retval = B_NO_MEMORY;
|
||||
goto close_return;
|
||||
}
|
||||
|
||||
for( idx = 0; idx < lib->header.num_objects; idx ++ ) {
|
||||
/* Load the name and copy it into the right spot.
|
||||
*/
|
||||
retval = fseek( fp, lib->files[idx].off_filename, SEEK_SET );
|
||||
if( retval ) {
|
||||
retval = B_IO_ERROR;
|
||||
goto close_return;
|
||||
}
|
||||
|
||||
if( fgets( obj_name, PATH_MAX, fp ) == NULL ) {
|
||||
retval = B_IO_ERROR;
|
||||
goto close_return;
|
||||
}
|
||||
|
||||
lib->names[idx] = strdup( obj_name );
|
||||
if( lib->names[idx] == NULL ) {
|
||||
retval = B_NO_MEMORY;
|
||||
goto close_return;
|
||||
}
|
||||
|
||||
/* Load the object data.
|
||||
*/
|
||||
lib->data[idx] = (char *)malloc( lib->files[idx].object_size );
|
||||
if( lib->data[idx] == NULL ) {
|
||||
retval = B_NO_MEMORY;
|
||||
goto close_return;
|
||||
}
|
||||
|
||||
retval = fseek( fp, lib->files[idx].off_object, SEEK_SET );
|
||||
if( retval ) {
|
||||
retval = B_IO_ERROR;
|
||||
goto close_return;
|
||||
}
|
||||
|
||||
recs = fread( lib->data[idx], lib->files[idx].object_size, 1, fp );
|
||||
if( recs != 1 ) {
|
||||
retval = B_IO_ERROR;
|
||||
goto close_return;
|
||||
}
|
||||
}
|
||||
|
||||
close_return:
|
||||
fclose( fp );
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
** Load the file header from a Metrowerks library file.
|
||||
**
|
||||
** Returns:
|
||||
** B_OK - All is well
|
||||
** B_IO_ERROR - Error reading the file
|
||||
*/
|
||||
static status_t load_MWLibFile( FILE *file, MWLibFile *libfile )
|
||||
{
|
||||
size_t recs = 0;
|
||||
uint32 tmp32 = 0;
|
||||
|
||||
ASSERT( file != NULL );
|
||||
ASSERT( libfile != NULL );
|
||||
|
||||
/* Load the modification time.
|
||||
*/
|
||||
recs = fread( &tmp32, sizeof( uint32 ), 1, file );
|
||||
libfile->m_time = (time_t)B_BENDIAN_TO_HOST_INT32( tmp32 );
|
||||
if( recs != 1 ) {
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
/* Load the various offsets.
|
||||
*/
|
||||
recs = fread( &tmp32, sizeof( uint32 ), 1, file );
|
||||
libfile->off_filename = B_BENDIAN_TO_HOST_INT32( tmp32 );
|
||||
if( recs != 1 ) {
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
recs = fread( &tmp32, sizeof( uint32 ), 1, file );
|
||||
libfile->off_fullpath = B_BENDIAN_TO_HOST_INT32( tmp32 );
|
||||
if( recs != 1 ) {
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
recs = fread( &tmp32, sizeof( uint32 ), 1, file );
|
||||
libfile->off_object = B_BENDIAN_TO_HOST_INT32( tmp32 );
|
||||
if( recs != 1 ) {
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
/* Load the object size.
|
||||
*/
|
||||
recs = fread( &tmp32, sizeof( uint32 ), 1, file );
|
||||
libfile->object_size = B_BENDIAN_TO_HOST_INT32( tmp32 );
|
||||
if( recs != 1 ) {
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
** 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.
|
||||
**
|
||||
** Two-pass technique:
|
||||
**
|
||||
** pass 1 - write file header (need CODE SIZE and DATA SIZE)
|
||||
** write object headers (need offsets for FILENAME, FULL PATH, DATA)
|
||||
** write filenames (store offsets for object headers)
|
||||
** write padding (file size % 4 bytes)
|
||||
** write file data (store offset for object header; add to code/data
|
||||
** size for file header; pad data size % 4 bytes)
|
||||
**
|
||||
** pass 2 - fill in file header CODE SIZE and DATA SIZE
|
||||
** fill in object headers FILENAME, FULL PATH, DATA
|
||||
**
|
||||
** You could avoid this by building up the file headers in memory, but this is
|
||||
** easier (?) and I'm not that concerned with speed...
|
||||
**
|
||||
*/
|
||||
|
||||
typedef struct file_header_offsets {
|
||||
long codesize_offset;
|
||||
long datasize_offset;
|
||||
} file_header_offsets;
|
||||
|
||||
typedef struct obj_header_offsets {
|
||||
long filename_offset;
|
||||
uint32 filename_offset_value;
|
||||
|
||||
long fullpath_offset;
|
||||
uint32 fullpath_offset_value;
|
||||
|
||||
long data_offset;
|
||||
uint32 data_offset_value;
|
||||
} obj_header_offsets;
|
||||
|
||||
static size_t fwrite_big32( uint32 x, FILE *fp )
|
||||
{
|
||||
uint32 tmp32 = B_HOST_TO_BENDIAN_INT32( x );
|
||||
|
||||
ASSERT( fp != NULL );
|
||||
|
||||
return fwrite( &tmp32, sizeof(tmp32), 1, fp );
|
||||
}
|
||||
|
||||
static size_t fwrite_big32_seek( uint32 x, long offset, FILE *fp )
|
||||
{
|
||||
uint32 tmp32 = B_HOST_TO_BENDIAN_INT32( x );
|
||||
|
||||
ASSERT( fp != NULL );
|
||||
|
||||
if( fseek( fp, offset, SEEK_SET ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return fwrite( &tmp32, sizeof(tmp32), 1, fp );
|
||||
}
|
||||
|
||||
static status_t add_object_sizes( MWObject *obj, uint32 *code, uint32 *data )
|
||||
{
|
||||
ASSERT( obj != NULL );
|
||||
ASSERT( code != NULL );
|
||||
ASSERT( data != NULL );
|
||||
|
||||
if( B_BENDIAN_TO_HOST_INT32( obj->magic_word ) != 'MWOB' ||
|
||||
B_BENDIAN_TO_HOST_INT32( obj->arch ) != 'PPC ' ) {
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
*code += B_BENDIAN_TO_HOST_INT32( obj->code_size );
|
||||
*data += B_BENDIAN_TO_HOST_INT32( obj->data_size );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void setfiletype( const char *file, const char *type )
|
||||
{
|
||||
int fd;
|
||||
attr_info fa;
|
||||
ssize_t wrote_bytes;
|
||||
|
||||
fd = open( file, O_RDWR );
|
||||
if( fd < 0 ) {
|
||||
fprintf( stderr, "ar: can't open %s to write file type, %s",
|
||||
file, strerror( errno ) );
|
||||
return;
|
||||
}
|
||||
|
||||
fa.type = B_MIME_STRING_TYPE;
|
||||
fa.size = (off_t)(strlen( type ) + 1);
|
||||
|
||||
wrote_bytes = fs_write_attr( fd, "BEOS:TYPE", fa.type, 0,
|
||||
type, fa.size );
|
||||
if( wrote_bytes != (ssize_t)fa.size ) {
|
||||
fprintf( stderr, "ar: couldn't write complete file type, %s",
|
||||
strerror( errno ) );
|
||||
}
|
||||
|
||||
close( fd );
|
||||
}
|
||||
|
||||
status_t write_MW_lib( MWLib *lib, const char *filename )
|
||||
{
|
||||
char *padding = "\0\0\0\0";
|
||||
long pad_amount;
|
||||
|
||||
file_header_offsets head_offs;
|
||||
obj_header_offsets *obj_offs;
|
||||
uint32 codesize = 0;
|
||||
uint32 datasize = 0;
|
||||
uint32 num_objects = 0;
|
||||
|
||||
FILE *fp;
|
||||
char *tmp_filename = NULL;
|
||||
uint32 idx = 0;
|
||||
size_t recs;
|
||||
status_t retval;
|
||||
|
||||
mode_t mode_bits = 0666;
|
||||
|
||||
ASSERT( lib != NULL );
|
||||
ASSERT( filename != NULL );
|
||||
|
||||
#if 0
|
||||
/* Apparently, I don't understand umask()... */
|
||||
|
||||
/* Find the default file creation mask. The semantics of umask() suck.
|
||||
*/
|
||||
mode_bits = umask( (mode_t)0 );
|
||||
(void)umask( mode_bits );
|
||||
#endif
|
||||
|
||||
/* Easier access to the number of objects.
|
||||
*/
|
||||
num_objects = lib->header.num_objects;
|
||||
|
||||
/* Allocate some storage for keeping track of the things we need to
|
||||
** write out in the second pass.
|
||||
*/
|
||||
head_offs.codesize_offset = 0;
|
||||
head_offs.datasize_offset = 0;
|
||||
|
||||
obj_offs = (obj_header_offsets *)malloc( sizeof(obj_header_offsets) *
|
||||
num_objects );
|
||||
if( obj_offs == NULL ) {
|
||||
fprintf( stderr, "ar: can't allocate memory for writing file\n" );
|
||||
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
memset( obj_offs, 0, sizeof(obj_header_offsets) * num_objects );
|
||||
|
||||
/* If the file exists, move it somewhere so we can recover if there's
|
||||
** an error.
|
||||
*/
|
||||
retval = access( filename, F_OK );
|
||||
if( retval == 0 ) {
|
||||
struct stat s;
|
||||
|
||||
/* Preserve the mode bits.
|
||||
*/
|
||||
retval = stat( filename, &s );
|
||||
if( retval != 0 ) {
|
||||
fprintf( stderr, "ar: can't stat %s, %s\n", filename,
|
||||
strerror( errno ) );
|
||||
} else {
|
||||
mode_bits = s.st_mode;
|
||||
}
|
||||
|
||||
tmp_filename = (char *)malloc( strlen( filename ) + 2 );
|
||||
if( tmp_filename == NULL ) {
|
||||
fprintf( stderr,
|
||||
"ar: can't allocate memory for temporary filename\n" );
|
||||
} else {
|
||||
sprintf( tmp_filename, "%s~", filename );
|
||||
|
||||
retval = access( tmp_filename, F_OK );
|
||||
if( retval == 0 ) {
|
||||
retval = unlink( tmp_filename );
|
||||
if( retval != 0 ) {
|
||||
fprintf( stderr, "ar: can't unlink %s, %s\n", tmp_filename,
|
||||
strerror( errno ) );
|
||||
|
||||
free( tmp_filename );
|
||||
tmp_filename = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if( tmp_filename ) {
|
||||
retval = rename( filename, tmp_filename );
|
||||
if( retval != 0 ) {
|
||||
fprintf( stderr, "ar: can't move %s to backup, %s\n",
|
||||
filename, strerror( errno ) );
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Attempt to open the archive file.
|
||||
*/
|
||||
fp = fopen( filename, "w" );
|
||||
if( fp == NULL ) {
|
||||
fprintf( stderr, "ar: can't open %s for write, %s\n", filename,
|
||||
strerror( errno ) );
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
** Write the file. Pass 1.
|
||||
*/
|
||||
recs = fwrite_big32( lib->header.magicword, fp );
|
||||
recs += fwrite_big32( lib->header.magicproc, fp );
|
||||
recs += fwrite_big32( lib->header.magicflags, fp );
|
||||
recs += fwrite_big32( lib->header.version, fp );
|
||||
if( recs != 4 ) {
|
||||
fprintf( stderr, "ar: error writing header for %s, %s\n", filename,
|
||||
strerror( errno ) );
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
/* Keep track of the code/data size offsets.
|
||||
*/
|
||||
head_offs.codesize_offset = ftell( fp );
|
||||
recs = fwrite_big32( codesize, fp );
|
||||
head_offs.datasize_offset = ftell( fp );
|
||||
recs += fwrite_big32( datasize, fp );
|
||||
if( recs != 2 ) {
|
||||
fprintf( stderr, "ar: error writing header for %s, %s\n", filename,
|
||||
strerror( errno ) );
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
recs = fwrite_big32( num_objects, fp );
|
||||
if( recs != 1 ) {
|
||||
fprintf( stderr, "ar: error writing header for %s, %s\n", filename,
|
||||
strerror( errno ) );
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
/* Write the object headers.
|
||||
*/
|
||||
for( idx = 0; idx < num_objects; idx++ ) {
|
||||
recs = fwrite_big32( lib->files[idx].m_time, fp );
|
||||
|
||||
/* Keep track of the offsets, and write 0 for now.
|
||||
*/
|
||||
obj_offs[idx].filename_offset = ftell( fp );
|
||||
recs += fwrite_big32( 0, fp );
|
||||
obj_offs[idx].fullpath_offset = ftell( fp );
|
||||
recs += fwrite_big32( 0, fp );
|
||||
obj_offs[idx].data_offset = ftell( fp );
|
||||
recs += fwrite_big32( 0, fp );
|
||||
|
||||
recs += fwrite_big32( lib->files[idx].object_size, fp );
|
||||
|
||||
if( recs != 5 ) {
|
||||
fprintf( stderr, "ar: error writing object header for %s, %s\n",
|
||||
filename, strerror( errno ) );
|
||||
goto error_return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the file names.
|
||||
*/
|
||||
for( idx = 0; idx < num_objects; idx++ ) {
|
||||
/* Need to make sure that all the file names we write into the
|
||||
** library DO NOT HAVE PATHS IN THEM, the world might end or something.
|
||||
*/
|
||||
size_t name_len = 0;
|
||||
char *name_ptr = strrchr( lib->names[idx], '/' );
|
||||
|
||||
if( name_ptr == NULL ) {
|
||||
name_ptr = lib->names[idx];
|
||||
} else {
|
||||
name_ptr++;
|
||||
}
|
||||
|
||||
name_len = strlen( name_ptr ) + 1;
|
||||
|
||||
obj_offs[idx].filename_offset_value = ftell( fp );
|
||||
recs = fwrite( name_ptr, name_len, 1, fp );
|
||||
obj_offs[idx].fullpath_offset_value = ftell( fp );
|
||||
recs += fwrite( name_ptr, name_len, 1, fp );
|
||||
|
||||
if( recs != 2 ) {
|
||||
fprintf( stderr, "ar: error writing object name for %s, %s\n",
|
||||
filename, strerror( errno ) );
|
||||
goto error_return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pad the file if necessary.
|
||||
*/
|
||||
pad_amount = ftell( fp ) % 4;
|
||||
if( pad_amount > 0 ) {
|
||||
recs = fwrite( padding, pad_amount, 1, fp );
|
||||
|
||||
if( recs != 1 ) {
|
||||
fprintf( stderr, "ar: error padding file %s, %s\n", filename,
|
||||
strerror( errno ) );
|
||||
goto error_return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the object file data.
|
||||
*/
|
||||
for( idx = 0; idx < num_objects; idx++ ) {
|
||||
obj_offs[idx].data_offset_value = ftell( fp );
|
||||
|
||||
recs = fwrite( lib->data[idx], lib->files[idx].object_size, 1, fp );
|
||||
if( recs != 1 ) {
|
||||
fprintf( stderr, "ar: writing object data for %s, %s\n", filename,
|
||||
strerror( errno ) );
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
/* Add up the code/data size.
|
||||
*/
|
||||
retval = add_object_sizes( (MWObject *)lib->data[idx],
|
||||
&codesize, &datasize );
|
||||
if( retval != B_OK ) {
|
||||
fprintf( stderr, "ar - warning: %s is not an object file!\n",
|
||||
lib->names[idx] );
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
pad_amount = ftell( fp ) % 4;
|
||||
if( pad_amount > 0 ) {
|
||||
recs = fwrite( padding, pad_amount, 1, fp );
|
||||
|
||||
if( recs != 1 ) {
|
||||
fprintf( stderr, "ar: error padding file %s, %s\n", filename,
|
||||
strerror( errno ) );
|
||||
goto error_return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
** Write the offsets into the file. Pass 2.
|
||||
*/
|
||||
|
||||
/* Write the code/data sizes.
|
||||
*/
|
||||
recs = fwrite_big32_seek( codesize, head_offs.codesize_offset, fp );
|
||||
recs += fwrite_big32_seek( datasize, head_offs.datasize_offset, fp );
|
||||
if( recs != 2 ) {
|
||||
fprintf( stderr, "ar - error writing code and data sizes, %s\n",
|
||||
strerror( errno ) );
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
/* Write the offsets for each file.
|
||||
*/
|
||||
for( idx = 0; idx < num_objects; idx++ ) {
|
||||
recs = fwrite_big32_seek( obj_offs[idx].filename_offset_value,
|
||||
obj_offs[idx].filename_offset, fp );
|
||||
recs += fwrite_big32_seek( obj_offs[idx].fullpath_offset_value,
|
||||
obj_offs[idx].fullpath_offset, fp );
|
||||
recs += fwrite_big32_seek( obj_offs[idx].data_offset_value,
|
||||
obj_offs[idx].data_offset, fp );
|
||||
|
||||
if( recs != 3 ) {
|
||||
fprintf( stderr, "ar - error writing object offsets, %s\n",
|
||||
strerror( errno ) );
|
||||
goto error_return;
|
||||
}
|
||||
}
|
||||
|
||||
/* If all is OK, close the file and get out of here after nuking the
|
||||
** temp file (if any), preserving the original file mode, and preserving
|
||||
** the file attributes.
|
||||
*/
|
||||
|
||||
fclose( fp );
|
||||
|
||||
/* Preserve the original file mode bits.
|
||||
*/
|
||||
retval = chmod( filename, mode_bits );
|
||||
if( retval != 0 ) {
|
||||
fprintf( stderr, "ar: unable to change file mode for %s, %s\n",
|
||||
filename, strerror( errno ) );
|
||||
}
|
||||
|
||||
/* Nuke the temp file (if any), after copying over any file attributes.
|
||||
*/
|
||||
if( tmp_filename != NULL ) {
|
||||
retval = copy_attrs( filename, tmp_filename );
|
||||
|
||||
retval = unlink( tmp_filename );
|
||||
if( retval != 0 ) {
|
||||
fprintf( stderr, "ar - error unlinking %s, %s\n", tmp_filename,
|
||||
strerror( errno ) );
|
||||
}
|
||||
free( tmp_filename );
|
||||
} else {
|
||||
/* If there isn't a temp file, we should still give this new
|
||||
** file a file type attribute.
|
||||
*/
|
||||
setfiletype( filename, "application/x-mw-library" );
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
|
||||
error_return:
|
||||
/* Restore the original file if we had any problems.
|
||||
*/
|
||||
fclose( fp );
|
||||
|
||||
if( tmp_filename != NULL ) {
|
||||
retval = unlink( filename );
|
||||
retval = rename( tmp_filename, filename );
|
||||
if( retval != 0 ) {
|
||||
fprintf( stderr, "ar: can't restore %s to %s, %s\n",
|
||||
tmp_filename, filename, strerror( errno ) );
|
||||
}
|
||||
}
|
||||
|
||||
return B_ERROR;
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
** 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 );
|
|
@ -0,0 +1,102 @@
|
|||
#! /bin/sh
|
||||
#
|
||||
# linkcc for Python
|
||||
# Chris Herborth (chrish@qnx.com)
|
||||
#
|
||||
# This is covered by the same copyright/licensing terms as the rest of
|
||||
# Python.
|
||||
#
|
||||
# Shell script to build the Python shared library properly; if we haven't
|
||||
# already built the export list, we'll need to link twice (argh...) so we
|
||||
# can eliminate some unwatnted global symbols from the system glue/init
|
||||
# objects.
|
||||
#
|
||||
# This is called by the Modules/Makefile as part of $(LINKCC):
|
||||
#
|
||||
# $(LINKCC) $(LDFLAGS) $(LINKFORSHARED) $(MAINOBJ) \
|
||||
# -L.. -lpython$(VERSION) $(MODLIBS) $(LIBS) $(SYSLIBS) -o python $(LDLAST)
|
||||
#
|
||||
# In 1.5.1 this changed to:
|
||||
#
|
||||
# $(LINKCC) $(LDFLAGS) $(LINKFORSHARED) $(MAINOBJ) \
|
||||
# $(LIBRARY) $(MODLIBS) $(LIBS) $(SYSLIBS) -o python $(LDLAST)
|
||||
#
|
||||
# For BeOS we should set $(LINKCC) to this in configure (similar to the
|
||||
# AIX situation):
|
||||
#
|
||||
# $(srcdir)../BeOS/linkcc $(LIBRARY) $(PURIFY) $(CC) -nodup $(OPT)
|
||||
#
|
||||
# -L.. -lpython$(VERSION) will automagically pick up the shared library.
|
||||
|
||||
# Check to make sure we know what we're doing.
|
||||
system="`uname -m`"
|
||||
if [ "$system" != "BeMac" ] && [ "$system" != "BeBox" ] ; then
|
||||
echo "Sorry, BeOS Python doesn't support x86 yet."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
LIBRARY="$1"; shift
|
||||
|
||||
# What we want to end up with.
|
||||
EXPORTS=${LIBRARY%.a}.exp
|
||||
DYNAMIC=${LIBRARY%.a}.so
|
||||
LINK_DYNAMIC="-l`echo ${DYNAMIC%.so} | sed -e s,\\\.\\\./,, -e s,lib,,`"
|
||||
|
||||
# Grab the rest of the args and build them into the command used to
|
||||
# link the python binary. Make sure we link against the shared lib
|
||||
# and not the static lib.
|
||||
LINK_CMD=""
|
||||
while [ "$#" != "0" ] ; do
|
||||
case "$1" in
|
||||
$LIBRARY)
|
||||
LINK_CMD="$LINK_CMD -L.. $LINK_DYNAMIC"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
LINK_CMD="$LINK_CMD $1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# The shared libraries and glue objects we need to link against.
|
||||
LIBS="-lbe -lnet -lroot"
|
||||
GLUE="/boot/develop/lib/ppc/glue-noinit.a /boot/develop/lib/ppc/init_term_dyn.o"
|
||||
|
||||
# Unwanted symbols we need to eliminate; these are regular expressions
|
||||
# passed to egrep.
|
||||
SYMS="opterr optind optarg getopt __.* longjmp _.*_"
|
||||
|
||||
# Check to see if we've already got an exports file, and delete it if
|
||||
# it's older than the lib.
|
||||
if [ -e $EXPORTS ] && [ $LIBRARY -nt $EXPORTS ] ; then
|
||||
echo "Deleting old exports file for $DYNAMIC..."
|
||||
rm -f $EXPORTS
|
||||
fi
|
||||
|
||||
if [ ! -e $EXPORTS ] ; then
|
||||
# First link; create the exports file with the unwanted global symbols
|
||||
# in it. It's a pity we don't have "nm" or something like that...
|
||||
rm -f temp-exports.exp
|
||||
mwcc -xms -f temp-exports.exp -o $DYNAMIC $LIBRARY $GLUE $LIBS -nodup
|
||||
|
||||
# Now clean out those bad symbols.
|
||||
for sym in $SYMS ; do
|
||||
rm -f temp-exports.exp2
|
||||
egrep -v "^$sym$" < temp-exports.exp > temp-exports.exp2
|
||||
mv -f temp-exports.exp2 temp-exports.exp
|
||||
done
|
||||
|
||||
rm -f temp-exports.exp2
|
||||
mv -f temp-exports.exp $EXPORTS
|
||||
fi
|
||||
|
||||
# Now link against the clean exports file.
|
||||
mwcc -xms -f $EXPORTS -o $DYNAMIC $LIBRARY $GLUE $LIBS -nodup
|
||||
|
||||
# We'll need this or the python binary won't load libpython.so...
|
||||
( cd .. ; ln -sf `pwd` lib )
|
||||
|
||||
# Now build the python binary.
|
||||
echo "Link command: $LINK_CMD"
|
||||
$LINK_CMD
|
|
@ -0,0 +1,70 @@
|
|||
#! /bin/sh
|
||||
#
|
||||
# linkmodule for Python
|
||||
# Chris Herborth (chrish@qnx.com)
|
||||
#
|
||||
# This is covered by the same copyright/licensing terms as the rest of
|
||||
# Python
|
||||
#
|
||||
# Shell script to build shared library versions of the modules; the
|
||||
# idea is to build an export list containing only the init*() function
|
||||
# for the module. We _could_ assume for foomodule.o it was initfoo, but
|
||||
# that's asking for trouble... this is a little less efficient but correct.
|
||||
#
|
||||
# This is called by the Modules/Makefile as $(LDSHARED):
|
||||
#
|
||||
# $(LDSHARED) foomodule.o -o foomodule$(SO)
|
||||
#
|
||||
# Could also be called as:
|
||||
#
|
||||
# $(LDSHARED) readline.o -L/boot/home/config/lib -lreadline -ltermcap \
|
||||
# -o readline$(SO)
|
||||
|
||||
# Check to make sure we know what we're doing.
|
||||
system="`uname -m`"
|
||||
if [ "$system" != "BeMac" ] && [ "$system" != "BeBox" ] ; then
|
||||
echo "Sorry, BeOS Python doesn't support x86 yet."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Make sure we got reasonable arguments.
|
||||
TARGET=""
|
||||
ARGS=""
|
||||
|
||||
while [ "$#" != "0" ]; do
|
||||
case "$1" in
|
||||
-o) TARGET="$2"; shift; shift;;
|
||||
*) ARGS="$ARGS $1"; shift;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$TARGET" = "" ] ; then
|
||||
echo "Usage:"
|
||||
echo
|
||||
echo " $0 [args] -o foomodule.so [args] foomodule.o [args]"
|
||||
echo
|
||||
echo "Where:"
|
||||
echo
|
||||
echo " [args] normal mwcc arguments"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
EXPORTS=${TARGET%.so}.exp
|
||||
|
||||
# The shared libraries and glue objects we need to link against; these
|
||||
# libs are overkill for most of the standard modules, but it makes life
|
||||
# in this shell script easier.
|
||||
LIBS="-L.. -lpython1.5 -lbe -lnet -lroot"
|
||||
GLUE="/boot/develop/lib/ppc/glue-noinit.a /boot/develop/lib/ppc/init_term_dyn.o"
|
||||
|
||||
# Check to see if we've already got an exports file; we don't need to
|
||||
# update this once we've got it because we only ever want to export
|
||||
# one symbol.
|
||||
if [ ! -e $EXPORTS ] ; then
|
||||
# The init*() function has to be related to the module's .so name
|
||||
# for importdl to work.
|
||||
echo init${TARGET%.so} | sed -e s/module// > $EXPORTS
|
||||
fi
|
||||
|
||||
# Now link against the clean exports file.
|
||||
mwcc -xms -f $EXPORTS -o $TARGET $ARGS $GLUE $LIBS -nodup
|
Loading…
Reference in New Issue