Major overhaul: this is now little more than a user interface, the
preference handling code is in modules pythonprefs and preferences.
This should finally make it easier for someone (Just?) to write a
decent interface to preference setting, and it'll allow setting
initial sys.path and such from ConfigurePython.
diff --git a/Mac/scripts/EditPythonPrefs.py b/Mac/scripts/EditPythonPrefs.py
index bc7e2da..d45a612 100644
--- a/Mac/scripts/EditPythonPrefs.py
+++ b/Mac/scripts/EditPythonPrefs.py
@@ -13,9 +13,8 @@
 import os
 import sys
 import Res # For Res.Error
-
-# Resource in the Python resource chain
-PREFNAME_NAME="PythonPreferenceFileName"
+import pythonprefs
+import EasyDialogs
 
 # resource IDs in our own resources (dialogs, etc)
 MESSAGE_ID = 256
@@ -31,88 +30,46 @@
 # The options dialog. There is a correspondence between
 # the dialog item numbers and the option.
 OPT_DIALOG_ID = 510
-# 1 thru 9 are the options
+
+# Map dialog item numbers to option names (and the reverse)
+opt_dialog_map = [
+	None,
+	"inspect",
+	"verbose",
+	"optimize",
+	"unbuffered",
+	"debugging",
+	"keepopen",
+	"keeperror",
+	"nointopt",
+	"noargs",
+	"delayconsole"]
+opt_dialog_dict = {}
+for i in range(len(opt_dialog_map)):
+	if opt_dialog_map[i]:
+		opt_dialog_dict[opt_dialog_map[i]] = i
+# 1 thru 10 are the options
 # The GUSI creator/type and delay-console
-OD_CREATOR_ITEM = 10
-OD_TYPE_ITEM = 11
-OD_DELAYCONSOLE_ITEM = 12
+OD_CREATOR_ITEM = 11
+OD_TYPE_ITEM = 12
 OD_OK_ITEM = 13
 OD_CANCEL_ITEM = 14
 
-# Resource IDs in the preferences file
-PATH_STRINGS_ID = 128
-DIRECTORY_ID = 128
-OPTIONS_ID = 128
-GUSI_ID = 10240
-
-# Override IDs (in the applet)
-OVERRIDE_PATH_STRINGS_ID = 129
-OVERRIDE_DIRECTORY_ID = 129
-OVERRIDE_OPTIONS_ID = 129
-OVERRIDE_GUSI_ID = 10241
-
-# Things we know about the GUSI resource. Note the code knows these too.
-GUSIPOS_TYPE=0
-GUSIPOS_CREATOR=4
-GUSIPOS_SKIP=8
-GUSIPOS_FLAGS=9
-GUSIPOS_VERSION=10
-GUSIVERSION='0181'
-GUSIFLAGS_DELAY=0x20 # Mask
-
-READ = 1
-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)
-	d.SetDialogDefaultItem(1)
-	tp, h, rect = d.GetDialogItem(2)
-	SetDialogItemText(h, str)
-	while 1:
-		n = ModalDialog(None)
-		if n == 1: break
-		
-def optinteract((options, creator, type, delaycons)):
+def optinteract(options):
 	"""Let the user interact with the options dialog"""
-	old_options = (options[:], creator, type, delaycons)
 	d = GetNewDialog(OPT_DIALOG_ID, -1)
 	tp, h, rect = d.GetDialogItem(OD_CREATOR_ITEM)
-	SetDialogItemText(h, creator)
+	SetDialogItemText(h, options['creator'])
 	tp, h, rect = d.GetDialogItem(OD_TYPE_ITEM)
-	SetDialogItemText(h, type)
+	SetDialogItemText(h, options['type'])
 	d.SetDialogDefaultItem(OD_OK_ITEM)
 	d.SetDialogCancelItem(OD_CANCEL_ITEM)
+	
 	while 1:
-		for i in range(len(options)):
-			tp, h, rect = d.GetDialogItem(i+1)
-			h.as_Control().SetControlValue(options[i])
-		tp, h, rect = d.GetDialogItem(OD_DELAYCONSOLE_ITEM)
-		h.as_Control().SetControlValue(delaycons)
+		for name in opt_dialog_dict.keys():
+			num = opt_dialog_dict[name]
+			tp, h, rect = d.GetDialogItem(num)
+			h.as_Control().SetControlValue(options[name])
 		n = ModalDialog(None)
 		if n == OD_OK_ITEM:
 			tp, h, rect = d.GetDialogItem(OD_CREATOR_ITEM)
@@ -120,25 +77,24 @@
 			tp, h, rect = d.GetDialogItem(OD_TYPE_ITEM)
 			ntype = GetDialogItemText(h)
 			if len(ncreator) == 4 and len(ntype) == 4:
-				return options, ncreator, ntype, delaycons
+				options['creator'] = ncreator
+				options['type'] = ntype
+				return options
 			else:
-				sys.stderr.write('\007')
+				MacOS.SysBeep()
 		elif n == OD_CANCEL_ITEM:
-			return old_options
+			return
 		elif n in (OD_CREATOR_ITEM, OD_TYPE_ITEM):
 			pass
-		elif n == OD_DELAYCONSOLE_ITEM:
-			delaycons = (not delaycons)
-		elif 1 <= n <= len(options):
-			options[n-1] = (not options[n-1])
+		elif 1 <= n <= len(opt_dialog_map):
+			options[opt_dialog_map[n]] = (not options[opt_dialog_map[n]])
 
 			
-def interact(list, pythondir, options, title):
+def interact(options, title):
 	"""Let the user interact with the dialog"""
-	opythondir = pythondir
 	try:
 		# Try to go to the "correct" dir for GetDirectory
-		os.chdir(pythondir.as_pathname())
+		os.chdir(options['dir'].as_pathname())
 	except os.error:
 		pass
 	d = GetNewDialog(DIALOG_ID, -1)
@@ -146,7 +102,7 @@
 	SetDialogItemText(h, title)
 	tp, h, rect = d.GetDialogItem(TEXT_ITEM)
 ##	SetDialogItemText(h, string.joinfields(list, '\r'))
-	h.data = string.joinfields(list, '\r')
+	h.data = string.joinfields(options['path'], '\r')
 	d.SelectDialogItemText(TEXT_ITEM, 0, 32767)
 	d.SelectDialogItemText(TEXT_ITEM, 0, 0)
 ##	d.SetDialogDefaultItem(OK_ITEM)
@@ -164,272 +120,34 @@
 		if n == DIR_ITEM:
 			fss, ok = macfs.GetDirectory('Select python home folder:')
 			if ok:
-				pythondir = fss
+				options['dir'] = fss
 		if n == OPTIONS_ITEM:
-			options = optinteract(options)
+			noptions = options
+			for k in options.keys():
+				noptions[k] = options[k]
+			noptions = optinteract(noptions)
+			if noptions:
+				options = noptions
 	tmp = string.splitfields(h.data, '\r')
-	rv = []
+	newpath = []
 	for i in tmp:
 		if i:
-			rv.append(i)
-	return rv, pythondir, options
+			newpath.append(i)
+	options['path'] = newpath
+	return options
 	
-def getprefpath(id):
-	# Load the path and directory resources
-	try:
-		sr = GetResource('STR#', id)
-	except (MacOS.Error, Res.Error):
-		return None, None
-	d = sr.data
-	l = restolist(d)
-	return l, sr
-
-def getprefdir(id):
-	try:
-		dr = GetResource('alis', id)
-		fss, fss_changed = macfs.RawAlias(dr.data).Resolve()
-	except (MacOS.Error, Res.Error):
-		return None, None, 1
-	return fss, dr, fss_changed
-
-def getoptions(id):
-	try:
-		opr = GetResource('Popt', id)
-	except (MacOS.Error, Res.Error):
-		return [0]*9, None
-	options = map(lambda x: ord(x), opr.data)
-	while len(options) < 9:
-		options = options + [0]
-	return options, opr
-	
-def getgusioptions(id):
-	try:
-		opr = GetResource('GU\267I', id)
-	except (MacOS.Error, Res.Error):
-		return '????', '????', 0, None
-	data = opr.data
-	type = data[GUSIPOS_TYPE:GUSIPOS_TYPE+4]
-	creator = data[GUSIPOS_CREATOR:GUSIPOS_CREATOR+4]
-	flags = ord(data[GUSIPOS_FLAGS])
-	version = data[GUSIPOS_VERSION:GUSIPOS_VERSION+4]
-	if version <> GUSIVERSION:
-		message('GU\267I resource version "%s", fixing to "%s"'%(version, GUSIVERSION))
-		flags = 0
-	delay = (not not (flags & GUSIFLAGS_DELAY))
-	return creator, type, delay, opr
-	
-def setgusioptions(opr, creator, type, delay):
-	data = opr.data
-	flags = ord(data[GUSIPOS_FLAGS])
-	version = data[GUSIPOS_VERSION:GUSIPOS_VERSION+4]
-	if version <> GUSIVERSION:
-		flags = 0x88
-		version = GUSIVERSION
-	if delay:
-		flags = flags | GUSIFLAGS_DELAY
-	else:
-		flags = flags & ~GUSIFLAGS_DELAY
-	data = type + creator + data[GUSIPOS_SKIP] + chr(flags) + GUSIVERSION + data[GUSIPOS_VERSION+4:]
-	return data
-	
-def openpreffile(rw):
-	# Find the preferences folder and our prefs file, create if needed.	
-	vrefnum, dirid = macfs.FindFolder(kOnSystemDisk, 'pref', 0)
-	try:
-		pnhandle = GetNamedResource('STR ', PREFNAME_NAME)
-	except Res.Error:
-		message("No %s resource (old Python?)"%PREFNAME_NAME)
-		sys.exit(1)
-	prefname = pnhandle.data[1:]
-	preff_fss = macfs.FSSpec((vrefnum, dirid, prefname))
-	try:
-		preff_handle = FSpOpenResFile(preff_fss, rw)
-	except Res.Error:
-		# Create it
-		message('No preferences file, creating one...')
-		FSpCreateResFile(preff_fss, 'Pyth', 'pref', smAllScripts)
-		preff_handle = FSpOpenResFile(preff_fss, rw)
-	return preff_handle
-	
-def openapplet(name):
-	fss = macfs.FSSpec(name)
-	try:
-		app_handle = FSpOpenResFile(fss, WRITE)
-	except Res.Error:
-		message('File does not have a resource fork.')
-		sys.exit(0)
-	return app_handle
-		
 	
 def edit_preferences():
-	preff_handle = openpreffile(WRITE)
-	
-	l, sr = getprefpath(PATH_STRINGS_ID)
-	if l == None:	
-		message('Cannot find any sys.path resource! (Old python?)')
-		sys.exit(0)
-		
-	fss, dr, fss_changed = getprefdir(DIRECTORY_ID)
-	if fss == None:
-		fss = macfs.FSSpec(os.getcwd())
-		fss_changed = 1
-		
-	options, opr = getoptions(OPTIONS_ID)
-	saved_options = options[:]
-	
-	creator, type, delaycons, gusi_opr = getgusioptions(GUSI_ID)
-	saved_gusi_options = creator, type, delaycons
-	
-	# Let the user play away
-	result = interact(l, fss, (options, creator, type, delaycons),
-			 'System-wide preferences')
-	
-	# See what we have to update, and how
-	if result == None:
-		sys.exit(0)
-		
-	pathlist, nfss, (options, creator, type, delaycons) = result
-	if nfss != fss:
-		fss_changed = 1
-		
-	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, '')
-			
-	if options != saved_options:
-		newdata = reduce(lambda x, y: x+chr(y), options, '')
-		if opr and opr.HomeResFile() == preff_handle:
-			opr.data = newdata
-			opr.ChangedResource()
-		else:
-			opr = Resource(newdata)
-			opr.AddResource('Popt', OPTIONS_ID, '')
-			
-	if (creator, type, delaycons) != saved_gusi_options:
-		newdata = setgusioptions(gusi_opr, creator, type, delaycons)
-		if gusi_opr.HomeResFile() == preff_handle:
-			gusi_opr.data = newdata
-			gusi_opr.ChangedResource()
-		else:
-			ngusi_opr = Resource(newdata)
-			ngusi_opr.AddResource('GU\267I', GUSI_ID, '')
-				
-	CloseResFile(preff_handle)
+	handler = pythonprefs.PythonOptions()
+	result = interact(handler.load(), 'System-wide preferences')
+	if result:
+		handler.save(result)
 	
 def edit_applet(name):
-	pref_handle = openpreffile(READ)
-	app_handle = openapplet(name)
-	
-	notfound = ''
-	l, sr = getprefpath(OVERRIDE_PATH_STRINGS_ID)
-	if l == None:
-		notfound = 'path'
-		
-		l, dummy = getprefpath(PATH_STRINGS_ID)
-		if l == None:	
-			message('Cannot find any sys.path resource! (Old python?)')
-			sys.exit(0)
-		
-	fss, dr, fss_changed = getprefdir(OVERRIDE_DIRECTORY_ID)
-	if fss == None:
-		if notfound:
-			notfound = notfound + ', directory'
-		else:
-			notfound = 'directory'
-		fss, dummy, dummy2 = getprefdir(DIRECTORY_ID)
-		if fss == None:
-			fss = macfs.FSSpec(os.getcwd())
-			fss_changed = 1
-
-	options, opr = getoptions(OVERRIDE_OPTIONS_ID)
-	if not opr:
-		if notfound:
-			notfound = notfound + ', options'
-		else:
-			notfound = 'options'
-		options, dummy = getoptions(OPTIONS_ID)
-	saved_options = options[:]
-	
-	creator, type, delaycons, gusi_opr = getgusioptions(OVERRIDE_GUSI_ID)
-	if not gusi_opr:
-		if notfound:
-			notfound = notfound + ', GUSI options'
-		else:
-			notfound = 'GUSI options'
-		creator, type, delaycons, gusi_opr = getgusioptions(GUSI_ID)
-	saved_gusi_options = creator, type, delaycons
-	
-	dummy = dummy2 = None # Discard them.
-	
-	if notfound:
-		message('Warning: initial %s taken from system-wide defaults'%notfound)
-	# Let the user play away
-	result = interact(l, fss, (options, creator, type, delaycons), name)
-	
-	# See what we have to update, and how
-	if result == None:
-		sys.exit(0)
-		
-	pathlist, nfss, (options, creator, type, delaycons) = result
-	if nfss != fss:
-		fss_changed = 1
-		
-	if fss_changed:
-		alias = nfss.NewAlias()
-		if dr:
-			dr.data = alias.data
-			dr.ChangedResource()
-		else:
-			dr = Resource(alias.data)
-			dr.AddResource('alis', OVERRIDE_DIRECTORY_ID, '')
-			
-	if pathlist != l:
-		if pathlist == []:
-			if sr.HomeResFile() == app_handle:
-				sr.RemoveResource()
-		elif sr and sr.HomeResFile() == app_handle:
-			sr.data = listtores(pathlist)
-			sr.ChangedResource()
-		else:
-			sr = Resource(listtores(pathlist))
-			sr.AddResource('STR#', OVERRIDE_PATH_STRINGS_ID, '')
-			
-	if options != saved_options:
-		newdata = reduce(lambda x, y: x+chr(y), options, '')
-		if opr and opr.HomeResFile() == app_handle:
-			opr.data = newdata
-			opr.ChangedResource()
-		else:
-			opr = Resource(newdata)
-			opr.AddResource('Popt', OVERRIDE_OPTIONS_ID, '')
-			
-	if (creator, type, delaycons) != saved_gusi_options:
-		newdata = setgusioptions(gusi_opr, creator, type, delaycons)
-		id, type, name = gusi_opr.GetResInfo()
-		if gusi_opr.HomeResFile() == app_handle and id == OVERRIDE_GUSI_ID:
-			gusi_opr.data = newdata
-			gusi_opr.ChangedResource()
-		else:
-			ngusi_opr = Resource(newdata)
-			ngusi_opr.AddResource('GU\267I', OVERRIDE_GUSI_ID, '')
-			
-	CloseResFile(app_handle)
+	handler = pythonprefs.AppletOptions(name)
+	result = interact(handler.load(), os.path.split(name)[1])
+	if result:
+		handler.save(result)
 
 def main():
 	try: