@@ -139,6 +139,111 @@ public void save() throws IOException {
139
139
}
140
140
}
141
141
142
+ private final String buildToolsHeader = "\n /** Arduino IDE Board Tool details\n " ;
143
+ private final String buildToolsHeaderEnd = "*/" ;
144
+
145
+ /**
146
+ * Checks the code for a valid build tool header
147
+ * @param program The code to scan for the build tools
148
+ * @return True if the build tool header was found ONE time. Returns false if found MORE than one time, or not found at all.
149
+ */
150
+ private boolean containsBuildSettings (String program ){
151
+ return program .contains (buildToolsHeader ) && (program .indexOf (buildToolsHeader ) == program .lastIndexOf (buildToolsHeader ));
152
+ }
153
+
154
+ /**
155
+ * This function returns the index of the Nth occurrence of the substring in the specified string (http://programming.guide/java/nth-occurrence-in-string.html)
156
+ * @param str The string to find the Nth occurrence in
157
+ * @param substr The string to find
158
+ * @param n The occurrence number you'd like to find
159
+ * @return
160
+ */
161
+ private static int ordinalIndexOf (String str , String substr , int n ) {
162
+ int pos = str .indexOf (substr );
163
+ while (--n > 0 && pos != -1 )
164
+ pos = str .indexOf (substr , pos + 1 );
165
+ return pos ;
166
+ }
167
+
168
+ private String removeBuildSettingsHeader (Sketch sketch ){
169
+ if (sketch .getPrimaryFile ().getProgram ().contains (buildToolsHeader )) {
170
+ int headerStartIndex = sketch .getPrimaryFile ().getProgram ().indexOf (buildToolsHeader );
171
+ int headerStopIndex = sketch .getPrimaryFile ().getProgram ().indexOf (buildToolsHeaderEnd );
172
+ if (headerStartIndex > headerStopIndex ) {
173
+ System .err .println ("The build tool header is not the first comment block in your file! Please fix this." );
174
+ for (int i = 0 ; i < sketch .getPrimaryFile ().getProgram ().length (); i ++) {
175
+ if (headerStartIndex < ordinalIndexOf (sketch .getPrimaryFile ().getProgram (), buildToolsHeaderEnd , i )) {
176
+ headerStopIndex = ordinalIndexOf (sketch .getPrimaryFile ().getProgram (), buildToolsHeaderEnd , i );
177
+ break ;
178
+ }
179
+ }
180
+ }
181
+ String header = sketch .getPrimaryFile ().getProgram ().substring (headerStartIndex , headerStopIndex + buildToolsHeaderEnd .length ());
182
+ return sketch .getPrimaryFile ().getProgram ().replace (header , "" );
183
+ }
184
+ return sketch .getPrimaryFile ().getProgram ();
185
+ }
186
+
187
+ /**
188
+ * This checks the program code for a valid build tool settings header and returns the LinkedHashMap with the setting name and the value.
189
+ * The build tools header should not be changed or manipulated by the pre-processor as the pre-processors output may depend on the build tools.
190
+ * @param program The program code
191
+ * @return The {@code LinkedHashMap} with the settings and their values of the <b>first</b> header that was found in the program code
192
+ */
193
+ public LinkedHashMap <String , String > getBuildSettingsFromProgram (String program ){
194
+ LinkedHashMap <String , String > buildSettings = new LinkedHashMap <>();
195
+ if (containsBuildSettings (program )){
196
+ int headerStartIndex = program .indexOf (buildToolsHeader );
197
+ int headerStopIndex = program .indexOf (buildToolsHeaderEnd );
198
+ if (headerStartIndex > headerStopIndex ){
199
+ System .err .println ("The build tool header is not the first comment block in your file! Please fix this." );
200
+ for (int i = 0 ; i < program .length (); i ++){
201
+ if (headerStartIndex < ordinalIndexOf (program , buildToolsHeaderEnd , i )){
202
+ headerStopIndex = ordinalIndexOf (program , buildToolsHeaderEnd , i );
203
+ break ;
204
+ }
205
+ }
206
+ }
207
+ String header = program .substring (headerStartIndex + buildToolsHeader .length (), headerStopIndex );
208
+
209
+ String [] headerLines = header .split ("\n " );
210
+
211
+ for (int line = 0 ; line < headerLines .length ; line ++){
212
+ String [] setting = headerLines [line ].replace ("*" ,"" ).trim ().split (": " );
213
+ if (headerLines [line ].indexOf (": " ) != (headerLines [line ].length () -1 )){
214
+ // The value of the setting is not empty
215
+ buildSettings .put (setting [0 ].trim (), setting [1 ].trim ());
216
+ }else {
217
+ buildSettings .put (setting [0 ], "" );
218
+ }
219
+ }
220
+ }else {
221
+ if (!program .contains (buildToolsHeader )){
222
+ // There are multiple headers, remove them
223
+ // TODO Create a dialog asking the user to add a build header to the file
224
+ }
225
+ }
226
+
227
+ return buildSettings ;
228
+ }
229
+
230
+ private boolean isBuildSettingsEqual (LinkedHashMap <String ,String > first , LinkedHashMap <String , String > second ){
231
+ return first .keySet ().containsAll (second .keySet ()) && first .values ().containsAll (second .values ());
232
+ }
233
+
234
+ public String setBuildSettings (Sketch sketch , LinkedHashMap <String , String > buildSettings ){
235
+ if (sketch != this ){
236
+ return "" ;
237
+ }
238
+
239
+ String customBoardSettingsHeader = buildSettings .entrySet ().stream ().map (entry -> String .format (" * %s: %s\n " , entry .getKey (), entry .getValue ())).collect (Collectors .joining ("" , buildToolsHeader , "*/" ));
240
+ if (!isBuildSettingsEqual (getBuildSettingsFromProgram (sketch .getPrimaryFile ().getProgram ()),buildSettings )){
241
+ String headerLessProgram = removeBuildSettingsHeader (sketch );
242
+ return customBoardSettingsHeader + ((headerLessProgram .charAt (0 ) == '\n' ) ? "" : "\n " ) + headerLessProgram ;
243
+ }
244
+ return "" ;
245
+ }
246
+
142
247
public int getCodeCount () {
143
248
return files .size ();
144
249
}
0 commit comments