mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 03:44:55 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			444 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			444 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""Edit the Python Preferences file."""
 | 
						|
#
 | 
						|
# This program is getting more and more clunky. It should really
 | 
						|
# be rewritten in a modeless way some time soon.
 | 
						|
 | 
						|
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 in the Python resource chain
 | 
						|
PREFNAME_NAME="PythonPreferenceFileName"
 | 
						|
 | 
						|
# resource IDs in our own resources (dialogs, etc)
 | 
						|
MESSAGE_ID = 256
 | 
						|
 | 
						|
DIALOG_ID = 511
 | 
						|
TEXT_ITEM = 1
 | 
						|
OK_ITEM = 2
 | 
						|
CANCEL_ITEM = 3
 | 
						|
DIR_ITEM = 4
 | 
						|
TITLE_ITEM = 5
 | 
						|
OPTIONS_ITEM = 7
 | 
						|
 | 
						|
# 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
 | 
						|
# The GUSI creator/type and delay-console
 | 
						|
OD_CREATOR_ITEM = 10
 | 
						|
OD_TYPE_ITEM = 11
 | 
						|
OD_DELAYCONSOLE_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)):
 | 
						|
	"""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)
 | 
						|
	tp, h, rect = d.GetDialogItem(OD_TYPE_ITEM)
 | 
						|
	SetDialogItemText(h, 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)
 | 
						|
		n = ModalDialog(None)
 | 
						|
		if n == OD_OK_ITEM:
 | 
						|
			tp, h, rect = d.GetDialogItem(OD_CREATOR_ITEM)
 | 
						|
			ncreator = GetDialogItemText(h)
 | 
						|
			tp, h, rect = d.GetDialogItem(OD_TYPE_ITEM)
 | 
						|
			ntype = GetDialogItemText(h)
 | 
						|
			if len(ncreator) == 4 and len(ntype) == 4:
 | 
						|
				return options, ncreator, ntype, delaycons
 | 
						|
			else:
 | 
						|
				sys.stderr.write('\007')
 | 
						|
		elif n == OD_CANCEL_ITEM:
 | 
						|
			return old_options
 | 
						|
		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])
 | 
						|
 | 
						|
			
 | 
						|
def interact(list, pythondir, 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())
 | 
						|
	except os.error:
 | 
						|
		pass
 | 
						|
	d = GetNewDialog(DIALOG_ID, -1)
 | 
						|
	tp, h, rect = d.GetDialogItem(TITLE_ITEM)
 | 
						|
	SetDialogItemText(h, title)
 | 
						|
	tp, h, rect = d.GetDialogItem(TEXT_ITEM)
 | 
						|
	SetDialogItemText(h, string.joinfields(list, '\r'))
 | 
						|
##	d.SetDialogDefaultItem(OK_ITEM)
 | 
						|
	d.SetDialogCancelItem(CANCEL_ITEM)
 | 
						|
	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('Select python home folder:')
 | 
						|
			if ok:
 | 
						|
				pythondir = fss
 | 
						|
		if n == OPTIONS_ITEM:
 | 
						|
			options = optinteract(options)
 | 
						|
	tmp = string.splitfields(GetDialogItemText(h), '\r')
 | 
						|
	rv = []
 | 
						|
	for i in tmp:
 | 
						|
		if i:
 | 
						|
			rv.append(i)
 | 
						|
	return rv, pythondir, 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)
 | 
						|
	
 | 
						|
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
 | 
						|
	print 'DBG interaction'
 | 
						|
	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)
 | 
						|
 | 
						|
def main():
 | 
						|
	try:
 | 
						|
		h = OpenResFile('EditPythonPrefs.rsrc')
 | 
						|
	except Res.Error:
 | 
						|
		pass	# Assume we already have acces to our own resource
 | 
						|
	
 | 
						|
	if len(sys.argv) <= 1:
 | 
						|
		edit_preferences()
 | 
						|
	else:
 | 
						|
		for appl in sys.argv[1:]:
 | 
						|
			edit_applet(appl)
 | 
						|
		
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
	main()
 |