VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/stream.cpp@ 26626

Last change on this file since 26626 was 25926, checked in by vboxsync, 15 years ago

Runtime: fixed uninitialized var

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 22.7 KB
Line 
1/* $Id: stream.cpp 25926 2010-01-20 11:36:41Z vboxsync $ */
2/** @file
3 * IPRT - I/O Stream.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32
33/*******************************************************************************
34* Header Files *
35*******************************************************************************/
36#include <iprt/stream.h>
37#include "internal/iprt.h"
38
39#include <iprt/asm.h>
40#include <iprt/critsect.h>
41#include <iprt/string.h>
42#include <iprt/assert.h>
43#include <iprt/alloc.h>
44#include <iprt/err.h>
45#include <iprt/param.h>
46#include <iprt/string.h>
47
48#include "internal/alignmentchecks.h"
49#include "internal/magics.h"
50
51#include <stdio.h>
52#include <errno.h>
53
54#if defined(RT_OS_LINUX) /* PORTME: check for the _unlocked functions in stdio.h */
55#define HAVE_FWRITE_UNLOCKED
56#endif
57
58
59/*******************************************************************************
60* Structures and Typedefs *
61*******************************************************************************/
62/**
63 * File stream.
64 */
65typedef struct RTSTREAM
66{
67 /** Magic value used to validate the stream. (RTSTREAM_MAGIC) */
68 uint32_t u32Magic;
69 /** File stream error. */
70 int32_t volatile i32Error;
71 /** Pointer to the LIBC file stream. */
72 FILE *pFile;
73#ifndef HAVE_FWRITE_UNLOCKED
74 /** Critical section for serializing access to the stream. */
75 PRTCRITSECT pCritSect;
76#endif
77} RTSTREAM;
78
79
80/*******************************************************************************
81* Global Variables *
82*******************************************************************************/
83/** The standard input stream. */
84static RTSTREAM g_StdIn =
85{
86 RTSTREAM_MAGIC,
87 0,
88 stdin
89#ifndef HAVE_FWRITE_UNLOCKED
90 , NULL
91#endif
92};
93
94/** The standard error stream. */
95static RTSTREAM g_StdErr =
96{
97 RTSTREAM_MAGIC,
98 0,
99 stderr
100#ifndef HAVE_FWRITE_UNLOCKED
101 , NULL
102#endif
103};
104
105/** The standard output stream. */
106static RTSTREAM g_StdOut =
107{
108 RTSTREAM_MAGIC,
109 0,
110 stdout
111#ifndef HAVE_FWRITE_UNLOCKED
112 , NULL
113#endif
114};
115
116/** Pointer to the standard input stream. */
117RTDATADECL(PRTSTREAM) g_pStdIn = &g_StdIn;
118
119/** Pointer to the standard output stream. */
120RTDATADECL(PRTSTREAM) g_pStdErr = &g_StdErr;
121
122/** Pointer to the standard output stream. */
123RTDATADECL(PRTSTREAM) g_pStdOut = &g_StdOut;
124
125
126#ifndef HAVE_FWRITE_UNLOCKED
127/**
128 * Allocates and acquires the lock for the stream.
129 *
130 * @returns IPRT status.
131 * @param pStream The stream (valid).
132 */
133static int rtStrmAllocLock(PRTSTREAM pStream)
134{
135 Assert(pStream->pCritSect == NULL);
136
137 PRTCRITSECT pCritSect = (PRTCRITSECT)RTMemAlloc(sizeof(*pCritSect));
138 if (!pCritSect)
139 return VERR_NO_MEMORY;
140
141 /* The native stream lock are normally not recursive. */
142 int rc = RTCritSectInitEx(pCritSect, RTCRITSECT_FLAGS_NO_NESTING,
143 NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, "RTSemSpinMutex");
144 if (RT_SUCCESS(rc))
145 {
146 rc = RTCritSectEnter(pCritSect);
147 if (RT_SUCCESS(rc))
148 {
149 if (RT_LIKELY(ASMAtomicCmpXchgPtr((void * volatile *)&pStream->pCritSect, pCritSect, NULL)))
150 return VINF_SUCCESS;
151
152 RTCritSectLeave(pCritSect);
153 }
154 RTCritSectDelete(pCritSect);
155 }
156 RTMemFree(pCritSect);
157
158 /* Handle the lost race case... */
159 pCritSect = (PRTCRITSECT)ASMAtomicReadPtr((void * volatile *)&pStream->pCritSect);
160 if (pCritSect)
161 return RTCritSectEnter(pCritSect);
162
163 return rc;
164}
165#endif /* !HAVE_FWRITE_UNLOCKED */
166
167
168/**
169 * Locks the stream. May have to allocate the lock as well.
170 *
171 * @param pStream The stream (valid).
172 */
173DECLINLINE(void) rtStrmLock(PRTSTREAM pStream)
174{
175#ifdef HAVE_FWRITE_UNLOCKED
176 flockfile(pStream->pFile);
177#else
178 if (RT_LIKELY(pStream->pCritSect))
179 RTCritSectEnter(pStream->pCritSect);
180 else
181 rtStrmAllocLock(pStream);
182#endif
183}
184
185
186/**
187 * Unlocks the stream.
188 *
189 * @param pStream The stream (valid).
190 */
191DECLINLINE(void) rtStrmUnlock(PRTSTREAM pStream)
192{
193#ifdef HAVE_FWRITE_UNLOCKED
194 funlockfile(pStream->pFile);
195#else
196 if (RT_LIKELY(pStream->pCritSect))
197 RTCritSectLeave(pStream->pCritSect);
198#endif
199}
200
201
202/**
203 * Opens a file stream.
204 *
205 * @returns iprt status code.
206 * @param pszFilename Path to the file to open.
207 * @param pszMode The open mode. See fopen() standard.
208 * Format: <a|r|w>[+][b|t]
209 * @param ppStream Where to store the opened stream.
210 */
211RTR3DECL(int) RTStrmOpen(const char *pszFilename, const char *pszMode, PRTSTREAM *ppStream)
212{
213 /*
214 * Validate input.
215 */
216 if (!pszMode || !*pszMode)
217 {
218 AssertMsgFailed(("No pszMode!\n"));
219 return VERR_INVALID_PARAMETER;
220 }
221 if (!pszFilename)
222 {
223 AssertMsgFailed(("No pszFilename!\n"));
224 return VERR_INVALID_PARAMETER;
225 }
226 bool fOk = true;
227 switch (*pszMode)
228 {
229 case 'a':
230 case 'w':
231 case 'r':
232 switch (pszMode[1])
233 {
234 case '\0':
235 break;
236 case '+':
237 switch (pszMode[2])
238 {
239 case '\0':
240 //case 't':
241 case 'b':
242 break;
243 default:
244 fOk = false;
245 break;
246 }
247 break;
248 //case 't':
249 case 'b':
250 break;
251 default:
252 fOk = false;
253 break;
254 }
255 break;
256 default:
257 fOk = false;
258 break;
259 }
260 if (!fOk)
261 {
262 AssertMsgFailed(("Invalid pszMode='%s', '<a|r|w>[+][b|t]'\n", pszMode));
263 return VINF_SUCCESS;
264 }
265
266 /*
267 * Allocate the stream handle and try open it.
268 */
269 PRTSTREAM pStream = (PRTSTREAM)RTMemAlloc(sizeof(*pStream));
270 if (pStream)
271 {
272 pStream->u32Magic = RTSTREAM_MAGIC;
273 pStream->i32Error = VINF_SUCCESS;
274#ifndef HAVE_FWRITE_UNLOCKED
275 pStream->pCritSect = NULL;
276#endif /* HAVE_FWRITE_UNLOCKED */
277 pStream->pFile = fopen(pszFilename, pszMode);
278 if (pStream->pFile)
279 {
280 *ppStream = pStream;
281 return VINF_SUCCESS;
282 }
283 return RTErrConvertFromErrno(errno);
284 }
285 return VERR_NO_MEMORY;
286}
287
288
289/**
290 * Opens a file stream.
291 *
292 * @returns iprt status code.
293 * @param pszMode The open mode. See fopen() standard.
294 * Format: <a|r|w>[+][b|t]
295 * @param ppStream Where to store the opened stream.
296 * @param pszFilenameFmt Filename path format string.
297 * @param args Arguments to the format string.
298 */
299RTR3DECL(int) RTStrmOpenFV(const char *pszMode, PRTSTREAM *ppStream, const char *pszFilenameFmt, va_list args)
300{
301 int rc;
302 char szFilename[RTPATH_MAX];
303 size_t cch = RTStrPrintfV(szFilename, sizeof(szFilename), pszFilenameFmt, args);
304 if (cch < sizeof(szFilename))
305 rc = RTStrmOpen(szFilename, pszMode, ppStream);
306 else
307 {
308 AssertMsgFailed(("The filename is too long cch=%d\n", cch));
309 rc = VERR_FILENAME_TOO_LONG;
310 }
311 return rc;
312}
313
314
315/**
316 * Opens a file stream.
317 *
318 * @returns iprt status code.
319 * @param pszMode The open mode. See fopen() standard.
320 * Format: <a|r|w>[+][b|t]
321 * @param ppStream Where to store the opened stream.
322 * @param pszFilenameFmt Filename path format string.
323 * @param ... Arguments to the format string.
324 */
325RTR3DECL(int) RTStrmOpenF(const char *pszMode, PRTSTREAM *ppStream, const char *pszFilenameFmt, ...)
326{
327 va_list args;
328 va_start(args, pszFilenameFmt);
329 int rc = RTStrmOpenFV(pszMode, ppStream, pszFilenameFmt, args);
330 va_end(args);
331 return rc;
332}
333
334
335/**
336 * Closes the specified stream.
337 *
338 * @returns iprt status code.
339 * @param pStream The stream to close.
340 */
341RTR3DECL(int) RTStrmClose(PRTSTREAM pStream)
342{
343 if (pStream && pStream->u32Magic == RTSTREAM_MAGIC)
344 {
345 if (!fclose(pStream->pFile))
346 {
347 pStream->u32Magic = 0xdeaddead;
348 pStream->pFile = NULL;
349#ifndef HAVE_FWRITE_UNLOCKED
350 if (pStream->pCritSect)
351 {
352 RTCritSectEnter(pStream->pCritSect);
353 RTCritSectLeave(pStream->pCritSect);
354 RTCritSectDelete(pStream->pCritSect);
355 RTMemFree(pStream->pCritSect);
356 pStream->pCritSect = NULL;
357 }
358#endif
359 RTMemFree(pStream);
360 return VINF_SUCCESS;
361 }
362
363 return RTErrConvertFromErrno(errno);
364 }
365 else
366 {
367 AssertMsgFailed(("Invalid stream!\n"));
368 return VERR_INVALID_PARAMETER;
369 }
370}
371
372
373/**
374 * Get the pending error of the stream.
375 *
376 * @returns iprt status code. of the stream.
377 * @param pStream The stream.
378 */
379RTR3DECL(int) RTStrmError(PRTSTREAM pStream)
380{
381 int rc;
382 if (pStream && pStream->u32Magic == RTSTREAM_MAGIC)
383 rc = pStream->i32Error;
384 else
385 {
386 AssertMsgFailed(("Invalid stream!\n"));
387 rc = VERR_INVALID_PARAMETER;
388 }
389 return rc;
390}
391
392
393/**
394 * Clears stream error condition.
395 *
396 * All stream operations save RTStrmClose and this will fail
397 * while an error is asserted on the stream
398 *
399 * @returns iprt status code.
400 * @param pStream The stream.
401 */
402RTR3DECL(int) RTStrmClearError(PRTSTREAM pStream)
403{
404 int rc;
405 if (pStream && pStream->u32Magic == RTSTREAM_MAGIC)
406 {
407 clearerr(pStream->pFile);
408 ASMAtomicXchgS32(&pStream->i32Error, VINF_SUCCESS);
409 rc = VINF_SUCCESS;
410 }
411 else
412 {
413 AssertMsgFailed(("Invalid stream!\n"));
414 rc = VERR_INVALID_PARAMETER;
415 }
416 return rc;
417}
418
419
420/**
421 * Rewinds the stream.
422 *
423 * Stream errors will be reset on success.
424 *
425 * @returns IPRT status code.
426 *
427 * @param pStream The stream.
428 *
429 * @remarks Not all streams are rewindable and that behavior is currently
430 * undefined for those.
431 */
432RTR3DECL(int) RTStrmRewind(PRTSTREAM pStream)
433{
434 AssertPtrReturn(pStream, VERR_INVALID_HANDLE);
435 AssertReturn(pStream->u32Magic == RTSTREAM_MAGIC, VERR_INVALID_HANDLE);
436
437 int rc;
438 clearerr(pStream->pFile);
439 errno = 0;
440 if (!fseek(pStream->pFile, 0, SEEK_SET))
441 {
442 ASMAtomicXchgS32(&pStream->i32Error, VINF_SUCCESS);
443 rc = VINF_SUCCESS;
444 }
445 else
446 {
447 rc = RTErrConvertFromErrno(errno);
448 ASMAtomicXchgS32(&pStream->i32Error, rc);
449 }
450
451 return rc;
452}
453
454
455/**
456 * Reads from a file stream.
457 *
458 * @returns iprt status code.
459 * @param pStream The stream.
460 * @param pvBuf Where to put the read bits.
461 * Must be cbRead bytes or more.
462 * @param cbRead Number of bytes to read.
463 * @param pcbRead Where to store the number of bytes actually read.
464 * If NULL cbRead bytes are read or an error is returned.
465 */
466RTR3DECL(int) RTStrmReadEx(PRTSTREAM pStream, void *pvBuf, size_t cbRead, size_t *pcbRead)
467{
468 int rc;
469 if (pStream && pStream->u32Magic == RTSTREAM_MAGIC)
470 {
471 rc = pStream->i32Error;
472 if (RT_SUCCESS(rc))
473 {
474 if (pcbRead)
475 {
476 /*
477 * Can do with a partial read.
478 */
479 *pcbRead = fread(pvBuf, 1, cbRead, pStream->pFile);
480 if ( *pcbRead == cbRead
481 || !ferror(pStream->pFile))
482 return VINF_SUCCESS;
483 if (feof(pStream->pFile))
484 {
485 if (*pcbRead)
486 return VINF_EOF;
487 rc = VERR_EOF;
488 }
489 else if (ferror(pStream->pFile))
490 rc = VERR_READ_ERROR;
491 else
492 {
493 AssertMsgFailed(("This shouldn't happen\n"));
494 rc = VERR_INTERNAL_ERROR;
495 }
496 }
497 else
498 {
499 /*
500 * Must read it all!
501 */
502 if (fread(pvBuf, cbRead, 1, pStream->pFile) == 1)
503 return VINF_SUCCESS;
504
505 /* possible error/eof. */
506 if (feof(pStream->pFile))
507 rc = VERR_EOF;
508 else if (ferror(pStream->pFile))
509 rc = VERR_READ_ERROR;
510 else
511 {
512 AssertMsgFailed(("This shouldn't happen\n"));
513 rc = VERR_INTERNAL_ERROR;
514 }
515 }
516 ASMAtomicXchgS32(&pStream->i32Error, rc);
517 }
518 }
519 else
520 {
521 AssertMsgFailed(("Invalid stream!\n"));
522 rc = VERR_INVALID_PARAMETER;
523 }
524 return rc;
525}
526
527
528/**
529 * Writes to a file stream.
530 *
531 * @returns iprt status code.
532 * @param pStream The stream.
533 * @param pvBuf Where to get the bits to write from.
534 * @param cbWrite Number of bytes to write.
535 * @param pcbWritten Where to store the number of bytes actually written.
536 * If NULL cbWrite bytes are written or an error is returned.
537 */
538RTR3DECL(int) RTStrmWriteEx(PRTSTREAM pStream, const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
539{
540 int rc;
541 if (pStream && pStream->u32Magic == RTSTREAM_MAGIC)
542 {
543 rc = pStream->i32Error;
544 if (RT_SUCCESS(rc))
545 {
546 if (pcbWritten)
547 {
548 IPRT_ALIGNMENT_CHECKS_DISABLE(); /* glibc / mempcpy again */
549 *pcbWritten = fwrite(pvBuf, 1, cbWrite, pStream->pFile);
550 IPRT_ALIGNMENT_CHECKS_ENABLE();
551 if ( *pcbWritten == cbWrite
552 || !ferror(pStream->pFile))
553 return VINF_SUCCESS;
554 rc = VERR_WRITE_ERROR;
555 }
556 else
557 {
558 /*
559 * Must write it all!
560 */
561 IPRT_ALIGNMENT_CHECKS_DISABLE(); /* glibc / mempcpy again */
562 size_t cbWritten = fwrite(pvBuf, cbWrite, 1, pStream->pFile);
563 IPRT_ALIGNMENT_CHECKS_ENABLE();
564 if (cbWritten == 1)
565 return VINF_SUCCESS;
566 if (!ferror(pStream->pFile))
567 return VINF_SUCCESS; /* WEIRD! But anyway... */
568
569 rc = VERR_WRITE_ERROR;
570 }
571 ASMAtomicXchgS32(&pStream->i32Error, rc);
572 }
573 }
574 else
575 {
576 AssertMsgFailed(("Invalid stream!\n"));
577 rc = VERR_INVALID_PARAMETER;
578 }
579 return rc;
580}
581
582
583/**
584 * Reads a character from a file stream.
585 *
586 * @returns The char as an unsigned char cast to int.
587 * @returns -1 on failure.
588 * @param pStream The stream.
589 */
590RTR3DECL(int) RTStrmGetCh(PRTSTREAM pStream)
591{
592 unsigned char ch;
593 int rc = RTStrmReadEx(pStream, &ch, 1, NULL);
594 if (RT_SUCCESS(rc))
595 return ch;
596 return -1;
597}
598
599
600/**
601 * Writes a character to a file stream.
602 *
603 * @returns iprt status code.
604 * @param pStream The stream.
605 * @param ch The char to write.
606 */
607RTR3DECL(int) RTStrmPutCh(PRTSTREAM pStream, int ch)
608{
609 return RTStrmWriteEx(pStream, &ch, 1, NULL);
610}
611
612
613/**
614 * Writes a string to a file stream.
615 *
616 * @returns iprt status code.
617 * @param pStream The stream.
618 * @param pszString The string to write.
619 * No newlines or anything is appended or prepended.
620 * The terminating '\\0' is not written, of course.
621 */
622RTR3DECL(int) RTStrmPutStr(PRTSTREAM pStream, const char *pszString)
623{
624 size_t cch = strlen(pszString);
625 return RTStrmWriteEx(pStream, pszString, cch, NULL);
626}
627
628
629/**
630 * Reads a line from a file stream.
631 * A line ends with a '\\n', '\\0' or the end of the file.
632 *
633 * @returns iprt status code.
634 * @returns VINF_BUFFER_OVERFLOW if the buffer wasn't big enough to read an entire line.
635 * @param pStream The stream.
636 * @param pszString Where to store the line.
637 * The line will *NOT* contain any '\\n'.
638 * @param cchString The size of the string buffer.
639 */
640RTR3DECL(int) RTStrmGetLine(PRTSTREAM pStream, char *pszString, size_t cchString)
641{
642 int rc;
643 if (pStream && pStream->u32Magic == RTSTREAM_MAGIC)
644 {
645 if (pszString && cchString > 1)
646 {
647 rc = pStream->i32Error;
648 if (RT_SUCCESS(rc))
649 {
650 cchString--; /* save space for the terminator. */
651 rtStrmLock(pStream);
652 for (;;)
653 {
654#ifdef HAVE_FWRITE_UNLOCKED /** @todo darwin + freebsd(?) has fgetc_unlocked but not fwrite_unlocked, optimize... */
655 int ch = fgetc_unlocked(pStream->pFile);
656#else
657 int ch = fgetc(pStream->pFile);
658#endif
659 if (ch == EOF)
660 {
661#ifdef HAVE_FWRITE_UNLOCKED
662 if (feof_unlocked(pStream->pFile))
663#else
664 if (feof(pStream->pFile))
665#endif
666 {
667 rc = VERR_EOF;
668 break;
669 }
670#ifdef HAVE_FWRITE_UNLOCKED
671 if (ferror_unlocked(pStream->pFile))
672#else
673 if (ferror(pStream->pFile))
674#endif
675 rc = VERR_READ_ERROR;
676 else
677 {
678 AssertMsgFailed(("This shouldn't happen\n"));
679 rc = VERR_INTERNAL_ERROR;
680 }
681 break;
682 }
683 if (ch == '\0' || ch == '\n' || ch == '\r')
684 break;
685 *pszString++ = ch;
686 if (--cchString <= 0)
687 {
688 rc = VINF_BUFFER_OVERFLOW;
689 break;
690 }
691 }
692 rtStrmUnlock(pStream);
693
694 *pszString = '\0';
695 if (RT_FAILURE(rc))
696 ASMAtomicXchgS32(&pStream->i32Error, rc);
697 }
698 }
699 else
700 {
701 AssertMsgFailed(("no buffer or too small buffer!\n"));
702 rc = VERR_INVALID_PARAMETER;
703 }
704 }
705 else
706 {
707 AssertMsgFailed(("Invalid stream!\n"));
708 rc = VERR_INVALID_PARAMETER;
709 }
710 return rc;
711}
712
713
714/**
715 * Flushes a stream.
716 *
717 * @returns iprt status code.
718 * @param pStream The stream to flush.
719 */
720RTR3DECL(int) RTStrmFlush(PRTSTREAM pStream)
721{
722 if (!fflush(pStream->pFile))
723 return VINF_SUCCESS;
724 return RTErrConvertFromErrno(errno);
725}
726
727
728/**
729 * Output callback.
730 *
731 * @returns number of bytes written.
732 * @param pvArg User argument.
733 * @param pachChars Pointer to an array of utf-8 characters.
734 * @param cchChars Number of bytes in the character array pointed to by pachChars.
735 */
736static DECLCALLBACK(size_t) rtstrmOutput(void *pvArg, const char *pachChars, size_t cchChars)
737{
738 if (cchChars)
739 {
740 PRTSTREAM pStream = (PRTSTREAM)pvArg;
741 int rc = pStream->i32Error;
742 if (RT_SUCCESS(rc))
743 {
744 IPRT_ALIGNMENT_CHECKS_DISABLE(); /* glibc / mempcpy again */
745#ifdef HAVE_FWRITE_UNLOCKED
746 if (fwrite_unlocked(pachChars, cchChars, 1, pStream->pFile) != 1)
747#else
748 if (fwrite(pachChars, cchChars, 1, pStream->pFile) != 1)
749#endif
750 ASMAtomicXchgS32(&pStream->i32Error, VERR_WRITE_ERROR);
751 IPRT_ALIGNMENT_CHECKS_ENABLE();
752 }
753 }
754 /* else: ignore termination call. */
755 return cchChars;
756}
757
758
759/**
760 * Prints a formatted string to the specified stream.
761 *
762 * @returns Number of bytes printed.
763 * @param pStream The stream to print to.
764 * @param pszFormat IPRT format string.
765 * @param args Arguments specified by pszFormat.
766 */
767RTR3DECL(int) RTStrmPrintfV(PRTSTREAM pStream, const char *pszFormat, va_list args)
768{
769 int rc;
770 if (pStream && pStream->u32Magic == RTSTREAM_MAGIC)
771 {
772 rc = pStream->i32Error;
773 if (RT_SUCCESS(rc))
774 {
775 rtStrmLock(pStream);
776 rc = (int)RTStrFormatV(rtstrmOutput, pStream, NULL, NULL, pszFormat, args);
777 rtStrmUnlock(pStream);
778 Assert(rc >= 0);
779 }
780 else
781 rc = -1;
782 }
783 else
784 {
785 AssertMsgFailed(("Invalid stream!\n"));
786 rc = -1;
787 }
788 return rc;
789}
790
791
792/**
793 * Prints a formatted string to the specified stream.
794 *
795 * @returns Number of bytes printed.
796 * @param pStream The stream to print to.
797 * @param pszFormat IPRT format string.
798 * @param ... Arguments specified by pszFormat.
799 */
800RTR3DECL(int) RTStrmPrintf(PRTSTREAM pStream, const char *pszFormat, ...)
801{
802 va_list args;
803 va_start(args, pszFormat);
804 int rc = RTStrmPrintfV(pStream, pszFormat, args);
805 va_end(args);
806 return rc;
807}
808
809
810/**
811 * Prints a formatted string to the standard output stream (g_pStdOut).
812 *
813 * @returns Number of bytes printed.
814 * @param pszFormat IPRT format string.
815 * @param args Arguments specified by pszFormat.
816 */
817RTR3DECL(int) RTPrintfV(const char *pszFormat, va_list args)
818{
819 return RTStrmPrintfV(g_pStdOut, pszFormat, args);
820}
821
822
823/**
824 * Prints a formatted string to the standard output stream (g_pStdOut).
825 *
826 * @returns Number of bytes printed.
827 * @param pszFormat IPRT format string.
828 * @param ... Arguments specified by pszFormat.
829 */
830RTR3DECL(int) RTPrintf(const char *pszFormat, ...)
831{
832 va_list args;
833 va_start(args, pszFormat);
834 int rc = RTStrmPrintfV(g_pStdOut, pszFormat, args);
835 va_end(args);
836 return rc;
837}
838
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette