virbuffer.c 19.1 KB
Newer Older
D
Daniel Veillard 已提交
1
/*
2
 * virbuffer.c: buffers for libvirt
D
Daniel Veillard 已提交
3
 *
4
 * Copyright (C) 2005-2008, 2010-2015 Red Hat, Inc.
D
Daniel Veillard 已提交
5
 *
O
Osier Yang 已提交
6 7 8 9 10 11 12 13 14 15 16
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library.  If not, see
O
Osier Yang 已提交
18
 * <http://www.gnu.org/licenses/>.
D
Daniel Veillard 已提交
19 20 21 22
 *
 * Daniel Veillard <veillard@redhat.com>
 */

23
#include <config.h>
J
Jim Meyering 已提交
24

D
Daniel Veillard 已提交
25 26 27 28
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
J
Jim Meyering 已提交
29
#include "c-ctype.h"
30

31 32
#define __VIR_BUFFER_C__

33
#include "virbuffer.h"
34
#include "viralloc.h"
J
Ján Tomko 已提交
35
#include "virerror.h"
D
Daniel Veillard 已提交
36

37 38 39 40 41 42

/* If adding more fields, ensure to edit buf.h to match
   the number of fields */
struct _virBuffer {
    unsigned int size;
    unsigned int use;
E
Eric Blake 已提交
43
    unsigned int error; /* errno value, or -1 for usage error */
E
Eric Blake 已提交
44
    int indent;
45 46 47 48 49 50
    char *content;
};

/**
 * virBufferFail
 * @buf: the buffer
E
Eric Blake 已提交
51
 * @error: which error occurred (errno value, or -1 for usage)
52
 *
E
Eric Blake 已提交
53
 * Mark the buffer as failed, free the content and set the error flag.
54 55
 */
static void
E
Eric Blake 已提交
56
virBufferSetError(virBufferPtr buf, int error)
57
{
58
    VIR_FREE(buf->content);
59 60
    buf->size = 0;
    buf->use = 0;
E
Eric Blake 已提交
61
    buf->indent = 0;
E
Eric Blake 已提交
62
    buf->error = error;
63 64
}

E
Eric Blake 已提交
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
/**
 * virBufferAdjustIndent:
 * @buf: the buffer
 * @indent: adjustment to make
 *
 * Alter the auto-indent value by adding indent (positive to increase,
 * negative to decrease).  Automatic indentation is performed by all
 * additive functions when the existing buffer is empty or ends with a
 * newline (however, note that no indentation is added after newlines
 * embedded in an appended string).  If @indent would cause overflow,
 * the buffer error indicator is set.
 */
void
virBufferAdjustIndent(virBufferPtr buf, int indent)
{
    if (!buf || buf->error)
        return;
    if (indent > 0 ? INT_MAX - indent < buf->indent
        : buf->indent < -indent) {
        virBufferSetError(buf, -1);
        return;
    }
    buf->indent += indent;
}

/**
 * virBufferGetIndent:
 * @buf: the buffer
 * @dynamic: if false, return set value; if true, return 0 unless next
 * append would be affected by auto-indent
 *
 * Return the current auto-indent value, or -1 if there has been an error.
 */
int
99
virBufferGetIndent(const virBuffer *buf, bool dynamic)
E
Eric Blake 已提交
100 101 102 103 104 105 106 107
{
    if (!buf || buf->error)
        return -1;
    if (dynamic && buf->use && buf->content[buf->use - 1] != '\n')
        return 0;
    return buf->indent;
}

D
Daniel Veillard 已提交
108
/**
D
Daniel P. Berrange 已提交
109
 * virBufferGrow:
E
Eric Blake 已提交
110 111
 * @buf: the buffer
 * @len: the minimum free size to allocate on top of existing used space
D
Daniel Veillard 已提交
112
 *
113
 * Grow the available space of a buffer to at least @len bytes.
D
Daniel Veillard 已提交
114
 *
115
 * Returns zero on success or -1 on error
D
Daniel Veillard 已提交
116 117
 */
static int
D
Daniel P. Berrange 已提交
118
virBufferGrow(virBufferPtr buf, unsigned int len)
D
Daniel Veillard 已提交
119 120 121
{
    int size;

122 123 124 125 126
    if (buf->error)
        return -1;

    if ((len + buf->use) < buf->size)
        return 0;
D
Daniel Veillard 已提交
127 128 129

    size = buf->use + len + 1000;

130
    if (VIR_REALLOC_N_QUIET(buf->content, size) < 0) {
E
Eric Blake 已提交
131
        virBufferSetError(buf, errno);
132 133
        return -1;
    }
D
Daniel Veillard 已提交
134
    buf->size = size;
135
    return 0;
D
Daniel Veillard 已提交
136 137 138
}

/**
D
Daniel P. Berrange 已提交
139
 * virBufferAdd:
E
Eric Blake 已提交
140 141 142
 * @buf: the buffer to append to
 * @str: the string
 * @len: the number of bytes to add, or -1
D
Daniel Veillard 已提交
143
 *
E
Eric Blake 已提交
144 145
 * Add a string range to an XML buffer. If @len == -1, the length of
 * str is recomputed to the full string.  Auto indentation may be applied.
D
Daniel Veillard 已提交
146 147
 *
 */
148
void
E
Eric Blake 已提交
149
virBufferAdd(virBufferPtr buf, const char *str, int len)
D
Daniel Veillard 已提交
150 151
{
    unsigned int needSize;
E
Eric Blake 已提交
152
    int indent;
D
Daniel Veillard 已提交
153

E
Eric Blake 已提交
154
    if (!str || !buf || (len == 0 && buf->indent == 0))
155 156
        return;

E
Eric Blake 已提交
157
    indent = virBufferGetIndent(buf, true);
158 159
    if (indent < 0)
        return;
E
Eric Blake 已提交
160

D
Daniel Veillard 已提交
161 162 163
    if (len < 0)
        len = strlen(str);

E
Eric Blake 已提交
164
    needSize = buf->use + indent + len + 2;
165
    if (virBufferGrow(buf, needSize - buf->use) < 0)
166
        return;
167

E
Eric Blake 已提交
168 169 170
    memset(&buf->content[buf->use], ' ', indent);
    memcpy(&buf->content[buf->use + indent], str, len);
    buf->use += indent + len;
171
    buf->content[buf->use] = '\0';
D
Daniel Veillard 已提交
172 173
}

174 175 176 177 178 179 180 181 182
/**
 * virBufferAddBuffer:
 * @buf: the buffer to append to
 * @toadd: the buffer to append
 *
 * Add a buffer into another buffer without need to go through:
 * virBufferContentAndReset(), virBufferAdd(). Auto indentation
 * is (intentionally) NOT applied!
 *
183
 * The @toadd virBuffer is consumed and cleared.
184 185 186 187
 */
void
virBufferAddBuffer(virBufferPtr buf, virBufferPtr toadd)
{
188
    if (!toadd)
189 190
        return;

191 192 193
    if (!buf)
        goto done;

194 195 196
    if (buf->error || toadd->error) {
        if (!buf->error)
            buf->error = toadd->error;
197
        goto done;
198 199
    }

C
Chen Hanxiao 已提交
200
    if (virBufferGrow(buf, toadd->use) < 0)
201
        goto done;
202 203 204 205

    memcpy(&buf->content[buf->use], toadd->content, toadd->use);
    buf->use += toadd->use;
    buf->content[buf->use] = '\0';
206 207

 done:
208 209 210
    virBufferFreeAndReset(toadd);
}

211 212
/**
 * virBufferAddChar:
E
Eric Blake 已提交
213
 * @buf: the buffer to append to
214 215
 * @c: the character to add
 *
E
Eric Blake 已提交
216
 * Add a single character 'c' to a buffer.  Auto indentation may be applied.
217 218
 *
 */
219
void
E
Eric Blake 已提交
220
virBufferAddChar(virBufferPtr buf, char c)
221
{
E
Eric Blake 已提交
222
    virBufferAdd(buf, &c, 1);
223 224
}

225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
/**
 * virBufferCurrentContent:
 * @buf: Buffer
 *
 * Get the current content from the buffer.  The content is only valid
 * until the next operation on @buf, and an empty string is returned if
 * no content is present yet.
 *
 * Returns the buffer content or NULL in case of error.
 */
const char *
virBufferCurrentContent(virBufferPtr buf)
{
    if (!buf || buf->error)
        return NULL;
    return buf->use ? buf->content : "";
}

243
/**
244 245
 * virBufferContentAndReset:
 * @buf: Buffer
246
 *
247 248
 * Get the content from the buffer and free (only) the buffer structure.
 * The caller owns the returned string & should free it when no longer
249 250 251
 * required. The buffer object is reset to its initial state.  This
 * interface intentionally returns NULL instead of an empty string if
 * there is no content.
252
 *
253
 * Returns the buffer content or NULL in case of error.
254
 */
255
char *
E
Eric Blake 已提交
256
virBufferContentAndReset(virBufferPtr buf)
D
Daniel Veillard 已提交
257
{
258 259 260
    char *str;
    if (buf == NULL)
        return NULL;
D
Daniel Veillard 已提交
261

262 263
    if (buf->error) {
        memset(buf, 0, sizeof(*buf));
D
Daniel Veillard 已提交
264 265 266
        return NULL;
    }

267 268 269
    str = buf->content;
    memset(buf, 0, sizeof(*buf));
    return str;
D
Daniel Veillard 已提交
270 271
}

272 273 274 275 276 277
/**
 * virBufferFreeAndReset:
 * @buf: the buffer to free and reset
 *
 * Frees the buffer content and resets the buffer structure.
 */
E
Eric Blake 已提交
278
void virBufferFreeAndReset(virBufferPtr buf)
279 280 281 282 283 284
{
    char *str = virBufferContentAndReset(buf);

    VIR_FREE(str);
}

285
/**
286 287
 * virBufferError:
 * @buf: the buffer
288
 *
289
 * Check to see if the buffer is in an error state due
E
Eric Blake 已提交
290
 * to failed memory allocation or usage error
291
 *
E
Eric Blake 已提交
292
 * Return positive errno value or -1 on usage error, 0 if normal
293
 */
294
int
295
virBufferError(const virBuffer *buf)
D
Daniel Veillard 已提交
296
{
297
    if (buf == NULL)
E
Eric Blake 已提交
298
        return -1;
299 300

    return buf->error;
D
Daniel Veillard 已提交
301 302
}

J
Ján Tomko 已提交
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
/**
 * virBufferCheckErrorInternal:
 * @buf: the buffer
 *
 * Report an error if the buffer is in an error state.
 *
 * Return -1 if an error has been reported, 0 otherwise.
 */
int
virBufferCheckErrorInternal(const virBuffer *buf,
                            int domcode,
                            const char *filename,
                            const char *funcname,
                            size_t linenr)
{
    if (buf->error == 0)
        return 0;

    if (buf->error == ENOMEM) {
        virReportOOMErrorFull(domcode, filename, funcname, linenr);
        errno = ENOMEM;
    } else {
        virReportErrorHelper(domcode, VIR_ERR_INTERNAL_ERROR, filename,
                             funcname, linenr, "%s",
                             _("Invalid buffer API usage"));
        errno = EINVAL;
    }
    return -1;
}

D
Daniel Veillard 已提交
333
/**
334 335
 * virBufferUse:
 * @buf: the usage of the string in the buffer
D
Daniel Veillard 已提交
336
 *
337
 * Return the string usage in bytes
D
Daniel Veillard 已提交
338
 */
339
unsigned int
340
virBufferUse(const virBuffer *buf)
D
Daniel Veillard 已提交
341
{
342
    if (buf == NULL)
343
        return 0;
D
Daniel Veillard 已提交
344

345
    return buf->use;
D
Daniel Veillard 已提交
346 347 348
}

/**
349
 * virBufferAsprintf:
E
Eric Blake 已提交
350
 * @buf: the buffer to append to
E
Eric Blake 已提交
351 352
 * @format: the format
 * @...: the variable list of arguments
D
Daniel Veillard 已提交
353
 *
E
Eric Blake 已提交
354
 * Do a formatted print to an XML buffer.  Auto indentation may be applied.
D
Daniel Veillard 已提交
355
 */
356
void
E
Eric Blake 已提交
357
virBufferAsprintf(virBufferPtr buf, const char *format, ...)
D
Daniel Veillard 已提交
358
{
359
    va_list argptr;
E
Eric Blake 已提交
360 361 362 363 364 365 366
    va_start(argptr, format);
    virBufferVasprintf(buf, format, argptr);
    va_end(argptr);
}

/**
 * virBufferVasprintf:
E
Eric Blake 已提交
367
 * @buf: the buffer to append to
E
Eric Blake 已提交
368 369
 * @format: the format
 * @argptr: the variable list of arguments
E
Eric Blake 已提交
370
 *
E
Eric Blake 已提交
371
 * Do a formatted print to an XML buffer.  Auto indentation may be applied.
E
Eric Blake 已提交
372 373
 */
void
E
Eric Blake 已提交
374
virBufferVasprintf(virBufferPtr buf, const char *format, va_list argptr)
E
Eric Blake 已提交
375 376 377
{
    int size, count, grow_size;
    va_list copy;
D
Daniel Veillard 已提交
378

379 380 381 382 383
    if ((format == NULL) || (buf == NULL))
        return;

    if (buf->error)
        return;
384

E
Eric Blake 已提交
385 386
    virBufferAddLit(buf, ""); /* auto-indent */

387 388
    if (buf->size == 0 &&
        virBufferGrow(buf, 100) < 0)
389
        return;
390

E
Eric Blake 已提交
391
    va_copy(copy, argptr);
392 393 394

    size = buf->size - buf->use;
    if ((count = vsnprintf(&buf->content[buf->use],
E
Eric Blake 已提交
395
                           size, format, copy)) < 0) {
E
Eric Blake 已提交
396
        virBufferSetError(buf, errno);
E
Eric Blake 已提交
397 398
        va_end(copy);
        return;
399
    }
E
Eric Blake 已提交
400
    va_end(copy);
401 402 403

    /* Grow buffer if necessary and retry */
    if (count >= size) {
D
Daniel Veillard 已提交
404
        buf->content[buf->use] = 0;
405

406
        grow_size = (count + 1 > 1000) ? count + 1 : 1000;
407
        if (virBufferGrow(buf, grow_size) < 0)
E
Eric Blake 已提交
408
            return;
409

410 411 412
        size = buf->size - buf->use;
        if ((count = vsnprintf(&buf->content[buf->use],
                               size, format, argptr)) < 0) {
E
Eric Blake 已提交
413
            virBufferSetError(buf, errno);
E
Eric Blake 已提交
414
            return;
415
        }
D
Daniel Veillard 已提交
416 417 418 419
    }
    buf->use += count;
}

P
Pavel Hrdina 已提交
420 421 422 423 424 425 426 427 428
/* Work around spurious strchr() diagnostics given by -Wlogical-op
 * for gcc < 4.6.  Doing it via a local pragma keeps the damage
 * smaller than disabling it on the package level.  Unfortunately, the
 * affected GCCs don't allow diagnostic push/pop which would have
 * further reduced the impact. */
#if BROKEN_GCC_WLOGICALOP
# pragma GCC diagnostic ignored "-Wlogical-op"
#endif

429 430
/**
 * virBufferEscapeString:
E
Eric Blake 已提交
431
 * @buf: the buffer to append to
432
 * @format: a printf like format string but with only one %s parameter
E
Eric Blake 已提交
433
 * @str: the string argument which needs to be escaped
434
 *
E
Eric Blake 已提交
435 436 437 438
 * Do a formatted print with a single string to an XML buffer. The
 * string is escaped for use in XML.  If @str is NULL, nothing is
 * added (not even the rest of @format).  Auto indentation may be
 * applied.
439
 */
440
void
E
Eric Blake 已提交
441
virBufferEscapeString(virBufferPtr buf, const char *format, const char *str)
442
{
443
    int len;
444 445
    char *escaped, *out;
    const char *cur;
446 447 448 449 450 451 452
    const char forbidden_characters[] = {
        0x01,   0x02,   0x03,   0x04,   0x05,   0x06,   0x07,   0x08,
        /*\t*/  /*\n*/  0x0B,   0x0C,   /*\r*/  0x0E,   0x0F,   0x10,
        0x11,   0x12,   0x13,   0x14,   0x15,   0x16,   0x17,   0x18,
        0x19,   '"',    '&',    '\'',   '<',    '>',
        '\0'
    };
453

454 455 456 457 458
    if ((format == NULL) || (buf == NULL) || (str == NULL))
        return;

    if (buf->error)
        return;
459 460

    len = strlen(str);
461
    if (strcspn(str, forbidden_characters) == len) {
462
        virBufferAsprintf(buf, format, str);
463 464 465
        return;
    }

466
    if (xalloc_oversized(6, len) ||
467
        VIR_ALLOC_N_QUIET(escaped, 6 * len + 1) < 0) {
E
Eric Blake 已提交
468
        virBufferSetError(buf, errno);
469
        return;
470
    }
471

472 473 474 475
    cur = str;
    out = escaped;
    while (*cur != 0) {
        if (*cur == '<') {
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
            *out++ = '&';
            *out++ = 'l';
            *out++ = 't';
            *out++ = ';';
        } else if (*cur == '>') {
            *out++ = '&';
            *out++ = 'g';
            *out++ = 't';
            *out++ = ';';
        } else if (*cur == '&') {
            *out++ = '&';
            *out++ = 'a';
            *out++ = 'm';
            *out++ = 'p';
            *out++ = ';';
491 492 493 494 495 496 497 498 499 500 501 502 503 504
        } else if (*cur == '"') {
            *out++ = '&';
            *out++ = 'q';
            *out++ = 'u';
            *out++ = 'o';
            *out++ = 't';
            *out++ = ';';
        } else if (*cur == '\'') {
            *out++ = '&';
            *out++ = 'a';
            *out++ = 'p';
            *out++ = 'o';
            *out++ = 's';
            *out++ = ';';
505
        } else if (!strchr(forbidden_characters, *cur)) {
506 507 508 509 510 511 512
            /*
             * default case, just copy !
             * Note that character over 0x80 are likely to give problem
             * with UTF-8 XML, but since our string don't have an encoding
             * it's hard to handle properly we have to assume it's UTF-8 too
             */
            *out++ = *cur;
513 514
        } else {
            /* silently ignore control characters */
515 516
        }
        cur++;
517 518 519
    }
    *out = 0;

520
    virBufferAsprintf(buf, format, escaped);
521
    VIR_FREE(escaped);
522 523
}

524 525
/**
 * virBufferEscapeSexpr:
E
Eric Blake 已提交
526
 * @buf: the buffer to append to
527
 * @format: a printf like format string but with only one %s parameter
E
Eric Blake 已提交
528
 * @str: the string argument which needs to be escaped
529
 *
E
Eric Blake 已提交
530 531 532 533
 * Do a formatted print with a single string to an sexpr buffer. The
 * string is escaped to avoid generating a sexpr that xen will choke
 * on. This doesn't fully escape the sexpr, just enough for our code
 * to work.  Auto indentation may be applied.
534 535
 */
void
E
Eric Blake 已提交
536
virBufferEscapeSexpr(virBufferPtr buf,
537 538
                     const char *format,
                     const char *str)
S
Sage Weil 已提交
539
{
540
    virBufferEscape(buf, '\\', "\\'", format, str);
S
Sage Weil 已提交
541 542 543 544
}

/**
 * virBufferEscape:
E
Eric Blake 已提交
545
 * @buf: the buffer to append to
546
 * @escape: the escape character to inject
E
Eric Blake 已提交
547
 * @toescape: NUL-terminated list of characters to escape
S
Sage Weil 已提交
548
 * @format: a printf like format string but with only one %s parameter
E
Eric Blake 已提交
549
 * @str: the string argument which needs to be escaped
S
Sage Weil 已提交
550 551
 *
 * Do a formatted print with a single string to a buffer.  Any characters
552 553 554
 * in the provided list that are contained in @str are escaped with the
 * given escape.  Escaping is not applied to characters specified in @format.
 * Auto indentation may be applied.
S
Sage Weil 已提交
555 556
 */
void
557
virBufferEscape(virBufferPtr buf, char escape, const char *toescape,
E
Eric Blake 已提交
558
                const char *format, const char *str)
559 560 561 562 563 564 565 566 567 568 569 570
{
    int len;
    char *escaped, *out;
    const char *cur;

    if ((format == NULL) || (buf == NULL) || (str == NULL))
        return;

    if (buf->error)
        return;

    len = strlen(str);
S
Sage Weil 已提交
571
    if (strcspn(str, toescape) == len) {
572
        virBufferAsprintf(buf, format, str);
573 574 575
        return;
    }

576
    if (xalloc_oversized(2, len) ||
577
        VIR_ALLOC_N_QUIET(escaped, 2 * len + 1) < 0) {
E
Eric Blake 已提交
578
        virBufferSetError(buf, errno);
579 580 581 582 583 584
        return;
    }

    cur = str;
    out = escaped;
    while (*cur != 0) {
585
        if (strchr(toescape, *cur))
586
            *out++ = escape;
S
Sage Weil 已提交
587
        *out++ = *cur;
588 589 590 591
        cur++;
    }
    *out = 0;

592
    virBufferAsprintf(buf, format, escaped);
593 594 595
    VIR_FREE(escaped);
}

596 597
/**
 * virBufferURIEncodeString:
E
Eric Blake 已提交
598
 * @buf: the buffer to append to
E
Eric Blake 已提交
599
 * @str: the string argument which will be URI-encoded
600 601 602
 *
 * Append the string to the buffer.  The string will be URI-encoded
 * during the append (ie any non alpha-numeric characters are replaced
E
Eric Blake 已提交
603
 * with '%xx' hex sequences).  Auto indentation may be applied.
604
 */
605
void
E
Eric Blake 已提交
606
virBufferURIEncodeString(virBufferPtr buf, const char *str)
607 608 609 610 611 612
{
    int grow_size = 0;
    const char *p;
    unsigned char uc;
    const char *hex = "0123456789abcdef";

613 614 615 616 617 618
    if ((buf == NULL) || (str == NULL))
        return;

    if (buf->error)
        return;

E
Eric Blake 已提交
619 620
    virBufferAddLit(buf, ""); /* auto-indent */

621
    for (p = str; *p; ++p) {
J
Jim Meyering 已提交
622
        if (c_isalnum(*p))
623 624 625 626 627
            grow_size++;
        else
            grow_size += 3; /* %ab */
    }

E
Eric Blake 已提交
628
    if (virBufferGrow(buf, grow_size) < 0)
629
        return;
630 631

    for (p = str; *p; ++p) {
632
        if (c_isalnum(*p)) {
633
            buf->content[buf->use++] = *p;
634
        } else {
635 636 637 638 639 640 641 642 643 644
            uc = (unsigned char) *p;
            buf->content[buf->use++] = '%';
            buf->content[buf->use++] = hex[uc >> 4];
            buf->content[buf->use++] = hex[uc & 0xf];
        }
    }

    buf->content[buf->use] = '\0';
}

G
Guido Günther 已提交
645 646
/**
 * virBufferEscapeShell:
E
Eric Blake 已提交
647 648
 * @buf: the buffer to append to
 * @str: an unquoted string
G
Guido Günther 已提交
649 650
 *
 * Quotes a string so that the shell (/bin/sh) will interpret the
E
Eric Blake 已提交
651
 * quoted string to mean str.  Auto indentation may be applied.
G
Guido Günther 已提交
652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
 */
void
virBufferEscapeShell(virBufferPtr buf, const char *str)
{
    int len;
    char *escaped, *out;
    const char *cur;

    if ((buf == NULL) || (str == NULL))
        return;

    if (buf->error)
        return;

    /* Only quote if str includes shell metacharacters. */
667
    if (*str && !strpbrk(str, "\r\t\n !\"#$&'()*;<>?[\\]^`{|}~")) {
G
Guido Günther 已提交
668 669 670 671
        virBufferAdd(buf, str, -1);
        return;
    }

672 673 674
    if (*str) {
        len = strlen(str);
        if (xalloc_oversized(4, len) ||
675
            VIR_ALLOC_N_QUIET(escaped, 4 * len + 3) < 0) {
E
Eric Blake 已提交
676
            virBufferSetError(buf, errno);
677 678 679
            return;
        }
    } else {
680
        virBufferAddLit(buf, "''");
G
Guido Günther 已提交
681 682 683 684 685 686 687 688 689
        return;
    }

    cur = str;
    out = escaped;

    *out++ = '\'';
    while (*cur != 0) {
        if (*cur == '\'') {
690
            *out++ = '\'';
G
Guido Günther 已提交
691 692 693 694
            /* Replace literal ' with a close ', a \', and a open ' */
            *out++ = '\\';
            *out++ = '\'';
        }
695
        *out++ = *cur++;
G
Guido Günther 已提交
696 697 698 699 700 701 702 703
    }
    *out++ = '\'';
    *out = 0;

    virBufferAdd(buf, escaped, -1);
    VIR_FREE(escaped);
}

D
Daniel Veillard 已提交
704
/**
D
Daniel P. Berrange 已提交
705
 * virBufferStrcat:
E
Eric Blake 已提交
706
 * @buf: the buffer to append to
E
Eric Blake 已提交
707
 * @...: the variable list of strings, the last argument must be NULL
D
Daniel Veillard 已提交
708
 *
E
Eric Blake 已提交
709 710
 * Concatenate strings to an XML buffer.  Auto indentation may be applied
 * after each string argument.
D
Daniel Veillard 已提交
711
 */
712
void
D
Daniel P. Berrange 已提交
713
virBufferStrcat(virBufferPtr buf, ...)
D
Daniel Veillard 已提交
714 715 716 717
{
    va_list ap;
    char *str;

718 719 720
    if (buf->error)
        return;

D
Daniel Veillard 已提交
721
    va_start(ap, buf);
E
Eric Blake 已提交
722 723
    while ((str = va_arg(ap, char *)) != NULL)
        virBufferAdd(buf, str, -1);
D
Daniel Veillard 已提交
724 725
    va_end(ap);
}
726 727 728 729 730 731 732 733 734 735 736 737

/**
 * virBufferTrim:
 * @buf: the buffer to trim
 * @str: the optional string, to force an exact trim
 * @len: the number of bytes to trim, or -1 to use @str
 *
 * Trim the tail of a buffer.  If @str is provided, the trim only occurs
 * if the current tail of the buffer matches @str; a non-negative @len
 * further limits how much of the tail is trimmed.  If @str is NULL, then
 * @len must be non-negative.
 *
J
Ján Tomko 已提交
738
 * Sets error to -1 (usage) if str is NULL and len is less than zero.
739
 */
J
Ján Tomko 已提交
740
void
741 742 743 744
virBufferTrim(virBufferPtr buf, const char *str, int len)
{
    size_t len2 = 0;

J
Ján Tomko 已提交
745 746 747 748 749 750
    if (!buf || buf->error)
        return;
    if (!str && len < 0) {
        virBufferSetError(buf, -1);
        return;
    }
751 752

    if (len > 0 && len > buf->use)
J
Ján Tomko 已提交
753
        return;
754 755 756 757
    if (str) {
        len2 = strlen(str);
        if (len2 > buf->use ||
            memcmp(&buf->content[buf->use - len2], str, len2) != 0)
J
Ján Tomko 已提交
758
            return;
759 760 761 762
    }
    buf->use -= len < 0 ? len2 : len;
    buf->content[buf->use] = '\0';
}
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791


/**
 * virBufferAddStr:
 * @buf: the buffer to append to
 * @str: string to append
 *
 * Appends @str to @buffer. Applies autoindentation on the separate lines of
 * @str.
 */
void
virBufferAddStr(virBufferPtr buf,
                const char *str)
{
    const char *end;

    if (!buf || !str || buf->error)
        return;

    while (*str) {
        if ((end = strchr(str, '\n'))) {
            virBufferAdd(buf, str, (end - str) + 1);
            str = end + 1;
        } else {
            virBufferAdd(buf, str, -1);
            break;
        }
    }
}