1 /* 2 * Copyright (c) 2007, 2025, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.javap; 27 28 import java.io.PrintWriter; 29 import java.lang.classfile.AccessFlags; 30 import java.lang.reflect.AccessFlag; 31 import java.lang.reflect.ClassFileFormatVersion; 32 import java.lang.reflect.Modifier; 33 import java.util.EnumMap; 34 import java.util.Map; 35 import java.util.Set; 36 import java.util.function.Supplier; 37 38 /* 39 * A writer similar to a PrintWriter but which does not hide exceptions. 40 * The standard print calls are line-buffered; report calls write messages directly. 41 * 42 * <p><b>This is NOT part of any supported API. 43 * If you write code that depends on this, you do so at your own risk. 44 * This code and its internal interfaces are subject to change or 45 * deletion without notice.</b> 46 */ 47 public class BasicWriter { 48 49 protected BasicWriter(Context context) { 50 lineWriter = LineWriter.instance(context); 51 out = context.get(PrintWriter.class); 52 messages = context.get(Messages.class); 53 if (messages == null) 54 throw new AssertionError(); 55 } 56 57 protected Set<AccessFlag> flagsReportUnknown(AccessFlags flags, ClassFileFormatVersion cffv) { 58 return maskToAccessFlagsReportUnknown(flags.flagsMask(), flags.location(), cffv); 59 } 60 61 protected Set<AccessFlag> maskToAccessFlagsReportUnknown(int mask, AccessFlag.Location location, ClassFileFormatVersion cffv) { 62 try { 63 return AccessFlag.maskToAccessFlags(mask, location, cffv); 64 } catch (IllegalArgumentException ex) { 65 mask &= location.flagsMask(cffv); 66 report("Access Flags: " + ex.getMessage()); 67 return AccessFlag.maskToAccessFlags(mask, location, cffv); 68 } 69 } 70 71 protected void print(String s) { 72 lineWriter.print(s); 73 } 74 75 protected void print(Object o) { 76 lineWriter.print(o == null ? null : o.toString()); 77 } 78 79 protected void print(Supplier<Object> safeguardedCode) { 80 try { 81 print(safeguardedCode.get()); 82 } catch (IllegalArgumentException e) { 83 print(report(e)); 84 } 85 } 86 87 protected void println() { 88 lineWriter.println(); 89 } 90 91 protected void println(String s) { 92 lineWriter.print(s); 93 lineWriter.println(); 94 } 95 96 protected void println(Object o) { 97 lineWriter.print(o == null ? null : o.toString()); 98 lineWriter.println(); 99 } 100 101 protected void println(Supplier<Object> safeguardedCode) { 102 print(safeguardedCode); 103 lineWriter.println(); 104 } 105 106 protected void indent(int delta) { 107 lineWriter.indent(delta); 108 } 109 110 protected void tab() { 111 lineWriter.tab(); 112 } 113 114 protected void setPendingNewline(boolean b) { 115 lineWriter.pendingNewline = b; 116 } 117 118 protected String report(Exception e) { 119 out.println("Error: " + e.getMessage()); // i18n? 120 errorReported = true; 121 return "???"; 122 } 123 124 protected String report(String msg) { 125 out.println("Error: " + msg); // i18n? 126 errorReported = true; 127 return "???"; 128 } 129 130 protected String space(int w) { 131 if (w < spaces.length && spaces[w] != null) 132 return spaces[w]; 133 134 StringBuilder sb = new StringBuilder(); 135 for (int i = 0; i < w; i++) 136 sb.append(" "); 137 138 String s = sb.toString(); 139 if (w < spaces.length) 140 spaces[w] = s; 141 142 return s; 143 } 144 145 private String[] spaces = new String[80]; 146 147 private LineWriter lineWriter; 148 private PrintWriter out; 149 protected Messages messages; 150 protected boolean errorReported; 151 152 private static class LineWriter { 153 static LineWriter instance(Context context) { 154 LineWriter instance = context.get(LineWriter.class); 155 if (instance == null) 156 instance = new LineWriter(context); 157 return instance; 158 } 159 160 protected LineWriter(Context context) { 161 context.put(LineWriter.class, this); 162 Options options = Options.instance(context); 163 indentWidth = options.indentWidth; 164 tabColumn = options.tabColumn; 165 out = context.get(PrintWriter.class); 166 buffer = new StringBuilder(); 167 } 168 169 protected void print(String s) { 170 if (pendingNewline) { 171 println(); 172 pendingNewline = false; 173 } 174 if (s == null) 175 s = "null"; 176 for (int i = 0; i < s.length(); i++) { 177 char c = s.charAt(i); 178 switch (c) { 179 case ' ': 180 pendingSpaces++; 181 break; 182 183 case '\n': 184 println(); 185 break; 186 187 default: 188 if (buffer.length() == 0) 189 indent(); 190 if (pendingSpaces > 0) { 191 for (int sp = 0; sp < pendingSpaces; sp++) 192 buffer.append(' '); 193 pendingSpaces = 0; 194 } 195 buffer.append(c); 196 } 197 } 198 199 } 200 201 protected void println() { 202 // ignore/discard pending spaces 203 pendingSpaces = 0; 204 out.println(buffer); 205 buffer.setLength(0); 206 } 207 208 protected void indent(int delta) { 209 indentCount += delta; 210 } 211 212 protected void tab() { 213 int col = indentCount * indentWidth + tabColumn; 214 pendingSpaces += (col <= buffer.length() ? 1 : col - buffer.length()); 215 } 216 217 private void indent() { 218 pendingSpaces += (indentCount * indentWidth); 219 } 220 221 private final PrintWriter out; 222 private final StringBuilder buffer; 223 private int indentCount; 224 private final int indentWidth; 225 private final int tabColumn; 226 private boolean pendingNewline; 227 private int pendingSpaces; 228 } 229 } 230