1    	package acl2s.plugin.prefs;
2    	
3    	import java.io.File;
4    	import java.io.FileInputStream;
5    	import java.io.IOException;
6    	import java.util.StringTokenizer;
7    	
8    	import org.eclipse.core.runtime.CoreException;
9    	import org.eclipse.core.runtime.FileLocator;
10   	import org.eclipse.core.runtime.Platform;
11   	import org.eclipse.core.runtime.Status;
12   	import org.eclipse.jface.preference.DirectoryFieldEditor;
13   	import org.eclipse.jface.preference.FieldEditorPreferencePage;
14   	import org.eclipse.jface.preference.IPreferenceStore;
15   	import org.eclipse.jface.preference.RadioGroupFieldEditor;
16   	import org.eclipse.swt.widgets.Shell;
17   	import org.eclipse.ui.IWorkbench;
18   	import org.eclipse.ui.IWorkbenchPreferencePage;
19   	import org.osgi.framework.Bundle;
20   	import org.peterd.util.io.MiscIO;
21   	import org.peterd.util.io.StreamCopier;
22   	
23   	import acl2s.lib.session.MyBaseConfig;
24   	import acl2s.plugin.Acl2sPlugin;
25   	import acl2s.plugin.ISessionDocument;
26   	
27   	public final class Acl2Prefs {
28   		private Acl2Prefs() {}
29   	
30   		public static final String ACL2_HOME_KEY = "Acl2.Home";
31   		public static final String CUST_KEY = "Acl2.Customization";
32   		public static final String CUST_DEFAULT = "";
33   		public static final String CUST_NEVER = "NEVER";
34   		public static final String CUST_ALWAYS = "ALWAYS";
35   	
36   		public static void initializeDefaultPreferences(IPreferenceStore store) {
37   			store.setDefault(ACL2_HOME_KEY, "");
38   			store.setDefault(CUST_KEY, CUST_DEFAULT);
39   		}
40   		
41   		public static class Page extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
42   			public Page() {
43   				super(GRID);
44   				setPreferenceStore(Acl2sPlugin.getDefault().getPreferenceStore());
45   				setDescription("To use a custom ACL2 build/install, specify the path to that build below.  Otherwise, leave it blank and ACL2s will look for an Eclipse-installed version, an ACL2_HOME environment variable setting, or just run the command \"acl2\" (in that order).");
46   			}
47   	
48   			protected void createFieldEditors() {
49   				addField(new DirectoryFieldEditor(ACL2_HOME_KEY,
50   						                          "ACL2 build path:",
51   						                          getFieldEditorParent()));
52   				addField(new RadioGroupFieldEditor(CUST_KEY,
53   					"Load acl2-customization file ...",
54   					1,
55   					new String[][] {
56   					 { "never", CUST_NEVER },
57   					 { "for non-introductory modes (such as Compatible)", CUST_DEFAULT },
58   					 { "always", CUST_ALWAYS }
59   					}, getFieldEditorParent()));
60   			}
61   	
62   			public void init(IWorkbench workbench) {
63   				// nothing needed?
64   			}
65   		}
66   		
67   		public static Boolean getCustomizationOverride(Shell parent, ISessionDocument sesdoc) {
68   			IPreferenceStore store = Acl2sPlugin.getDefault().getPreferenceStore();
69   			String pref = store.getString(CUST_KEY);
70   			if (pref == null) pref = "";
71   			if (pref.equals(CUST_NEVER)) {
72   				return Boolean.FALSE;
73   			} else if (pref.equals(CUST_ALWAYS)) {
74   				return Boolean.TRUE;
75   			} else {
76   				return null;
77   			}
78   		}
79   		
80   		//harshrc:: return value can be 
81   		//1. ACL2 build path set in eclipse preferences
82   		//2. ACL2s image plugin path (bundle in eclipse terminology)
83   		//3. ACL2_HOME environment variable set in OS
84   		//4. null (in which case we try to execute 'acl2')
85   		public static File getAcl2HomePref(Shell shellOption) {
86   			IPreferenceStore store = Acl2sPlugin.getDefault().getPreferenceStore();
87   			String pref = store.getString(ACL2_HOME_KEY);
88   			if (pref == null) pref = "";
89   			while (pref.length() > 1 && pref.endsWith(File.separator)) {
90   				pref = pref.substring(0, pref.length() - 1);
91   			}
92   			
93   			if (pref.length() > 0) {
94   				File home = new File(pref);
95   				if (home.isDirectory()) {
96   					return home;
97   				}
98   				Acl2sPlugin.logWarning("Acl2 home preference is not a directory.  Falling back on other image location means.", null);
99   			}
100  			
101  			File fromImage = getAcl2ImageDir();
102  			if (fromImage != null) {
103  				return fromImage;
104  			}
105  			File fromEnv = MyBaseConfig.getACL2HomeFromEnvironment();
106  			if (fromEnv != null) {
107  				return fromEnv;
108  			}
109  			return null;
110  		}
111  	
112  		public static File getAcl2ImageDir() {
113  			Bundle acl2Plugin = Acl2Prefs.getAcl2ImagePlugin();
114  			if (acl2Plugin != null) {
115  				try {
116  					File imageDir = new File(FileLocator.resolve(acl2Plugin.getEntry("/")).getPath());
117  					if (!imageDir.isDirectory()) throw new IOException("ACL2 image plugin root is not a directory!");
118  					
119  					// return if chmod not needed
120  					File execLstFile = new File(imageDir, "exec-files.lst");
121  					if (!execLstFile.exists() || File.separatorChar == '\\') {
122  						return imageDir;
123  					}
124  	
125  					try {
126  						String execLst = new String(StreamCopier.dump(new FileInputStream(execLstFile)));
127  						StringTokenizer execTokens = new StringTokenizer(execLst,"\r\n");
128  	
129  						if (!execLstFile.canWrite()) {
130  							// but i'm not allowed to modify this stuff
131  							StringBuilder msg = new StringBuilder();
132  							msg.append("The Eclipse-installed ACL2 image needs execute permission added to certain files, but it appears I don't have the permission to do this.  Please run these commands as an administrator to fix the problem:\n");
133  							while (execTokens.hasMoreTokens()) {
134  								msg.append("chmod a+x ");
135  								msg.append(imageDir.getAbsolutePath());
136  								msg.append(File.separatorChar);
137  								msg.append(execTokens.nextToken());
138  								msg.append('\n');
139  							}
140  							msg.append("rm -f ");
141  							msg.append(execLstFile.getAbsolutePath());
142  							msg.append('\n');
143  							throw new CoreException(new Status(Status.WARNING,Acl2sPlugin.id,msg.toString()));
144  						}
145  	
146  						// do chmod
147  						while (execTokens.hasMoreTokens()) {
148  							MiscIO.addExecutePerm(new File(imageDir, execTokens.nextToken()),true);
149  						}
150  						if (!execLstFile.delete()) {
151  							// oh well for now
152  							//throw new CoreException(new Status(Status.WARNING,Acl2sPlugin.id,msg));
153  						}
154  					} catch (IOException e) {
155  						Acl2sPlugin.logError("I/O Error while attempting to add execute permissions to ACL2 image feature", e);
156  					} catch (CoreException e) {
157  						Acl2sPlugin.logError(e.getStatus().getMessage(), e);
158  					}
159  					return imageDir;
160  				} catch (IOException e) {
161  					Acl2sPlugin.logError("Error while reading ACL2 Image feature", e);
162  				}
163  			}
164  			return null;
165  		}
166  		
167  		//harshc:: changed to fallback to a 32bit image plugin if the 64bit plugin inferred by name of OS/Arch
168  		//is not what the user installed. This only helps the case of linux 32bit plugin on a X86_64 arch.
169  		public static Bundle getAcl2ImagePlugin() {
170  			Bundle imagePlugin =  Platform.getBundle(acl2BundleName);
171  			if (imagePlugin != null) {
172  				return imagePlugin;
173  			}
174  			else {
175  			return 	Platform.getBundle(acl2BundleName_fallback); //fallback to 32bit plugin
176  			}
177  		}
178  		
179  		//new function added to recognize 64bit Windows OS
180  		static boolean isWin64FromEnvironment() {
181  			String tmp = System.getenv("PROGRAMFILES(X86)");
182  			if (tmp == null)
183  				return false;
184  			else
185  				return true;
186  		}
187  		
188  		static final String arch;
189  		static final String os;
190  		
191  		public static final String acl2BundleName;
192  		public static final String acl2BundleName_fallback;
193  		
194  		static {
195  			String a = Platform.getOSArch().toLowerCase();
196  			String a_f = null; //a_f is the fallback OSArch
197  			if (a.contains("x86_64") || a.contains("x64") || a.contains("amd64")) {
198  				a = "x86_64"; a_f = "X86";
199  			} else if (a.contains("86") || a.contains("amd") || a.contains("intel")) {
200  				a = "x86"; a_f = "x86";
201  			}  else if (a.contains("power") || a.contains("ppc") || a.contains("g3") || a.contains("g4")) {
202  				a = "ppc"; a_f = "ppc";
203  			} else {
204  				Acl2sPlugin.logWarning("Unknown/unsuported architecture encountered: " + a, null);
205  			}
206  			arch = a;
207  			
Event do_not_call: "java.lang.String.toLowerCase()" implicitly uses the environment's default character set, which might lead to unexpected behavior. Consider using toLowerCase(Locale locale).
208  			String o = Platform.getOS().toLowerCase();
209  			String o_f = null; //o_f is the fallback OS
210  			if (o.contains("win")) {
211  				if (a.contains("x86_64") && isWin64FromEnvironment() ) { 
212  					o = "win64"; o_f = "win32";
213  				}
214  				else {
215  					o = "win32"; o_f = "win32";
216  				}
217  			} else if (o.contains("linux")) {
218  				o = "linux"; o_f = "linux";
219  			} else if (o.contains("mac") || o.contains("darwin")) {
220  				o = "macosx"; o_f = "macosx";
221  			} else {
222  				Acl2sPlugin.logWarning("Unknown/unsupported OS encountered: " + o, null);
223  			}
224  			os = o;
225  			
226  			acl2BundleName = "acl2_image." + os + "." + arch;
227  			acl2BundleName_fallback =  "acl2_image." + o_f + "." + a_f;
228  		}
229  	}