1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * String utility functions with dynamic memory management.
14 */
15
16 /*
17 * Copyright 2014, Joyent, Inc.
18 */
19
20 #include <stdlib.h>
21 #include <err.h>
22 #include <string.h>
23
24 #include "libcmdutils.h"
25
26 struct custr {
27 size_t cus_strlen;
28 size_t cus_datalen;
29 char *cus_data;
30 };
31
32 #define STRING_CHUNK_SIZE 64
33
34 void
custr_reset(custr_t * cus)35 custr_reset(custr_t *cus)
36 {
37 if (cus->cus_data == NULL)
38 return;
39
40 cus->cus_strlen = 0;
41 cus->cus_data[0] = '\0';
42 }
43
44 size_t
custr_len(custr_t * cus)45 custr_len(custr_t *cus)
46 {
47 return (cus->cus_strlen);
48 }
49
50 const char *
custr_cstr(custr_t * cus)51 custr_cstr(custr_t *cus)
52 {
53 return (cus->cus_data);
54 }
55
56 int
custr_appendc(custr_t * cus,char newc)57 custr_appendc(custr_t *cus, char newc)
58 {
59 char news[2];
60
61 news[0] = newc;
62 news[1] = '\0';
63
64 return (custr_append(cus, news));
65 }
66
67 int
custr_append(custr_t * cus,const char * news)68 custr_append(custr_t *cus, const char *news)
69 {
70 size_t len = strlen(news);
71 size_t chunksz = STRING_CHUNK_SIZE;
72
73 while (chunksz < len) {
74 chunksz *= 2;
75 }
76
77 if (len + cus->cus_strlen + 1 >= cus->cus_datalen) {
78 char *new_data;
79 size_t new_datalen = cus->cus_datalen + chunksz;
80
81 /*
82 * Allocate replacement memory:
83 */
84 if ((new_data = malloc(new_datalen)) == NULL) {
85 return (-1);
86 }
87
88 /*
89 * Copy existing data into replacement memory and free
90 * the old memory.
91 */
92 if (cus->cus_data != NULL) {
93 (void) memcpy(new_data, cus->cus_data,
94 cus->cus_strlen + 1);
95 free(cus->cus_data);
96 }
97
98 /*
99 * Swap in the replacement buffer:
100 */
101 cus->cus_data = new_data;
102 cus->cus_datalen = new_datalen;
103 }
104 /*
105 * Append new string to existing string:
106 */
107 (void) memcpy(cus->cus_data + cus->cus_strlen, news, len + 1);
108 cus->cus_strlen += len;
109
110 return (0);
111 }
112
113 int
custr_alloc(custr_t ** cus)114 custr_alloc(custr_t **cus)
115 {
116 custr_t *t;
117
118 if ((t = calloc(1, sizeof (*t))) == NULL) {
119 *cus = NULL;
120 return (-1);
121 }
122
123 *cus = t;
124 return (0);
125 }
126
127 void
custr_free(custr_t * cus)128 custr_free(custr_t *cus)
129 {
130 if (cus == NULL)
131 return;
132
133 free(cus->cus_data);
134 free(cus);
135 }
136