1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.millscript.millscript.tools;
23
24 import org.millscript.commons.util.IList;
25 import org.millscript.commons.util.ListIterator;
26 import org.millscript.commons.util.MapIterator;
27 import org.millscript.commons.util.Maplet;
28 import org.millscript.millscript.alert.Alerts;
29
30 import java.io.PrintWriter;
31 import java.util.Iterator;
32 import java.util.List;
33 import java.util.Map;
34
35 /**
36 * This utility class provides MillScripts print, show and formatted printing
37 * functionality.
38 */
39 public final class FormatPrint {
40
41 /**
42 * Hidden constructor.
43 */
44 private FormatPrint() {
45 }
46
47 /**
48 * Shows the specified object to the specified writer. Showing an object
49 * will display it in a way that is more appropriate for debugging. e.g.
50 * strings will be quoted, absent will be expanded, lists will be quoted
51 * and comma separated.
52 *
53 * @param out the writer to show to
54 * @param x the object to show
55 */
56 public static void show( final PrintWriter out, final Object x ) {
57 if ( x == null ) {
58 out.print( "<absent>" );
59 } else if ( x instanceof String ) {
60 out.print( '"' );
61 out.print( x );
62 out.print( '"' );
63 } else if ( x instanceof Character ) {
64 out.print( "'" );
65 out.print( x );
66 out.print( "'" );
67 } else if ( x instanceof Boolean ) {
68 out.print( ((Boolean)x).booleanValue() ? "<true>" : "<false>" );
69 } else if ( x instanceof Map.Entry ) {
70 out.print( "( " );
71 out.print( ((Maplet) x).getKey() );
72 out.print( " ==> " );
73 out.print( ((Maplet) x).getValue() );
74 out.print( " )" );
75 } else {
76 out.print( x );
77 }
78 }
79
80 /**
81 * Format prints the specified control string to the specified writer,
82 * using the specified list of arguments. The control string is iterpreted
83 * to find percent based escape sequences, which are then formatted
84 * accordingly.
85 * <dl>
86 * <dt>%%</dt>
87 * <dd>Prints a single %</dd>
88 * <dt>%p</dt>
89 * <dd>Prints the next argument in the list</dd>
90 * <dt>%s</dt>
91 * <dd>Shows the next argument in the list</dd>
92 * <dt>%x</dt>
93 * <dd>Prints the next argument as a hexadecimal number</dd>
94 * </dl>
95 *
96 * @param out the writer to print to
97 * @param control the format control string
98 * @param list the list of arguments for formatting
99 */
100 public static void print( final PrintWriter out, final String control, final IList< ? > list ) {
101 final ListIterator< ? > itr = list.iterator( true );
102 final int len = control.length();
103 for ( int i = 0; i < len; i++ ) {
104 final char ch = control.charAt( i );
105 char nch = ch;
106 if ( ch == '%' ) {
107 i++;
108 if ( i < len ) {
109 nch = control.charAt( i );
110 } else {
111 throw(
112 Alerts.eval(
113 "Invalid format string",
114 "Format string requires additional characters to be valid"
115 ).culprit( "control string", control ).mishap()
116 );
117 }
118 if ( nch == '%' ) {
119 out.print( '%' );
120 } else {
121 int total = 0;
122 int dig;
123 while ( ( dig = Character.digit( nch, 10 ) ) > -1 ) {
124 total = total * 10 + dig;
125 i++;
126 if ( i < len ) {
127 nch = control.charAt( i );
128 } else {
129 throw(
130 Alerts.eval(
131 "Invalid format string",
132 "Format string requires additional character to indicate type of formatting ('p', 's' or 'x' supported)"
133 ).culprit( "control string", control ).mishap()
134 );
135 }
136 }
137 Object item = null;
138 if ( total == 0 && itr.hasNext() ) {
139 item = itr.nextValue();
140 } else if ( total <= list.size() && total >= 1 ) {
141 item = list.get( total );
142 } else {
143 throw(
144 Alerts.eval(
145 "Too few arguments passed to format function",
146 "A reference was made to argument "
147 + ( ( total == 0 ) ? 1 : total ) + " when " + list.size() + " argument"
148 + ( ( list.size() == 1 ) ? " " : "s " )
149 + ( ( list.size() == 1 ) ? "was" : "were" ) + " provided"
150 ).culprit( "control string", control ).mishap()
151 );
152 }
153 if ( nch == 'p' ) {
154 print1( out, item );
155 } else if ( nch == 's' ) {
156 show( out, item );
157 } else if ( nch == 'x' ) {
158 int n = CastLibrary.toInt( item );
159 out.print( Integer.toString( n, 16 ) );
160 } else {
161 throw(
162 Alerts.eval(
163 "Invalid character in format string",
164 "Format strings accept %%, %p, %s and %x (so far)"
165 ).culprit( "control string", control ).mishap()
166 );
167 }
168 }
169 } else {
170 out.print( ch );
171 }
172 }
173 }
174
175 /**
176 * Prints the specified object to the specified writer. Printing an object
177 * will display it in a way that is more appropriate for output. e.g.
178 * strings will be displayed without quoted, absent would not print
179 * anything, lists will have each item in them printed.
180 *
181 * @param out the writer to print to
182 * @param x the object to print
183 */
184 public static void print1( final PrintWriter out, final Object x ) {
185 if ( x == null ) {
186
187 } else if ( x instanceof IList ) {
188 MapIterator it = ((IList) x).iterator( true );
189 while ( it.hasNext() ) {
190 print1( out, it.nextValue() );
191 }
192 } else if ( x instanceof List ) {
193 Iterator it = ((List) x).iterator();
194 while ( it.hasNext() ) {
195 print1( out, it.next() );
196 }
197 } else {
198 out.print( x );
199 }
200 }
201
202 }