MacOS X: Enable 4-way universal builds

This patch adds a new configure argument on OSX:
        --with-universal-archs=[32-bit|64-bit|all]

When used with the --enable-universalsdk option this controls which
CPU architectures are includes in the framework. The default is 32-bit,
meaning i386 and ppc. The most useful alternative is 'all', which includes
all 4 CPU architectures supported by MacOS X (i386, ppc, x86_64 and ppc64).

This includes limited support for the Carbon bindings in 64-bit mode as well,
limited because (a) I haven't done extensive testing and (b) a large portion
of the Carbon API's aren't available in 64-bit mode anyway.

I've also duplicated a feature of Apple's build of python: setting the
environment variable 'ARCHFLAGS' controls the '-arch' flags used for building
extensions using distutils.
diff --git a/Mac/Modules/MacOS.c b/Mac/Modules/MacOS.c
index a888320..99e531b 100644
--- a/Mac/Modules/MacOS.c
+++ b/Mac/Modules/MacOS.c
@@ -30,6 +30,7 @@
 #include <Carbon/Carbon.h>
 #include <ApplicationServices/ApplicationServices.h>
 
+
 static PyObject *MacOS_Error; /* Exception MacOS.Error */
 
 #define PATHNAMELEN 1024
@@ -40,7 +41,7 @@
 
 typedef struct {
 	PyObject_HEAD
-	short fRefNum;
+	FSIORefNum fRefNum;
 	int isclosed;
 } rfobject;
 
@@ -54,7 +55,7 @@
 do_close(rfobject *self)
 {
 	if (self->isclosed ) return;
-	(void)FSClose(self->fRefNum);
+	(void)FSCloseFork(self->fRefNum);
 	self->isclosed = 1;
 }
 
@@ -68,6 +69,7 @@
 	long n;
 	PyObject *v;
 	OSErr err;
+	ByteCount n2;
 	
 	if (self->isclosed) {
 		PyErr_SetString(PyExc_ValueError, "Operation on closed file");
@@ -81,13 +83,13 @@
 	if (v == NULL)
 		return NULL;
 		
-	err = FSRead(self->fRefNum, &n, PyBytes_AsString(v));
+	err = FSReadFork(self->fRefNum, fsAtMark, 0, n, PyString_AsString(v), &n2);
 	if (err && err != eofErr) {
 		PyMac_Error(err);
 		Py_DECREF(v);
 		return NULL;
 	}
-	_PyBytes_Resize(&v, n);
+	_PyString_Resize(&v, n2);
 	return v;
 }
 
@@ -109,7 +111,7 @@
 	}
 	if (!PyArg_ParseTuple(args, "s#", &buffer, &size))
 		return NULL;
-	err = FSWrite(self->fRefNum, &size, buffer);
+	err = FSWriteFork(self->fRefNum, fsAtMark, 0, size, buffer, NULL);
 	if (err) {
 		PyMac_Error(err);
 		return NULL;
@@ -126,47 +128,36 @@
 static PyObject *
 rf_seek(rfobject *self, PyObject *args)
 {
-	long amount, pos;
+	long amount;
 	int whence = SEEK_SET;
-	long eof;
+	int mode;
 	OSErr err;
 	
 	if (self->isclosed) {
 		PyErr_SetString(PyExc_ValueError, "Operation on closed file");
 		return NULL;
 	}
-	if (!PyArg_ParseTuple(args, "l|i", &amount, &whence))
+	if (!PyArg_ParseTuple(args, "l|i", &amount, &whence)) {
 		return NULL;
-	
-	if ((err = GetEOF(self->fRefNum, &eof)))
-		goto ioerr;
+	}
 	
 	switch (whence) {
 	case SEEK_CUR:
-		if ((err = GetFPos(self->fRefNum, &pos)))
-			goto ioerr; 
+		mode = fsFromMark;
 		break;
 	case SEEK_END:
-		pos = eof;
+		mode = fsFromLEOF;
 		break;
 	case SEEK_SET:
-		pos = 0;
+		mode = fsFromStart;
 		break;
 	default:
 		PyErr_BadArgument();
 		return NULL;
 	}
-	
-	pos += amount;
-	
-	/* Don't bother implementing seek past EOF */
-	if (pos > eof || pos < 0) {
-		PyErr_BadArgument();
-		return NULL;
-	}
-	
-	if ((err = SetFPos(self->fRefNum, fsFromStart, pos)) ) {
-ioerr:
+
+	err = FSSetForkPosition(self->fRefNum, mode, amount);
+	if (err != noErr) {
 		PyMac_Error(err);
 		return NULL;
 	}
@@ -182,7 +173,7 @@
 static PyObject *
 rf_tell(rfobject *self, PyObject *args)
 {
-	long where;
+	long long where;
 	OSErr err;
 	
 	if (self->isclosed) {
@@ -191,11 +182,13 @@
 	}
 	if (!PyArg_ParseTuple(args, ""))
 		return NULL;
-	if ((err = GetFPos(self->fRefNum, &where)) ) {
+
+	err = FSGetForkPosition(self->fRefNum, &where);
+	if (err != noErr) {
 		PyMac_Error(err);
 		return NULL;
 	}
-	return PyInt_FromLong(where);
+	return PyLong_FromLongLong(where);
 }
 
 static char rf_close__doc__[] = 
@@ -281,6 +274,7 @@
 	Rftype__doc__ /* Documentation string */
 };
 
+
 /* End of code for Resource fork objects */
 /* -------------------------------------------------------- */
 
@@ -292,17 +286,61 @@
 static PyObject *
 MacOS_GetCreatorAndType(PyObject *self, PyObject *args)
 {
-	FSSpec fss;
-	FInfo info;
 	PyObject *creator, *type, *res;
 	OSErr err;
-	
-	if (!PyArg_ParseTuple(args, "O&", PyMac_GetFSSpec, &fss))
+	FSRef ref;
+	FSCatalogInfo	cataloginfo;
+	FileInfo* finfo;
+
+	if (!PyArg_ParseTuple(args, "O&", PyMac_GetFSRef, &ref)) {
+#ifndef __LP64__
+		/* This function is documented to take an FSSpec as well,
+		 * which only works in 32-bit mode.
+		 */
+		PyErr_Clear();
+		FSSpec fss;
+		FInfo info;
+
+		if (!PyArg_ParseTuple(args, "O&", PyMac_GetFSSpec, &fss))
+			return NULL;
+
+		if ((err = FSpGetFInfo(&fss, &info)) != noErr) {
+			return PyErr_Mac(MacOS_Error, err);
+		}
+		creator = PyString_FromStringAndSize(
+				(char *)&info.fdCreator, 4);
+		type = PyString_FromStringAndSize((char *)&info.fdType, 4);
+		res = Py_BuildValue("OO", creator, type);
+		Py_DECREF(creator);
+		Py_DECREF(type);
+		return res;
+#else	/* __LP64__ */
 		return NULL;
-	if ((err = FSpGetFInfo(&fss, &info)) != noErr)
-		return PyErr_Mac(MacOS_Error, err);
-	creator = PyBytes_FromStringAndSize((char *)&info.fdCreator, 4);
-	type = PyBytes_FromStringAndSize((char *)&info.fdType, 4);
+#endif	/* __LP64__ */
+	}
+
+	err = FSGetCatalogInfo(&ref, 
+			kFSCatInfoFinderInfo|kFSCatInfoNodeFlags, &cataloginfo, 
+			NULL, NULL, NULL);
+	if (err != noErr) {
+		PyErr_Mac(MacOS_Error, err);
+		return NULL;
+	}
+
+	if ((cataloginfo.nodeFlags & kFSNodeIsDirectoryMask) != 0) {
+		/* Directory: doesn't have type/creator info.
+		 *
+		 * The specific error code is for backward compatibility with
+		 * earlier versions.
+		 */
+		PyErr_Mac(MacOS_Error, fnfErr);
+		return NULL;
+
+	} 
+	finfo = (FileInfo*)&(cataloginfo.finderInfo);
+	creator = PyString_FromStringAndSize((char*)&(finfo->fileCreator), 4);
+	type = PyString_FromStringAndSize((char*)&(finfo->fileType), 4);
+
 	res = Py_BuildValue("OO", creator, type);
 	Py_DECREF(creator);
 	Py_DECREF(type);
@@ -314,20 +352,66 @@
 static PyObject *
 MacOS_SetCreatorAndType(PyObject *self, PyObject *args)
 {
-	FSSpec fss;
 	ResType creator, type;
-	FInfo info;
+	FSRef ref;
+	FileInfo* finfo;
 	OSErr err;
-	
+	FSCatalogInfo	cataloginfo;
+
 	if (!PyArg_ParseTuple(args, "O&O&O&",
+			PyMac_GetFSRef, &ref, PyMac_GetOSType, &creator, PyMac_GetOSType, &type)) {
+#ifndef __LP64__
+		/* Try to handle FSSpec arguments, for backward compatibility */
+		FSSpec fss;
+		FInfo info;
+
+		if (!PyArg_ParseTuple(args, "O&O&O&",
 			PyMac_GetFSSpec, &fss, PyMac_GetOSType, &creator, PyMac_GetOSType, &type))
+			return NULL;
+
+		if ((err = FSpGetFInfo(&fss, &info)) != noErr)
+			return PyErr_Mac(MacOS_Error, err);
+
+		info.fdCreator = creator;
+		info.fdType = type;
+
+		if ((err = FSpSetFInfo(&fss, &info)) != noErr)
+			return PyErr_Mac(MacOS_Error, err);
+		Py_INCREF(Py_None);
+		return Py_None;
+#else /* __LP64__ */
 		return NULL;
-	if ((err = FSpGetFInfo(&fss, &info)) != noErr)
-		return PyErr_Mac(MacOS_Error, err);
-	info.fdCreator = creator;
-	info.fdType = type;
-	if ((err = FSpSetFInfo(&fss, &info)) != noErr)
-		return PyErr_Mac(MacOS_Error, err);
+#endif /* __LP64__ */
+	}
+	
+	err = FSGetCatalogInfo(&ref, 
+			kFSCatInfoFinderInfo|kFSCatInfoNodeFlags, &cataloginfo, 
+			NULL, NULL, NULL);
+	if (err != noErr) {
+		PyErr_Mac(MacOS_Error, err);
+		return NULL;
+	}
+
+	if ((cataloginfo.nodeFlags & kFSNodeIsDirectoryMask) != 0) {
+		/* Directory: doesn't have type/creator info.
+		 *
+		 * The specific error code is for backward compatibility with
+		 * earlier versions.
+		 */
+		PyErr_Mac(MacOS_Error, fnfErr);
+		return NULL;
+
+	} 
+	finfo = (FileInfo*)&(cataloginfo.finderInfo);
+	finfo->fileCreator = creator;
+	finfo->fileType = type;
+
+	err = FSSetCatalogInfo(&ref, kFSCatInfoFinderInfo, &cataloginfo);
+	if (err != noErr) {
+		PyErr_Mac(MacOS_Error, fnfErr);
+		return NULL;
+	}
+
 	Py_INCREF(Py_None);
 	return Py_None;
 }
@@ -399,6 +483,9 @@
 	return Py_BuildValue("s", buf);
 }
 
+
+#ifndef __LP64__
+
 static char splash_doc[] = "Open a splash-screen dialog by resource-id (0=close)";
 
 static PyObject *
@@ -417,7 +504,7 @@
 		return NULL;
 	olddialog = curdialog;
 	curdialog = NULL;
-		
+
 	if ( resid != -1 ) {
 		curdialog = GetNewDialog(resid, NULL, (WindowPtr)-1);
 		if ( curdialog ) {
@@ -452,11 +539,13 @@
 	
 	if (!PyArg_ParseTuple(args, "O&|O", PyMac_GetStr255, message, &object))
 		return NULL;
+	
 	DebugStr(message);
 	Py_INCREF(Py_None);
 	return Py_None;
 }
 
+
 static char SysBeep_doc[] = "BEEEEEP!!!";
 
 static PyObject *
@@ -471,6 +560,8 @@
 	return Py_None;
 }
 
+#endif /* __LP64__ */
+
 static char WMAvailable_doc[] = 
 	"True if this process can interact with the display."
 	"Will foreground the application on the first call as a side-effect."
@@ -530,51 +621,37 @@
 {
 	OSErr err;
 	char *mode = "r";
-	FSSpec fss;
-	SignedByte permission = 1;
+	FSRef ref;
+	SInt8 permission = fsRdPerm;
 	rfobject *fp;
+	HFSUniStr255 name;
 		
-	if (!PyArg_ParseTuple(args, "O&|s", PyMac_GetFSSpec, &fss, &mode))
+	if (!PyArg_ParseTuple(args, "O&|s", PyMac_GetFSRef, &ref, &mode))
 		return NULL;
 	while (*mode) {
 		switch (*mode++) {
 		case '*': break;
-		case 'r': permission = 1; break;
-		case 'w': permission = 2; break;
+		case 'r': permission = fsRdPerm; break;
+		case 'w': permission = fsWrPerm; break;
 		case 'b': break;
 		default:
 			PyErr_BadArgument();
 			return NULL;
 		}
 	}
+
+	err = FSGetResourceForkName(&name);
+	if (err != noErr) {
+		PyMac_Error(err);
+		return NULL;
+	}
 	
 	if ( (fp = newrfobject()) == NULL )
 		return NULL;
-		
-	err = HOpenRF(fss.vRefNum, fss.parID, fss.name, permission, &fp->fRefNum);
+
 	
-	if ( err == fnfErr ) {
-		/* In stead of doing complicated things here to get creator/type
-		** correct we let the standard i/o library handle it
-		*/
-		FILE *tfp;
-		char pathname[PATHNAMELEN];
-		
-		if ( (err=PyMac_GetFullPathname(&fss, pathname, PATHNAMELEN)) ) {
-			PyMac_Error(err);
-			Py_DECREF(fp);
-			return NULL;
-		}
-		
-		if ( (tfp = fopen(pathname, "w")) == NULL ) {
-			PyMac_Error(fnfErr); /* What else... */
-			Py_DECREF(fp);
-			return NULL;
-		}
-		fclose(tfp);
-		err = HOpenRF(fss.vRefNum, fss.parID, fss.name, permission, &fp->fRefNum);
-	}
-	if ( err ) {
+	err = FSOpenFork(&ref, name.length, name.unicode, permission, &fp->fRefNum);
+	if (err != noErr) {
 		Py_DECREF(fp);
 		PyMac_Error(err);
 		return NULL;
@@ -584,15 +661,18 @@
 }
 
 
+
 static PyMethodDef MacOS_Methods[] = {
 	{"GetCreatorAndType",		MacOS_GetCreatorAndType, 1,	getcrtp_doc},
 	{"SetCreatorAndType",		MacOS_SetCreatorAndType, 1,	setcrtp_doc},
 	{"GetErrorString",		MacOS_GetErrorString,	1,	geterr_doc},
 	{"openrf",			MacOS_openrf, 		1, 	openrf_doc},
+#ifndef __LP64__
 	{"splash",			MacOS_splash,		1, 	splash_doc},
 	{"DebugStr",			MacOS_DebugStr,		1,	DebugStr_doc},
-	{"GetTicks",			MacOS_GetTicks,		1,	GetTicks_doc},
 	{"SysBeep",			MacOS_SysBeep,		1,	SysBeep_doc},
+#endif /* __LP64__ */
+	{"GetTicks",			MacOS_GetTicks,		1,	GetTicks_doc},
 	{"WMAvailable",			MacOS_WMAvailable,		1,	WMAvailable_doc},
 	{NULL,				NULL}		 /* Sentinel */
 };