1 /* PrintStream.java -- OutputStream for printing output
2    Copyright (C) 1998, 1999, 2001, 2003, 2004, 2005, 2006
3    Free Software Foundation, Inc.
4 
5 This file is part of GNU Classpath.
6 
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11 
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING.  If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA.
21 
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library.  Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
26 
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module.  An independent module is a module which is not derived from
34 or based on this library.  If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so.  If you do not wish to do so, delete this
37 exception statement from your version. */
38 
39 
40 package java.io;
41 
42 import java.util.Locale;
43 import java.util.Formatter;
44 
45 import gnu.classpath.SystemProperties;
46 
47 /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
48  * "The Java Language Specification", ISBN 0-201-63451-1
49  * Status:  Believed complete and correct to 1.3
50  */
51 
52 /**
53  * This class prints Java primitive values and object to a stream as
54  * text.  None of the methods in this class throw an exception.  However,
55  * errors can be detected by calling the <code>checkError()</code> method.
56  * Additionally, this stream can be designated as "autoflush" when
57  * created so that any writes are automatically flushed to the underlying
58  * output sink when the current line is terminated.
59  * <p>
60  * This class converts char's into byte's using the system default encoding.
61  *
62  * @author Aaron M. Renn (arenn@urbanophile.com)
63  * @author Tom Tromey (tromey@cygnus.com)
64  * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
65  */
66 public class PrintStream extends FilterOutputStream implements Appendable
67 {
68   /* Notice the implementation is quite similar to OutputStreamWriter.
69    * This leads to some minor duplication, because neither inherits
70    * from the other, and we want to maximize performance. */
71 
72   // Line separator string.
73   private static final char[] line_separator
74     = SystemProperties.getProperty("line.separator", "\n").toCharArray();
75 
76   /**
77    *  Encoding name
78    */
79   private final String encoding;
80 
81   /**
82    * This boolean indicates whether or not an error has ever occurred
83    * on this stream.
84    */
85   private boolean error_occurred = false;
86 
87   /**
88    * This is <code>true</code> if auto-flush is enabled,
89    * <code>false</code> otherwise
90    */
91   private final boolean auto_flush;
92 
93   /**
94    * This method initializes a new <code>PrintStream</code> object to write
95    * to the specified output File. Doesn't autoflush.
96    *
97    * @param file The <code>File</code> to write to.
98    * @throws FileNotFoundException if an error occurs while opening the file.
99    *
100    * @since 1.5
101    */
PrintStream(File file)102   public PrintStream (File file)
103     throws FileNotFoundException
104   {
105     this (new FileOutputStream(file), false);
106   }
107 
108   /**
109    * This method initializes a new <code>PrintStream</code> object to write
110    * to the specified output File. Doesn't autoflush.
111    *
112    * @param file The <code>File</code> to write to.
113    * @param encoding The name of the character encoding to use for this
114    * object.
115    * @throws FileNotFoundException If an error occurs while opening the file.
116    * @throws UnsupportedEncodingException If the charset specified by
117    * <code>encoding</code> is invalid.
118    *
119    * @since 1.5
120    */
PrintStream(File file, String encoding)121   public PrintStream (File file, String encoding)
122     throws FileNotFoundException,UnsupportedEncodingException
123   {
124     this (new FileOutputStream(file), false, encoding);
125   }
126 
127   /**
128    * This method initializes a new <code>PrintStream</code> object to write
129    * to the specified output File. Doesn't autoflush.
130    *
131    * @param fileName The name of the <code>File</code> to write to.
132    * @throws FileNotFoundException if an error occurs while opening the file,
133    *
134    * @since 1.5
135    */
PrintStream(String fileName)136   public PrintStream (String fileName)
137     throws FileNotFoundException
138   {
139     this (new FileOutputStream(new File(fileName)), false);
140   }
141 
142   /**
143    * This method initializes a new <code>PrintStream</code> object to write
144    * to the specified output File. Doesn't autoflush.
145    *
146    * @param fileName The name of the <code>File</code> to write to.
147    * @param encoding The name of the character encoding to use for this
148    * object.
149    * @throws FileNotFoundException if an error occurs while opening the file.
150    * @throws UnsupportedEncodingException If the charset specified by
151    * <code>encoding</code> is invalid.
152    *
153    * @since 1.5
154    */
PrintStream(String fileName, String encoding)155   public PrintStream (String fileName, String encoding)
156       throws FileNotFoundException,UnsupportedEncodingException
157   {
158     this (new FileOutputStream(new File(fileName)), false, encoding);
159   }
160 
161   /**
162    * This method initializes a new <code>PrintStream</code> object to write
163    * to the specified output sink. Doesn't autoflush.
164    *
165    * @param out The <code>OutputStream</code> to write to.
166    */
PrintStream(OutputStream out)167   public PrintStream (OutputStream out)
168   {
169     this (out, false);
170   }
171 
172   /**
173    * This method initializes a new <code>PrintStream</code> object to write
174    * to the specified output sink.  This constructor also allows "auto-flush"
175    * functionality to be specified where the stream will be flushed after
176    * every <code>print</code> or <code>println</code> call, when the
177    * <code>write</code> methods with array arguments are called, or when a
178    * single new-line character is written.
179    * <p>
180    *
181    * @param out The <code>OutputStream</code> to write to.
182    * @param auto_flush <code>true</code> to flush the stream after every
183    * line, <code>false</code> otherwise
184    * @exception NullPointerException If out is null.
185    */
PrintStream(OutputStream out, boolean auto_flush)186   public PrintStream (OutputStream out, boolean auto_flush)
187   {
188     super (out);
189 
190     if (out == null)
191       throw new NullPointerException("out is null");
192 
193     String encoding;
194     try {
195         encoding = SystemProperties.getProperty("file.encoding");
196     } catch (SecurityException e){
197         encoding = "ISO8859_1";
198     } catch (IllegalArgumentException e){
199         encoding = "ISO8859_1";
200     } catch (NullPointerException e){
201         encoding = "ISO8859_1";
202     }
203     this.encoding = encoding;
204     this.auto_flush = auto_flush;
205   }
206 
207   /**
208    * This method initializes a new <code>PrintStream</code> object to write
209    * to the specified output sink.  This constructor also allows "auto-flush"
210    * functionality to be specified where the stream will be flushed after
211    * every <code>print</code> or <code>println</code> call, when the
212    * <code>write</code> methods with array arguments are called, or when a
213    * single new-line character is written.
214    * <p>
215    *
216    * @param out The <code>OutputStream</code> to write to.
217    * @param auto_flush <code>true</code> to flush the stream after every
218    * line, <code>false</code> otherwise
219    * @param encoding The name of the character encoding to use for this
220    * object.
221    * @exception NullPointerException If out or encoding is null.
222    */
PrintStream(OutputStream out, boolean auto_flush, String encoding)223   public PrintStream (OutputStream out, boolean auto_flush, String encoding)
224     throws UnsupportedEncodingException
225   {
226     super (out);
227 
228     if (out == null)
229       throw new NullPointerException("out is null");
230 
231     if (encoding == null)
232       throw new NullPointerException("encoding is null");
233 
234     new String(new byte[]{0}, encoding);    // check if encoding is supported
235     this.encoding = encoding;
236     this.auto_flush = auto_flush;
237   }
238 
239   /**
240    * This method checks to see if an error has occurred on this stream.  Note
241    * that once an error has occurred, this method will continue to report
242    * <code>true</code> forever for this stream.  Before checking for an
243    * error condition, this method flushes the stream.
244    *
245    * @return <code>true</code> if an error has occurred,
246    * <code>false</code> otherwise
247    */
checkError()248   public boolean checkError ()
249   {
250     flush ();
251     return error_occurred;
252   }
253 
254   /**
255    * This method can be called by subclasses to indicate that an error
256    * has occurred and should be reported by <code>checkError</code>.
257    */
setError()258   protected void setError ()
259   {
260     error_occurred = true;
261   }
262 
263   /**
264    * This method closes this stream and all underlying streams.
265    */
close()266   public void close ()
267   {
268     try
269       {
270         flush();
271         out.close();
272       }
273     catch (InterruptedIOException iioe)
274       {
275         Thread.currentThread().interrupt();
276       }
277     catch (IOException e)
278       {
279         setError ();
280       }
281   }
282 
283   /**
284    * This method flushes any buffered bytes to the underlying stream and
285    * then flushes that stream as well.
286    */
flush()287   public void flush ()
288   {
289     try
290       {
291         out.flush();
292       }
293     catch (InterruptedIOException iioe)
294       {
295         Thread.currentThread().interrupt();
296       }
297     catch (IOException e)
298       {
299         setError ();
300       }
301   }
302 
print(String str, boolean println)303   private synchronized void print (String str, boolean println)
304   {
305     try
306       {
307         writeChars(str, 0, str.length());
308         if (println)
309           writeChars(line_separator, 0, line_separator.length);
310         if (auto_flush)
311           flush();
312       }
313     catch (InterruptedIOException iioe)
314       {
315         Thread.currentThread().interrupt();
316       }
317     catch (IOException e)
318       {
319         setError ();
320       }
321   }
322 
print(char[] chars, int pos, int len, boolean println)323   private synchronized void print (char[] chars, int pos, int len,
324                                    boolean println)
325   {
326     try
327       {
328         writeChars(chars, pos, len);
329         if (println)
330           writeChars(line_separator, 0, line_separator.length);
331         if (auto_flush)
332           flush();
333       }
334     catch (InterruptedIOException iioe)
335       {
336         Thread.currentThread().interrupt();
337       }
338     catch (IOException e)
339       {
340         setError ();
341       }
342   }
343 
writeChars(char[] buf, int offset, int count)344   private void writeChars(char[] buf, int offset, int count)
345     throws IOException
346   {
347       byte[] bytes = (new String(buf, offset, count)).getBytes(encoding);
348       out.write(bytes, 0, bytes.length);
349   }
350 
writeChars(String str, int offset, int count)351   private void writeChars(String str, int offset, int count)
352     throws IOException
353   {
354       byte[] bytes = str.substring(offset, offset+count).getBytes(encoding);
355       out.write(bytes, 0, bytes.length);
356   }
357 
358   /**
359    * This methods prints a boolean value to the stream.  <code>true</code>
360    * values are printed as "true" and <code>false</code> values are printed
361    * as "false".
362    *
363    * @param bool The <code>boolean</code> value to print
364    */
print(boolean bool)365   public void print (boolean bool)
366   {
367     print(String.valueOf(bool), false);
368   }
369 
370   /**
371    * This method prints an integer to the stream.  The value printed is
372    * determined using the <code>String.valueOf()</code> method.
373    *
374    * @param inum The <code>int</code> value to be printed
375    */
print(int inum)376   public void print (int inum)
377   {
378     print(String.valueOf(inum), false);
379   }
380 
381   /**
382    * This method prints a long to the stream.  The value printed is
383    * determined using the <code>String.valueOf()</code> method.
384    *
385    * @param lnum The <code>long</code> value to be printed
386    */
print(long lnum)387   public void print (long lnum)
388   {
389     print(String.valueOf(lnum), false);
390   }
391 
392   /**
393    * This method prints a float to the stream.  The value printed is
394    * determined using the <code>String.valueOf()</code> method.
395    *
396    * @param fnum The <code>float</code> value to be printed
397    */
print(float fnum)398   public void print (float fnum)
399   {
400     print(String.valueOf(fnum), false);
401   }
402 
403   /**
404    * This method prints a double to the stream.  The value printed is
405    * determined using the <code>String.valueOf()</code> method.
406    *
407    * @param dnum The <code>double</code> value to be printed
408    */
print(double dnum)409   public void print (double dnum)
410   {
411     print(String.valueOf(dnum), false);
412   }
413 
414   /**
415    * This method prints an <code>Object</code> to the stream.  The actual
416    * value printed is determined by calling the <code>String.valueOf()</code>
417    * method.
418    *
419    * @param obj The <code>Object</code> to print.
420    */
print(Object obj)421   public void print (Object obj)
422   {
423     print(obj == null ? "null" : obj.toString(), false);
424   }
425 
426   /**
427    * This method prints a <code>String</code> to the stream.  The actual
428    * value printed depends on the system default encoding.
429    *
430    * @param str The <code>String</code> to print.
431    */
print(String str)432   public void print (String str)
433   {
434     print(str == null ? "null" : str, false);
435   }
436 
437   /**
438    * This method prints a char to the stream.  The actual value printed is
439    * determined by the character encoding in use.
440    *
441    * @param ch The <code>char</code> value to be printed
442    */
print(char ch)443   public synchronized void print (char ch)
444   {
445     print(new char[]{ch}, 0, 1, false);
446   }
447 
448   /**
449    * This method prints an array of characters to the stream.  The actual
450    * value printed depends on the system default encoding.
451    *
452    * @param charArray The array of characters to print.
453    */
print(char[] charArray)454   public void print (char[] charArray)
455   {
456     print(charArray, 0, charArray.length, false);
457   }
458 
459   /**
460    * This method prints a line separator sequence to the stream.  The value
461    * printed is determined by the system property <xmp>line.separator</xmp>
462    * and is not necessarily the Unix '\n' newline character.
463    */
println()464   public void println ()
465   {
466     print(line_separator, 0, line_separator.length, false);
467   }
468 
469   /**
470    * This methods prints a boolean value to the stream.  <code>true</code>
471    * values are printed as "true" and <code>false</code> values are printed
472    * as "false".
473    * <p>
474    * This method prints a line termination sequence after printing the value.
475    *
476    * @param bool The <code>boolean</code> value to print
477    */
println(boolean bool)478   public void println (boolean bool)
479   {
480     print(String.valueOf(bool), true);
481   }
482 
483   /**
484    * This method prints an integer to the stream.  The value printed is
485    * determined using the <code>String.valueOf()</code> method.
486    * <p>
487    * This method prints a line termination sequence after printing the value.
488    *
489    * @param inum The <code>int</code> value to be printed
490    */
println(int inum)491   public void println (int inum)
492   {
493     print(String.valueOf(inum), true);
494   }
495 
496   /**
497    * This method prints a long to the stream.  The value printed is
498    * determined using the <code>String.valueOf()</code> method.
499    * <p>
500    * This method prints a line termination sequence after printing the value.
501    *
502    * @param lnum The <code>long</code> value to be printed
503    */
println(long lnum)504   public void println (long lnum)
505   {
506     print(String.valueOf(lnum), true);
507   }
508 
509   /**
510    * This method prints a float to the stream.  The value printed is
511    * determined using the <code>String.valueOf()</code> method.
512    * <p>
513    * This method prints a line termination sequence after printing the value.
514    *
515    * @param fnum The <code>float</code> value to be printed
516    */
println(float fnum)517   public void println (float fnum)
518   {
519     print(String.valueOf(fnum), true);
520   }
521 
522   /**
523    * This method prints a double to the stream.  The value printed is
524    * determined using the <code>String.valueOf()</code> method.
525    * <p>
526    * This method prints a line termination sequence after printing the value.
527    *
528    * @param dnum The <code>double</code> value to be printed
529    */
println(double dnum)530   public void println (double dnum)
531   {
532     print(String.valueOf(dnum), true);
533   }
534 
535   /**
536    * This method prints an <code>Object</code> to the stream.  The actual
537    * value printed is determined by calling the <code>String.valueOf()</code>
538    * method.
539    * <p>
540    * This method prints a line termination sequence after printing the value.
541    *
542    * @param obj The <code>Object</code> to print.
543    */
println(Object obj)544   public void println (Object obj)
545   {
546     print(obj == null ? "null" : obj.toString(), true);
547   }
548 
549   /**
550    * This method prints a <code>String</code> to the stream.  The actual
551    * value printed depends on the system default encoding.
552    * <p>
553    * This method prints a line termination sequence after printing the value.
554    *
555    * @param str The <code>String</code> to print.
556    */
println(String str)557   public void println (String str)
558   {
559     print (str == null ? "null" : str, true);
560   }
561 
562   /**
563    * This method prints a char to the stream.  The actual value printed is
564    * determined by the character encoding in use.
565    * <p>
566    * This method prints a line termination sequence after printing the value.
567    *
568    * @param ch The <code>char</code> value to be printed
569    */
println(char ch)570   public synchronized void println (char ch)
571   {
572     print(new char[]{ch}, 0, 1, true);
573   }
574 
575   /**
576    * This method prints an array of characters to the stream.  The actual
577    * value printed depends on the system default encoding.
578    * <p>
579    * This method prints a line termination sequence after printing the value.
580    *
581    * @param charArray The array of characters to print.
582    */
println(char[] charArray)583   public void println (char[] charArray)
584   {
585     print(charArray, 0, charArray.length, true);
586   }
587 
588   /**
589    * This method writes a byte of data to the stream.  If auto-flush is
590    * enabled, printing a newline character will cause the stream to be
591    * flushed after the character is written.
592    *
593    * @param oneByte The byte to be written
594    */
write(int oneByte)595   public void write (int oneByte)
596   {
597     try
598       {
599         out.write (oneByte & 0xff);
600 
601         if (auto_flush && (oneByte == '\n'))
602           flush ();
603       }
604     catch (InterruptedIOException iioe)
605       {
606         Thread.currentThread ().interrupt ();
607       }
608     catch (IOException e)
609       {
610         setError ();
611       }
612   }
613 
614   /**
615    * This method writes <code>len</code> bytes from the specified array
616    * starting at index <code>offset</code> into the array.
617    *
618    * @param buffer The array of bytes to write
619    * @param offset The index into the array to start writing from
620    * @param len The number of bytes to write
621    */
write(byte[] buffer, int offset, int len)622   public void write (byte[] buffer, int offset, int len)
623   {
624     try
625       {
626         out.write (buffer, offset, len);
627 
628         if (auto_flush)
629           flush ();
630       }
631     catch (InterruptedIOException iioe)
632       {
633         Thread.currentThread ().interrupt ();
634       }
635     catch (IOException e)
636       {
637         setError ();
638       }
639   }
640 
641   /** @since 1.5 */
append(char c)642   public PrintStream append(char c)
643   {
644     print(c);
645     return this;
646   }
647 
648   /** @since 1.5 */
append(CharSequence cs)649   public PrintStream append(CharSequence cs)
650   {
651     print(cs == null ? "null" : cs.toString());
652     return this;
653   }
654 
655   /** @since 1.5 */
append(CharSequence cs, int start, int end)656   public PrintStream append(CharSequence cs, int start, int end)
657   {
658     print(cs == null ? "null" : cs.subSequence(start, end).toString());
659     return this;
660   }
661 
662   /** @since 1.5 */
printf(String format, Object... args)663   public PrintStream printf(String format, Object... args)
664   {
665     return format(format, args);
666   }
667 
668   /** @since 1.5 */
printf(Locale locale, String format, Object... args)669   public PrintStream printf(Locale locale, String format, Object... args)
670   {
671     return format(locale, format, args);
672   }
673 
674   /** @since 1.5 */
format(String format, Object... args)675   public PrintStream format(String format, Object... args)
676   {
677     return format(Locale.getDefault(), format, args);
678   }
679 
680   /** @since 1.5 */
format(Locale locale, String format, Object... args)681   public PrintStream format(Locale locale, String format, Object... args)
682   {
683     Formatter f = new Formatter(this, locale);
684     f.format(format, args);
685     return this;
686   }
687 } // class PrintStream
688