001/* PrintStream.java -- OutputStream for printing output
002   Copyright (C) 1998, 1999, 2001, 2003, 2004, 2005, 2006
003   Free Software Foundation, Inc.
004
005This file is part of GNU Classpath.
006
007GNU Classpath is free software; you can redistribute it and/or modify
008it under the terms of the GNU General Public License as published by
009the Free Software Foundation; either version 2, or (at your option)
010any later version.
011
012GNU Classpath is distributed in the hope that it will be useful, but
013WITHOUT ANY WARRANTY; without even the implied warranty of
014MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015General Public License for more details.
016
017You should have received a copy of the GNU General Public License
018along with GNU Classpath; see the file COPYING.  If not, write to the
019Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02002110-1301 USA.
021
022Linking this library statically or dynamically with other modules is
023making a combined work based on this library.  Thus, the terms and
024conditions of the GNU General Public License cover the whole
025combination.
026
027As a special exception, the copyright holders of this library give you
028permission to link this library with independent modules to produce an
029executable, regardless of the license terms of these independent
030modules, and to copy and distribute the resulting executable under
031terms of your choice, provided that you also meet, for each linked
032independent module, the terms and conditions of the license of that
033module.  An independent module is a module which is not derived from
034or based on this library.  If you modify this library, you may extend
035this exception to your version of the library, but you are not
036obligated to do so.  If you do not wish to do so, delete this
037exception statement from your version. */
038
039
040package java.io;
041
042import java.util.Locale;
043import java.util.Formatter;
044
045import gnu.classpath.SystemProperties;
046
047/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
048 * "The Java Language Specification", ISBN 0-201-63451-1
049 * Status:  Believed complete and correct to 1.3
050 */
051
052/**
053 * This class prints Java primitive values and object to a stream as
054 * text.  None of the methods in this class throw an exception.  However,
055 * errors can be detected by calling the <code>checkError()</code> method.
056 * Additionally, this stream can be designated as "autoflush" when
057 * created so that any writes are automatically flushed to the underlying
058 * output sink when the current line is terminated.
059 * <p>
060 * This class converts char's into byte's using the system default encoding.
061 *
062 * @author Aaron M. Renn (arenn@urbanophile.com)
063 * @author Tom Tromey (tromey@cygnus.com)
064 * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
065 */
066public class PrintStream extends FilterOutputStream implements Appendable
067{
068  /* Notice the implementation is quite similar to OutputStreamWriter.
069   * This leads to some minor duplication, because neither inherits
070   * from the other, and we want to maximize performance. */
071
072  // Line separator string.
073  private static final char[] line_separator
074    = SystemProperties.getProperty("line.separator", "\n").toCharArray();
075
076  /**
077   *  Encoding name
078   */
079  private final String encoding;
080
081  /**
082   * This boolean indicates whether or not an error has ever occurred
083   * on this stream.
084   */
085  private boolean error_occurred = false;
086
087  /**
088   * This is <code>true</code> if auto-flush is enabled,
089   * <code>false</code> otherwise
090   */
091  private final boolean auto_flush;
092
093  /**
094   * This method initializes a new <code>PrintStream</code> object to write
095   * to the specified output File. Doesn't autoflush.
096   *
097   * @param file The <code>File</code> to write to.
098   * @throws FileNotFoundException if an error occurs while opening the file.
099   *
100   * @since 1.5
101   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
258  protected void setError ()
259  {
260    error_occurred = true;
261  }
262
263  /**
264   * This method closes this stream and all underlying streams.
265   */
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   */
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
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
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
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
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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   */
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 */
642  public PrintStream append(char c)
643  {
644    print(c);
645    return this;
646  }
647
648  /** @since 1.5 */
649  public PrintStream append(CharSequence cs)
650  {
651    print(cs == null ? "null" : cs.toString());
652    return this;
653  }
654
655  /** @since 1.5 */
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 */
663  public PrintStream printf(String format, Object... args)
664  {
665    return format(format, args);
666  }
667
668  /** @since 1.5 */
669  public PrintStream printf(Locale locale, String format, Object... args)
670  {
671    return format(locale, format, args);
672  }
673
674  /** @since 1.5 */
675  public PrintStream format(String format, Object... args)
676  {
677    return format(Locale.getDefault(), format, args);
678  }
679
680  /** @since 1.5 */
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