~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/ikvm/ikvmdoc/IKVMDoc.java

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 
 
3
  This software is provided 'as-is', without any express or implied
 
4
  warranty.  In no event will the authors be held liable for any damages
 
5
  arising from the use of this software.
 
6
 
 
7
  Permission is granted to anyone to use this software for any purpose,
 
8
  including commercial applications, and to alter it and redistribute it
 
9
  freely.
 
10
  
 
11
*/
 
12
 
 
13
import java.io.*;
 
14
import java.util.*;
 
15
 
 
16
import javax.xml.parsers.*;
 
17
 
 
18
import org.xml.sax.*;
 
19
import org.xml.sax.helpers.*;
 
20
 
 
21
import com.sun.javadoc.*;
 
22
import com.sun.tools.javadoc.Main;
 
23
 
 
24
/**
 
25
 * Java Doclet for generating .NET XML API documentation.
 
26
 * <p>
 
27
 * The current implementation may has not been tested
 
28
 * with (and thus may not support) the following features:
 
29
 * {@code}; should be converted to <c> tags
 
30
 * {@docRoot}
 
31
 * {@inheritDoc}
 
32
 * {@literal}
 
33
 * {@value}
 
34
 * references to package documentation
 
35
 * annotations
 
36
 * <p>
 
37
 * Other issues:
 
38
 * <p>
 
39
 * <pre>
 
40
 * <b>Usage reports "javadoc" instead of "ikvmdoc"</b>:
 
41
 * 
 
42
 * usage: javadoc [options] [packagenames] [sourcefiles] [@files]
 
43
 * 
 
44
 * <b>should be:</b>
 
45
 *  
 
46
 * usage: ikvmdoc [options] [packagenames] [sourcefiles] [@files]
 
47
 * </pre>
 
48
 * <p>
 
49
 * HTML tag parsing is not forgiving; should be made more fault tolerant
 
50
 * <p>
 
51
 * Javadoc HTML -> .NET tag conversions that should be considered/evaluated:
 
52
 * <code>true</code> -> <see langref="true"/>
 
53
 * <code>false</code> -> <see langref="false"/>
 
54
 * <code>null</code> -> <see langref="null"/>
 
55
 * 
 
56
 * @author Brian Heineman
 
57
 */
 
58
public class IKVMDoc extends Doclet {
 
59
        /**
 
60
         * Map of Java data types to .NET data types.
 
61
         */
 
62
        private static final Map<String, String> DATA_TYPE_MAPPING = new HashMap<String, String>();
 
63
        
 
64
        /**
 
65
         * Name of the assembly file parameter.
 
66
         */
 
67
        private static final String ASSEMBLY_PARAMETER = "-assembly";
 
68
 
 
69
        /**
 
70
         * Name of the HTML parameter.
 
71
         */
 
72
        private static final String HTML_PARAMETER = "-nohtml";
 
73
        
 
74
        /**
 
75
         * Name of the strict final field semantics parameter.
 
76
         */
 
77
        private static final String STRICT_FINAL_FIELD_SEMANTICS_PARAMETER = "-strictfinalfieldsemantics";
 
78
 
 
79
        /**
 
80
         * Name of the author parameter.
 
81
         */
 
82
        private static final String AUTHOR_PARAMETER = "-author";
 
83
        
 
84
        /**
 
85
         * Name of the deprecated parameter.
 
86
         */
 
87
        private static final String DEPRECATED_PARAMETER = "-nodeprecated";
 
88
        
 
89
        /**
 
90
         * Name of the since parameter.
 
91
         */
 
92
        private static final String SINCE_PARAMETER = "-nosince";
 
93
        
 
94
        /**
 
95
         * Name of the version parameter.
 
96
         */
 
97
        private static final String VERSION_PARAMETER = "-version";
 
98
        
 
99
        /**
 
100
         * The assembly file the .NET documentation will be generated for.
 
101
         */
 
102
        private static File ASSEMBLY_FILE;
 
103
 
 
104
        /**
 
105
         * Indicates if HTML should be included in the .NET XML documentation.
 
106
         * Default is <code>true</code> to reflect the standard doclet behavior.
 
107
         * <p>
 
108
         * NOTE: The Java Runtime API contains invalid HTML which requires this
 
109
         * option to be set to <code>false</code> when generating its
 
110
         * .NET XML documentation.
 
111
         */
 
112
        private static boolean OUTPUT_HTML = true;
 
113
        
 
114
        /**
 
115
         * Indicates if the author information should be included in the .NET XML documentation.
 
116
         * Default is <code>false</code> to reflect the standard doclet behavior.
 
117
         */
 
118
        private static boolean OUTPUT_AUTHOR = false;
 
119
 
 
120
        /**
 
121
         * Indicates if the deprecated information should be included in the .NET XML documentation.
 
122
         * Default is <code>true</code> to reflect the standard doclet behavior.
 
123
         */
 
124
        private static boolean OUTPUT_DEPRECATED = true;
 
125
        
 
126
        /**
 
127
         * Indicates if the since information should be included in the .NET XML documentation.
 
128
         * Default is <code>true</code> to reflect the standard doclet behavior.
 
129
         */
 
130
        private static boolean OUTPUT_SINCE = true;
 
131
        
 
132
        /**
 
133
         * Indicates if the version information should be included in the .NET XML documentation.
 
134
         * Default is <code>false</code> to reflect the standard doclet behavior.
 
135
         */
 
136
        private static boolean OUTPUT_VERSION = false;
 
137
 
 
138
        /**
 
139
         * The reported used to report failures to. 
 
140
         */
 
141
        private static DocErrorReporter ERROR_REPORTER;
 
142
        
 
143
        static {
 
144
                // Populate the Java->.NET data type mappings
 
145
                DATA_TYPE_MAPPING.put("boolean", "System.Boolean");
 
146
                DATA_TYPE_MAPPING.put("byte", "System.Byte");
 
147
                DATA_TYPE_MAPPING.put("char", "System.Char");
 
148
                DATA_TYPE_MAPPING.put("short", "System.Int16");
 
149
                DATA_TYPE_MAPPING.put("int", "System.Int32");
 
150
                DATA_TYPE_MAPPING.put("long", "System.Int64");
 
151
                DATA_TYPE_MAPPING.put("float", "System.Single");
 
152
                DATA_TYPE_MAPPING.put("double", "System.Double");
 
153
                DATA_TYPE_MAPPING.put("java.lang.Object", "System.Object");
 
154
                DATA_TYPE_MAPPING.put("java.lang.String", "System.String");
 
155
                DATA_TYPE_MAPPING.put("java.lang.Throwable", "System.Exception");
 
156
        }
 
157
        
 
158
        /**
 
159
         * Generate the .NET XML Documentation.
 
160
         * 
 
161
         * @param root represents the root of the program structure information for one run of javadoc 
 
162
         * @return <code>true</code> on success; <code>false</code> on failure
 
163
         */
 
164
    public static boolean start(RootDoc root) {
 
165
        String assemblyName = ASSEMBLY_FILE.getName();
 
166
        int extensionIndex = assemblyName.lastIndexOf('.');
 
167
        
 
168
        if (extensionIndex != -1) {
 
169
                assemblyName = assemblyName.substring(0, extensionIndex);
 
170
        }
 
171
        
 
172
        File documentationFile = new File(ASSEMBLY_FILE.getParent(), assemblyName + ".xml");
 
173
        PrintWriter pw = null;
 
174
        
 
175
        try {
 
176
                FileOutputStream fos = new FileOutputStream(documentationFile);
 
177
                OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
 
178
                BufferedWriter bw = new BufferedWriter(osw);
 
179
                pw = new PrintWriter(bw);
 
180
                
 
181
                // Write the header
 
182
                pw.println("<?xml version=\"1.0\"?>");
 
183
                pw.println("<doc>");
 
184
                printIndent(pw, 1);
 
185
                pw.println("<assembly>");
 
186
                printIndent(pw, 2);
 
187
                pw.print("<name>");
 
188
                pw.print(assemblyName);
 
189
                pw.println("</name>");
 
190
                printIndent(pw, 1);
 
191
                pw.println("</assembly>");
 
192
                printIndent(pw, 1);
 
193
                pw.println("<members>");
 
194
 
 
195
                ClassDoc[] classes = root.classes();
 
196
                
 
197
                for (ClassDoc classDoc : classes) {
 
198
                        print(pw, classDoc);
 
199
                }
 
200
                
 
201
                // Write the footer
 
202
                printIndent(pw, 1);
 
203
                pw.println("</members>");
 
204
                pw.println("</doc>");
 
205
                pw.close();
 
206
                
 
207
                validate(documentationFile);
 
208
        } catch (Exception e) {
 
209
                e.printStackTrace();
 
210
                return false;
 
211
        } finally {
 
212
                if (pw != null) {
 
213
                        pw.close();
 
214
                }
 
215
        }
 
216
        
 
217
        return true;
 
218
        }
 
219
    
 
220
    /**
 
221
     * Prints the member documentation.
 
222
     * 
 
223
     * @param pw the writer to print the documentation to
 
224
     * @param programElementDoc the member to document
 
225
     */
 
226
    private static void print(PrintWriter pw, ProgramElementDoc programElementDoc) {
 
227
        /*
 
228
         * Implementation of proposed @exclude tag: http://java.sun.com/j2se/javadoc/proposed-tags.html 
 
229
         */
 
230
        if (programElementDoc.tags("@exclude").length > 0) {
 
231
                return;
 
232
        }
 
233
        
 
234
        printIndent(pw, 2);
 
235
        pw.print("<member name=\"");
 
236
        printReference(pw, programElementDoc, true);
 
237
        pw.println("\">");
 
238
        
 
239
        printIndent(pw, 3);
 
240
        pw.print("<summary>");
 
241
        
 
242
        if (OUTPUT_DEPRECATED) {
 
243
                printTags(pw, programElementDoc, "DEPRECATED:", "@deprecated");
 
244
        }
 
245
        
 
246
                printComment(pw, programElementDoc, programElementDoc.inlineTags());
 
247
                
 
248
                if (OUTPUT_AUTHOR) {
 
249
                        printTags(pw, programElementDoc, "Author:", "@author");
 
250
                }
 
251
                
 
252
                if (OUTPUT_VERSION) {
 
253
                        printTags(pw, programElementDoc, "Version:", "@version");
 
254
                }
 
255
                
 
256
                if (OUTPUT_SINCE) {
 
257
                        printTags(pw, programElementDoc, "Since:", "@since");
 
258
                }
 
259
                
 
260
        printTags(pw, programElementDoc, "Serial:", "@serial");
 
261
        printTags(pw, programElementDoc, "Serial Field:", "@serialField");
 
262
        printTags(pw, programElementDoc, "Serial Data:", "@serialData");
 
263
        
 
264
        pw.println("</summary>");
 
265
        
 
266
        if (programElementDoc instanceof ExecutableMemberDoc) {
 
267
                ExecutableMemberDoc executableMemberDoc = (ExecutableMemberDoc) programElementDoc;
 
268
                
 
269
                printParamTags(pw, executableMemberDoc);
 
270
                printReturnTag(pw, executableMemberDoc);
 
271
                printThrowsTags(pw, executableMemberDoc);
 
272
        }
 
273
 
 
274
        printSeeTags(pw, programElementDoc);
 
275
        
 
276
        printIndent(pw, 2);
 
277
        pw.println("</member>");
 
278
 
 
279
        // Document class members
 
280
        if (programElementDoc instanceof ClassDoc) {
 
281
                ClassDoc classDoc = (ClassDoc) programElementDoc;
 
282
                FieldDoc[] fields = classDoc.fields();
 
283
                
 
284
                for (FieldDoc fieldDoc : fields) {
 
285
                        print(pw, fieldDoc);
 
286
                }
 
287
                
 
288
                ConstructorDoc[] constructors = classDoc.constructors();
 
289
                
 
290
                for (ConstructorDoc constructorDoc : constructors) {
 
291
                        print(pw, constructorDoc);
 
292
                }
 
293
                
 
294
                MethodDoc[] methods = classDoc.methods();
 
295
                
 
296
                for (MethodDoc methodDoc : methods) {
 
297
                        print(pw, methodDoc);
 
298
                }
 
299
        }
 
300
    }
 
301
 
 
302
    /**
 
303
     * Prints the parameter documentation.
 
304
     * 
 
305
     * @param pw the writer to print the parameter documentation to
 
306
     * @param memberDoc the member to document the parameters for
 
307
     */
 
308
    private static void printParameters(PrintWriter pw, ExecutableMemberDoc memberDoc) {
 
309
        Parameter[] parameters = memberDoc.parameters();
 
310
        
 
311
        if (parameters.length > 0) {
 
312
                pw.print("(");
 
313
        }
 
314
        
 
315
        for (int i = 0; i < parameters.length; i++) {
 
316
                Type parameterType = parameters[i].type();
 
317
                
 
318
                if (i != 0) {
 
319
                        pw.print(",");
 
320
                }
 
321
 
 
322
                String qualifiedTypeName = parameterType.qualifiedTypeName();
 
323
                String mappedDataType = DATA_TYPE_MAPPING.get(qualifiedTypeName);
 
324
 
 
325
                // Print the mapped data type if there is one
 
326
                if (mappedDataType != null) {
 
327
                        pw.print(mappedDataType);
 
328
                } else {
 
329
                        pw.print(qualifiedTypeName);
 
330
                }
 
331
 
 
332
                pw.print(parameterType.dimension());
 
333
        }
 
334
        
 
335
        if (parameters.length > 0) {
 
336
                pw.print(")");
 
337
        }
 
338
    }
 
339
    
 
340
    /**
 
341
     * Prints the parameter documentation.
 
342
     * 
 
343
     * @param pw the writer to print the parameter documentation to
 
344
     * @param memberDoc the member to document the parameters for
 
345
     */
 
346
    private static void printParamTags(PrintWriter pw, ExecutableMemberDoc memberDoc) {
 
347
        ParamTag[] paramTags = memberDoc.paramTags();
 
348
        
 
349
        for (ParamTag paramTag : paramTags) {
 
350
                printIndent(pw, 3);
 
351
                pw.print("<param name=\"");
 
352
                pw.print(paramTag.parameterName());
 
353
                pw.print("\">");
 
354
                printComment(pw, memberDoc, paramTag.inlineTags());
 
355
                pw.println("</param>");
 
356
        }
 
357
    }
 
358
 
 
359
    /**
 
360
     * Prints the return documentation.
 
361
     * 
 
362
     * @param pw the writer to print the return documentation to
 
363
     * @param memberDoc the member to document the return for
 
364
     */
 
365
    private static void printReturnTag(PrintWriter pw, ExecutableMemberDoc memberDoc) {
 
366
        Tag[] returnDoc = memberDoc.tags("@return");
 
367
        
 
368
        if (returnDoc.length == 1) {
 
369
                printIndent(pw, 3);
 
370
                pw.print("<returns>");
 
371
                printComment(pw, memberDoc, returnDoc[0].inlineTags());
 
372
                pw.println("</returns>");
 
373
        } else if (returnDoc.length > 1) {
 
374
                ERROR_REPORTER.printError("More than one return tag specified for '" + memberDoc.qualifiedName() + "'");
 
375
        }
 
376
    }
 
377
    
 
378
    /**
 
379
     * Prints the exception documentation.
 
380
     * 
 
381
     * @param pw the writer to print the exception documentation to
 
382
     * @param memberDoc the member to document the exceptions for
 
383
     */
 
384
    private static void printThrowsTags(PrintWriter pw, ExecutableMemberDoc memberDoc) {
 
385
        ThrowsTag[] throwsTags = memberDoc.throwsTags();
 
386
        
 
387
        for (ThrowsTag throwsTag : throwsTags) {
 
388
                ClassDoc exceptionDoc = throwsTag.exception();
 
389
                
 
390
                if (exceptionDoc == null) {
 
391
                        ERROR_REPORTER.printError("Unable to locate class '" + throwsTag.exceptionName() + "' for '" + memberDoc.qualifiedName() + "'");
 
392
                        continue;
 
393
                }
 
394
                
 
395
                printIndent(pw, 3);
 
396
                pw.print("<exception cref=\"");
 
397
                printReference(pw, exceptionDoc, true);
 
398
                pw.print("\">");
 
399
                printComment(pw, memberDoc, throwsTag.inlineTags());
 
400
                pw.println("</exception>");
 
401
        }
 
402
    }
 
403
 
 
404
    /**
 
405
     * Prints the see tag documentation.
 
406
     * 
 
407
     * @param pw the writer to print the see tag documentation to
 
408
     * @param memberDoc the member to document the see tags for
 
409
     */
 
410
    private static void printSeeTags(PrintWriter pw, ProgramElementDoc memberDoc) {
 
411
        SeeTag[] seeTags = memberDoc.seeTags();
 
412
        
 
413
        for (SeeTag seeTag : seeTags) {
 
414
                printSeeTag(pw, memberDoc, seeTag, true);
 
415
        }
 
416
    }
 
417
 
 
418
    /**
 
419
     * Prints the specified see tag.
 
420
     * 
 
421
     * @param pw the writer to print the see tag to
 
422
     * @param memberDoc the member to document the see tag for
 
423
     * @param seeTag the see tags to print
 
424
     * @param asSeeAlso <code>true</code> if a "seealso" tag should be printed;
 
425
     *   <code>false</code> if a "see" tag should be printed
 
426
     */
 
427
    private static void printSeeTag(PrintWriter pw, ProgramElementDoc memberDoc, SeeTag seeTag, boolean asSeeAlso) {
 
428
                String label = seeTag.label();
 
429
                String text = seeTag.text();
 
430
                boolean isAnchor = (text.startsWith("<a") && text.endsWith("</a>"));
 
431
                int endIndex = -1;
 
432
        ProgramElementDoc referencedMemberDoc = seeTag.referencedMember();
 
433
        
 
434
        if (isAnchor) {
 
435
                endIndex = text.indexOf('>') + 1;
 
436
                
 
437
                if (endIndex == text.length()) {
 
438
                                ERROR_REPORTER.printError("Invalid anchor '" + text + "' for '" + memberDoc.qualifiedName() + "'");
 
439
                        
 
440
                                printText(pw, text);
 
441
                                return;
 
442
                }
 
443
        } else {
 
444
                // If the member reference is null, attempt to use the referenced class 
 
445
                if (referencedMemberDoc == null) {
 
446
                        referencedMemberDoc = seeTag.referencedClass();
 
447
                }
 
448
                        
 
449
                        if (referencedMemberDoc == null) {
 
450
                                ERROR_REPORTER.printError("Unable to locate reference '" + text + "' for '" + memberDoc.qualifiedName() + "'");
 
451
                                
 
452
                                if (label == null || label.trim().length() == 0) {
 
453
                                        printText(pw, text);
 
454
                                } else {
 
455
                                        printText(pw, label);
 
456
                                }
 
457
                                
 
458
                                return;
 
459
                        }
 
460
        }
 
461
 
 
462
                String type = (asSeeAlso) ? "seealso" : "see";
 
463
 
 
464
                if (asSeeAlso) {
 
465
                        printIndent(pw, 3);
 
466
                }
 
467
                
 
468
                pw.print("<");
 
469
                pw.print(type);
 
470
                
 
471
                if (isAnchor) {
 
472
                        pw.print(text.substring(2, endIndex));
 
473
                        printText(pw, text.substring(endIndex, text.length() - 4));
 
474
                } else {
 
475
                        pw.print(" cref=\"");
 
476
                        printReference(pw, referencedMemberDoc, true);
 
477
                        pw.print("\">");
 
478
                        
 
479
                        if (label == null || label.trim().length() == 0) {
 
480
                                printReference(pw, referencedMemberDoc, false);
 
481
                        } else {
 
482
                                printText(pw, label);
 
483
                        }
 
484
                }
 
485
                
 
486
                pw.print("</");
 
487
                pw.print(type);
 
488
                pw.print(">");
 
489
                
 
490
                if (asSeeAlso) {
 
491
                        pw.println();
 
492
                }
 
493
    }
 
494
 
 
495
    /**
 
496
     * Prints the documentation for the specified tag.
 
497
     * 
 
498
     * @param pw the writer to print the tag documentation to
 
499
     * @param referenceDoc the member to document the tags for
 
500
     * @param label the label to print for the tag documentation
 
501
     * @param tagName the name of the tags to print the documentation for
 
502
     */
 
503
    private static void printTags(PrintWriter pw, ProgramElementDoc referenceDoc, String label, String tagName) {
 
504
        Tag[] tags = referenceDoc.tags(tagName);
 
505
        
 
506
        for (Tag tag : tags) {
 
507
                pw.print("<para><c>");
 
508
                pw.print(label);
 
509
                pw.print("</c> ");
 
510
                printComment(pw, referenceDoc, tag.inlineTags());
 
511
                pw.println("</para>");
 
512
        }
 
513
    }
 
514
    
 
515
    /**
 
516
     * Prints the specified reference.
 
517
     * 
 
518
     * @param pw the writer to print the reference to
 
519
     * @param referenceDoc the reference to print
 
520
     * @param includeType <code>true</code> if the type identifier should be included;
 
521
     *   <code>false</code> if the type identifier should be omitted
 
522
     */
 
523
    private static void printReference(PrintWriter pw, ProgramElementDoc referenceDoc, boolean includeType) {
 
524
        ClassDoc classDoc = (referenceDoc.isClass() || referenceDoc.isInterface()) ? (ClassDoc) referenceDoc : referenceDoc.containingClass();
 
525
        
 
526
        if (includeType) {
 
527
                if (referenceDoc.isField()) {
 
528
                        if (referenceDoc.isFinal() && !classDoc.isInterface()) {
 
529
                                pw.print("P:");
 
530
                        } else {
 
531
                                pw.print("F:");
 
532
                        }
 
533
                } else if (referenceDoc.isConstructor() || referenceDoc.isMethod()) {
 
534
                        pw.print("M:");
 
535
                } else {
 
536
                        pw.print("T:");
 
537
                }
 
538
        }
 
539
        
 
540
        pw.print(classDoc.qualifiedName());
 
541
        
 
542
                if (referenceDoc.isField()) {
 
543
                        if (classDoc.isInterface()) {
 
544
                        pw.print(".__Fields.");
 
545
                        } else {
 
546
                        pw.print(".");
 
547
                        }
 
548
                
 
549
                        pw.print(referenceDoc.name());
 
550
                } else if (referenceDoc.isConstructor()) {
 
551
                pw.print(".#ctor");
 
552
                printParameters(pw, (ConstructorDoc) referenceDoc);
 
553
                } else if (referenceDoc.isMethod()){
 
554
                pw.print(".");
 
555
                pw.print(referenceDoc.name());
 
556
                printParameters(pw, (MethodDoc) referenceDoc);
 
557
                }
 
558
    }
 
559
    
 
560
    /**
 
561
     * Prints comment tags.
 
562
     * 
 
563
     * @param pw the writer to print the comment tags to
 
564
     * @param memberDoc the member to print the comment tags for
 
565
     * @param commentTags the comment tags to print
 
566
     */
 
567
    private static void printComment(PrintWriter pw, ProgramElementDoc memberDoc, Tag[] commentTags) {
 
568
        for (Tag tag : commentTags) {
 
569
                if (tag instanceof SeeTag) {
 
570
                        SeeTag seeTag = (SeeTag) tag;
 
571
                        
 
572
                        printSeeTag(pw, memberDoc, seeTag, false);
 
573
                } else {
 
574
                        String text = tag.text();
 
575
 
 
576
                        printText(pw, memberDoc, text);
 
577
                }
 
578
        }
 
579
    }
 
580
 
 
581
    /**
 
582
     * Prints the specified javadoc text in a .NET XML documentation format.
 
583
     * 
 
584
     * @param pw the writer to print the comment tags to
 
585
     * @param memberDoc the member to print the comment tags for
 
586
     * @param text the text to print
 
587
     */
 
588
    private static void printText(PrintWriter pw, ProgramElementDoc memberDoc, String text) {
 
589
        char[] characters = text.toCharArray();
 
590
        
 
591
        for (int index = 0; index < characters.length; index++) {
 
592
                        char character = characters[index];
 
593
                        
 
594
                        switch (character) {
 
595
                        case '<':
 
596
                                int x = Character.offsetByCodePoints(text, 0, index);
 
597
                                if (x != index) {
 
598
                                        System.out.println("x = " + x);
 
599
                                }
 
600
                                
 
601
                                int endIndex = text.indexOf('>', index);
 
602
                                
 
603
                                // Handle invalid HTML (use of "<" or "<>" in text)
 
604
                                if (endIndex == -1 || endIndex - index < 2) {
 
605
                                        pw.print("&lt;");
 
606
                                        continue;
 
607
                                }
 
608
                                
 
609
                                String tag = text.substring(index + 1, endIndex).trim().toLowerCase();
 
610
                                boolean isEndTag = false;
 
611
                                boolean isStandAloneTag = false;
 
612
 
 
613
                                if (tag.length() > 1) {
 
614
                                        if (tag.startsWith("/")) {
 
615
                                                tag = tag.substring(1);
 
616
                                                isEndTag = true;
 
617
                                        } else if (tag.endsWith("/")) {
 
618
                                                tag = tag.substring(0, tag.length() - 1);
 
619
                                                isStandAloneTag = true;
 
620
                                        }
 
621
                                }
 
622
                                
 
623
                                /*
 
624
                                 * Process/convert HTML tags to .NET XML
 
625
                                 */
 
626
                                
 
627
                                if ("p".equals(tag)) {
 
628
                                        // Translate <p> to <para/>; ignore end tags
 
629
                                        if (!isEndTag) {
 
630
                                                pw.print("<para/>");
 
631
                                        }
 
632
                                        
 
633
                                        index = endIndex;
 
634
                                } else if ("br".equals(tag) || "hr".equals(tag) || "img".equals(tag)) {
 
635
                                        if (!isEndTag) {
 
636
                                                pw.print("<");
 
637
                                                pw.print(tag);
 
638
                                                pw.print("/>");
 
639
                                        }
 
640
                                        
 
641
                                        index = endIndex;
 
642
                                } else if (OUTPUT_HTML) {
 
643
                                        if ("code".equals(tag)) {
 
644
                                                // Translate "code" tags to "c" tags
 
645
                                                tag = "c";
 
646
                                        } else if ("li".equals(tag)) {
 
647
                                                // Translate "li" tags to "item" tags
 
648
                                                tag = "item";
 
649
                                        } else if ("ol".equals(tag)) {
 
650
                                                // Translate "ol" tags to "list" tags
 
651
                                                tag = "list";
 
652
                                                
 
653
                                                if (!isEndTag) {
 
654
                                                        tag += " type=\"number\"";
 
655
                                                }
 
656
                                        } else if ("pre".equals(tag)) {
 
657
                                                // Translate "pre" tags to "code" tags
 
658
                                                tag = "code";
 
659
                                        } else if ("ul".equals(tag)) {
 
660
                                                // Translate "ul" tags to "list" tags
 
661
                                                tag = "list";
 
662
                                                
 
663
                                                if (!isEndTag) {
 
664
                                                        tag += " type=\"bullet\"";
 
665
                                                }
 
666
                                        }
 
667
                                        
 
668
                                        pw.print("<");
 
669
                                        
 
670
                                        if (isEndTag) {
 
671
                                                pw.print("/");
 
672
                                        }
 
673
                                        
 
674
                                        pw.print(tag);
 
675
                                        
 
676
                                        if (isStandAloneTag) {
 
677
                                                pw.print("/");
 
678
                                        }
 
679
                                        
 
680
                                        pw.print(">");
 
681
                                        index = endIndex;
 
682
                                } else {
 
683
                                        pw.print("&lt;");
 
684
                                }
 
685
                                
 
686
                                break;
 
687
            case '>':
 
688
                pw.print("&gt;");
 
689
                break;
 
690
            case '&':
 
691
                // TODO: Update to handle HTML escape sequences (&nbsp;, &#nnnn;, etc) 
 
692
                pw.print("&amp;");
 
693
                break;
 
694
            case '\'':
 
695
                pw.print("&apos;");
 
696
                break;
 
697
            case '"':
 
698
                pw.print("&quot;");
 
699
                break;
 
700
                        default:
 
701
                                pw.print(character);
 
702
                        }
 
703
        }
 
704
    }
 
705
 
 
706
    /**
 
707
     * Prints the specified text and escapes any XML characters.
 
708
     * 
 
709
     * @param pw the writer to print the text to
 
710
     * @param text the text to print
 
711
     */
 
712
    private static void printText(PrintWriter pw, String text) {
 
713
        char[] characters = text.toCharArray();
 
714
        
 
715
        for (int index = 0; index < characters.length; index++) {
 
716
                        char character = characters[index];
 
717
                        
 
718
                        switch (character) {
 
719
                        case '<':
 
720
                pw.print("&lt;");
 
721
                                break;
 
722
            case '>':
 
723
                pw.print("&gt;");
 
724
                break;
 
725
            case '&':
 
726
                // TODO: Update to handle HTML escape sequences (&nbsp;, &#nnnn;, etc) 
 
727
                pw.print("&amp;");
 
728
                break;
 
729
            case '\'':
 
730
                pw.print("&apos;");
 
731
                break;
 
732
            case '"':
 
733
                pw.print("&quot;");
 
734
                break;
 
735
                        default:
 
736
                                pw.print(character);
 
737
                        }
 
738
        }
 
739
    }
 
740
    
 
741
    /**
 
742
     * Prints an indentation a specified number of times.
 
743
     * 
 
744
     * @param pw the writer to print the indentations to
 
745
     * @param indentations the number of indentations to print
 
746
     */
 
747
    public static void printIndent(PrintWriter pw, int indentations) {
 
748
        for (int i = 0; i < indentations; i++) {
 
749
                pw.write("\t");
 
750
        }
 
751
    }
 
752
    
 
753
    /**
 
754
     * Validates the specified file is well formed XML.
 
755
     * 
 
756
     * @param file the file to validate
 
757
     * @throws Exception if a failure occurs while validating the file
 
758
     */
 
759
    private static void validate(File file) throws Exception {
 
760
        SAXParserFactory factory = SAXParserFactory.newInstance();
 
761
                SAXParser parser = factory.newSAXParser();
 
762
                
 
763
                parser.parse(file, new DefaultHandler() {
 
764
                        public void error(SAXParseException e) throws SAXException {
 
765
                                fatalError(e);
 
766
                        }
 
767
                        
 
768
                        public void fatalError(SAXParseException e) throws SAXException {
 
769
                                ERROR_REPORTER.printError(e.getMessage());
 
770
                                ERROR_REPORTER.printError("Line: " + e.getLineNumber() + ", Column: " + e.getColumnNumber());
 
771
                                throw e;
 
772
                        }
 
773
                });
 
774
    }
 
775
 
 
776
    /**
 
777
     * Execute IKVMDoc without the use of the javadoc executable.
 
778
     * 
 
779
     * @param args the program arguments
 
780
     */
 
781
        public static void main(String[] args) {
 
782
                Main.execute("ikvmdoc", IKVMDoc.class.getName(), args);         
 
783
        }
 
784
 
 
785
    /**
 
786
     * Check for ikvmdoc specific options. Returns the number of arguments that must be specified on the command
 
787
     * line for the given option. For example, "-assembly IKVM.OpenJDK.ClassLibrary.dll" would return 2.
 
788
     * 
 
789
     * @param option the option to evaluate and return the number of arguments for 
 
790
     * @return number of arguments on the command line for an option including the option name itself.
 
791
     *   Zero return means option not known. Negative value means error occurred.
 
792
     */
 
793
    public static int optionLength(String option) {
 
794
        if (ASSEMBLY_PARAMETER.equals(option)) {
 
795
                return 2;
 
796
        } else if (STRICT_FINAL_FIELD_SEMANTICS_PARAMETER.equals(option)) {
 
797
                return 1;
 
798
        } else if (HTML_PARAMETER.equals(option)) {
 
799
                return 1;
 
800
        } else if (AUTHOR_PARAMETER.equals(option)) {
 
801
                return 1;
 
802
        } else if (DEPRECATED_PARAMETER.equals(option)) {
 
803
                return 1;
 
804
        } else if (SINCE_PARAMETER.equals(option)) {
 
805
                return 1;
 
806
        } else if (VERSION_PARAMETER.equals(option)) {
 
807
                return 1;
 
808
        }
 
809
 
 
810
        return 0;
 
811
    }
 
812
    
 
813
    /**
 
814
     * Check that ikvmdoc options have the correct arguments.
 
815
     * 
 
816
     * @param options the options to check
 
817
     * @param reporter the error reported used to report any failures to
 
818
     * @return <code>true</code> if the options are valid;
 
819
     *   <code>false</code> if the options are invalid
 
820
     */
 
821
    public static boolean validOptions(String[][] options, DocErrorReporter reporter) {
 
822
        ERROR_REPORTER = reporter;
 
823
        
 
824
        for (String[] option : options) {
 
825
                if (ASSEMBLY_PARAMETER.equals(option[0])) {
 
826
                        ASSEMBLY_FILE = new File(option[1]);
 
827
                        
 
828
                if (!ASSEMBLY_FILE.isFile() || !ASSEMBLY_FILE.exists()) {
 
829
                        reporter.printError("The assembly file specified '" + ASSEMBLY_FILE.getAbsolutePath() + "' is invalid.");
 
830
                        return false;
 
831
                }
 
832
                } else if (HTML_PARAMETER.equals(option[0])) {
 
833
                        OUTPUT_HTML = false;
 
834
                } else if (AUTHOR_PARAMETER.equals(option[0])) {
 
835
                        OUTPUT_AUTHOR = true;
 
836
                } else if (DEPRECATED_PARAMETER.equals(option[0])) {
 
837
                        OUTPUT_DEPRECATED = false;
 
838
                } else if (SINCE_PARAMETER.equals(option[0])) {
 
839
                        OUTPUT_SINCE = false;
 
840
                } else if (VERSION_PARAMETER.equals(option[0])) {
 
841
                        OUTPUT_VERSION = true;
 
842
                }
 
843
        }
 
844
        
 
845
        return true;
 
846
    }
 
847
}