buf.c 16.4 KB
Newer Older
D
Daniel Veillard 已提交
1
/*
D
Daniel P. Berrange 已提交
2
 * buf.c: buffers for libvirt
D
Daniel Veillard 已提交
3
 *
4
 * Copyright (C) 2005-2008, 2010-2012 Red Hat, Inc.
D
Daniel Veillard 已提交
5
 *
O
Osier Yang 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18
 * 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
 * License along with this library;  If not, see
 * <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__

D
Daniel Veillard 已提交
33
#include "buf.h"
34
#include "memory.h"
D
Daniel Veillard 已提交
35

36 37 38 39 40 41

/* 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 已提交
42
    unsigned int error; /* errno value, or -1 for usage error */
E
Eric Blake 已提交
43
    int indent;
44 45 46 47 48 49
    char *content;
};

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

E
Eric Blake 已提交
64 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 99 100 101 102 103 104 105 106
/**
 * 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
virBufferGetIndent(const virBufferPtr buf, bool dynamic)
{
    if (!buf || buf->error)
        return -1;
    if (dynamic && buf->use && buf->content[buf->use - 1] != '\n')
        return 0;
    return buf->indent;
}

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

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

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

    size = buf->use + len + 1000;

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

/**
D
Daniel P. Berrange 已提交
138
 * virBufferAdd:
E
Eric Blake 已提交
139 140 141
 * @buf: the buffer to append to
 * @str: the string
 * @len: the number of bytes to add, or -1
D
Daniel Veillard 已提交
142
 *
E
Eric Blake 已提交
143 144
 * 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 已提交
145 146
 *
 */
147
void
E
Eric Blake 已提交
148
virBufferAdd(virBufferPtr buf, const char *str, int len)
D
Daniel Veillard 已提交
149 150
{
    unsigned int needSize;
E
Eric Blake 已提交
151
    int indent;
D
Daniel Veillard 已提交
152

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

    if (buf->error)
        return;
D
Daniel Veillard 已提交
158

E
Eric Blake 已提交
159 160
    indent = virBufferGetIndent(buf, true);

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

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

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

175 176
/**
 * virBufferAddChar:
E
Eric Blake 已提交
177
 * @buf: the buffer to append to
178 179
 * @c: the character to add
 *
E
Eric Blake 已提交
180
 * Add a single character 'c' to a buffer.  Auto indentation may be applied.
181 182
 *
 */
183
void
E
Eric Blake 已提交
184
virBufferAddChar(virBufferPtr buf, char c)
185
{
E
Eric Blake 已提交
186
    virBufferAdd(buf, &c, 1);
187 188
}

189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
/**
 * 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 : "";
}

207
/**
208 209
 * virBufferContentAndReset:
 * @buf: Buffer
210
 *
211 212
 * Get the content from the buffer and free (only) the buffer structure.
 * The caller owns the returned string & should free it when no longer
213 214 215
 * 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.
216
 *
217
 * Returns the buffer content or NULL in case of error.
218
 */
219
char *
E
Eric Blake 已提交
220
virBufferContentAndReset(virBufferPtr buf)
D
Daniel Veillard 已提交
221
{
222 223 224
    char *str;
    if (buf == NULL)
        return NULL;
D
Daniel Veillard 已提交
225

226 227
    if (buf->error) {
        memset(buf, 0, sizeof(*buf));
D
Daniel Veillard 已提交
228 229 230
        return NULL;
    }

231 232 233
    str = buf->content;
    memset(buf, 0, sizeof(*buf));
    return str;
D
Daniel Veillard 已提交
234 235
}

236 237 238 239 240 241
/**
 * virBufferFreeAndReset:
 * @buf: the buffer to free and reset
 *
 * Frees the buffer content and resets the buffer structure.
 */
E
Eric Blake 已提交
242
void virBufferFreeAndReset(virBufferPtr buf)
243 244 245 246 247 248
{
    char *str = virBufferContentAndReset(buf);

    VIR_FREE(str);
}

249
/**
250 251
 * virBufferError:
 * @buf: the buffer
252
 *
253
 * Check to see if the buffer is in an error state due
E
Eric Blake 已提交
254
 * to failed memory allocation or usage error
255
 *
E
Eric Blake 已提交
256
 * Return positive errno value or -1 on usage error, 0 if normal
257
 */
258
int
D
Daniel P. Berrange 已提交
259
virBufferError(const virBufferPtr buf)
D
Daniel Veillard 已提交
260
{
261
    if (buf == NULL)
E
Eric Blake 已提交
262
        return -1;
263 264

    return buf->error;
D
Daniel Veillard 已提交
265 266 267
}

/**
268 269
 * virBufferUse:
 * @buf: the usage of the string in the buffer
D
Daniel Veillard 已提交
270
 *
271
 * Return the string usage in bytes
D
Daniel Veillard 已提交
272
 */
273 274
unsigned int
virBufferUse(const virBufferPtr buf)
D
Daniel Veillard 已提交
275
{
276
    if (buf == NULL)
277
        return 0;
D
Daniel Veillard 已提交
278

279
    return buf->use;
D
Daniel Veillard 已提交
280 281 282
}

/**
283
 * virBufferAsprintf:
E
Eric Blake 已提交
284
 * @buf: the buffer to append to
D
Daniel Veillard 已提交
285
 * @format:  the format
286
 * @...:  the variable list of arguments
D
Daniel Veillard 已提交
287
 *
E
Eric Blake 已提交
288
 * Do a formatted print to an XML buffer.  Auto indentation may be applied.
D
Daniel Veillard 已提交
289
 */
290
void
E
Eric Blake 已提交
291
virBufferAsprintf(virBufferPtr buf, const char *format, ...)
D
Daniel Veillard 已提交
292
{
293
    va_list argptr;
E
Eric Blake 已提交
294 295 296 297 298 299 300
    va_start(argptr, format);
    virBufferVasprintf(buf, format, argptr);
    va_end(argptr);
}

/**
 * virBufferVasprintf:
E
Eric Blake 已提交
301
 * @buf: the buffer to append to
E
Eric Blake 已提交
302 303 304
 * @format:  the format
 * @argptr:  the variable list of arguments
 *
E
Eric Blake 已提交
305
 * Do a formatted print to an XML buffer.  Auto indentation may be applied.
E
Eric Blake 已提交
306 307
 */
void
E
Eric Blake 已提交
308
virBufferVasprintf(virBufferPtr buf, const char *format, va_list argptr)
E
Eric Blake 已提交
309 310 311
{
    int size, count, grow_size;
    va_list copy;
D
Daniel Veillard 已提交
312

313 314 315 316 317
    if ((format == NULL) || (buf == NULL))
        return;

    if (buf->error)
        return;
318

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

321 322
    if (buf->size == 0 &&
        virBufferGrow(buf, 100) < 0)
323
        return;
324

E
Eric Blake 已提交
325
    va_copy(copy, argptr);
326 327 328

    size = buf->size - buf->use;
    if ((count = vsnprintf(&buf->content[buf->use],
E
Eric Blake 已提交
329
                           size, format, copy)) < 0) {
E
Eric Blake 已提交
330
        virBufferSetError(buf, errno);
E
Eric Blake 已提交
331 332
        va_end(copy);
        return;
333
    }
E
Eric Blake 已提交
334
    va_end(copy);
335 336 337

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

340
        grow_size = (count + 1 > 1000) ? count + 1 : 1000;
341
        if (virBufferGrow(buf, grow_size) < 0) {
E
Eric Blake 已提交
342
            return;
343
        }
344

345 346 347
        size = buf->size - buf->use;
        if ((count = vsnprintf(&buf->content[buf->use],
                               size, format, argptr)) < 0) {
E
Eric Blake 已提交
348
            virBufferSetError(buf, errno);
E
Eric Blake 已提交
349
            return;
350
        }
D
Daniel Veillard 已提交
351 352 353 354
    }
    buf->use += count;
}

355 356
/**
 * virBufferEscapeString:
E
Eric Blake 已提交
357
 * @buf: the buffer to append to
358
 * @format: a printf like format string but with only one %s parameter
E
Eric Blake 已提交
359
 * @str: the string argument which needs to be escaped
360
 *
E
Eric Blake 已提交
361 362 363 364
 * 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.
365
 */
366
void
E
Eric Blake 已提交
367
virBufferEscapeString(virBufferPtr buf, const char *format, const char *str)
368
{
369
    int len;
370 371 372
    char *escaped, *out;
    const char *cur;

373 374 375 376 377
    if ((format == NULL) || (buf == NULL) || (str == NULL))
        return;

    if (buf->error)
        return;
378 379

    len = strlen(str);
380
    if (strcspn(str, "<>&'\"") == len) {
381
        virBufferAsprintf(buf, format, str);
382 383 384
        return;
    }

385 386
    if (xalloc_oversized(6, len) ||
        VIR_ALLOC_N(escaped, 6 * len + 1) < 0) {
E
Eric Blake 已提交
387
        virBufferSetError(buf, errno);
388
        return;
389
    }
390

391 392 393 394
    cur = str;
    out = escaped;
    while (*cur != 0) {
        if (*cur == '<') {
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
            *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++ = ';';
410 411 412 413 414 415 416 417 418 419 420 421 422 423
        } 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++ = ';';
424
        } else if (((unsigned char)*cur >= 0x20) || (*cur == '\n') || (*cur == '\t') ||
425 426 427 428 429 430 431 432 433 434
                   (*cur == '\r')) {
            /*
             * 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;
        }
        cur++;
435 436 437
    }
    *out = 0;

438
    virBufferAsprintf(buf, format, escaped);
439
    VIR_FREE(escaped);
440 441
}

442 443
/**
 * virBufferEscapeSexpr:
E
Eric Blake 已提交
444
 * @buf: the buffer to append to
445
 * @format: a printf like format string but with only one %s parameter
E
Eric Blake 已提交
446
 * @str: the string argument which needs to be escaped
447
 *
E
Eric Blake 已提交
448 449 450 451
 * 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.
452 453
 */
void
E
Eric Blake 已提交
454
virBufferEscapeSexpr(virBufferPtr buf,
455 456
                     const char *format,
                     const char *str)
S
Sage Weil 已提交
457
{
458
    virBufferEscape(buf, '\\', "\\'", format, str);
S
Sage Weil 已提交
459 460 461 462
}

/**
 * virBufferEscape:
E
Eric Blake 已提交
463
 * @buf: the buffer to append to
464
 * @escape: the escape character to inject
E
Eric Blake 已提交
465
 * @toescape: NUL-terminated list of characters to escape
S
Sage Weil 已提交
466
 * @format: a printf like format string but with only one %s parameter
E
Eric Blake 已提交
467
 * @str: the string argument which needs to be escaped
S
Sage Weil 已提交
468 469
 *
 * Do a formatted print with a single string to a buffer.  Any characters
470
 * in the provided list are escaped with the given escape.  Auto indentation
E
Eric Blake 已提交
471
 * may be applied.
S
Sage Weil 已提交
472 473
 */
void
474
virBufferEscape(virBufferPtr buf, char escape, const char *toescape,
E
Eric Blake 已提交
475
                const char *format, const char *str)
476 477 478 479 480 481 482 483 484 485 486 487
{
    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 已提交
488
    if (strcspn(str, toescape) == len) {
489
        virBufferAsprintf(buf, format, str);
490 491 492
        return;
    }

493 494
    if (xalloc_oversized(2, len) ||
        VIR_ALLOC_N(escaped, 2 * len + 1) < 0) {
E
Eric Blake 已提交
495
        virBufferSetError(buf, errno);
496 497 498 499 500 501
        return;
    }

    cur = str;
    out = escaped;
    while (*cur != 0) {
502 503 504 505 506
        /* strchr work-around for gcc 4.3 & 4.4 bug with -Wlogical-op
         * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36513
         */
        char needle[2] = { *cur, 0 };
        if (strstr(toescape, needle))
507
            *out++ = escape;
S
Sage Weil 已提交
508
        *out++ = *cur;
509 510 511 512
        cur++;
    }
    *out = 0;

513
    virBufferAsprintf(buf, format, escaped);
514 515 516
    VIR_FREE(escaped);
}

517 518
/**
 * virBufferURIEncodeString:
E
Eric Blake 已提交
519
 * @buf: the buffer to append to
520 521 522 523
 * @str:  the string argument which will be URI-encoded
 *
 * 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 已提交
524
 * with '%xx' hex sequences).  Auto indentation may be applied.
525
 */
526
void
E
Eric Blake 已提交
527
virBufferURIEncodeString(virBufferPtr buf, const char *str)
528 529 530 531 532 533
{
    int grow_size = 0;
    const char *p;
    unsigned char uc;
    const char *hex = "0123456789abcdef";

534 535 536 537 538 539
    if ((buf == NULL) || (str == NULL))
        return;

    if (buf->error)
        return;

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

542
    for (p = str; *p; ++p) {
J
Jim Meyering 已提交
543
        if (c_isalnum(*p))
544 545 546 547 548
            grow_size++;
        else
            grow_size += 3; /* %ab */
    }

E
Eric Blake 已提交
549
    if (virBufferGrow(buf, grow_size) < 0)
550
        return;
551 552

    for (p = str; *p; ++p) {
J
Jim Meyering 已提交
553
        if (c_isalnum(*p))
554 555 556 557 558 559 560 561 562 563 564 565
            buf->content[buf->use++] = *p;
        else {
            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 已提交
566 567
/**
 * virBufferEscapeShell:
E
Eric Blake 已提交
568 569
 * @buf: the buffer to append to
 * @str: an unquoted string
G
Guido Günther 已提交
570 571
 *
 * Quotes a string so that the shell (/bin/sh) will interpret the
E
Eric Blake 已提交
572
 * quoted string to mean str.  Auto indentation may be applied.
G
Guido Günther 已提交
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
 */
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. */
588
    if (*str && !strpbrk(str, "\r\t\n !\"#$&'()*;<>?[\\]^`{|}~")) {
G
Guido Günther 已提交
589 590 591 592
        virBufferAdd(buf, str, -1);
        return;
    }

593 594 595 596
    if (*str) {
        len = strlen(str);
        if (xalloc_oversized(4, len) ||
            VIR_ALLOC_N(escaped, 4 * len + 3) < 0) {
E
Eric Blake 已提交
597
            virBufferSetError(buf, errno);
598 599 600
            return;
        }
    } else {
601
        virBufferAddLit(buf, "''");
G
Guido Günther 已提交
602 603 604 605 606 607 608 609 610
        return;
    }

    cur = str;
    out = escaped;

    *out++ = '\'';
    while (*cur != 0) {
        if (*cur == '\'') {
611
            *out++ = '\'';
G
Guido Günther 已提交
612 613 614 615
            /* Replace literal ' with a close ', a \', and a open ' */
            *out++ = '\\';
            *out++ = '\'';
        }
616
        *out++ = *cur++;
G
Guido Günther 已提交
617 618 619 620 621 622 623 624
    }
    *out++ = '\'';
    *out = 0;

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

D
Daniel Veillard 已提交
625
/**
D
Daniel P. Berrange 已提交
626
 * virBufferStrcat:
E
Eric Blake 已提交
627
 * @buf: the buffer to append to
628
 * @...:  the variable list of strings, the last argument must be NULL
D
Daniel Veillard 已提交
629
 *
E
Eric Blake 已提交
630 631
 * Concatenate strings to an XML buffer.  Auto indentation may be applied
 * after each string argument.
D
Daniel Veillard 已提交
632
 */
633
void
D
Daniel P. Berrange 已提交
634
virBufferStrcat(virBufferPtr buf, ...)
D
Daniel Veillard 已提交
635 636 637 638
{
    va_list ap;
    char *str;

639 640 641
    if (buf->error)
        return;

D
Daniel Veillard 已提交
642
    va_start(ap, buf);
E
Eric Blake 已提交
643 644
    while ((str = va_arg(ap, char *)) != NULL)
        virBufferAdd(buf, str, -1);
D
Daniel Veillard 已提交
645 646
    va_end(ap);
}
647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682

/**
 * 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.
 *
 * Returns -1 if @buf has previously encountered an error or if @len is
 * invalid, 0 if there was nothing to trim (@buf was too short or @str
 * didn't match), and 1 if the trim was successful.
 */
int
virBufferTrim(virBufferPtr buf, const char *str, int len)
{
    size_t len2 = 0;

    if (!buf || buf->error || (!str && len < 0))
        return -1;

    if (len > 0 && len > buf->use)
        return 0;
    if (str) {
        len2 = strlen(str);
        if (len2 > buf->use ||
            memcmp(&buf->content[buf->use - len2], str, len2) != 0)
            return 0;
    }
    buf->use -= len < 0 ? len2 : len;
    buf->content[buf->use] = '\0';
    return 1;
}