blob: 1782417d94b277079aa981181ba8444104a17b96 [file] [log] [blame]
njnc44a6c22005-06-03 13:21:18 +00001
2/*--------------------------------------------------------------------*/
3/*--- Libc printing. m_libcprint.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
njn9f207462009-03-10 22:02:09 +000010 Copyright (C) 2000-2009 Julian Seward
njnc44a6c22005-06-03 13:21:18 +000011 jseward@acm.org
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29*/
30
njnc7561b92005-06-19 01:24:32 +000031#include "pub_core_basics.h"
sewardj4cfea4f2006-10-14 19:26:10 +000032#include "pub_core_vki.h"
njnc44a6c22005-06-03 13:21:18 +000033#include "pub_core_debuglog.h"
34#include "pub_core_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000035#include "pub_core_libcassert.h"
sewardj592ae092005-11-08 19:01:44 +000036#include "pub_core_libcfile.h" // VG_(write)(), VG_(write_socket)()
njnc44a6c22005-06-03 13:21:18 +000037#include "pub_core_libcprint.h"
sewardj592ae092005-11-08 19:01:44 +000038#include "pub_core_libcproc.h" // VG_(getpid)(), VG_(read_millisecond_timer()
njnc44a6c22005-06-03 13:21:18 +000039#include "pub_core_options.h"
njn24a6efb2005-06-20 03:36:51 +000040#include "valgrind.h" // For RUNNING_ON_VALGRIND
njnc44a6c22005-06-03 13:21:18 +000041
njnc44a6c22005-06-03 13:21:18 +000042
43/* ---------------------------------------------------------------------
44 Writing to file or a socket
45 ------------------------------------------------------------------ */
46
sewardj738856f2009-07-15 14:48:32 +000047/* The destination sinks for normal and XML output. These have their
48 initial values here; they are set to final values by
49 m_main.main_process_cmd_line_options(). See comment at the top of
50 that function for the associated logic. */
51OutputSink VG_(log_output_sink) = { 2, False }; /* 2 = stderr */
52OutputSink VG_(xml_output_sink) = { -1, False }; /* disabled */
53
njnc44a6c22005-06-03 13:21:18 +000054/* Do the low-level send of a message to the logging sink. */
sewardj738856f2009-07-15 14:48:32 +000055static
56void send_bytes_to_logging_sink ( OutputSink* sink, Char* msg, Int nbytes )
njnc44a6c22005-06-03 13:21:18 +000057{
sewardj738856f2009-07-15 14:48:32 +000058 if (sink->is_socket) {
59 Int rc = VG_(write_socket)( sink->fd, msg, nbytes );
60 if (rc == -1) {
61 // For example, the listener process died. Switch back to stderr.
62 sink->is_socket = False;
63 sink->fd = 2;
64 VG_(write)( sink->fd, msg, nbytes );
65 }
66 } else {
67 /* sink->fd could have been set to -1 in the various
sewardj6e31f802007-11-17 22:29:25 +000068 sys-wrappers for sys_fork, if --child-silent-after-fork=yes
69 is in effect. That is a signal that we should not produce
70 any more output. */
sewardj738856f2009-07-15 14:48:32 +000071 if (sink->fd >= 0)
72 VG_(write)( sink->fd, msg, nbytes );
njnc44a6c22005-06-03 13:21:18 +000073 }
74}
75
sewardj738856f2009-07-15 14:48:32 +000076
njnc44a6c22005-06-03 13:21:18 +000077/* ---------------------------------------------------------------------
78 printf() and friends
79 ------------------------------------------------------------------ */
80
sewardj738856f2009-07-15 14:48:32 +000081/* --------- printf --------- */
82
sewardj45f4e7c2005-09-27 19:20:21 +000083typedef
84 struct {
sewardj738856f2009-07-15 14:48:32 +000085 HChar buf[512];
86 Int buf_used;
87 OutputSink* sink;
sewardj45f4e7c2005-09-27 19:20:21 +000088 }
sewardj738856f2009-07-15 14:48:32 +000089 printf_buf_t;
bart1a0cb6a2008-04-14 16:35:32 +000090
njnc44a6c22005-06-03 13:21:18 +000091// Adds a single char to the buffer. When the buffer gets sufficiently
92// full, we write its contents to the logging sink.
sewardj738856f2009-07-15 14:48:32 +000093static void add_to__printf_buf ( HChar c, void *p )
njnc44a6c22005-06-03 13:21:18 +000094{
sewardj738856f2009-07-15 14:48:32 +000095 printf_buf_t *b = (printf_buf_t *)p;
njnc44a6c22005-06-03 13:21:18 +000096
sewardj738856f2009-07-15 14:48:32 +000097 if (b->buf_used > sizeof(b->buf) - 2 ) {
98 send_bytes_to_logging_sink( b->sink, b->buf, b->buf_used );
99 b->buf_used = 0;
njnc44a6c22005-06-03 13:21:18 +0000100 }
sewardj738856f2009-07-15 14:48:32 +0000101 b->buf[b->buf_used++] = c;
102 b->buf[b->buf_used] = 0;
103 tl_assert(b->buf_used < sizeof(b->buf));
104}
105
106static UInt vprintf_to_buf ( printf_buf_t* b,
107 const HChar *format, va_list vargs )
108{
109 UInt ret = 0;
110 if (b->sink->fd >= 0) {
111 ret = VG_(debugLog_vprintf)
112 ( add_to__printf_buf, b, format, vargs );
113 }
114 return ret;
115}
116
117static UInt vprintf_WRK ( OutputSink* sink,
118 const HChar *format, va_list vargs )
119{
120 printf_buf_t myprintf_buf
121 = { "", 0, sink };
122 UInt ret
123 = vprintf_to_buf(&myprintf_buf, format, vargs);
124 // Write out any chars left in the buffer.
125 if (myprintf_buf.buf_used > 0) {
126 send_bytes_to_logging_sink( myprintf_buf.sink,
127 myprintf_buf.buf,
128 myprintf_buf.buf_used );
129 }
130 return ret;
njnc44a6c22005-06-03 13:21:18 +0000131}
132
133UInt VG_(vprintf) ( const HChar *format, va_list vargs )
134{
sewardj738856f2009-07-15 14:48:32 +0000135 return vprintf_WRK( &VG_(log_output_sink), format, vargs );
njnc44a6c22005-06-03 13:21:18 +0000136}
137
138UInt VG_(printf) ( const HChar *format, ... )
139{
140 UInt ret;
141 va_list vargs;
njnc44a6c22005-06-03 13:21:18 +0000142 va_start(vargs, format);
143 ret = VG_(vprintf)(format, vargs);
144 va_end(vargs);
njnc44a6c22005-06-03 13:21:18 +0000145 return ret;
146}
147
sewardj738856f2009-07-15 14:48:32 +0000148UInt VG_(vprintf_xml) ( const HChar *format, va_list vargs )
149{
150 return vprintf_WRK( &VG_(xml_output_sink), format, vargs );
151}
152
153UInt VG_(printf_xml) ( const HChar *format, ... )
bart1a0cb6a2008-04-14 16:35:32 +0000154{
155 UInt ret;
156 va_list vargs;
bart1a0cb6a2008-04-14 16:35:32 +0000157 va_start(vargs, format);
sewardj738856f2009-07-15 14:48:32 +0000158 ret = VG_(vprintf_xml)(format, vargs);
bart1a0cb6a2008-04-14 16:35:32 +0000159 va_end(vargs);
bart1a0cb6a2008-04-14 16:35:32 +0000160 return ret;
161}
162
sewardj738856f2009-07-15 14:48:32 +0000163/* An exact clone of VG_(printf_xml), unfortunately. */
164UInt VG_(printf_xml_no_f_c) ( const HChar *format, ... )
njnc44a6c22005-06-03 13:21:18 +0000165{
sewardj738856f2009-07-15 14:48:32 +0000166 UInt ret;
167 va_list vargs;
168 va_start(vargs, format);
169 ret = VG_(vprintf_xml)(format, vargs);
170 va_end(vargs);
171 return ret;
172}
173
174
175/* --------- sprintf --------- */
176
177/* If we had an explicit buf structure here, it would contain only one
178 field, indicating where the next char is to go. So use p directly
179 for that, rather than having it be a pointer to a structure. */
180
181static void add_to__sprintf_buf ( HChar c, void *p )
182{
183 HChar** b = p;
184 *(*b)++ = c;
njnc44a6c22005-06-03 13:21:18 +0000185}
186
187UInt VG_(vsprintf) ( Char* buf, const HChar *format, va_list vargs )
188{
189 Int ret;
sewardj738856f2009-07-15 14:48:32 +0000190 HChar* sprintf_ptr = buf;
njnc44a6c22005-06-03 13:21:18 +0000191
192 ret = VG_(debugLog_vprintf)
sewardj738856f2009-07-15 14:48:32 +0000193 ( add_to__sprintf_buf, &sprintf_ptr, format, vargs );
194 add_to__sprintf_buf('\0', &sprintf_ptr);
njnc44a6c22005-06-03 13:21:18 +0000195
196 vg_assert(VG_(strlen)(buf) == ret);
197
198 return ret;
199}
200
201UInt VG_(sprintf) ( Char* buf, const HChar *format, ... )
202{
203 UInt ret;
204 va_list vargs;
njnc44a6c22005-06-03 13:21:18 +0000205 va_start(vargs,format);
206 ret = VG_(vsprintf)(buf, format, vargs);
207 va_end(vargs);
njnc44a6c22005-06-03 13:21:18 +0000208 return ret;
209}
210
sewardj45f4e7c2005-09-27 19:20:21 +0000211
sewardj738856f2009-07-15 14:48:32 +0000212/* --------- snprintf --------- */
213
sewardj45f4e7c2005-09-27 19:20:21 +0000214typedef
215 struct {
216 HChar* buf;
217 Int buf_size;
218 Int buf_used;
219 }
sewardj738856f2009-07-15 14:48:32 +0000220 snprintf_buf_t;
sewardj45f4e7c2005-09-27 19:20:21 +0000221
sewardj738856f2009-07-15 14:48:32 +0000222static void add_to__snprintf_buf ( HChar c, void* p )
sewardj45f4e7c2005-09-27 19:20:21 +0000223{
sewardj738856f2009-07-15 14:48:32 +0000224 snprintf_buf_t* b = p;
sewardj45f4e7c2005-09-27 19:20:21 +0000225 if (b->buf_size > 0 && b->buf_used < b->buf_size) {
226 b->buf[b->buf_used++] = c;
227 if (b->buf_used < b->buf_size)
228 b->buf[b->buf_used] = 0;
sewardj03e2bb82006-12-24 03:02:18 +0000229 else
230 b->buf[b->buf_size-1] = 0; /* pre: b->buf_size > 0 */
sewardj45f4e7c2005-09-27 19:20:21 +0000231 }
232}
233
234UInt VG_(vsnprintf) ( Char* buf, Int size, const HChar *format, va_list vargs )
235{
236 Int ret;
sewardj738856f2009-07-15 14:48:32 +0000237 snprintf_buf_t b;
sewardj45f4e7c2005-09-27 19:20:21 +0000238 b.buf = buf;
239 b.buf_size = size < 0 ? 0 : size;
240 b.buf_used = 0;
241
242 ret = VG_(debugLog_vprintf)
sewardj738856f2009-07-15 14:48:32 +0000243 ( add_to__snprintf_buf, &b, format, vargs );
sewardj45f4e7c2005-09-27 19:20:21 +0000244
245 return b.buf_used;
246}
247
248UInt VG_(snprintf) ( Char* buf, Int size, const HChar *format, ... )
249{
250 UInt ret;
251 va_list vargs;
sewardj45f4e7c2005-09-27 19:20:21 +0000252 va_start(vargs,format);
253 ret = VG_(vsnprintf)(buf, size, format, vargs);
254 va_end(vargs);
sewardj45f4e7c2005-09-27 19:20:21 +0000255 return ret;
256}
257
258
sewardj738856f2009-07-15 14:48:32 +0000259/* --------- vcbprintf --------- */
260
261void VG_(vcbprintf)( void(*char_sink)(HChar, void* opaque),
262 void* opaque,
263 const HChar* format, va_list vargs )
264{
265 (void) VG_(debugLog_vprintf)
266 ( char_sink, opaque, format, vargs );
267}
268
269
njnc44a6c22005-06-03 13:21:18 +0000270/* ---------------------------------------------------------------------
njn856c54e2005-06-26 18:43:40 +0000271 percentify()
272 ------------------------------------------------------------------ */
273
njn7a5915e2005-07-17 16:12:59 +0000274// Percentify n/m with d decimal places. Includes the '%' symbol at the end.
njn5eaff2f2005-09-25 19:11:45 +0000275// Right justifies in 'buf'.
276void VG_(percentify)(ULong n, ULong m, UInt d, Int n_buf, char buf[])
njn856c54e2005-06-26 18:43:40 +0000277{
278 Int i, len, space;
njn641e6162005-07-17 16:16:41 +0000279 ULong p1;
njn5eaff2f2005-09-25 19:11:45 +0000280 Char fmt[32];
njn856c54e2005-06-26 18:43:40 +0000281
njn641e6162005-07-17 16:16:41 +0000282 if (m == 0) {
njn5eaff2f2005-09-25 19:11:45 +0000283 // Have to generate the format string in order to be flexible about
284 // the width of the field.
njn8a7b41b2007-09-23 00:51:24 +0000285 VG_(sprintf)(fmt, "%%-%ds", n_buf);
njn5eaff2f2005-09-25 19:11:45 +0000286 // fmt is now "%<n_buf>s" where <d> is 1,2,3...
287 VG_(sprintf)(buf, fmt, "--%");
njn641e6162005-07-17 16:16:41 +0000288 return;
289 }
290
291 p1 = (100*n) / m;
njn856c54e2005-06-26 18:43:40 +0000292
293 if (d == 0) {
294 VG_(sprintf)(buf, "%lld%%", p1);
295 } else {
296 ULong p2;
297 UInt ex;
njn856c54e2005-06-26 18:43:40 +0000298 switch (d) {
299 case 1: ex = 10; break;
300 case 2: ex = 100; break;
301 case 3: ex = 1000; break;
302 default: VG_(tool_panic)("Currently can only handle 3 decimal places");
303 }
304 p2 = ((100*n*ex) / m) % ex;
305 // Have to generate the format string in order to be flexible about
306 // the width of the post-decimal-point part.
307 VG_(sprintf)(fmt, "%%lld.%%0%dlld%%%%", d);
308 // fmt is now "%lld.%0<d>lld%%" where <d> is 1,2,3...
309 VG_(sprintf)(buf, fmt, p1, p2);
310 }
311
312 len = VG_(strlen)(buf);
313 space = n_buf - len;
314 if (space < 0) space = 0; /* Allow for v. small field_width */
315 i = len;
316
317 /* Right justify in field */
318 for ( ; i >= 0; i--) buf[i + space] = buf[i];
319 for (i = 0; i < space; i++) buf[i] = ' ';
320}
321
sewardja11553a2005-07-19 12:17:05 +0000322
323/* ---------------------------------------------------------------------
sewardj592ae092005-11-08 19:01:44 +0000324 elapsed_wallclock_time()
sewardja11553a2005-07-19 12:17:05 +0000325 ------------------------------------------------------------------ */
326
sewardj592ae092005-11-08 19:01:44 +0000327/* Get the elapsed wallclock time since startup into buf, which must
328 16 chars long. This is unchecked. It also relies on the
329 millisecond timer having been set to zero by an initial read in
330 m_main during startup. */
sewardja11553a2005-07-19 12:17:05 +0000331
sewardj592ae092005-11-08 19:01:44 +0000332void VG_(elapsed_wallclock_time) ( /*OUT*/HChar* buf )
sewardja11553a2005-07-19 12:17:05 +0000333{
sewardj592ae092005-11-08 19:01:44 +0000334 UInt t, ms, s, mins, hours, days;
335
336 t = VG_(read_millisecond_timer)(); /* milliseconds */
337
338 ms = t % 1000;
339 t /= 1000; /* now in seconds */
340
341 s = t % 60;
342 t /= 60; /* now in minutes */
343
344 mins = t % 60;
345 t /= 60; /* now in hours */
346
347 hours = t % 24;
348 t /= 24; /* now in days */
349
350 days = t;
351
njn82baca72009-07-24 05:35:49 +0000352 VG_(sprintf)(buf, "%02u:%02u:%02u:%02u.%03u ", days, hours, mins, s, ms);
sewardja11553a2005-07-19 12:17:05 +0000353}
354
355
njn856c54e2005-06-26 18:43:40 +0000356/* ---------------------------------------------------------------------
njnc44a6c22005-06-03 13:21:18 +0000357 message()
358 ------------------------------------------------------------------ */
359
sewardj738856f2009-07-15 14:48:32 +0000360/* A buffer for accumulating VG_(message) style output. This is
361 pretty much the same as VG_(printf)'s scheme, with two differences:
362
363 * The message buffer persists between calls, so that multiple
364 calls to VG_(message) can build up output.
365
366 * Whenever the first character on a line is emitted, the
367 ==PID== style preamble is stuffed in before it.
368*/
369typedef
370 struct {
371 HChar buf[512+128];
372 Int buf_used;
373 Bool atLeft; /* notionally, is the next char position at the
374 leftmost column? */
375 /* Current message kind - changes from call to call */
376 VgMsgKind kind;
377 /* PID; acquired just once and stays constant */
378 Int my_pid;
379 /* destination */
380 OutputSink* sink;
381 }
382 vmessage_buf_t;
383
384static vmessage_buf_t vmessage_buf
385 = { "", 0, True, Vg_UserMsg, -1, &VG_(log_output_sink) };
386
387
388// Adds a single char to the buffer. We aim to have at least 128
389// bytes free in the buffer, so that it's always possible to emit
390// the preamble into the buffer if c happens to be the character
391// following a \n. When the buffer gets too full, we write its
392// contents to the logging sink.
393static void add_to__vmessage_buf ( HChar c, void *p )
394{
395 HChar tmp[64];
396 vmessage_buf_t* b = (vmessage_buf_t*)p;
397
398 vg_assert(b->buf_used >= 0 && b->buf_used < sizeof(b->buf)-128);
399
400 if (UNLIKELY(b->atLeft)) {
401 // insert preamble
402 HChar ch;
403 Int i, depth;
404
405 switch (b->kind) {
406 case Vg_UserMsg: ch = '='; break;
407 case Vg_DebugMsg: ch = '-'; break;
408 case Vg_DebugExtraMsg: ch = '+'; break;
409 case Vg_ClientMsg: ch = '*'; break;
410 default: ch = '?'; break;
411 }
412
413 // Print one '>' in front of the messages for each level of
414 // self-hosting being performed.
415 depth = RUNNING_ON_VALGRIND;
416 if (depth > 10)
417 depth = 10; // ?!?!
418 for (i = 0; i < depth; i++) {
419 b->buf[b->buf_used++] = '>';
420 }
421
422 b->buf[b->buf_used++] = ch;
423 b->buf[b->buf_used++] = ch;
424
425 if (VG_(clo_time_stamp)) {
426 VG_(memset)(tmp, 0, sizeof(tmp));
427 VG_(elapsed_wallclock_time)(tmp);
428 tmp[sizeof(tmp)-1] = 0;
429 for (i = 0; tmp[i]; i++)
430 b->buf[b->buf_used++] = tmp[i];
431 }
432
433 VG_(sprintf)(tmp, "%d", b->my_pid);
434 tmp[sizeof(tmp)-1] = 0;
435 for (i = 0; tmp[i]; i++)
436 b->buf[b->buf_used++] = tmp[i];
437
438 b->buf[b->buf_used++] = ch;
439 b->buf[b->buf_used++] = ch;
440 b->buf[b->buf_used++] = ' ';
441
442 /* We can't possibly have stuffed 96 chars in merely as a result
443 of making the preamble (can we?) */
444 vg_assert(b->buf_used < sizeof(b->buf)-32);
445 }
446
447 b->buf[b->buf_used++] = c;
448 b->buf[b->buf_used] = 0;
449
450 if (b->buf_used >= sizeof(b->buf) - 128) {
451 send_bytes_to_logging_sink( b->sink, b->buf, b->buf_used );
452 b->buf_used = 0;
453 }
454
455 b->atLeft = c == '\n';
456}
457
458
njnc44a6c22005-06-03 13:21:18 +0000459UInt VG_(vmessage) ( VgMsgKind kind, const HChar* format, va_list vargs )
460{
sewardj738856f2009-07-15 14:48:32 +0000461 UInt ret;
njnc44a6c22005-06-03 13:21:18 +0000462
sewardj738856f2009-07-15 14:48:32 +0000463 /* Note (carefully) that the buf persists from call to call, unlike
464 with the other printf variants in earlier parts of this file. */
465 vmessage_buf_t* b = &vmessage_buf; /* shorthand for convenience */
466
467 /* We have to set this each call, so that the correct flavour
468 of preamble is emitted at each \n. */
469 b->kind = kind;
470
471 /* Cache the results of getpid just once, so we don't have to call
472 getpid once for each line of text output. */
473 if (UNLIKELY(b->my_pid == -1)) {
474 b->my_pid = VG_(getpid)();
475 vg_assert(b->my_pid >= 0);
njnc44a6c22005-06-03 13:21:18 +0000476 }
477
sewardj738856f2009-07-15 14:48:32 +0000478 ret = VG_(debugLog_vprintf) ( add_to__vmessage_buf,
479 b, format, vargs );
njnc44a6c22005-06-03 13:21:18 +0000480
sewardj738856f2009-07-15 14:48:32 +0000481 /* If the message finished exactly with a \n, then flush it at this
482 point. If not, assume more bits of the same line will turn up
483 in later messages, so don't bother to flush it right now. */
484
485 if (b->atLeft && b->buf_used > 0) {
486 send_bytes_to_logging_sink( b->sink, b->buf, b->buf_used );
487 b->buf_used = 0;
njnc44a6c22005-06-03 13:21:18 +0000488 }
489
sewardj738856f2009-07-15 14:48:32 +0000490 return ret;
njnc44a6c22005-06-03 13:21:18 +0000491}
492
barta0b6b2c2008-07-07 06:49:24 +0000493/* Send a simple single-part XML message. */
494UInt VG_(message_no_f_c) ( VgMsgKind kind, const HChar* format, ... )
495{
496 UInt count;
497 va_list vargs;
498 va_start(vargs,format);
499 count = VG_(vmessage) ( kind, format, vargs );
500 va_end(vargs);
501 return count;
502}
503
njnc44a6c22005-06-03 13:21:18 +0000504/* Send a simple single-part message. */
505UInt VG_(message) ( VgMsgKind kind, const HChar* format, ... )
506{
507 UInt count;
508 va_list vargs;
509 va_start(vargs,format);
510 count = VG_(vmessage) ( kind, format, vargs );
511 va_end(vargs);
512 return count;
513}
514
sewardj738856f2009-07-15 14:48:32 +0000515/* VG_(message) variants with hardwired first argument. */
516UInt VG_(umsg) ( const HChar* format, ... )
517{
518 UInt count;
519 va_list vargs;
520 va_start(vargs,format);
521 count = VG_(vmessage) ( Vg_UserMsg, format, vargs );
522 va_end(vargs);
523 return count;
524}
525
526UInt VG_(dmsg) ( const HChar* format, ... )
527{
528 UInt count;
529 va_list vargs;
530 va_start(vargs,format);
531 count = VG_(vmessage) ( Vg_DebugMsg, format, vargs );
532 va_end(vargs);
533 return count;
534}
535
536UInt VG_(emsg) ( const HChar* format, ... )
537{
538 UInt count;
539 va_list vargs;
540 va_start(vargs,format);
541 count = VG_(vmessage) ( Vg_DebugExtraMsg, format, vargs );
542 va_end(vargs);
543 return count;
544}
545
546/* Flush any output that has accumulated in vmessage_buf as a
547 result of previous calls to VG_(message) et al. */
548void VG_(message_flush) ( void )
549{
550 vmessage_buf_t* b = &vmessage_buf;
551 send_bytes_to_logging_sink( b->sink, b->buf, b->buf_used );
552 b->buf_used = 0;
553}
554
555
njnc44a6c22005-06-03 13:21:18 +0000556/*--------------------------------------------------------------------*/
557/*--- end ---*/
558/*--------------------------------------------------------------------*/
559