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