1 /*===========================================================================
2 *
3 *                            PUBLIC DOMAIN NOTICE
4 *               National Center for Biotechnology Information
5 *
6 *  This software/database is a "United States Government Work" under the
7 *  terms of the United States Copyright Act.  It was written as part of
8 *  the author's official duties as a United States Government employee and
9 *  thus cannot be copyrighted.  This software/database is freely available
10 *  to the public for use. The National Library of Medicine and the U.S.
11 *  Government have not placed any restriction on its use or reproduction.
12 *
13 *  Although all reasonable efforts have been taken to ensure the accuracy
14 *  and reliability of the software and data, the NLM and the U.S.
15 *  Government do not and cannot warrant the performance or results that
16 *  may be obtained by using this software or data. The NLM and the U.S.
17 *  Government disclaim all warranties, express or implied, including
18 *  warranties of performance, merchantability or fitness for any particular
19 *  purpose.
20 *
21 *  Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26 
27 #include "dyn_string.h"
28 #include <klib/text.h>
29 #include <klib/printf.h>
30 #include <klib/out.h>
31 
32 typedef struct dyn_string
33 {
34     char * data;
35     size_t allocated;
36     size_t data_len;
37 } dyn_string;
38 
39 
allocated_dyn_string(struct dyn_string ** self,size_t size)40 rc_t allocated_dyn_string ( struct dyn_string **self, size_t size )
41 {
42     rc_t rc = 0;
43     struct dyn_string * res = malloc( sizeof *res );
44     *self = NULL;
45     if ( res == NULL )
46         rc = RC( rcApp, rcNoTarg, rcConstructing, rcMemory, rcExhausted );
47     else
48     {
49         res->data_len = 0;
50         res->data = malloc( size );
51         if ( res->data != NULL )
52             res->allocated = size;
53         else
54         {
55             res->allocated = 0;
56             rc = RC( rcApp, rcNoTarg, rcConstructing, rcMemory, rcExhausted );
57         }
58         if ( rc != 0 )
59             free( res );
60         else
61             *self = res;
62     }
63     return rc;
64 }
65 
66 
free_dyn_string(struct dyn_string * self)67 void free_dyn_string ( struct dyn_string *self )
68 {
69     free( self->data );
70     self->data = NULL;
71     self->allocated = 0;
72     self->data_len = 0;
73     free( ( void * ) self );
74 }
75 
76 
reset_dyn_string(struct dyn_string * self)77 void reset_dyn_string( struct dyn_string *self )
78 {
79     self->data_len = 0;
80 }
81 
82 
expand_dyn_string(struct dyn_string * self,size_t new_size)83 rc_t expand_dyn_string( struct dyn_string *self, size_t new_size )
84 {
85     rc_t rc = 0;
86     if ( new_size > self->allocated )
87     {
88         self->data = realloc ( self->data, new_size );
89         if ( self->data != NULL )
90         {
91             self->allocated = new_size;
92         }
93         else
94         {
95             self->allocated = 0;
96             self->data_len = 0;
97             rc = RC( rcApp, rcNoTarg, rcConstructing, rcMemory, rcExhausted );
98         }
99     }
100     return rc;
101 }
102 
103 
add_char_2_dyn_string(struct dyn_string * self,const char c)104 rc_t add_char_2_dyn_string( struct dyn_string *self, const char c )
105 {
106     /* does nothing if self->data_len + 2 < self->allocated */
107     rc_t rc = expand_dyn_string( self, self->data_len + 2 );
108     if ( rc == 0 )
109     {
110         self->data[ self->data_len++ ] = c;
111         self->data[ self->data_len ] = 0;
112     }
113     return rc;
114 }
115 
116 
dyn_string_char(struct dyn_string * self,uint32_t idx)117 char * dyn_string_char( struct dyn_string *self, uint32_t idx )
118 {
119     return( &self->data[ idx ] );
120 }
121 
122 
add_string_2_dyn_string(struct dyn_string * self,const char * s)123 rc_t add_string_2_dyn_string( struct dyn_string *self, const char * s )
124 {
125     rc_t rc;
126     size_t size = string_size ( s );
127     /* does nothing if self->data_len + size + 1 < self->allocated */
128     rc = expand_dyn_string( self, self->data_len + size + 1 );
129     if ( rc == 0 )
130     {
131         string_copy ( &(self->data[ self->data_len ]), self->allocated, s, size );
132         self->data_len += size;
133         self->data[ self->data_len ] = 0;
134     }
135     return rc;
136 }
137 
138 
add_dyn_string_2_dyn_string(struct dyn_string * self,struct dyn_string * other)139 rc_t add_dyn_string_2_dyn_string( struct dyn_string *self, struct dyn_string *other )
140 {
141     rc_t rc = 0;
142     size_t size = other->data_len;
143 	if ( size > 0 )
144 	{
145 		/* does nothing if self->data_len + size + 1 < self->allocated */
146 		rc = expand_dyn_string( self, self->data_len + size + 1 );
147 		if ( rc == 0 )
148 		{
149 			string_copy ( &(self->data[ self->data_len ]), self->allocated, other->data, size );
150 			self->data_len += size;
151 			self->data[ self->data_len ] = 0;
152 		}
153 	}
154     return rc;
155 
156 }
157 
158 
print_2_dyn_string(struct dyn_string * self,const char * fmt,...)159 rc_t print_2_dyn_string( struct dyn_string * self, const char *fmt, ... )
160 {
161     rc_t rc = 0;
162     bool not_enough;
163 
164     do
165     {
166         size_t num_writ;
167         va_list args;
168         va_start ( args, fmt );
169         rc = string_vprintf ( &(self->data[ self->data_len ]),
170                               self->allocated - ( self->data_len + 1 ),
171                               &num_writ,
172                               fmt,
173                               args );
174         va_end ( args );
175 
176         if ( rc == 0 )
177         {
178             self->data_len += num_writ;
179             self->data[ self->data_len ] = 0;
180         }
181         not_enough = ( GetRCState( rc ) == rcInsufficient );
182         if ( not_enough )
183         {
184             rc = expand_dyn_string( self, self->allocated + ( num_writ * 2 ) );
185         }
186     } while ( not_enough && rc == 0 );
187     return rc;
188 }
189 
190 
print_dyn_string(struct dyn_string * self)191 rc_t print_dyn_string( struct dyn_string * self )
192 {
193     if ( self != NULL )
194         return KOutMsg( "%.*s", self->data_len, self->data );
195     else
196         return 0;
197 }
198 
199 
dyn_string_len(struct dyn_string * self)200 size_t dyn_string_len( struct dyn_string * self )
201 {
202     if ( self != NULL )
203         return self->data_len;
204     else
205         return 0;
206 }
207