Adding the BeOS port. More checkins to follow.

This commit is contained in:
Guido van Rossum 1998-08-04 17:57:28 +00:00
parent 3f7b6fcea0
commit d8eb2119b5
22 changed files with 3749 additions and 0 deletions

View File

@ -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>

140
BeOS/README Normal file
View File

@ -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

56
BeOS/README.readline-2.2 Normal file
View File

@ -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

48
BeOS/ar-1.1/Makefile Normal file
View File

@ -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 $@

1
BeOS/ar-1.1/README.html Normal file
View File

@ -0,0 +1 @@
docs/ar.html

29
BeOS/ar-1.1/README.txt Normal file
View File

@ -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)

BIN
BeOS/ar-1.1/ar Normal file

Binary file not shown.

461
BeOS/ar-1.1/ar.xMAP Normal file
View File

@ -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

809
BeOS/ar-1.1/commands.c Normal file
View File

@ -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;
}

28
BeOS/ar-1.1/commands.h Normal file
View File

@ -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 );

128
BeOS/ar-1.1/copy_attrs.c Normal file
View File

@ -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;
}

24
BeOS/ar-1.1/copy_attrs.h Normal file
View File

@ -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 );

234
BeOS/ar-1.1/docs/ar.html Normal file
View File

@ -0,0 +1,234 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML3.2//EN">
<!-- $Id$ -->
<html> <head>
<title>ar - create and maintain library archives</title>
</head>
<body bgcolor="#ffffcb">
<h1>ar</h1>
<h4 align="right">create and maintain library archives</h4>
<h2>Synopsis</h2>
<pre>
ar [-][dprtx][cuv] <i>archive</i> [<i>file</i> ...]
</pre>
<h2>Options</h2>
<table>
<tr>
<td valign="top"><b>-</b></td>
<td valign="top">
The <b>-</b> is optional for introducing <tt>ar</tt> command-line
arguments; this is a POSIX requirement, and I've never seen anyone
use it.</td>
</tr>
<tr>
<td valign="top"><b>c</b></td>
<td valign="top">
Don't print a diagnostic message to <i>stderr</i> when
<i>archive</i> is created.</td>
</tr>
<tr>
<td valign="top"><b>d</b></td>
<td valign="top">
Delete <i>file(s)</i> from <i>archive</i>.</td>
</tr>
<tr>
<td valign="top"><b>p</b></td>
<td valign="top">
Write the contents of the named <i>file(s)</i> to <i>stdout</i>.
If no <i>file(s)</i> are specified, all of the files in
<i>archive</i> are written in the order of the archive.</td>
</tr>
<tr>
<td valign="top"><b>r</b></td>
<td valign="top">
Replace or add <i>file(s)</i> to the <i>archive</i>. This will
create <i>archive</i> if it doesn't already exist.</td>
</tr>
<tr>
<td valign="top"><b>t</b></td>
<td valign="top">
Write the table of contents of <i>archive</i> to <i>stdout</i>.
If not <i>file(s)</i> are specified, list all of the files,
otherwise only list the specified files.</td>
</tr>
<tr>
<td valign="top"><b>u</b></td>
<td valign="top">
Update older files. When used with the <b>r</b> option, files
within the archive are only replaced if <i>file</i> has a
modification date at least as new as the <i>file</i> already in
the archive.</td>
</tr>
<tr>
<td valign="top"><b>v</b></td>
<td valign="top">Give verbose output.</td>
</tr>
<tr>
<td valign="top"><b>x</b></td>
<td valign="top">
Extract <i>file(s)</i> from the <i>archive</i>. If no
<i>file(s)</i> are specified, all of the files in <i>archive</i>
are extracted.</td>
</tr>
<tr>
<td valign="top"><i>archive</i></td>
<td valign="top">
The pathname of an archive file.</td>
</tr>
<tr>
<td valign="top"><i>file</i></td>
<td valign="top">
One more more pathnames of object files; only the file name is
used when comparing against the names of files in the
archive.</td>
</tr>
</table>
<h2>Description</h2>
<p>The <tt>ar</tt> utility creates and maintains groups of files
combined into a library. Once a library has been created, you can
add new files, and extract, delete, or replace existing files.</p>
<h2>Exit status</h2>
<p><tt>ar</tt> exits with one of the following values:</p>
<table>
<tr><td valign="top">0</td>
<td valign="top">Successful completion.</td></tr>
<tr><td valign="top">&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>

271
BeOS/ar-1.1/docs/dumpar.py Normal file
View File

@ -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()

BIN
BeOS/ar-1.1/docs/dumpar.pyc Normal file

Binary file not shown.

126
BeOS/ar-1.1/docs/dumpo.py Normal file
View File

@ -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()

34
BeOS/ar-1.1/docs/notes Normal file
View File

@ -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)

312
BeOS/ar-1.1/main.c Normal file
View File

@ -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;
}

711
BeOS/ar-1.1/mwlib.c Normal file
View File

@ -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;
}

118
BeOS/ar-1.1/mwlib.h Normal file
View File

@ -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 );

102
BeOS/linkcc Executable file
View File

@ -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

70
BeOS/linkmodule Executable file
View File

@ -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