1/*
2 * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25package build.tools.projectcreator;
26
27import java.io.File;
28import java.io.IOException;
29import java.io.PrintWriter;
30import java.util.Hashtable;
31import java.util.Iterator;
32import java.util.Stack;
33import java.util.Vector;
34
35abstract class HsArgHandler extends ArgHandler {
36    static final int STRING = 1;
37    static final int VECTOR = 2;
38    static final int HASH   = 3;
39
40    boolean nextNotKey(ArgIterator it) {
41        if (it.next()) {
42            String s = it.get();
43            return (s.length() == 0) || (s.charAt(0) != '-');
44        } else {
45            return false;
46        }
47    }
48
49    void empty(String key, String message) {
50        if (key != null) {
51            System.err.println("** Error: empty " + key);
52        }
53        if (message != null) {
54            System.err.println(message);
55        }
56        WinGammaPlatform.usage();
57    }
58
59    static String getCfg(String val) {
60        int under = val.indexOf('_');
61        int len = val.length();
62        if (under != -1 && under < len - 1) {
63            return val.substring(under+1, len);
64        } else {
65            return null;
66        }
67    }
68}
69
70class ArgRuleSpecific extends ArgRule {
71    ArgRuleSpecific(String arg, ArgHandler handler) {
72        super(arg, handler);
73    }
74
75    boolean match(String rulePattern, String arg) {
76        return rulePattern.startsWith(arg);
77    }
78}
79
80
81class SpecificHsArgHandler extends HsArgHandler {
82
83    String message, argKey, valKey;
84    int type;
85
86    public void handle(ArgIterator it) {
87        String cfg = getCfg(it.get());
88        if (nextNotKey(it)) {
89            String val = it.get();
90            switch (type) {
91            case VECTOR:
92                BuildConfig.addFieldVector(cfg, valKey, val);
93                break;
94            case HASH:
95                BuildConfig.putFieldHash(cfg, valKey, val, "1");
96                break;
97            case STRING:
98                BuildConfig.putField(cfg, valKey, val);
99                break;
100            default:
101                empty(valKey, "Unknown type: "+type);
102            }
103            it.next();
104
105        } else {
106            empty(argKey, message);
107        }
108    }
109
110    SpecificHsArgHandler(String argKey, String valKey, String message, int type) {
111        this.argKey = argKey;
112        this.valKey = valKey;
113        this.message = message;
114        this.type = type;
115    }
116}
117
118
119class HsArgRule extends ArgRuleSpecific {
120
121    HsArgRule(String argKey, String valKey, String message, int type) {
122        super(argKey, new SpecificHsArgHandler(argKey, valKey, message, type));
123    }
124
125}
126
127public abstract class WinGammaPlatform {
128
129    public boolean fileNameStringEquality(String s1, String s2) {
130        return s1.equalsIgnoreCase(s2);
131    }
132
133    static void usage() throws IllegalArgumentException {
134        System.err.println("WinGammaPlatform platform-specific options:");
135        System.err.println("  -sourceBase <path to directory (workspace) " +
136                           "containing source files; no trailing slash>");
137        System.err.println("  -projectFileName <full pathname to which project file " +
138                           "will be written; all parent directories must " +
139                           "already exist>");
140        System.err.println("  If any of the above are specified, "+
141                           "they must all be.");
142        System.err.println("  Note: if '-altRelativeInclude' option below " +
143                           "is used, then the '-relativeAltSrcInclude' " +
144                           "option must be used to specify the alternate " +
145                           "source dir, e.g., 'src\\closed'");
146        System.err.println("  Additional, optional arguments, which can be " +
147                           "specified multiple times:");
148        System.err.println("    -absoluteInclude <string containing absolute " +
149                           "path to include directory>");
150        System.err.println("    -altRelativeInclude <string containing " +
151                           "alternate include directory relative to " +
152                           "-sourceBase>");
153        System.err.println("    -relativeInclude <string containing include " +
154                           "directory relative to -sourceBase>");
155        System.err.println("    -define <preprocessor flag to be #defined " +
156                           "(note: doesn't yet support " +
157                           "#define (flag) (value))>");
158        System.err.println("    -startAt <subdir of sourceBase>");
159        System.err.println("    -additionalFile <file not in database but " +
160                           "which should show up in project file>");
161        System.err.println("    -additionalGeneratedFile <absolute path to " +
162                           "directory containing file; no trailing slash> " +
163                           "<name of file generated later in the build process>");
164        throw new IllegalArgumentException();
165    }
166
167
168    public void addPerFileLine(Hashtable table,
169                               String fileName,
170                               String line) {
171        Vector v = (Vector) table.get(fileName);
172        if (v != null) {
173            v.add(line);
174        } else {
175            v = new Vector();
176            v.add(line);
177            table.put(fileName, v);
178        }
179    }
180
181    protected static class PerFileCondData {
182        public String releaseString;
183        public String debugString;
184    }
185
186    protected void addConditionalPerFileLine(Hashtable table,
187                                           String fileName,
188                                           String releaseLine,
189                                           String debugLine) {
190        PerFileCondData data = new PerFileCondData();
191        data.releaseString = releaseLine;
192        data.debugString = debugLine;
193        Vector v = (Vector) table.get(fileName);
194        if (v != null) {
195            v.add(data);
196        } else {
197            v = new Vector();
198            v.add(data);
199            table.put(fileName, v);
200        }
201    }
202
203    protected static class PrelinkCommandData {
204      String description;
205      String commands;
206    }
207
208    protected void addPrelinkCommand(Hashtable table,
209                                     String build,
210                                     String description,
211                                     String commands) {
212      PrelinkCommandData data = new PrelinkCommandData();
213      data.description = description;
214      data.commands = commands;
215      table.put(build, data);
216    }
217
218    public boolean findString(Vector v, String s) {
219        for (Iterator iter = v.iterator(); iter.hasNext(); ) {
220            if (((String) iter.next()).equals(s)) {
221                return true;
222            }
223        }
224
225        return false;
226    }
227
228     String getProjectName(String fullPath, String extension)
229        throws IllegalArgumentException, IOException {
230        File file = new File(fullPath).getCanonicalFile();
231        fullPath = file.getCanonicalPath();
232        String parent = file.getParent();
233
234        if (!fullPath.endsWith(extension)) {
235            throw new IllegalArgumentException("project file name \"" +
236                                               fullPath +
237                                               "\" does not end in "+extension);
238        }
239
240        if ((parent != null) &&
241            (!fullPath.startsWith(parent))) {
242            throw new RuntimeException(
243                "Internal error: parent of file name \"" + parent +
244                "\" does not match file name \"" + fullPath + "\""
245            );
246        }
247
248        int len = parent.length();
249        if (!parent.endsWith(Util.sep)) {
250            len += Util.sep.length();
251        }
252
253        int end = fullPath.length() - extension.length();
254
255        if (len == end) {
256            throw new RuntimeException(
257                "Internal error: file name was empty"
258            );
259        }
260
261        return fullPath.substring(len, end);
262    }
263
264    protected abstract String getProjectExt();
265
266    public void createVcproj(String[] args)
267        throws IllegalArgumentException, IOException {
268
269        parseArguments(args);
270
271        String projectFileName = BuildConfig.getFieldString(null, "ProjectFileName");
272        String ext = getProjectExt();
273
274        String projectName = getProjectName(projectFileName, ext);
275
276        writeProjectFile(projectFileName, projectName, createAllConfigs(BuildConfig.getFieldString(null, "PlatformName")));
277    }
278
279    protected void writePrologue(String[] args) {
280        System.err.println("WinGammaPlatform platform-specific arguments:");
281        for (int i = 0; i < args.length; i++) {
282            System.err.print(args[i] + " ");
283        }
284        System.err.println();
285    }
286
287
288    void parseArguments(String[] args) {
289        new ArgsParser(args,
290                       new ArgRule[]
291            {
292                new ArgRule("-sourceBase",
293                            new HsArgHandler() {
294                                public void handle(ArgIterator it) {
295                                   String cfg = getCfg(it.get());
296                                   if (nextNotKey(it)) {
297                                      String sb = (String) it.get();
298                                      if (sb.endsWith(Util.sep)) {
299                                         sb = sb.substring(0, sb.length() - 1);
300                                      }
301                                      BuildConfig.putField(cfg, "SourceBase", sb);
302                                      it.next();
303                                   } else {
304                                      empty("-sourceBase", null);
305                                   }
306                                }
307                            }
308                            ),
309
310                new HsArgRule("-buildBase",
311                              "BuildBase",
312                              "   (Did you set the HotSpotBuildSpace environment variable?)",
313                              HsArgHandler.STRING
314                              ),
315
316               new HsArgRule("-buildSpace",
317                              "BuildSpace",
318                              null,
319                              HsArgHandler.STRING
320                              ),
321
322               new HsArgRule("-makeBinary",
323                              "MakeBinary",
324                              null,
325                              HsArgHandler.STRING
326                              ),
327
328               new HsArgRule("-makeOutput",
329                              "MakeOutput",
330                              null,
331                              HsArgHandler.STRING
332                              ),
333
334              new HsArgRule("-platformName",
335                              "PlatformName",
336                              null,
337                              HsArgHandler.STRING
338                              ),
339
340              new HsArgRule("-projectFileName",
341                              "ProjectFileName",
342                              null,
343                              HsArgHandler.STRING
344                              ),
345
346                new HsArgRule("-jdkTargetRoot",
347                              "JdkTargetRoot",
348                              "   (Did you set the HotSpotJDKDist environment variable?)",
349                              HsArgHandler.STRING
350                              ),
351
352                new HsArgRule("-compiler",
353                              "CompilerVersion",
354                              "   (Did you set the VcVersion correctly?)",
355                              HsArgHandler.STRING
356                              ),
357
358                new HsArgRule("-absoluteInclude",
359                              "AbsoluteInclude",
360                              null,
361                              HsArgHandler.VECTOR
362                              ),
363
364                new HsArgRule("-altRelativeInclude",
365                              "AltRelativeInclude",
366                              null,
367                              HsArgHandler.VECTOR
368                              ),
369
370                new HsArgRule("-relativeInclude",
371                              "RelativeInclude",
372                              null,
373                              HsArgHandler.VECTOR
374                              ),
375
376                new HsArgRule("-absoluteSrcInclude",
377                              "AbsoluteSrcInclude",
378                              null,
379                              HsArgHandler.VECTOR
380                              ),
381
382                new HsArgRule("-relativeAltSrcInclude",
383                              "RelativeAltSrcInclude",
384                              null,
385                              HsArgHandler.STRING
386                              ),
387
388                new HsArgRule("-relativeSrcInclude",
389                              "RelativeSrcInclude",
390                              null,
391                              HsArgHandler.VECTOR
392                              ),
393
394                new HsArgRule("-define",
395                              "Define",
396                              null,
397                              HsArgHandler.VECTOR
398                              ),
399
400                new HsArgRule("-useToGeneratePch",
401                              "UseToGeneratePch",
402                              null,
403                              HsArgHandler.STRING
404                              ),
405
406                new ArgRuleSpecific("-perFileLine",
407                            new HsArgHandler() {
408                                public void handle(ArgIterator it) {
409                                    String cfg = getCfg(it.get());
410                                    if (nextNotKey(it)) {
411                                        String fileName = it.get();
412                                        if (nextNotKey(it)) {
413                                            String line = it.get();
414                                            BuildConfig.putFieldHash(cfg, "PerFileLine", fileName, line);
415                                            it.next();
416                                            return;
417                                        }
418                                    }
419                                    empty(null, "** Error: wrong number of args to -perFileLine");
420                                }
421                            }
422                            ),
423
424                new ArgRuleSpecific("-conditionalPerFileLine",
425                            new HsArgHandler() {
426                                public void handle(ArgIterator it) {
427                                    String cfg = getCfg(it.get());
428                                    if (nextNotKey(it)) {
429                                        String fileName = it.get();
430                                        if (nextNotKey(it)) {
431                                            String productLine = it.get();
432                                            if (nextNotKey(it)) {
433                                                String debugLine = it.get();
434                                                BuildConfig.putFieldHash(cfg+"_debug", "CondPerFileLine",
435                                                                         fileName, debugLine);
436                                                BuildConfig.putFieldHash(cfg+"_product", "CondPerFileLine",
437                                                                         fileName, productLine);
438                                                it.next();
439                                                return;
440                                            }
441                                        }
442                                    }
443
444                                    empty(null, "** Error: wrong number of args to -conditionalPerFileLine");
445                                }
446                            }
447                            ),
448
449                new HsArgRule("-disablePch",
450                              "DisablePch",
451                              null,
452                              HsArgHandler.HASH
453                              ),
454
455                new ArgRule("-startAt",
456                            new HsArgHandler() {
457                                public void handle(ArgIterator it) {
458                                    if (BuildConfig.getField(null, "StartAt") != null) {
459                                        empty(null, "** Error: multiple -startAt");
460                                    }
461                                    if (nextNotKey(it)) {
462                                        BuildConfig.putField(null, "StartAt", it.get());
463                                        it.next();
464                                    } else {
465                                        empty("-startAt", null);
466                                    }
467                                }
468                            }
469                            ),
470
471                new HsArgRule("-ignoreFile",
472                                      "IgnoreFile",
473                                      null,
474                                      HsArgHandler.HASH
475                                      ),
476
477                new HsArgRule("-ignorePath",
478                              "IgnorePath",
479                              null,
480                              HsArgHandler.VECTOR
481                              ),
482
483                new HsArgRule("-hidePath",
484                      "HidePath",
485                      null,
486                      HsArgHandler.VECTOR
487                      ),
488
489                new HsArgRule("-additionalFile",
490                              "AdditionalFile",
491                              null,
492                              HsArgHandler.VECTOR
493                              ),
494
495                new ArgRuleSpecific("-additionalGeneratedFile",
496                            new HsArgHandler() {
497                                public void handle(ArgIterator it) {
498                                    String cfg = getCfg(it.get());
499                                    if (nextNotKey(it)) {
500                                        String dir = it.get();
501                                        if (nextNotKey(it)) {
502                                            String fileName = it.get();
503                                            BuildConfig.putFieldHash(cfg, "AdditionalGeneratedFile",
504                                                                     Util.normalize(dir + Util.sep + fileName),
505                                                                     fileName);
506                                            it.next();
507                                            return;
508                                        }
509                                    }
510                                    empty(null, "** Error: wrong number of args to -additionalGeneratedFile");
511                                }
512                            }
513                            ),
514
515                new ArgRule("-prelink",
516                            new HsArgHandler() {
517                                public void handle(ArgIterator it) {
518                                    if (nextNotKey(it)) {
519                                        if (nextNotKey(it)) {
520                                            String description = it.get();
521                                            if (nextNotKey(it)) {
522                                                String command = it.get();
523                                                BuildConfig.putField(null, "PrelinkDescription", description);
524                                                BuildConfig.putField(null, "PrelinkCommand", command);
525                                                it.next();
526                                                return;
527                                            }
528                                        }
529                                    }
530
531                                    empty(null,  "** Error: wrong number of args to -prelink");
532                                }
533                            }
534                            ),
535
536                new ArgRule("-postbuild",
537                            new HsArgHandler() {
538                                public void handle(ArgIterator it) {
539                                    if (nextNotKey(it)) {
540                                        if (nextNotKey(it)) {
541                                            String description = it.get();
542                                            if (nextNotKey(it)) {
543                                                String command = it.get();
544                                                BuildConfig.putField(null, "PostbuildDescription", description);
545                                                BuildConfig.putField(null, "PostbuildCommand", command);
546                                                it.next();
547                                                return;
548                                            }
549                                        }
550                                    }
551
552                                    empty(null,  "** Error: wrong number of args to -postbuild");
553                                }
554                            }
555                            ),
556            },
557                                       new ArgHandler() {
558                                           public void handle(ArgIterator it) {
559
560                                               throw new RuntimeException("Arg Parser: unrecognized option "+it.get());
561                                           }
562                                       }
563                                       );
564        if (BuildConfig.getField(null, "SourceBase") == null      ||
565            BuildConfig.getField(null, "BuildBase") == null       ||
566            BuildConfig.getField(null, "ProjectFileName") == null ||
567            BuildConfig.getField(null, "CompilerVersion") == null) {
568            usage();
569        }
570
571        BuildConfig.putField(null, "PlatformObject", this);
572    }
573
574    Vector createAllConfigs(String platform) {
575        Vector allConfigs = new Vector();
576
577        allConfigs.add(new C1DebugConfig());
578        allConfigs.add(new C1FastDebugConfig());
579        allConfigs.add(new C1ProductConfig());
580
581        allConfigs.add(new TieredDebugConfig());
582        allConfigs.add(new TieredFastDebugConfig());
583        allConfigs.add(new TieredProductConfig());
584
585        return allConfigs;
586    }
587
588    PrintWriter printWriter;
589
590    public void writeProjectFile(String projectFileName, String projectName,
591                                 Vector<BuildConfig> allConfigs) throws IOException {
592        throw new RuntimeException("use compiler version specific version");
593    }
594
595    int indent;
596    private Stack<String> tagStack = new Stack<String>();
597
598    private void startTagPrim(String name, String[] attrs, boolean close) {
599       startTagPrim(name, attrs, close, true);
600    }
601
602    private void startTagPrim(String name, String[] attrs, boolean close,
603          boolean newline) {
604       doIndent();
605       printWriter.print("<" + name);
606       indent++;
607
608       if (attrs != null && attrs.length > 0) {
609          for (int i = 0; i < attrs.length; i += 2) {
610             printWriter.print(" " + attrs[i] + "=\"" + attrs[i + 1] + "\"");
611             if (i < attrs.length - 2) {
612             }
613          }
614       }
615
616       if (close) {
617          indent--;
618          printWriter.print(" />");
619       } else {
620          // TODO push tag name, and change endTag to pop and print.
621          tagStack.push(name);
622          printWriter.print(">");
623       }
624       if (newline) {
625          printWriter.println();
626       }
627    }
628
629    void startTag(String name, String... attrs) {
630       startTagPrim(name, attrs, false);
631    }
632
633    void startTagV(String name, Vector attrs) {
634       String s[] = new String[attrs.size()];
635       for (int i = 0; i < attrs.size(); i++) {
636          s[i] = (String) attrs.elementAt(i);
637       }
638       startTagPrim(name, s, false);
639    }
640
641    void endTag() {
642       String name = tagStack.pop();
643       indent--;
644       doIndent();
645       printWriter.println("</" + name + ">");
646    }
647
648    private void endTagNoIndent() {
649       String name = tagStack.pop();
650       indent--;
651       printWriter.println("</" + name + ">");
652    }
653
654    void tag(String name, String... attrs) {
655       startTagPrim(name, attrs, true);
656    }
657
658    void tagData(String name, String data) {
659       startTagPrim(name, null, false, false);
660       printWriter.print(data);
661       endTagNoIndent();
662    }
663
664    void tagData(String name, String data, String... attrs) {
665       startTagPrim(name, attrs, false, false);
666       printWriter.print(data);
667       endTagNoIndent();
668    }
669
670    void tagV(String name, Vector attrs) {
671       String s[] = new String[attrs.size()];
672       for (int i = 0; i < attrs.size(); i++) {
673          s[i] = (String) attrs.elementAt(i);
674       }
675       startTagPrim(name, s, true);
676    }
677
678    void doIndent() {
679       for (int i = 0; i < indent; i++) {
680          printWriter.print("  ");
681       }
682    }
683
684
685}
686