neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

strbuf.c (4566B)


      1 /* strbuf - String buffer routines
      2 *
      3 * Copyright (c) 2010-2012  Mark Pulford <mark@kyne.com.au>
      4 *
      5 * Permission is hereby granted, free of charge, to any person obtaining
      6 * a copy of this software and associated documentation files (the
      7 * "Software"), to deal in the Software without restriction, including
      8 * without limitation the rights to use, copy, modify, merge, publish,
      9 * distribute, sublicense, and/or sell copies of the Software, and to
     10 * permit persons to whom the Software is furnished to do so, subject to
     11 * the following conditions:
     12 *
     13 * The above copyright notice and this permission notice shall be
     14 * included in all copies or substantial portions of the Software.
     15 *
     16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     19 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
     20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     21 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     22 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     23 */
     24 
     25 #include <stdio.h>
     26 #include <stdlib.h>
     27 #include <stdarg.h>
     28 #include <string.h>
     29 #include <stdint.h>
     30 
     31 #include "strbuf.h"
     32 
     33 static void die(const char *fmt, ...)
     34 {
     35    va_list arg;
     36 
     37    va_start(arg, fmt);
     38    vfprintf(stderr, fmt, arg);
     39    va_end(arg);
     40    fprintf(stderr, "\n");
     41 
     42    abort();
     43 }
     44 
     45 void strbuf_init(strbuf_t *s, size_t len)
     46 {
     47    size_t size;
     48 
     49    if (!len)
     50        size = STRBUF_DEFAULT_SIZE;
     51    else
     52        size = len + 1;         /* \0 terminator */
     53    if (size < len)
     54        die("Overflow, len: %zu", len);
     55    s->buf = NULL;
     56    s->size = size;
     57    s->length = 0;
     58    s->dynamic = 0;
     59    s->reallocs = 0;
     60    s->debug = 0;
     61 
     62    s->buf = (char *)malloc(size);
     63    if (!s->buf)
     64        die("Out of memory");
     65 
     66    strbuf_ensure_null(s);
     67 }
     68 
     69 strbuf_t *strbuf_new(size_t len)
     70 {
     71    strbuf_t *s;
     72 
     73    s = (strbuf_t*)malloc(sizeof(strbuf_t));
     74    if (!s)
     75        die("Out of memory");
     76 
     77    strbuf_init(s, len);
     78 
     79    /* Dynamic strbuf allocation / deallocation */
     80    s->dynamic = 1;
     81 
     82    return s;
     83 }
     84 
     85 static inline void debug_stats(strbuf_t *s)
     86 {
     87    if (s->debug) {
     88        fprintf(stderr, "strbuf(%lx) reallocs: %d, length: %zd, size: %zd\n",
     89                (long)s, s->reallocs, s->length, s->size);
     90    }
     91 }
     92 
     93 /* If strbuf_t has not been dynamically allocated, strbuf_free() can
     94 * be called any number of times strbuf_init() */
     95 void strbuf_free(strbuf_t *s)
     96 {
     97    debug_stats(s);
     98 
     99    if (s->buf) {
    100        free(s->buf);
    101        s->buf = NULL;
    102    }
    103    if (s->dynamic)
    104        free(s);
    105 }
    106 
    107 char *strbuf_free_to_string(strbuf_t *s, size_t *len)
    108 {
    109    char *buf;
    110 
    111    debug_stats(s);
    112 
    113    strbuf_ensure_null(s);
    114 
    115    buf = s->buf;
    116    if (len)
    117        *len = s->length;
    118 
    119    if (s->dynamic)
    120        free(s);
    121 
    122    return buf;
    123 }
    124 
    125 static size_t calculate_new_size(strbuf_t *s, size_t len)
    126 {
    127    size_t reqsize, newsize;
    128 
    129    if (len <= 0)
    130        die("BUG: Invalid strbuf length requested");
    131 
    132    /* Ensure there is room for optional NULL termination */
    133    reqsize = len + 1;
    134    if (reqsize < len)
    135        die("Overflow, len: %zu", len);
    136 
    137    /* If the user has requested to shrink the buffer, do it exactly */
    138    if (s->size > reqsize)
    139        return reqsize;
    140 
    141    newsize = s->size;
    142    if (reqsize >= SIZE_MAX / 2) {
    143        newsize = reqsize;
    144    } else {
    145        /* Exponential sizing */
    146        while (newsize < reqsize)
    147            newsize *= 2;
    148    }
    149 
    150    if (newsize < reqsize)
    151        die("BUG: strbuf length would overflow, len: %zu", len);
    152 
    153 
    154    return newsize;
    155 }
    156 
    157 
    158 /* Ensure strbuf can handle a string length bytes long (ignoring NULL
    159 * optional termination). */
    160 void strbuf_resize(strbuf_t *s, size_t len)
    161 {
    162    size_t newsize;
    163 
    164    newsize = calculate_new_size(s, len);
    165 
    166    if (s->debug > 1) {
    167        fprintf(stderr, "strbuf(%lx) resize: %zd => %zd\n",
    168                (long)s, s->size, newsize);
    169    }
    170 
    171    s->size = newsize;
    172    s->buf = (char *)realloc(s->buf, s->size);
    173    if (!s->buf)
    174        die("Out of memory, len: %zu", len);
    175    s->reallocs++;
    176 }
    177 
    178 void strbuf_append_string(strbuf_t *s, const char *str)
    179 {
    180    int i;
    181    size_t space;
    182 
    183    space = strbuf_empty_length(s);
    184 
    185    for (i = 0; str[i]; i++) {
    186        if (space < 1) {
    187            strbuf_resize(s, s->length + 1);
    188            space = strbuf_empty_length(s);
    189        }
    190 
    191        s->buf[s->length] = str[i];
    192        s->length++;
    193        space--;
    194    }
    195 }
    196 
    197 
    198 /* vi:ai et sw=4 ts=4:
    199 */