11#include <stdio.h>
22#include <stdarg.h>
33#include <string.h>
4+ #include <assert.h>
45#include "misc.h"
56
67// returned value is always at least 1 greater than argument
@@ -16,10 +17,23 @@ void vstr_init(vstr_t *vstr, int alloc) {
1617 }
1718 vstr -> buf [0 ] = 0 ;
1819 vstr -> had_error = false;
20+ vstr -> fixed_buf = false;
21+ }
22+
23+ void vstr_init_fixed_buf (vstr_t * vstr , int alloc , char * buf ) {
24+ assert (alloc > 0 ); // need at least room for the null byte
25+ vstr -> alloc = alloc ;
26+ vstr -> len = 0 ;
27+ vstr -> buf = buf ;
28+ vstr -> buf [0 ] = 0 ;
29+ vstr -> had_error = false;
30+ vstr -> fixed_buf = true;
1931}
2032
2133void vstr_clear (vstr_t * vstr ) {
22- m_del (char , vstr -> buf , vstr -> alloc );
34+ if (!vstr -> fixed_buf ) {
35+ m_del (char , vstr -> buf , vstr -> alloc );
36+ }
2337 vstr -> buf = NULL ;
2438}
2539
@@ -43,7 +57,9 @@ vstr_t *vstr_new_size(int alloc) {
4357
4458void vstr_free (vstr_t * vstr ) {
4559 if (vstr != NULL ) {
46- m_del (char , vstr -> buf , vstr -> alloc );
60+ if (!vstr -> fixed_buf ) {
61+ m_del (char , vstr -> buf , vstr -> alloc );
62+ }
4763 m_del_obj (vstr_t , vstr );
4864 }
4965}
@@ -73,7 +89,10 @@ int vstr_len(vstr_t *vstr) {
7389}
7490
7591// Extend vstr strictly to by requested size, return pointer to newly added chunk
76- char * vstr_extend (vstr_t * vstr , int size ) {
92+ char * vstr_extend (vstr_t * vstr , int size ) {
93+ if (vstr -> fixed_buf ) {
94+ return NULL ;
95+ }
7796 char * new_buf = m_renew (char , vstr -> buf , vstr -> alloc , vstr -> alloc + size );
7897 if (new_buf == NULL ) {
7998 vstr -> had_error = true;
@@ -87,6 +106,9 @@ char *vstr_extend(vstr_t *vstr, int size) {
87106
88107// Shrink vstr to be given size
89108bool vstr_set_size (vstr_t * vstr , int size ) {
109+ if (vstr -> fixed_buf ) {
110+ return false;
111+ }
90112 char * new_buf = m_renew (char , vstr -> buf , vstr -> alloc , size );
91113 if (new_buf == NULL ) {
92114 vstr -> had_error = true;
@@ -102,8 +124,11 @@ bool vstr_shrink(vstr_t *vstr) {
102124 return vstr_set_size (vstr , vstr -> len );
103125}
104126
105- bool vstr_ensure_extra (vstr_t * vstr , int size ) {
127+ static bool vstr_ensure_extra (vstr_t * vstr , int size ) {
106128 if (vstr -> len + size + 1 > vstr -> alloc ) {
129+ if (vstr -> fixed_buf ) {
130+ return false;
131+ }
107132 int new_alloc = ROUND_ALLOC ((vstr -> len + size + 1 ) * 2 );
108133 char * new_buf = m_renew (char , vstr -> buf , vstr -> alloc , new_alloc );
109134 if (new_buf == NULL ) {
@@ -156,8 +181,15 @@ void vstr_add_str(vstr_t *vstr, const char *str) {
156181
157182void vstr_add_strn (vstr_t * vstr , const char * str , int len ) {
158183 if (vstr -> had_error || !vstr_ensure_extra (vstr , len )) {
184+ // if buf is fixed, we got here because there isn't enough room left
185+ // so just try to copy as much as we can, with room for null byte
186+ if (vstr -> fixed_buf && vstr -> len + 1 < vstr -> alloc ) {
187+ len = vstr -> alloc - vstr -> len - 1 ;
188+ goto copy ;
189+ }
159190 return ;
160191 }
192+ copy :
161193 memmove (vstr -> buf + vstr -> len , str , len );
162194 vstr -> len += len ;
163195 vstr -> buf [vstr -> len ] = 0 ;
0 commit comments