virbuffer.c 18.8 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;
}

420 421 422

VIR_WARNINGS_NO_WLOGICALOP_STRCHR

P
Pavel Hrdina 已提交
423

424 425
/**
 * virBufferEscapeString:
E
Eric Blake 已提交
426
 * @buf: the buffer to append to
427
 * @format: a printf like format string but with only one %s parameter
E
Eric Blake 已提交
428
 * @str: the string argument which needs to be escaped
429
 *
E
Eric Blake 已提交
430 431 432 433
 * 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.
434
 */
435
void
E
Eric Blake 已提交
436
virBufferEscapeString(virBufferPtr buf, const char *format, const char *str)
437
{
438
    int len;
439 440
    char *escaped, *out;
    const char *cur;
441 442 443 444 445 446 447
    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'
    };
448

449 450 451 452 453
    if ((format == NULL) || (buf == NULL) || (str == NULL))
        return;

    if (buf->error)
        return;
454 455

    len = strlen(str);
456
    if (strcspn(str, forbidden_characters) == len) {
457
        virBufferAsprintf(buf, format, str);
458 459 460
        return;
    }

461
    if (xalloc_oversized(6, len) ||
462
        VIR_ALLOC_N_QUIET(escaped, 6 * len + 1) < 0) {
E
Eric Blake 已提交
463
        virBufferSetError(buf, errno);
464
        return;
465
    }
466

467 468 469 470
    cur = str;
    out = escaped;
    while (*cur != 0) {
        if (*cur == '<') {
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
            *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++ = ';';
486 487 488 489 490 491 492 493 494 495 496 497 498 499
        } 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++ = ';';
500
        } else if (!strchr(forbidden_characters, *cur)) {
501 502 503 504 505 506 507
            /*
             * 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;
508 509
        } else {
            /* silently ignore control characters */
510 511
        }
        cur++;
512 513 514
    }
    *out = 0;

515
    virBufferAsprintf(buf, format, escaped);
516
    VIR_FREE(escaped);
517 518
}

519 520
/**
 * virBufferEscapeSexpr:
E
Eric Blake 已提交
521
 * @buf: the buffer to append to
522
 * @format: a printf like format string but with only one %s parameter
E
Eric Blake 已提交
523
 * @str: the string argument which needs to be escaped
524
 *
E
Eric Blake 已提交
525 526 527 528
 * 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.
529 530
 */
void
E
Eric Blake 已提交
531
virBufferEscapeSexpr(virBufferPtr buf,
532 533
                     const char *format,
                     const char *str)
S
Sage Weil 已提交
534
{
535
    virBufferEscape(buf, '\\', "\\'", format, str);
S
Sage Weil 已提交
536 537 538 539
}

/**
 * virBufferEscape:
E
Eric Blake 已提交
540
 * @buf: the buffer to append to
541
 * @escape: the escape character to inject
E
Eric Blake 已提交
542
 * @toescape: NUL-terminated list of characters to escape
S
Sage Weil 已提交
543
 * @format: a printf like format string but with only one %s parameter
E
Eric Blake 已提交
544
 * @str: the string argument which needs to be escaped
S
Sage Weil 已提交
545 546
 *
 * Do a formatted print with a single string to a buffer.  Any characters
547 548 549
 * 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 已提交
550 551
 */
void
552
virBufferEscape(virBufferPtr buf, char escape, const char *toescape,
E
Eric Blake 已提交
553
                const char *format, const char *str)
554 555 556 557 558 559 560 561 562 563 564 565
{
    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 已提交
566
    if (strcspn(str, toescape) == len) {
567
        virBufferAsprintf(buf, format, str);
568 569 570
        return;
    }

571
    if (xalloc_oversized(2, len) ||
572
        VIR_ALLOC_N_QUIET(escaped, 2 * len + 1) < 0) {
E
Eric Blake 已提交
573
        virBufferSetError(buf, errno);
574 575 576 577 578 579
        return;
    }

    cur = str;
    out = escaped;
    while (*cur != 0) {
580
        if (strchr(toescape, *cur))
581
            *out++ = escape;
S
Sage Weil 已提交
582
        *out++ = *cur;
583 584 585 586
        cur++;
    }
    *out = 0;

587
    virBufferAsprintf(buf, format, escaped);
588 589 590
    VIR_FREE(escaped);
}

591 592
/**
 * virBufferURIEncodeString:
E
Eric Blake 已提交
593
 * @buf: the buffer to append to
E
Eric Blake 已提交
594
 * @str: the string argument which will be URI-encoded
595 596 597
 *
 * 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 已提交
598
 * with '%xx' hex sequences).  Auto indentation may be applied.
599
 */
600
void
E
Eric Blake 已提交
601
virBufferURIEncodeString(virBufferPtr buf, const char *str)
602 603 604 605 606 607
{
    int grow_size = 0;
    const char *p;
    unsigned char uc;
    const char *hex = "0123456789abcdef";

608 609 610 611 612 613
    if ((buf == NULL) || (str == NULL))
        return;

    if (buf->error)
        return;

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

616
    for (p = str; *p; ++p) {
J
Jim Meyering 已提交
617
        if (c_isalnum(*p))
618 619 620 621 622
            grow_size++;
        else
            grow_size += 3; /* %ab */
    }

E
Eric Blake 已提交
623
    if (virBufferGrow(buf, grow_size) < 0)
624
        return;
625 626

    for (p = str; *p; ++p) {
627
        if (c_isalnum(*p)) {
628
            buf->content[buf->use++] = *p;
629
        } else {
630 631 632 633 634 635 636 637 638 639
            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 已提交
640 641
/**
 * virBufferEscapeShell:
E
Eric Blake 已提交
642 643
 * @buf: the buffer to append to
 * @str: an unquoted string
G
Guido Günther 已提交
644 645
 *
 * Quotes a string so that the shell (/bin/sh) will interpret the
E
Eric Blake 已提交
646
 * quoted string to mean str.  Auto indentation may be applied.
G
Guido Günther 已提交
647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
 */
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. */
662
    if (*str && !strpbrk(str, "\r\t\n !\"#$&'()*;<>?[\\]^`{|}~")) {
G
Guido Günther 已提交
663 664 665 666
        virBufferAdd(buf, str, -1);
        return;
    }

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

    cur = str;
    out = escaped;

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

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

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

713 714 715
    if (buf->error)
        return;

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

/**
 * 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 已提交
733
 * Sets error to -1 (usage) if str is NULL and len is less than zero.
734
 */
J
Ján Tomko 已提交
735
void
736 737 738 739
virBufferTrim(virBufferPtr buf, const char *str, int len)
{
    size_t len2 = 0;

J
Ján Tomko 已提交
740 741 742 743 744 745
    if (!buf || buf->error)
        return;
    if (!str && len < 0) {
        virBufferSetError(buf, -1);
        return;
    }
746 747

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


/**
 * 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;
        }
    }
}