xref: /titanic_41/usr/src/lib/libcmdutils/common/custr.c (revision 28f17cb2cce2c4ba0dcda9d9f52a8935aa02e489)
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
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
45 custr_len(custr_t *cus)
46 {
47 	return (cus->cus_strlen);
48 }
49 
50 const char *
51 custr_cstr(custr_t *cus)
52 {
53 	return (cus->cus_data);
54 }
55 
56 int
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
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
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
128 custr_free(custr_t *cus)
129 {
130 	if (cus == NULL)
131 		return;
132 
133 	free(cus->cus_data);
134 	free(cus);
135 }
136