src/share/tools/ProjectCreator/WinGammaPlatform.java

Print this page
rev 3265 : projectcreator


   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 
  25 import java.io.File;
  26 import java.io.IOException;
  27 import java.io.PrintWriter;
  28 import java.util.Enumeration;
  29 import java.util.Hashtable;
  30 import java.util.Iterator;
  31 import java.util.List;
  32 import java.util.TreeSet;
  33 import java.util.Vector;
  34 
  35 abstract 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         }


 201     protected void addPrelinkCommand(Hashtable table,
 202                                      String build,
 203                                      String description,
 204                                      String commands) {
 205       PrelinkCommandData data = new PrelinkCommandData();
 206       data.description = description;
 207       data.commands = commands;
 208       table.put(build, data);
 209     }
 210 
 211     public boolean findString(Vector v, String s) {
 212         for (Iterator iter = v.iterator(); iter.hasNext(); ) {
 213             if (((String) iter.next()).equals(s)) {
 214                 return true;
 215             }
 216         }
 217 
 218         return false;
 219     }
 220 
 221     /* This returns a String containing the full path to the passed
 222        file name, or null if an error occurred. If the file was not
 223        found or was a duplicate and couldn't be resolved using the
 224        preferred paths, the file name is added to the appropriate
 225        Vector of Strings. */
 226     private String findFileInDirectory(String fileName,
 227                                        DirectoryTree directory,
 228                                        Vector preferredPaths,
 229                                        Vector filesNotFound,
 230                                        Vector filesDuplicate) {
 231         List locationsInTree = directory.findFile(fileName);
 232         int  rootNameLength = directory.getRootNodeName().length();
 233         String name = null;
 234         if ((locationsInTree == null) ||
 235             (locationsInTree.size() == 0)) {
 236             filesNotFound.add(fileName);
 237         } else if (locationsInTree.size() > 1) {
 238             // Iterate through them, trying to find one with a
 239             // preferred path
 240         search:
 241             {
 242                 for (Iterator locIter = locationsInTree.iterator();
 243                      locIter.hasNext(); ) {
 244                     DirectoryTreeNode node =
 245                         (DirectoryTreeNode) locIter.next();
 246                     String tmpName = node.getName();
 247                     for (Iterator prefIter = preferredPaths.iterator();
 248                          prefIter.hasNext(); ) {
 249                         // We need to make sure the preferred path is
 250                         // found from the file path not including the root node name.
 251                         if (tmpName.indexOf((String)prefIter.next(),
 252                                             rootNameLength) != -1) {
 253                             name = tmpName;
 254                             break search;
 255                         }
 256                     }
 257                 }
 258             }
 259 
 260             if (name == null) {
 261                 filesDuplicate.add(fileName);
 262             }
 263         } else {
 264             name = ((DirectoryTreeNode) locationsInTree.get(0)).getName();
 265         }
 266 
 267         return name;
 268     }
 269 
 270     protected String envVarPrefixedFileName(String fileName,
 271                                             int sourceBaseLen,
 272                                             DirectoryTree tree,
 273                                             Vector preferredPaths,
 274                                             Vector filesNotFound,
 275                                             Vector filesDuplicate) {
 276         String fullName = findFileInDirectory(fileName,
 277                                               tree,
 278                                               preferredPaths,
 279                                               filesNotFound,
 280                                               filesDuplicate);
 281         return fullName;
 282     }
 283 
 284      String getProjectName(String fullPath, String extension)
 285         throws IllegalArgumentException, IOException {
 286         File file = new File(fullPath).getCanonicalFile();
 287         fullPath = file.getCanonicalPath();
 288         String parent = file.getParent();
 289 
 290         if (!fullPath.endsWith(extension)) {
 291             throw new IllegalArgumentException("project file name \"" +
 292                                                fullPath +
 293                                                "\" does not end in "+extension);
 294         }
 295 
 296         if ((parent != null) &&
 297             (!fullPath.startsWith(parent))) {
 298             throw new RuntimeException(
 299                 "Internal error: parent of file name \"" + parent +
 300                 "\" does not match file name \"" + fullPath + "\""
 301             );
 302         }
 303 


 352                                    if (nextNotKey(it)) {
 353                                       String sb = (String) it.get();
 354                                       if (sb.endsWith(Util.sep)) {
 355                                          sb = sb.substring(0, sb.length() - 1);
 356                                       }
 357                                       BuildConfig.putField(cfg, "SourceBase", sb);
 358                                       it.next();
 359                                    } else {
 360                                       empty("-sourceBase", null);
 361                                    }
 362                                 }
 363                             }
 364                             ),
 365 
 366                 new HsArgRule("-buildBase",
 367                               "BuildBase",
 368                               "   (Did you set the HotSpotBuildSpace environment variable?)",
 369                               HsArgHandler.STRING
 370                               ),
 371 



 372               new HsArgRule("-platformName",
 373                               "PlatformName",
 374                               null,
 375                               HsArgHandler.STRING
 376                               ),
 377 
 378               new HsArgRule("-projectFileName",
 379                               "ProjectFileName",
 380                               null,
 381                               HsArgHandler.STRING
 382                               ),
 383 
 384                 new HsArgRule("-jdkTargetRoot",
 385                               "JdkTargetRoot",
 386                               "   (Did you set the HotSpotJDKDist environment variable?)",
 387                               HsArgHandler.STRING
 388                               ),
 389 
 390                 new HsArgRule("-compiler",
 391                               "CompilerVersion",
 392                               "   (Did you set the VcVersion correctly?)",
 393                               HsArgHandler.STRING
 394                               ),
 395 
 396                 new HsArgRule("-absoluteInclude",
 397                               "AbsoluteInclude",
 398                               null,
 399                               HsArgHandler.VECTOR
 400                               ),
 401 
 402                 new HsArgRule("-relativeInclude",
 403                               "RelativeInclude",
 404                               null,
 405                               HsArgHandler.VECTOR
 406                               ),
 407 






 408                 new HsArgRule("-define",
 409                               "Define",
 410                               null,
 411                               HsArgHandler.VECTOR
 412                               ),
 413 
 414                 new HsArgRule("-useToGeneratePch",
 415                               "UseToGeneratePch",
 416                               null,
 417                               HsArgHandler.STRING
 418                               ),
 419 
 420                 new ArgRuleSpecific("-perFileLine",
 421                             new HsArgHandler() {
 422                                 public void handle(ArgIterator it) {
 423                                     String cfg = getCfg(it.get());
 424                                     if (nextNotKey(it)) {
 425                                         String fileName = it.get();
 426                                         if (nextNotKey(it)) {
 427                                             String line = it.get();


 477                                         it.next();
 478                                     } else {
 479                                         empty("-startAt", null);
 480                                     }
 481                                 }
 482                             }
 483                             ),
 484 
 485                 new HsArgRule("-ignoreFile",
 486                                       "IgnoreFile",
 487                                       null,
 488                                       HsArgHandler.HASH
 489                                       ),
 490 
 491                 new HsArgRule("-ignorePath",
 492                               "IgnorePath",
 493                               null,
 494                               HsArgHandler.VECTOR
 495                               ),
 496 
 497                 new HsArgRule("-additionalFile",
 498                               "AdditionalFile",
 499                               null,
 500                               HsArgHandler.VECTOR
 501                               ),
 502 
 503                 new ArgRuleSpecific("-additionalGeneratedFile",
 504                             new HsArgHandler() {
 505                                 public void handle(ArgIterator it) {
 506                                     String cfg = getCfg(it.get());
 507                                     if (nextNotKey(it)) {
 508                                         String dir = it.get();
 509                                         if (nextNotKey(it)) {
 510                                             String fileName = it.get();
 511                                             BuildConfig.putFieldHash(cfg, "AdditionalGeneratedFile",
 512                                                                      Util.normalize(dir + Util.sep + fileName),
 513                                                                      fileName);
 514                                             it.next();
 515                                             return;
 516                                         }
 517                                     }
 518                                     empty(null, "** Error: wrong number of args to -additionalGeneratedFile");
 519                                 }
 520                             }
 521                             ),
 522 
 523                 new ArgRule("-prelink",
 524                             new HsArgHandler() {
 525                                 public void handle(ArgIterator it) {
 526                                     if (nextNotKey(it)) {
 527                                         if (nextNotKey(it)) {
 528                                             String description = it.get();
 529                                             if (nextNotKey(it)) {
 530                                                 String command = it.get();
 531                                                 BuildConfig.putField(null, "PrelinkDescription", description);
 532                                                 BuildConfig.putField(null, "PrelinkCommand", command);
 533                                                 it.next();
 534                                                 return;
 535                                             }
 536                                         }
 537                                     }
 538 
 539                                     empty(null,  "** Error: wrong number of args to -prelink");
 540                                 }
 541                             }
 542                             ),


 581         }
 582 
 583         BuildConfig.putField(null, "PlatformObject", this);
 584     }
 585 
 586     Vector createAllConfigs(String platform) {
 587         Vector allConfigs = new Vector();
 588 
 589         allConfigs.add(new C1DebugConfig());
 590         allConfigs.add(new C1FastDebugConfig());
 591         allConfigs.add(new C1ProductConfig());
 592 
 593         allConfigs.add(new C2DebugConfig());
 594         allConfigs.add(new C2FastDebugConfig());
 595         allConfigs.add(new C2ProductConfig());
 596 
 597         allConfigs.add(new TieredDebugConfig());
 598         allConfigs.add(new TieredFastDebugConfig());
 599         allConfigs.add(new TieredProductConfig());
 600 
 601         allConfigs.add(new CoreDebugConfig());
 602         allConfigs.add(new CoreFastDebugConfig());
 603         allConfigs.add(new CoreProductConfig());

 604 
 605         if (platform.equals("Win32")) {
 606             allConfigs.add(new KernelDebugConfig());
 607             allConfigs.add(new KernelFastDebugConfig());
 608             allConfigs.add(new KernelProductConfig());
 609         }
 610 
 611         return allConfigs;
 612     }
 613 
 614     class FileAttribute {
 615         int     numConfigs;
 616         Vector  configs;
 617         String  shortName;
 618         boolean noPch, pchRoot;
 619 
 620         FileAttribute(String shortName, BuildConfig cfg, int numConfigs) {
 621             this.shortName = shortName;
 622             this.noPch =  (cfg.lookupHashFieldInContext("DisablePch", shortName) != null);
 623             this.pchRoot = shortName.equals(BuildConfig.getFieldString(null, "UseToGeneratePch"));
 624             this.numConfigs = numConfigs;
 625 
 626             configs = new Vector();
 627             add(cfg.get("Name"));

 628         }
 629 
 630         void add(String confName) {
 631             configs.add(confName);
 632 
 633             // if presented in all configs
 634             if (configs.size() == numConfigs) {
 635                 configs = null;
 636             }
 637         }
 638     }
 639 
 640     class FileInfo implements Comparable {
 641         String        full;
 642         FileAttribute attr;


 643 
 644         FileInfo(String full, FileAttribute  attr) {
 645             this.full = full;
 646             this.attr = attr;

 647         }
 648 
 649         public int compareTo(Object o) {
 650             FileInfo oo = (FileInfo)o;
 651             return full.compareTo(oo.full);
 652         }
 653 
 654         boolean isHeader() {
 655             return attr.shortName.endsWith(".h") || attr.shortName.endsWith(".hpp");
 656         }
 657 
 658         boolean isCpp() {
 659             return attr.shortName.endsWith(".cpp");
 660         }



 661     }
 662 
 663 
 664     TreeSet sortFiles(Hashtable allFiles) {
 665         TreeSet rv = new TreeSet();
 666         Enumeration e = allFiles.keys();
 667         while (e.hasMoreElements()) {
 668             String fullPath = (String)e.nextElement();
 669             rv.add(new FileInfo(fullPath, (FileAttribute)allFiles.get(fullPath)));
 670         }
 671         return rv;
 672     }
 673 
 674     Hashtable computeAttributedFiles(Vector allConfigs) {
 675         Hashtable ht = new Hashtable();
 676         int numConfigs = allConfigs.size();
 677 
 678         for (Iterator i = allConfigs.iterator(); i.hasNext(); ) {
 679             BuildConfig bc = (BuildConfig)i.next();
 680             Hashtable  confFiles = (Hashtable)bc.getSpecificField("AllFilesHash");
 681             String confName = bc.get("Name");
 682 
 683             for (Enumeration e=confFiles.keys(); e.hasMoreElements(); ) {
 684                 String filePath = (String)e.nextElement();
 685                 FileAttribute fa = (FileAttribute)ht.get(filePath);
 686 
 687                 if (fa == null) {
 688                     fa = new FileAttribute((String)confFiles.get(filePath), bc, numConfigs);
 689                     ht.put(filePath, fa);
 690                 } else {
 691                     fa.add(confName);
 692                 }

 693             }






 694         }
 695 
 696         return ht;



 697     }
 698 
 699      Hashtable computeAttributedFiles(BuildConfig bc) {
 700         Hashtable ht = new Hashtable();
 701         Hashtable confFiles = (Hashtable)bc.getSpecificField("AllFilesHash");
 702 
 703         for (Enumeration e = confFiles.keys(); e.hasMoreElements(); ) {
 704             String filePath = (String)e.nextElement();
 705             ht.put(filePath,  new FileAttribute((String)confFiles.get(filePath), bc, 1));

 706         }
 707 
 708         return ht;



 709     }
 710 
 711     PrintWriter printWriter;






 712 
 713     public void writeProjectFile(String projectFileName, String projectName,
 714                                  Vector<BuildConfig> allConfigs) throws IOException {
 715         throw new RuntimeException("use compiler version specific version");
 716     }


 717 }


   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 
  25 import java.io.File;
  26 import java.io.IOException;
  27 import java.io.PrintWriter;

  28 import java.util.Hashtable;
  29 import java.util.Iterator;
  30 import java.util.Stack;

  31 import java.util.Vector;
  32 
  33 abstract class HsArgHandler extends ArgHandler {
  34     static final int STRING = 1;
  35     static final int VECTOR = 2;
  36     static final int HASH   = 3;
  37 
  38     boolean nextNotKey(ArgIterator it) {
  39         if (it.next()) {
  40             String s = it.get();
  41             return (s.length() == 0) || (s.charAt(0) != '-');
  42         } else {
  43             return false;
  44         }
  45     }
  46 
  47     void empty(String key, String message) {
  48         if (key != null) {
  49             System.err.println("** Error: empty " + key);
  50         }


 199     protected void addPrelinkCommand(Hashtable table,
 200                                      String build,
 201                                      String description,
 202                                      String commands) {
 203       PrelinkCommandData data = new PrelinkCommandData();
 204       data.description = description;
 205       data.commands = commands;
 206       table.put(build, data);
 207     }
 208 
 209     public boolean findString(Vector v, String s) {
 210         for (Iterator iter = v.iterator(); iter.hasNext(); ) {
 211             if (((String) iter.next()).equals(s)) {
 212                 return true;
 213             }
 214         }
 215 
 216       return false;
 217    }
 218 































































 219      String getProjectName(String fullPath, String extension)
 220         throws IllegalArgumentException, IOException {
 221         File file = new File(fullPath).getCanonicalFile();
 222         fullPath = file.getCanonicalPath();
 223         String parent = file.getParent();
 224 
 225         if (!fullPath.endsWith(extension)) {
 226             throw new IllegalArgumentException("project file name \"" +
 227                                                fullPath +
 228                                                "\" does not end in "+extension);
 229         }
 230 
 231         if ((parent != null) &&
 232             (!fullPath.startsWith(parent))) {
 233             throw new RuntimeException(
 234                 "Internal error: parent of file name \"" + parent +
 235                 "\" does not match file name \"" + fullPath + "\""
 236             );
 237         }
 238 


 287                                    if (nextNotKey(it)) {
 288                                       String sb = (String) it.get();
 289                                       if (sb.endsWith(Util.sep)) {
 290                                          sb = sb.substring(0, sb.length() - 1);
 291                                       }
 292                                       BuildConfig.putField(cfg, "SourceBase", sb);
 293                                       it.next();
 294                                    } else {
 295                                       empty("-sourceBase", null);
 296                                    }
 297                                 }
 298                             }
 299                             ),
 300 
 301                 new HsArgRule("-buildBase",
 302                               "BuildBase",
 303                               "   (Did you set the HotSpotBuildSpace environment variable?)",
 304                               HsArgHandler.STRING
 305                               ),
 306 
 307               new HsArgRule("-buildSpace", "BuildSpace", null,
 308                               HsArgHandler.STRING),
 309 
 310               new HsArgRule("-platformName",
 311                               "PlatformName",
 312                               null,
 313                               HsArgHandler.STRING
 314                               ),
 315 
 316               new HsArgRule("-projectFileName",
 317                               "ProjectFileName",
 318                               null,
 319                               HsArgHandler.STRING
 320                               ),
 321 
 322                 new HsArgRule("-jdkTargetRoot",
 323                               "JdkTargetRoot",
 324                               "   (Did you set the HotSpotJDKDist environment variable?)",
 325                               HsArgHandler.STRING
 326                               ),
 327 
 328                 new HsArgRule("-compiler",
 329                               "CompilerVersion",
 330                               "   (Did you set the VcVersion correctly?)",
 331                               HsArgHandler.STRING
 332                               ),
 333 
 334                 new HsArgRule("-absoluteInclude",
 335                               "AbsoluteInclude",
 336                               null,
 337                               HsArgHandler.VECTOR
 338                               ),
 339 
 340                 new HsArgRule("-relativeInclude",
 341                               "RelativeInclude",
 342                               null,
 343                               HsArgHandler.VECTOR
 344                               ),
 345 
 346                 new HsArgRule("-absoluteSrcInclude", "AbsoluteSrcInclude",
 347                               null, HsArgHandler.VECTOR),
 348 
 349                 new HsArgRule("-relativeSrcInclude", "RelativeSrcInclude",
 350                               null, HsArgHandler.VECTOR),
 351 
 352                 new HsArgRule("-define",
 353                               "Define",
 354                               null,
 355                               HsArgHandler.VECTOR
 356                               ),
 357 
 358                 new HsArgRule("-useToGeneratePch",
 359                               "UseToGeneratePch",
 360                               null,
 361                               HsArgHandler.STRING
 362                               ),
 363 
 364                 new ArgRuleSpecific("-perFileLine",
 365                             new HsArgHandler() {
 366                                 public void handle(ArgIterator it) {
 367                                     String cfg = getCfg(it.get());
 368                                     if (nextNotKey(it)) {
 369                                         String fileName = it.get();
 370                                         if (nextNotKey(it)) {
 371                                             String line = it.get();


 421                                         it.next();
 422                                     } else {
 423                                         empty("-startAt", null);
 424                                     }
 425                                 }
 426                             }
 427                             ),
 428 
 429                 new HsArgRule("-ignoreFile",
 430                                       "IgnoreFile",
 431                                       null,
 432                                       HsArgHandler.HASH
 433                                       ),
 434 
 435                 new HsArgRule("-ignorePath",
 436                               "IgnorePath",
 437                               null,
 438                               HsArgHandler.VECTOR
 439                               ),
 440                               
 441                 new HsArgRule("-hidePath",
 442                               "IgnorePath",
 443                               null,
 444                               HsArgHandler.VECTOR
 445                               ),
 446 
 447                 new HsArgRule("-additionalFile",
 448                               "AdditionalFile",
 449                               null,
 450                               HsArgHandler.VECTOR














 451                               ),

 452                 new ArgRule("-prelink",
 453                             new HsArgHandler() {
 454                                 public void handle(ArgIterator it) {
 455                                     if (nextNotKey(it)) {
 456                                         if (nextNotKey(it)) {
 457                                             String description = it.get();
 458                                             if (nextNotKey(it)) {
 459                                                 String command = it.get();
 460                                                 BuildConfig.putField(null, "PrelinkDescription", description);
 461                                                 BuildConfig.putField(null, "PrelinkCommand", command);
 462                                                 it.next();
 463                                                 return;
 464                                             }
 465                                         }
 466                                     }
 467 
 468                                     empty(null,  "** Error: wrong number of args to -prelink");
 469                                 }
 470                             }
 471                             ),


 510         }
 511 
 512         BuildConfig.putField(null, "PlatformObject", this);
 513     }
 514 
 515     Vector createAllConfigs(String platform) {
 516         Vector allConfigs = new Vector();
 517 
 518         allConfigs.add(new C1DebugConfig());
 519         allConfigs.add(new C1FastDebugConfig());
 520         allConfigs.add(new C1ProductConfig());
 521 
 522         allConfigs.add(new C2DebugConfig());
 523         allConfigs.add(new C2FastDebugConfig());
 524         allConfigs.add(new C2ProductConfig());
 525 
 526         allConfigs.add(new TieredDebugConfig());
 527         allConfigs.add(new TieredFastDebugConfig());
 528         allConfigs.add(new TieredProductConfig());
 529 
 530       // Removed for now, doesn't build and isn't tested
 531       //allConfigs.add(new CoreDebugConfig());
 532       //allConfigs.add(new CoreFastDebugConfig());
 533       //allConfigs.add(new CoreProductConfig());
 534 
 535         if (platform.equals("Win32")) {
 536             allConfigs.add(new KernelDebugConfig());
 537             allConfigs.add(new KernelFastDebugConfig());
 538             allConfigs.add(new KernelProductConfig());
 539         }
 540 
 541         return allConfigs;
 542     }
 543 
 544    PrintWriter printWriter;










 545 
 546    public void writeProjectFile(String projectFileName, String projectName,
 547          Vector<BuildConfig> allConfigs) throws IOException {
 548       throw new RuntimeException("use compiler version specific version");
 549    }
 550 
 551    int indent;
 552    private Stack<String> tagStack = new Stack<String>();
 553 
 554    private void startTagPrim(String name, String[] attrs, boolean close) {
 555       startTagPrim(name, attrs, close, true);



 556    }
 557 
 558    private void startTagPrim(String name, String[] attrs, boolean close,
 559          boolean newline) {
 560       doIndent();
 561       printWriter.print("<" + name);
 562       indent++;
 563 
 564       if (attrs != null && attrs.length > 0) {
 565          for (int i = 0; i < attrs.length; i += 2) {
 566             printWriter.print(" " + attrs[i] + "=\"" + attrs[i + 1] + "\"");
 567             if (i < attrs.length - 2) {
 568             }




 569          }



 570       }
 571 
 572       if (close) {
 573          indent--;
 574          printWriter.print(" />");
 575       } else {
 576          tagStack.push(name);
 577          printWriter.print(">");
 578       }
 579       if (newline) {
 580          printWriter.println();






 581       }

 582    }
 583 
 584    void startTag(String name, String... attrs) {
 585       startTagPrim(name, attrs, false);
 586    }









 587 
 588    void startTagV(String name, Vector attrs) {
 589       String s[] = new String[attrs.size()];
 590       for (int i = 0; i < attrs.size(); i++) {
 591          s[i] = (String) attrs.elementAt(i);

 592       }
 593       startTagPrim(name, s, false);
 594    }
 595 
 596    void endTag() {
 597       String name = tagStack.pop();
 598       indent--;
 599       doIndent();
 600       printWriter.println("</" + name + ">");
 601    }
 602 
 603    private void endTagNoIndent() {
 604       String name = tagStack.pop();
 605       indent--;
 606       printWriter.println("</" + name + ">");
 607    }
 608 
 609    void tag(String name, String... attrs) {
 610       startTagPrim(name, attrs, true);
 611    }
 612 
 613    void tagData(String name, String data) {
 614       startTagPrim(name, null, false, false);
 615       printWriter.print(data);
 616       endTagNoIndent();
 617    }
 618 
 619    void tagData(String name, String data, String... attrs) {
 620       startTagPrim(name, attrs, false, false);
 621       printWriter.print(data);
 622       endTagNoIndent();
 623    }
 624 
 625    void tagV(String name, Vector attrs) {
 626       String s[] = new String[attrs.size()];
 627       for (int i = 0; i < attrs.size(); i++) {
 628          s[i] = (String) attrs.elementAt(i);
 629       }
 630       startTagPrim(name, s, true);
 631    }
 632 
 633    void doIndent() {
 634       for (int i = 0; i < indent; i++) {
 635          printWriter.print("  ");
 636       }
 637    }
 638 
 639 }