View Javadoc

1   ////////////////////////////////////////////////////////////////////////////////
2   // MillScript: an Open Spice interpreter and batch website creation tool
3   // Copyright (C) 2001-2004 Open World Ltd
4   // Copyright (C) 2005 Kevin Rogers
5   //
6   // This file is part of MillScript.
7   //
8   // MillScript is free software; you can redistribute it and/or modify it under
9   // the terms of the GNU General Public License as published by the Free
10  // Software Foundation; either version 2 of the License, or (at your option)
11  // any later version.
12  //
13  // MillScript is distributed in the hope that it will be useful, but WITHOUT
14  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16  // more details.
17  //
18  // You should have received a copy of the GNU General Public License along with
19  // MillScript; if not, write to the Free Software Foundation, Inc., 59 Temple
20  // Place, Suite 330, Boston, MA  02111-1307  USA
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             // skip
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 }