]> mj.ucw.cz Git - libucw.git/blob - ucw/ff-printf.c
Opt: Make OPT_LAST_ARG actually work and document interface of opt_parse()
[libucw.git] / ucw / ff-printf.c
1 /*
2  *      UCW Library -- Printf on Fastbuf Streams
3  *
4  *      (c) 2002--2013 Martin Mares <mj@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU Lesser General Public License.
8  */
9
10 #include <ucw/lib.h>
11 #include <ucw/fastbuf.h>
12 #include <ucw/resource.h>
13
14 #include <stdio.h>
15 #include <stdbool.h>
16 #include <alloca.h>
17
18 int
19 vbprintf(struct fastbuf *b, const char *msg, va_list args)
20 {
21   byte *buf;
22   int remains, len;
23   va_list args2;
24
25   va_copy(args2, args);
26   remains = bdirect_write_prepare(b, &buf);
27   len = vsnprintf(buf, remains, msg, args2);
28   va_end(args2);
29
30   if (len <= remains)
31     {
32       bdirect_write_commit(b, buf + len);
33       return len;
34     }
35
36   /*
37    *  We need a temporary buffer. If it is small, let's use stack.
38    *  Otherwise, we malloc it, but we have to be careful, since we
39    *  might be running inside a transaction and bwrite() could
40    *  throw an exception.
41    *
42    *  FIXME: This deserves a more systematic solution, the same
43    *  problem is likely to happen at other places, too.
44    */
45   int bufsize = len + 1;
46   struct resource *res = NULL;
47   byte *extra_buffer = NULL;
48   if (bufsize <= 256)
49     buf = alloca(bufsize);
50   else if (rp_current())
51     buf = res_malloc(bufsize, &res);
52   else
53     buf = extra_buffer = xmalloc(bufsize);
54
55   vsnprintf(buf, bufsize, msg, args);
56   bwrite(b, buf, len);
57
58   if (res)
59     res_free(res);
60   else if (extra_buffer)
61     xfree(extra_buffer);
62   return len;
63 }
64
65 int
66 bprintf(struct fastbuf *b, const char *msg, ...)
67 {
68   va_list args;
69   int res;
70
71   va_start(args, msg);
72   res = vbprintf(b, msg, args);
73   va_end(args);
74   return res;
75 }
76
77 #ifdef TEST
78
79 int main(void)
80 {
81   struct fastbuf *b = bfdopen_shared(1, 65536);
82   for (int i=0; i<10000; i++)
83     bprintf(b, "13=%d str=<%s> msg=%m\n", 13, "str");
84   bclose(b);
85   return 0;
86 }
87
88 #endif