176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* ----------------------------------------------------------------------- *
276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   Copyright 2008 H. Peter Anvin - All Rights Reserved
476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   This program is free software; you can redistribute it and/or modify
676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   it under the terms of the GNU General Public License as published by
776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   Boston MA 02110-1301, USA; either version 2 of the License, or
976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   (at your option) any later version; incorporated herein by reference.
1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ----------------------------------------------------------------------- */
1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * refstr.c
1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Simple reference-counted strings
1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdlib.h>
2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <string.h>
2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdio.h>
2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "refstr.h"
2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Allocate space for a refstring of len bytes, plus final null */
2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* The final null is inserted in the string; the rest is uninitialized. */
2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanchar *refstr_alloc(size_t len)
2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    char *r = malloc(sizeof(unsigned int) + len + 1);
2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!r)
3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return NULL;
3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    *(unsigned int *)r = 1;
3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    r += sizeof(unsigned int);
3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    r[len] = '\0';
3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return r;
3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanconst char *refstrndup(const char *str, size_t len)
3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    char *r;
4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!str)
4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return NULL;
4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    len = strnlen(str, len);
4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    r = refstr_alloc(len);
4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (r)
4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memcpy(r, str, len);
4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return r;
4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanconst char *refstrdup(const char *str)
5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    char *r;
5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    size_t len;
5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!str)
5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return NULL;
5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    len = strlen(str);
6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    r = refstr_alloc(len);
6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (r)
6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memcpy(r, str, len);
6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return r;
6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint vrsprintf(const char **bufp, const char *fmt, va_list ap)
6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    va_list ap1;
6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int len;
7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    char *p;
7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    va_copy(ap1, ap);
7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    len = vsnprintf(NULL, 0, fmt, ap1);
7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    va_end(ap1);
7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    *bufp = p = refstr_alloc(len);
7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!p)
7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return -1;
7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return vsnprintf(p, len + 1, fmt, ap);
8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint rsprintf(const char **bufp, const char *fmt, ...)
8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int rv;
8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    va_list ap;
8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    va_start(ap, fmt);
8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    rv = vrsprintf(bufp, fmt, ap);
9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    va_end(ap);
9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return rv;
9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid refstr_put(const char *r)
9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    unsigned int *ref;
9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (r) {
10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	ref = (unsigned int *)r - 1;
10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (!--*ref)
10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    free(ref);
10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
106