]> granicus.if.org Git - python/commitdiff
Adding the BeOS port. More checkins to follow.
authorGuido van Rossum <guido@python.org>
Tue, 4 Aug 1998 17:57:28 +0000 (17:57 +0000)
committerGuido van Rossum <guido@python.org>
Tue, 4 Aug 1998 17:57:28 +0000 (17:57 +0000)
22 files changed:
BeOS/PyImport_BeImageID.html [new file with mode: 0644]
BeOS/README [new file with mode: 0644]
BeOS/README.readline-2.2 [new file with mode: 0644]
BeOS/ar-1.1/Makefile [new file with mode: 0644]
BeOS/ar-1.1/README.html [new file with mode: 0644]
BeOS/ar-1.1/README.txt [new file with mode: 0644]
BeOS/ar-1.1/ar [new file with mode: 0644]
BeOS/ar-1.1/ar.xMAP [new file with mode: 0644]
BeOS/ar-1.1/commands.c [new file with mode: 0644]
BeOS/ar-1.1/commands.h [new file with mode: 0644]
BeOS/ar-1.1/copy_attrs.c [new file with mode: 0644]
BeOS/ar-1.1/copy_attrs.h [new file with mode: 0644]
BeOS/ar-1.1/docs/ar.html [new file with mode: 0644]
BeOS/ar-1.1/docs/dumpar.py [new file with mode: 0644]
BeOS/ar-1.1/docs/dumpar.pyc [new file with mode: 0644]
BeOS/ar-1.1/docs/dumpo.py [new file with mode: 0644]
BeOS/ar-1.1/docs/notes [new file with mode: 0644]
BeOS/ar-1.1/main.c [new file with mode: 0644]
BeOS/ar-1.1/mwlib.c [new file with mode: 0644]
BeOS/ar-1.1/mwlib.h [new file with mode: 0644]
BeOS/linkcc [new file with mode: 0755]
BeOS/linkmodule [new file with mode: 0755]

diff --git a/BeOS/PyImport_BeImageID.html b/BeOS/PyImport_BeImageID.html
new file mode 100644 (file)
index 0000000..2d04528
--- /dev/null
@@ -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>
diff --git a/BeOS/README b/BeOS/README
new file mode 100644 (file)
index 0000000..c801afb
--- /dev/null
@@ -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
diff --git a/BeOS/README.readline-2.2 b/BeOS/README.readline-2.2
new file mode 100644 (file)
index 0000000..db53ac9
--- /dev/null
@@ -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
diff --git a/BeOS/ar-1.1/Makefile b/BeOS/ar-1.1/Makefile
new file mode 100644 (file)
index 0000000..8fb11ec
--- /dev/null
@@ -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 $@
diff --git a/BeOS/ar-1.1/README.html b/BeOS/ar-1.1/README.html
new file mode 100644 (file)
index 0000000..607c03a
--- /dev/null
@@ -0,0 +1 @@
+docs/ar.html
\ No newline at end of file
diff --git a/BeOS/ar-1.1/README.txt b/BeOS/ar-1.1/README.txt
new file mode 100644 (file)
index 0000000..f995789
--- /dev/null
@@ -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)
diff --git a/BeOS/ar-1.1/ar b/BeOS/ar-1.1/ar
new file mode 100644 (file)
index 0000000..e44e2dc
Binary files /dev/null and b/BeOS/ar-1.1/ar differ
diff --git a/BeOS/ar-1.1/ar.xMAP b/BeOS/ar-1.1/ar.xMAP
new file mode 100644 (file)
index 0000000..bee438d
--- /dev/null
@@ -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
diff --git a/BeOS/ar-1.1/commands.c b/BeOS/ar-1.1/commands.c
new file mode 100644 (file)
index 0000000..f9304d0
--- /dev/null
@@ -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;
+}
diff --git a/BeOS/ar-1.1/commands.h b/BeOS/ar-1.1/commands.h
new file mode 100644 (file)
index 0000000..e5c28c2
--- /dev/null
@@ -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 );
diff --git a/BeOS/ar-1.1/copy_attrs.c b/BeOS/ar-1.1/copy_attrs.c
new file mode 100644 (file)
index 0000000..c9f978d
--- /dev/null
@@ -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;
+}
+
diff --git a/BeOS/ar-1.1/copy_attrs.h b/BeOS/ar-1.1/copy_attrs.h
new file mode 100644 (file)
index 0000000..a761636
--- /dev/null
@@ -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 );
diff --git a/BeOS/ar-1.1/docs/ar.html b/BeOS/ar-1.1/docs/ar.html
new file mode 100644 (file)
index 0000000..50f002e
--- /dev/null
@@ -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">&gt; 0</td>
+       <td>An error occurred.</td></tr>
+</table>
+
+<h2>Bugs</h2>
+
+<p>No known bugs, but <em>please</em> read the comments in the code if
+you want to use it in another application.</p>
+
+<h2>Comments</h2>
+
+<p>This is a POSIX 1003.2-1992 based <tt>ar</tt> command; it's not
+100% POSIX 1003.2 because POSIX specifies a file format for
+<tt>ar</tt> archives.  The BeOS <tt>ar</tt> produces library files
+compatible (at least in theory <tt>:-)</tt>) with Metrowerks
+CodeWarrior for PowerPC.</p>
+
+<p>This <tt>ar</tt> and its source code were written as a service to
+the Be developer community, to make it easier for us to port UNIX
+applications and libraries.  The code was written from scratch, after
+reverse-engineering the Metrowerks library and object file format
+(mostly because the library/object file format documentation was
+incorrect).</p>
+
+<p>If you find this useful, please
+<a href="mailto:chrish@kagi.com">let me know</a>, and tell me what
+you're working on.  Be sure to include a URL for your homepage or your
+product homepages for my
+<a href="http://www.qnx.com/~chrish/Be/community/">Be Community</a>
+pages.</p>
+
+<p>If you find any bugs, please try to fix them, and send me a context
+diff (use <tt>diff -c original_file fixed_file</tt>) so I can include
+your fixes in the next update.  I <i>have</i> tested this, but these
+things have a way of slipping though.</p>
+
+<p>If you'd like to know what other things I'm working on, take a look
+at my <a href="http://www.qnx.com/~chrish/Be/software/">Be
+Software</a> pages, and my
+<a href="http://www.qnx.com/~chrish/Be/">Be Happy!</a> pages.</p>
+
+<h2>License</h2>
+
+<p>This program binary and its source code have been donated to the
+BeOS Developer Community by Arcane Dragon Software free of charge.  
+You can do whatever you want with it.</p>
+
+<p>If you <em>really</em> want to show your appreciation, you could
+always send me a gift of some sort; cool software you wrote, nice
+pictures for my desktop, ZIP drive disks, RAM, hard drives, post
+cards, a pointer to a really cool/useful/interesting web site,
+an MPEG audio file of an interesting band (make sure you can give me
+enough information to track down their CDs if I like it!), <i>etc.</i>  
+Send me some <a href="mailto:chrish@kagi.com">email</a> and I'll let you 
+know where to send it.</p>
+
+<p>But you don't have to do anything.  Just write good BeOS software.
+But you're already doing that, right?</p>
+
+<h2>Disclaimer</h2>
+
+<p>You use this at your own risk.  I've tried to ensure that the code
+is correct, but software usually has bugs.  If <tt>ar</tt> destroys
+your valuable data, formats your hard drive, kicks your cat, and lets
+the air out of your tires, I'm not responsible for it.  The code is
+here, so you should feel fairly safe that there's nothing evil going
+on.</p>
+
+<p>And, as I learned once again in December 1997, you really should
+keep backups of everything.  I only lost a day's work, but it was
+still annoying, and it could've been much, much worse.</p>
+
+<h3>A word about the code</h3>
+
+<p>This code isn't meant to be the ultimate in efficiency or speed,
+it's intended to be fairly easy to understand and maintain
+(hopefully).  I was also quite keen on having something that was
+correct, without jumping through a lot of unnecessary hoops.</p>
+
+<p>If you think this code sucks, don't use it.  You're already applying
+this to your choice of operating system!  <tt>:-)</tt></p>
+
+<h2>Versions</h2>
+
+<dl compact>
+
+<dt><strong>1.1 (April 18, 1998)</strong></dt>
+<dd>Changes include:
+       <ul>
+         <li>Extract option (<b>x</b>) will preserve a file's mode bits
+                 when overwriting an existing file (this may go away if it's
+                 not POSIX behaviour).</li>
+
+         <li>Extracted files will now have the proper file type.</li>
+
+         <li>Removed attempt to use <i>umask()</i> to set newly created
+                 archive's mode bits; apparently, I'm not sure how it
+                 works and my POSIX manual isn't helping.</li>
+
+         <li>Should be 100% endian-neutral now; using this on BeOS for
+                 x86 is only useful if you're manipulating <em>PowerPC</em>
+                 objects though.  The <tt>ar</tt> in
+                 <a href="http://www.ninemoons.com/GG/index.html">GeekGadgets</a>
+                 should work fine for x86 objects/libraries.</li>
+                 
+         <li>Updated the <tt>README.txt</tt> file; now it's got useful
+                 information about building/using the POSIX ar.</li>
+       </ul></dd>
+
+<dt><strong>1.0 (January 13, 1998)</strong></dt>
+<dd>Initial release.</dd>
+
+</dl>
+
+<hr>
+<p>Chris Herborth (<a href="mailto:chrish@qnx.com">chrish@qnx.com</a>)</p>
+<!-- hhmts start -->
+Last modified: $Date$
+<!-- hhmts end -->
+</body> </html>
diff --git a/BeOS/ar-1.1/docs/dumpar.py b/BeOS/ar-1.1/docs/dumpar.py
new file mode 100644 (file)
index 0000000..93e2283
--- /dev/null
@@ -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()
diff --git a/BeOS/ar-1.1/docs/dumpar.pyc b/BeOS/ar-1.1/docs/dumpar.pyc
new file mode 100644 (file)
index 0000000..bc5045f
Binary files /dev/null and b/BeOS/ar-1.1/docs/dumpar.pyc differ
diff --git a/BeOS/ar-1.1/docs/dumpo.py b/BeOS/ar-1.1/docs/dumpo.py
new file mode 100644 (file)
index 0000000..91bd8db
--- /dev/null
@@ -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()
diff --git a/BeOS/ar-1.1/docs/notes b/BeOS/ar-1.1/docs/notes
new file mode 100644 (file)
index 0000000..4a90a16
--- /dev/null
@@ -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)
diff --git a/BeOS/ar-1.1/main.c b/BeOS/ar-1.1/main.c
new file mode 100644 (file)
index 0000000..225ee62
--- /dev/null
@@ -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;
+}
diff --git a/BeOS/ar-1.1/mwlib.c b/BeOS/ar-1.1/mwlib.c
new file mode 100644 (file)
index 0000000..f3b8660
--- /dev/null
@@ -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;
+}
diff --git a/BeOS/ar-1.1/mwlib.h b/BeOS/ar-1.1/mwlib.h
new file mode 100644 (file)
index 0000000..67af325
--- /dev/null
@@ -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 );
diff --git a/BeOS/linkcc b/BeOS/linkcc
new file mode 100755 (executable)
index 0000000..9b95635
--- /dev/null
@@ -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
diff --git a/BeOS/linkmodule b/BeOS/linkmodule
new file mode 100755 (executable)
index 0000000..f0a6f9f
--- /dev/null
@@ -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