A new home for scripts/applets
EditPythonPrefs - Edit the preferences file (sys.path, python home)
PackLibDir - Convert a sys.path directory to a resource file
RunLibScript - import a module and run as __main__
mkapplet - Create a python applet

The resource files belonging to these should also be stored here, somehow..
diff --git a/Mac/scripts/BuildApplet.py b/Mac/scripts/BuildApplet.py
new file mode 100644
index 0000000..cf90901
--- /dev/null
+++ b/Mac/scripts/BuildApplet.py
@@ -0,0 +1,260 @@
+"""Create an applet from a Python script.
+
+This puts up a dialog asking for a Python source file ('TEXT').
+The output is a file with the same name but its ".py" suffix dropped.
+It is created by copying an applet template and then adding a 'PYC '
+resource named __main__ containing the compiled, marshalled script.
+"""
+
+import sys
+sys.stdout = sys.stderr
+
+import string
+import os
+import marshal
+import imp
+import macfs
+import MacOS
+from Res import *
+
+# .pyc file (and 'PYC ' resource magic number)
+MAGIC = imp.get_magic()
+
+# Template file (searched on sys.path)
+TEMPLATE = "PythonApplet"
+
+# Specification of our resource
+RESTYPE = 'PYC '
+RESNAME = '__main__'
+
+# A resource with this name sets the "owner" (creator) of the destination
+OWNERNAME = "owner resource"
+
+# OpenResFile mode parameters
+READ = 1
+WRITE = 2
+
+def main():
+	
+	# Find the template
+	# (there's no point in proceeding if we can't find it)
+	
+	for p in sys.path:
+		template = os.path.join(p, TEMPLATE)
+		try:
+			tmpl = open(template, "rb")
+			tmpl.close()
+			break
+		except IOError:
+			continue
+	else:
+		die("Template %s not found" % `template`)
+		return
+		
+	# Convert to full pathname
+	template = macfs.FSSpec(template).as_pathname()
+	
+	# Ask for source text if not specified in sys.argv[1:]
+	
+	if not sys.argv[1:]:
+		srcfss, ok = macfs.StandardGetFile('TEXT')
+		if not ok:
+			return
+		filename = srcfss.as_pathname()
+		tp, tf = os.path.split(filename)
+		if tf[-3:] == '.py':
+			tf = tf[:-3]
+		else:
+			tf = tf + '.applet'
+		dstfss, ok = macfs.StandardPutFile('Save application as:', tf)
+		if not ok: return
+		process(template, filename, dstfss.as_pathname())
+	else:
+		
+		# Loop over all files to be processed
+		for filename in sys.argv[1:]:
+			process(template, filename, '')
+
+undefs = ('Atmp', '????', '    ', '\0\0\0\0', 'BINA')
+
+def process(template, filename, output):
+	
+	print "Processing", `filename`, "..."
+	
+	# Read the source and compile it
+	# (there's no point overwriting the destination if it has a syntax error)
+	
+	fp = open(filename)
+	text = fp.read()
+	fp.close()
+	try:
+		code = compile(text, filename, "exec")
+	except (SyntaxError, EOFError):
+		die("Syntax error in script %s" % `filename`)
+		return
+	
+	# Set the destination file name
+	
+	if string.lower(filename[-3:]) == ".py":
+		destname = filename[:-3]
+		rsrcname = destname + '.rsrc'
+	else:
+		destname = filename + ".applet"
+		rsrcname = filename + '.rsrc'
+	
+	if output:
+		destname = output
+	# Copy the data from the template (creating the file as well)
+	
+	tmpl = open(template, "rb")
+	dest = open(destname, "wb")
+	data = tmpl.read()
+	if data:
+		dest.write(data)
+	dest.close()
+	tmpl.close()
+	
+	# Copy the creator of the template to the destination
+	# unless it already got one.  Set type to APPL
+	
+	tctor, ttype = MacOS.GetCreatorAndType(template)
+	ctor, type = MacOS.GetCreatorAndType(destname)
+	if type in undefs: type = 'APPL'
+	if ctor in undefs: ctor = tctor
+	
+	# Open the output resource fork
+	
+	try:
+		output = FSpOpenResFile(destname, WRITE)
+	except MacOS.Error:
+		print "Creating resource fork..."
+		CreateResFile(destname)
+		output = FSpOpenResFile(destname, WRITE)
+	
+	# Copy the resources from the template
+	
+	input = FSpOpenResFile(template, READ)
+	newctor = copyres(input, output)
+	CloseResFile(input)
+	if newctor: ctor = newctor
+	
+	# Copy the resources from the target specific resource template, if any
+	
+	try:
+		input = FSpOpenResFile(rsrcname, READ)
+	except MacOS.Error:
+		pass
+	else:
+		newctor = copyres(input, output)
+		CloseResFile(input)
+		if newctor: ctor = newctor
+	
+	# Now set the creator and type of the destination
+	
+	MacOS.SetCreatorAndType(destname, ctor, type)
+	
+	# Make sure we're manipulating the output resource file now
+	
+	UseResFile(output)
+	
+	# Delete any existing 'PYC 'resource named __main__
+	
+	try:
+		res = Get1NamedResource(RESTYPE, RESNAME)
+		res.RemoveResource()
+	except Error:
+		pass
+	
+	# Create the raw data for the resource from the code object
+	
+	data = marshal.dumps(code)
+	del code
+	data = (MAGIC + '\0\0\0\0') + data
+	
+	# Create the resource and write it
+	
+	id = 0
+	while id < 128:
+		id = Unique1ID(RESTYPE)
+	res = Resource(data)
+	res.AddResource(RESTYPE, id, RESNAME)
+	res.WriteResource()
+	res.ReleaseResource()
+	
+	# Close the output file
+	
+	CloseResFile(output)
+	
+	# Give positive feedback
+	
+	message("Applet %s created." % `destname`)
+
+
+# Copy resources between two resource file descriptors.
+# Exception: don't copy a __main__ resource.
+# If a resource's name is "owner resource", its type is returned
+# (so the caller can use it to set the destination's creator)
+
+def copyres(input, output):
+	ctor = None
+	UseResFile(input)
+	ntypes = Count1Types()
+	for itype in range(1, 1+ntypes):
+		type = Get1IndType(itype)
+		nresources = Count1Resources(type)
+		for ires in range(1, 1+nresources):
+			res = Get1IndResource(type, ires)
+			id, type, name = res.GetResInfo()
+			lcname = string.lower(name)
+			if (type, lcname) == (RESTYPE, RESNAME):
+				continue # Don't copy __main__ from template
+			if lcname == OWNERNAME: ctor = type
+			size = res.size
+			attrs = res.GetResAttrs()
+			print id, type, name, size, hex(attrs)
+			res.LoadResource()
+			res.DetachResource()
+			UseResFile(output)
+			try:
+				res2 = Get1Resource(type, id)
+			except MacOS.Error:
+				res2 = None
+			if res2:
+				print "Overwriting..."
+				res2.RemoveResource()
+			res.AddResource(type, id, name)
+			res.WriteResource()
+			attrs = attrs | res.GetResAttrs()
+			print "New attrs =", hex(attrs)
+			res.SetResAttrs(attrs)
+			UseResFile(input)
+	return ctor
+
+
+# Show a message and exit
+
+def die(str):
+	message(str)
+	sys.exit(1)
+
+
+# Show a message
+
+def message(str, id = 256):
+	from Dlg import *
+	d = GetNewDialog(id, -1)
+	if not d:
+		print "Error:", `str`
+		print "DLOG id =", id, "not found."
+		return
+	tp, h, rect = d.GetDialogItem(2)
+	SetDialogItemText(h, str)
+	while 1:
+		n = ModalDialog(None)
+		if n == 1: break
+	del d
+
+
+if __name__ == '__main__':
+	main()
+
diff --git a/Mac/scripts/EditPythonPrefs.py b/Mac/scripts/EditPythonPrefs.py
new file mode 100644
index 0000000..3e14ff3
--- /dev/null
+++ b/Mac/scripts/EditPythonPrefs.py
@@ -0,0 +1,168 @@
+"""Edit the Python Preferences file."""
+import addpack
+addpack.addpack('Tools')
+addpack.addpack('bgen')
+addpack.addpack('evt')
+
+from Dlg import *
+from Events import *
+from Res import *
+import string
+import struct
+import macfs
+import MacOS
+import os
+import sys
+import Res # For Res.Error
+
+# resource IDs in our own resources (dialogs, etc)
+MESSAGE_ID = 256
+
+DIALOG_ID = 131
+TEXT_ITEM = 1
+OK_ITEM = 2
+CANCEL_ITEM = 3
+REVERT_ITEM = 4
+DIR_ITEM = 5
+
+# Resource IDs in the preferences file
+PATH_STRINGS_ID = 128
+DIRECTORY_ID = 128
+
+WRITE = 2
+smAllScripts = -3
+kOnSystemDisk = 0x8000
+
+def restolist(data):
+	"""Convert STR# resource data to a list of strings"""
+	if not data:
+		return []
+	num, = struct.unpack('h', data[:2])
+	data = data[2:]
+	rv = []
+	for i in range(num):
+		strlen = ord(data[0])
+		if strlen < 0: strlen = strlen + 256
+		str = data[1:strlen+1]
+		data = data[strlen+1:]
+		rv.append(str)
+	return rv
+	
+def listtores(list):
+	"""Convert a list of strings to STR# resource data"""
+	rv = struct.pack('h', len(list))
+	for str in list:
+		rv = rv + chr(len(str)) + str
+	return rv
+
+def message(str = "Hello, world!", id = MESSAGE_ID):
+	"""Show a simple alert with a text message"""
+	d = GetNewDialog(id, -1)
+	print 'd=', d
+	tp, h, rect = d.GetDialogItem(2)
+	SetDialogItemText(h, str)
+	while 1:
+		n = ModalDialog(None)
+		if n == 1: break
+		
+def interact(list, pythondir):
+	"""Let the user interact with the dialog"""
+	opythondir = pythondir
+	try:
+		# Try to go to the "correct" dir for GetDirectory
+		os.chdir(pythondir.as_pathname())
+	except os.error:
+		pass
+	d = GetNewDialog(DIALOG_ID, -1)
+	tp, h, rect = d.GetDialogItem(1)
+	SetDialogItemText(h, string.joinfields(list, '\r'))
+	while 1:
+		n = ModalDialog(None)
+		if n == OK_ITEM:
+			break
+		if n == CANCEL_ITEM:
+			return None
+		if n == REVERT_ITEM:
+			return [], pythondir
+		if n == DIR_ITEM:
+			fss, ok = macfs.GetDirectory()
+			if ok:
+				pythondir = fss
+	tmp = string.splitfields(GetDialogItemText(h), '\r')
+	rv = []
+	for i in tmp:
+		if i:
+			rv.append(i)
+	return rv, pythondir
+	
+def main():
+	try:
+		h = OpenResFile('EditPythonPrefs.rsrc')
+	except Res.Error:
+		pass	# Assume we already have acces to our own resource
+	
+	# Find the preferences folder and our prefs file, create if needed.	
+	vrefnum, dirid = macfs.FindFolder(kOnSystemDisk, 'pref', 0)
+	preff_fss = macfs.FSSpec((vrefnum, dirid, 'Python Preferences'))
+	try:
+		preff_handle = FSpOpenResFile(preff_fss, WRITE)
+	except Res.Error:
+		# Create it
+		message('No preferences file, creating one...')
+		FSpCreateResFile(preff_fss, 'PYTH', 'pref', smAllScripts)
+		preff_handle = FSpOpenResFile(preff_fss, WRITE)
+		
+	# Load the path and directory resources
+	try:
+		sr = GetResource('STR#', PATH_STRINGS_ID)
+	except (MacOS.Error, Res.Error):
+		message('Cannot find any sys.path resource! (Old python?)')
+		sys.exit(0)
+	d = sr.data
+	l = restolist(d)
+	
+	try:
+		dr = GetResource('alis', DIRECTORY_ID)
+		fss, fss_changed = macfs.RawAlias(dr.data).Resolve()
+	except (MacOS.Error, Res.Error):
+		dr = None
+		fss = macfs.FSSpec(os.getcwd())
+		fss_changed = 1
+	
+	# Let the user play away
+	result = interact(l, fss)
+	
+	# See what we have to update, and how
+	if result == None:
+		sys.exit(0)
+		
+	pathlist, nfss = result
+	if nfss != fss:
+		fss_changed = 1
+		
+	if fss_changed or pathlist != l:
+		if fss_changed:
+			alias = nfss.NewAlias()
+			if dr:
+				dr.data = alias.data
+				dr.ChangedResource()
+			else:
+				dr = Resource(alias.data)
+				dr.AddResource('alis', DIRECTORY_ID, '')
+				
+		if pathlist != l:
+			if pathlist == []:
+				if sr.HomeResFile() == preff_handle:
+					sr.RemoveResource()
+			elif sr.HomeResFile() == preff_handle:
+				sr.data = listtores(pathlist)
+				sr.ChangedResource()
+			else:
+				sr = Resource(listtores(pathlist))
+				sr.AddResource('STR#', PATH_STRINGS_ID, '')
+				
+	CloseResFile(preff_handle)
+
+if __name__ == '__main__':
+	print # Stupid, to init toolboxes...
+	main()
diff --git a/Mac/scripts/PackLibDir.py b/Mac/scripts/PackLibDir.py
new file mode 100644
index 0000000..cdda87d
--- /dev/null
+++ b/Mac/scripts/PackLibDir.py
@@ -0,0 +1,93 @@
+#
+# Turn a pyc file into a resource file containing it in 'PYC ' resource form
+import addpack
+addpack.addpack('Tools')
+addpack.addpack('bgen')
+addpack.addpack('res')
+from Res import *
+import Res
+from Resources import *
+import os
+import macfs
+import sys
+
+READ = 1
+WRITE = 2
+smAllScripts = -3
+
+error = 'mkpycresourcefile.error'
+
+def Pstring(str):
+	if len(str) > 255:
+		raise ValueError, 'String too large'
+	return chr(len(str))+str
+	
+def createoutput(dst):
+	"""Create output file. Return handle and first id to use."""
+	
+
+	FSpCreateResFile(dst, 'PYTH', 'rsrc', smAllScripts)
+	output = FSpOpenResFile(dst, WRITE)
+	UseResFile(output)
+	num = 128
+	return output, num
+	
+def writemodule(name, id, data):
+	"""Write pyc code to a PYC resource with given name and id."""
+	# XXXX Check that it doesn't exist
+	res = Resource(data)
+	res.AddResource('PYC ', id, name)
+	res.WriteResource()
+	res.ReleaseResource()
+		
+def mkpycresourcefile(src, dst):
+	"""Copy pyc file/dir src to resource file dst."""
+	
+	if not os.path.isdir(src) and src[-4:] <> '.pyc':
+			raise error, 'I can only handle .pyc files or directories'
+	handle, oid = createoutput(dst)
+	if os.path.isdir(src):
+		id = handlesubdir(handle, oid, src)
+	else:
+		id = handleonepycfile(handle, oid, src)
+	print 'Wrote',id-oid,'PYC resources to', dst
+	CloseResFile(handle)
+			
+def handleonepycfile(handle, id, file):
+	"""Copy one pyc file to the open resource file"""
+	d, name = os.path.split(file)
+	name = name[:-4]
+	print '  module', name
+	writemodule(name, id, open(file, 'rb').read())
+	return id+1
+	
+def handlesubdir(handle, id, srcdir):
+	"""Recursively scan a directory for pyc files and copy to resources"""
+	print 'Directory', srcdir
+	src = os.listdir(srcdir)
+	for file in src:
+		file = os.path.join(srcdir, file)
+		if os.path.isdir(file):
+			id = handlesubdir(handle, id, file)
+		elif file[-4:] == '.pyc':
+			id = handleonepycfile(handle, id, file)
+	return id
+				
+	
+if __name__ == '__main__':
+	args = sys.argv[1:]
+	if not args:
+		ifss, ok = macfs.StandardGetFile('PYC ')
+		if ok:
+			args = [ifss.as_pathname()]
+		else:
+			ifss, ok = macfs.GetDirectory()
+			if not ok:
+				sys.exit(0)
+			args = [ifss.as_pathname()]
+	for ifn in args:
+		ofss, ok = macfs.StandardPutFile('Output for '+os.path.split(ifn)[1])
+		if not ok:
+			sys.exit(0)
+		mkpycresourcefile(ifn, ofss.as_pathname())
+	sys.exit(1)			# So we can see something...
diff --git a/Mac/scripts/RunLibScript.py b/Mac/scripts/RunLibScript.py
new file mode 100644
index 0000000..36787d9
--- /dev/null
+++ b/Mac/scripts/RunLibScript.py
@@ -0,0 +1,108 @@
+"""Import a module while pretending its name is __main__. This
+can be used to run scripts from the PackedLib resource file while pretending
+they have been double-clicked."""
+
+import imp
+import sys
+import os
+import string
+import Dlg
+import macfs
+
+DIALOG_ID = 140
+OK = 1
+CANCEL = 2
+SCRIPTNAME=3
+ARGV=4
+STDIN_CONS=5
+STDIN_FILE=6
+STDOUT_CONS=7
+STDOUT_FILE=8
+WORKING_DIR=9
+PAUSE=10
+
+def import_as_main(name):
+	fp, path, (suffix, mode, type) = imp.find_module(name)
+	if type == imp.PY_SOURCE:
+		imp.load_source('__main__', path)
+	elif type == imp.PY_COMPILED:
+		imp.load_compiled('__main__', path)
+	elif type == imp.PY_RESOURCE:
+		imp.load_resource('__main__', path)
+		
+def interact():
+	d = Dlg.GetNewDialog(DIALOG_ID, -1)
+	wdir = stdin = stdout = None
+	pause = 0
+
+	tp, in_c_h, rect = d.GetDialogItem(STDIN_CONS)
+	tp, in_f_h, rect = d.GetDialogItem(STDIN_FILE)
+	tp, out_c_h, rect = d.GetDialogItem(STDOUT_CONS)
+	tp, out_f_h, rect = d.GetDialogItem(STDOUT_FILE)
+	tp, pause_h, rect = d.GetDialogItem(PAUSE)
+	in_c_h = in_c_h.as_Control()
+	in_f_h = in_f_h.as_Control()
+	out_c_h = out_c_h.as_Control()
+	out_f_h = out_f_h.as_Control()
+	pause_h = pause_h.as_Control()
+
+	while 1:
+		in_c_h.SetControlValue(not stdin)
+		in_f_h.SetControlValue(not not stdin)
+		out_c_h.SetControlValue(not stdout)
+		out_f_h.SetControlValue(not not stdout)
+		pause_h.SetControlValue(pause)
+		
+		n = Dlg.ModalDialog(None)
+		if n == OK:
+			break
+		elif n == CANCEL:
+			sys.exit(0)
+		elif n == STDIN_CONS:
+			stdin = None
+		elif n == STDIN_FILE:
+			fss, ok = macfs.StandardGetFile('TEXT')
+			if ok:
+				stdin = fss
+		elif n == STDOUT_FILE:
+			fss, ok = macfs.StandardPutFile('stdout:')
+			if ok:
+				stdout = fss
+		elif n == WORKING_DIR:
+			fss, ok = macfs.GetDirectory()
+			if ok:
+				wdir = fss
+		elif n == PAUSE:
+			pause = (not pause)
+		
+	tp, h, rect = d.GetDialogItem(SCRIPTNAME)
+	name = Dlg.GetDialogItemText(h)
+	tp, h, rect = d.GetDialogItem(ARGV)
+	argv = Dlg.GetDialogItemText(h)
+	return name, argv, stdin, stdout, wdir, pause
+	
+def main():
+	curdir = os.getcwd()
+	import Res
+	Res.OpenResFile('RunLibScript.rsrc')
+	name, argv, stdin, stdout, wdir, pause = interact()
+	if not name:
+		sys.exit(0)
+	sys.argv = [name] + string.split(argv)
+	if stdin:
+		sys.stdin = open(stdin.as_pathname())
+	if stdout:
+		sys.stdout = open(stdout.as_pathname(), 'w')
+	if wdir:
+		os.chdir(wdir.as_pathname())
+	else:
+		os.chdir(curdir)
+
+	import_as_main(name)
+
+	if pause:
+		sys.exit(1)
+	
+if __name__ == '__main__':
+	main()
+