(root)/
util-linux-2.39/
lib/
buffer.c
       1  /*
       2   * No copyright is claimed.  This code is in the public domain; do with
       3   * it what you wish.
       4   *
       5   * Written by Karel Zak <kzak@redhat.com>
       6   */
       7  #include "buffer.h"
       8  #include "mbsalign.h"
       9  #include "strutils.h"
      10  
      11  void ul_buffer_reset_data(struct ul_buffer *buf)
      12  {
      13  	if (buf->begin)
      14  		buf->begin[0] = '\0';
      15  	buf->end = buf->begin;
      16  
      17  	if (buf->ptrs && buf->nptrs)
      18  		memset(buf->ptrs, 0, buf->nptrs * sizeof(char *));
      19  }
      20  
      21  void ul_buffer_free_data(struct ul_buffer *buf)
      22  {
      23  	assert(buf);
      24  
      25  	free(buf->begin);
      26  	buf->begin = NULL;
      27  	buf->end = NULL;
      28  	buf->sz = 0;
      29  
      30  	free(buf->ptrs);
      31  	buf->ptrs = NULL;
      32  	buf->nptrs = 0;
      33  
      34  	free(buf->encoded);
      35  	buf->encoded = NULL;
      36  	buf->encoded_sz = 0;
      37  }
      38  
      39  void ul_buffer_set_chunksize(struct ul_buffer *buf, size_t sz)
      40  {
      41  	buf->chunksize = sz;
      42  }
      43  
      44  int ul_buffer_is_empty(struct ul_buffer *buf)
      45  {
      46  	return buf->begin == buf->end;
      47  }
      48  
      49  int ul_buffer_save_pointer(struct ul_buffer *buf, unsigned short ptr_idx)
      50  {
      51  	if (ptr_idx >= buf->nptrs) {
      52  		char **tmp = realloc(buf->ptrs, (ptr_idx + 1) * sizeof(char *));
      53  
      54  		if (!tmp)
      55  			return -EINVAL;
      56  		buf->ptrs = tmp;
      57  		buf->nptrs = ptr_idx + 1;
      58  	}
      59  
      60  	buf->ptrs[ptr_idx] = buf->end;
      61  	return 0;
      62  }
      63  
      64  
      65  char *ul_buffer_get_pointer(struct ul_buffer *buf, unsigned short ptr_idx)
      66  {
      67  	if (ptr_idx < buf->nptrs)
      68  		return buf->ptrs[ptr_idx];
      69  	return NULL;
      70  }
      71  
      72  /* returns length from begin to the pointer */
      73  size_t ul_buffer_get_pointer_length(struct ul_buffer *buf, unsigned short ptr_idx)
      74  {
      75  	char *ptr = ul_buffer_get_pointer(buf, ptr_idx);
      76  
      77  	if (ptr && ptr > buf->begin)
      78  		return ptr - buf->begin;
      79  	return 0;
      80  }
      81  
      82  /* returns width of data in safe encoding (from the begin to the pointer) */
      83  size_t ul_buffer_get_safe_pointer_width(struct ul_buffer *buf, unsigned short ptr_idx)
      84  {
      85  	size_t len = ul_buffer_get_pointer_length(buf, ptr_idx);
      86  
      87  	if (!len)
      88  		return 0;
      89  
      90  	return mbs_safe_nwidth(buf->begin, len, NULL);
      91  }
      92  
      93  void ul_buffer_refer_string(struct ul_buffer *buf, char *str)
      94  {
      95  	if (buf->sz)
      96  		ul_buffer_free_data(buf);
      97  	buf->begin = str;
      98  	buf->sz = str ? strlen(str) : 0;
      99  	buf->end = buf->begin ? buf->begin + buf->sz : buf->begin;
     100  }
     101  
     102  int ul_buffer_alloc_data(struct ul_buffer *buf, size_t sz)
     103  {
     104  	char *tmp;
     105  	size_t len = 0;
     106  
     107  	assert(buf);
     108  
     109  	if (sz <= buf->sz)
     110  		return 0;
     111  
     112  	if (buf->end && buf->begin)
     113  		len = buf->end - buf->begin;
     114  
     115  	if (buf->chunksize)
     116  		sz = ((sz + buf->chunksize) / buf->chunksize) * buf->chunksize + 1;
     117  
     118  	tmp = realloc(buf->begin, sz);
     119  	if (!tmp)
     120  		return -ENOMEM;
     121  
     122  	buf->begin = tmp;
     123  	buf->end = buf->begin + len;
     124  	buf->sz = sz;
     125  
     126  	memset(buf->end, '\0', sz - len);
     127  
     128  	return 0;
     129  }
     130  
     131  int ul_buffer_append_data(struct ul_buffer *buf, const char *data, size_t sz)
     132  {
     133  	size_t maxsz = 0;
     134  
     135  	if (!buf)
     136  		return -EINVAL;
     137  	if (!data || !*data)
     138  		return 0;
     139  
     140  	if (buf->begin && buf->end)
     141  		maxsz = buf->sz - (buf->end - buf->begin);
     142  
     143  	if (maxsz <= sz + 1) {
     144  		int rc = ul_buffer_alloc_data(buf, buf->sz + sz + 1);
     145  		if (rc)
     146  			return rc;
     147  	}
     148  	if (!buf->end)
     149  		return -EINVAL;	/* make static analyzers happy */
     150  
     151  	buf->end = mempcpy(buf->end, data, sz);
     152  	*buf->end = '\0';	/* make sure it's terminated */
     153  	return 0;
     154  }
     155  
     156  int ul_buffer_append_string(struct ul_buffer *buf, const char *str)
     157  {
     158  	if (!str)
     159  		return 0;
     160  
     161  	return ul_buffer_append_data(buf, str, strlen(str));
     162  }
     163  
     164  int ul_buffer_append_ntimes(struct ul_buffer *buf, size_t n, const char *str)
     165  {
     166  	size_t i;
     167  	size_t len = strlen(str);
     168  
     169  	for (i = 0; len && i < n; i++) {
     170  		int rc = ul_buffer_append_data(buf, str, len);
     171  		if (rc)
     172  			return rc;
     173  	}
     174  	return 0;
     175  }
     176  
     177  int ul_buffer_set_data(struct ul_buffer *buf, const char *data, size_t sz)
     178  {
     179  	ul_buffer_reset_data(buf);
     180  	return ul_buffer_append_data(buf, data, sz);
     181  }
     182  
     183  char *ul_buffer_get_data(struct ul_buffer *buf, size_t *sz, size_t *width)
     184  {
     185  	if (sz)
     186  		*sz = buf->end - buf->begin;
     187  	if (width)
     188  		*width = buf->begin && *buf->begin ? mbs_width(buf->begin) : 0;
     189  	return buf->begin;
     190  }
     191  
     192  /* size of allocated area (!= size of stored data */
     193  size_t ul_buffer_get_bufsiz(struct ul_buffer *buf)
     194  {
     195  	return buf->sz;
     196  }
     197  
     198  /* encode data by mbs_safe_encode() to avoid control and non-printable chars */
     199  char *ul_buffer_get_safe_data(struct ul_buffer *buf, size_t *sz, size_t *width, const char *safechars)
     200  {
     201  	char *data = ul_buffer_get_data(buf, NULL, NULL);
     202  	size_t encsz, wsz = 0;
     203  	char *res = NULL;
     204  
     205  	if (!data)
     206  		goto nothing;
     207  
     208  	encsz = mbs_safe_encode_size(buf->sz) + 1;
     209  	if (encsz > buf->encoded_sz) {
     210  		char *tmp = realloc(buf->encoded, encsz);
     211  		if (!tmp)
     212  			goto nothing;
     213  		buf->encoded = tmp;
     214  		buf->encoded_sz = encsz;
     215  	}
     216  
     217  	res = mbs_safe_encode_to_buffer(data, &wsz, buf->encoded, safechars);
     218  	if (!res || !wsz || wsz == (size_t) -1)
     219  		goto nothing;
     220  
     221  	if (width)
     222  		*width = wsz;
     223  	if (sz)
     224  		*sz = strlen(res);
     225  	return res;
     226  nothing:
     227  	if (width)
     228  		*width = 0;
     229  	if (sz)
     230  		*sz = 0;
     231  	return NULL;
     232  }
     233  
     234  
     235  #ifdef TEST_PROGRAM_BUFFER
     236  
     237  enum {
     238  	PTR_AAA  = 0,
     239  	PTR_BBB,
     240  };
     241  
     242  int main(void)
     243  {
     244  	struct ul_buffer buf = UL_INIT_BUFFER;
     245  	char *str;
     246  	size_t sz = 0;
     247  
     248  	ul_buffer_set_chunksize(&buf, 16);
     249  
     250  	ul_buffer_append_string(&buf, "AAA");
     251  	ul_buffer_append_data(&buf, "=", 1);
     252  	ul_buffer_append_string(&buf, "aaa");
     253  	ul_buffer_save_pointer(&buf, PTR_AAA);
     254  
     255  	ul_buffer_append_data(&buf, ",", 1);
     256  	ul_buffer_append_string(&buf, "BBB");
     257  	ul_buffer_append_string(&buf, "=");
     258  	ul_buffer_append_string(&buf, "bbb");
     259  	ul_buffer_save_pointer(&buf, PTR_BBB);
     260  
     261  	str = ul_buffer_get_data(&buf, &sz, NULL);
     262  	printf("data [%zu] '%s'\n", sz, str);
     263  
     264  	printf(" pointer data len: AAA=%zu, BBB=%zu\n",
     265  			ul_buffer_get_pointer_length(&buf, PTR_AAA),
     266  			ul_buffer_get_pointer_length(&buf, PTR_BBB));
     267  	printf(" pointer data width: AAA=%zu, BBB=%zu\n",
     268  			ul_buffer_get_safe_pointer_width(&buf, PTR_AAA),
     269  			ul_buffer_get_safe_pointer_width(&buf, PTR_BBB));
     270  
     271  	ul_buffer_reset_data(&buf);
     272  	ul_buffer_append_string(&buf, "This is really long string to test the buffer function.");
     273  	ul_buffer_save_pointer(&buf, PTR_AAA);
     274  	ul_buffer_append_string(&buf, " YES!");
     275  	str = ul_buffer_get_data(&buf, &sz, NULL);
     276  	printf("data [%zu] '%s'\n", sz, str);
     277  	printf(" pointer data len: AAA=%zu\n", ul_buffer_get_pointer_length(&buf, PTR_AAA));
     278  
     279  	ul_buffer_free_data(&buf);
     280  	str = strdup("foo");
     281  	ul_buffer_refer_string(&buf, str);
     282  	ul_buffer_append_data(&buf, ",", 1);
     283  	ul_buffer_append_string(&buf, "bar");
     284  	str = ul_buffer_get_data(&buf, &sz, NULL);
     285  	printf("data [%zu] '%s'\n", sz, str);
     286  
     287  	ul_buffer_free_data(&buf);
     288  
     289          return EXIT_SUCCESS;
     290  }
     291  #endif /* TEST_PROGRAM_BUFFER */