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 if (cffv == null) 63 cffv = ClassFileFormatVersion.CURRENT_PREVIEW_FEATURES; // Aggressive fallback 64 try { 65 return AccessFlag.maskToAccessFlags(mask, location, cffv); 66 } catch (IllegalArgumentException ex) { 67 mask &= location.flagsMask(cffv); 68 report("Access Flags: " + ex.getMessage()); 69 return AccessFlag.maskToAccessFlags(mask, location, cffv); 70 } 71 } 72 73 protected void print(String s) { 74 lineWriter.print(s); 75 } 76 77 protected void print(Object o) { 78 lineWriter.print(o == null ? null : o.toString()); 79 } 80 81 protected void print(Supplier<Object> safeguardedCode) { 82 try { 83 print(safeguardedCode.get()); 84 } catch (IllegalArgumentException e) { 85 print(report(e)); 86 } 87 } 88 89 protected void println() { 90 lineWriter.println(); 91 } 92 93 protected void println(String s) { 94 lineWriter.print(s); 95 lineWriter.println(); 96 } 97 98 protected void println(Object o) { 99 lineWriter.print(o == null ? null : o.toString()); 100 lineWriter.println(); 101 } 102 103 protected void println(Supplier<Object> safeguardedCode) { 104 print(safeguardedCode); 105 lineWriter.println(); 106 } 107 108 protected void indent(int delta) { 109 lineWriter.indent(delta); 110 } 111 112 protected void tab() { 113 lineWriter.tab(); 114 } 115 116 protected void setPendingNewline(boolean b) { 117 lineWriter.pendingNewline = b; 118 } 119 120 protected String report(Exception e) { 121 out.println("Error: " + e.getMessage()); // i18n? 122 errorReported = true; 123 return "???"; 124 } 125 126 protected String report(String msg) { 127 out.println("Error: " + msg); // i18n? 128 errorReported = true; 129 return "???"; 130 } 131 132 protected String space(int w) { 133 if (w < spaces.length && spaces[w] != null) 134 return spaces[w]; 135 136 StringBuilder sb = new StringBuilder(); 137 for (int i = 0; i < w; i++) 138 sb.append(" "); 139 140 String s = sb.toString(); 141 if (w < spaces.length) 142 spaces[w] = s; 143 144 return s; 145 } 146 147 private String[] spaces = new String[80]; 148 149 private LineWriter lineWriter; 150 private PrintWriter out; 151 protected Messages messages; 152 protected boolean errorReported; 153 154 private static class LineWriter { 155 static LineWriter instance(Context context) { 156 LineWriter instance = context.get(LineWriter.class); 157 if (instance == null) 158 instance = new LineWriter(context); 159 return instance; 160 } 161 162 protected LineWriter(Context context) { 163 context.put(LineWriter.class, this); 164 Options options = Options.instance(context); 165 indentWidth = options.indentWidth; 166 tabColumn = options.tabColumn; 167 out = context.get(PrintWriter.class); 168 buffer = new StringBuilder(); 169 } 170 171 protected void print(String s) { 172 if (pendingNewline) { 173 println(); 174 pendingNewline = false; 175 } 176 if (s == null) 177 s = "null"; 178 for (int i = 0; i < s.length(); i++) { 179 char c = s.charAt(i); 180 switch (c) { 181 case ' ': 182 pendingSpaces++; 183 break; 184 185 case '\n': 186 println(); 187 break; 188 189 default: 190 if (buffer.length() == 0) 191 indent(); 192 if (pendingSpaces > 0) { 193 for (int sp = 0; sp < pendingSpaces; sp++) 194 buffer.append(' '); 195 pendingSpaces = 0; 196 } 197 buffer.append(c); 198 } 199 } 200 201 } 202 203 protected void println() { 204 // ignore/discard pending spaces 205 pendingSpaces = 0; 206 out.println(buffer); 207 buffer.setLength(0); 208 } 209 210 protected void indent(int delta) { 211 indentCount += delta; 212 } 213 214 protected void tab() { 215 int col = indentCount * indentWidth + tabColumn; 216 pendingSpaces += (col <= buffer.length() ? 1 : col - buffer.length()); 217 } 218 219 private void indent() { 220 pendingSpaces += (indentCount * indentWidth); 221 } 222 223 private final PrintWriter out; 224 private final StringBuilder buffer; 225 private int indentCount; 226 private final int indentWidth; 227 private final int tabColumn; 228 private boolean pendingNewline; 229 private int pendingSpaces; 230 } 231 } 232