view interps/cfunge/cfunge-src/lib/stringbuffer/stringbuffer.c @ 12518:2d8fe55c6e65 draft default tip

<int-e> learn The password of the month is release incident pilot.
author HackEso <hackeso@esolangs.org>
date Sun, 03 Nov 2024 00:31:02 +0000
parents 859f9b4339e6
children
line wrap: on
line source

/*
    This code was taken (and slightly modified to compile in cfunge) from:
      CrossFire, A Multiplayer game for X-windows

    Copyright (C) 2008 Crossfire Development Team

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    The authors can be reached via e-mail at crossfire-devel@real-time.com
*/

/*
 * Modifications for cfunge:
 * - Drop some crossfire specific includes and functions that depended on other
 *   parts of crossfire.
 * - Adding stringbuffer_destroy
 * - Adding GCC attributes.
 *
 */

#include <stdarg.h>
#include <stdlib.h>
#include <string.h>

#include "../../src/global.h"
#include <stdbool.h>
#include "stringbuffer.h"


struct StringBuffer {
    /**
     * The string buffer. The first {@link #pos} bytes contain the collected
     * string. It's size is at least {@link #size} bytes.
     */
    char *buf;

    /**
     * The current length of {@link #buf}. The invariant <code>pos <
     * size</code> always holds; this means there is always enough room to
     * attach a trailing \0 character.
     */
    size_t pos;

    /**
     * The allocation size of {@link #buf}.
     */
    size_t size;
};


/**
 * Make sure that at least <code>len</code> bytes are available in the passed
 * string buffer.
 *
 * @param sb The string buffer to modify.
 *
 * @param len The number of bytes to allocate.
 */
FUNGE_ATTR_FAST
static bool stringbuffer_ensure(StringBuffer *sb, size_t len);

FUNGE_ATTR_FAST
StringBuffer *stringbuffer_new(void)
{
    StringBuffer *sb;

    sb = malloc(sizeof(*sb));
    if (sb == NULL) {
        return NULL;
    }

    sb->size = 256;
    sb->buf = malloc(sb->size);
    sb->pos = 0;
    return sb;
}

FUNGE_ATTR_FAST
void stringbuffer_destroy(StringBuffer *sb)
{
    free(sb->buf);
    free(sb);
}

FUNGE_ATTR_FAST
char *stringbuffer_finish(StringBuffer * restrict sb, size_t * restrict length)
{
    char *result;

    sb->buf[sb->pos] = '\0';
    if (length)
        *length = sb->pos;
    result = sb->buf;
    free(sb);
    return result;
}

FUNGE_ATTR_FAST
void stringbuffer_append_char(StringBuffer *sb, const char c)
{
    stringbuffer_ensure(sb, 2);
    sb->buf[sb->pos] = c;
    sb->pos += 1;
}

FUNGE_ATTR_FAST
void stringbuffer_append_string(StringBuffer *sb, const char *str)
{
    size_t len;

    len = strlen(str);
    stringbuffer_ensure(sb, len+1);
    memcpy(sb->buf+sb->pos, str, len);
    sb->pos += len;
}

FUNGE_ATTR_FAST
void stringbuffer_append_printf(StringBuffer *sb, const char *format, ...)
{
    size_t size;

    size = 100;                 /* arbitrary guess */
    for (;;) {
        int n;
        va_list arg;

        stringbuffer_ensure(sb, size);

        va_start(arg, format);
        n = vsnprintf(sb->buf+sb->pos, size, format, arg);
        va_end(arg);

        if (n > -1 && (size_t)n < size) {
            sb->pos += (size_t)n;
            break;
        }

        if (n > -1) {
            size = (size_t)(n+1);         /* precisely what is needed */
        } else {
            size *= 2;          /* twice the old size */
        }
    }
}

FUNGE_ATTR_FAST
void stringbuffer_append_stringbuffer(StringBuffer * restrict sb,
                                      const StringBuffer * restrict sb2)
{
    stringbuffer_ensure(sb, sb2->pos+1);
    memcpy(sb->buf+sb->pos, sb2->buf, sb2->pos);
    sb->pos += sb2->pos;
}

FUNGE_ATTR_FAST
static bool stringbuffer_ensure(StringBuffer *sb, size_t len)
{
    char *tmp;
    size_t new_size;

    if (sb->pos+len <= sb->size) {
        return true;
    }

    new_size = sb->pos+len+256;
    tmp = realloc(sb->buf, new_size);
    if (tmp == NULL) {
        return false;
    }
    sb->buf = tmp;
    sb->size = new_size;
    return true;
}