LAL 7.7.0.1-678514e
StringVector.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2015 Karl Wette
3 * Copyright (C) 2008 Reinhard Prix
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with with program; see the file COPYING. If not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1301 USA
19 */
20
21/*---------- INCLUDES ----------*/
22#include <string.h>
23#include <stdlib.h>
24#include <stdarg.h>
25
26#include <lal/XLALError.h>
27#include <lal/StringVector.h>
28#include <lal/LALMalloc.h>
29#include <lal/LALString.h>
30
31/*---------- DEFINES ----------*/
32/*---------- internal types ----------*/
33
34/*---------- Global variables ----------*/
35/*---------- internal prototypes ----------*/
36
37/*==================== FUNCTION DEFINITIONS ====================*/
38
39/**
40 * Append the given string to the string-vector (XLAL interface), return
41 * pointer to the resulting string-vector, or NULL on error.
42 *
43 * \note It is allowed to pass NULL as the input string-vector 'vect', which corresponds
44 * to creating a new string-vector with a single element 'string'
45 */
47XLALAppendString2Vector (LALStringVector *vect, /**< input string-vector to append to */
48 const CHAR *string /**< string to append */
49 )
50{
51 UINT4 oldlen;
52 LALStringVector *ret;
53
54 if ( !string ) {
55 XLALPrintError ("\n%s: NULL 'string' passed to append\n\n", __func__ );
57 }
58
59 if ( ! vect )
60 { /* special case: NULL string-vector to append to */
61 if ( (ret = XLALCreateStringVector ( string, NULL )) == NULL) {
62 XLALPrintError ("%s: XLALCreateStringVector() failed!\n", __func__ );
64 }
65 }
66 else
67 {
68 ret = vect;
69 oldlen = ret->length;
70
71 if ( (ret->data = XLALRealloc ( ret->data, (oldlen + 1)*sizeof( *ret->data ) )) == NULL ) {
72 XLALPrintError ("%s: XLALRealloc(%d) failed!\n", __func__, oldlen + 1 );
74 }
75
76 ret->length ++;
77
78 if ( (ret->data[oldlen] = XLALCalloc(1, strlen(string) + 1 )) == NULL ) {
79 XLALPrintError ("%s: XLALCalloc(%zu) failed!\n", __func__, strlen(string) + 1 );
81 }
82
83 strcpy ( ret->data[oldlen], string );
84 }
85
86 return ret;
87
88} /* XLALAppendString2Vector() */
89
90
91
92
93/**
94 * Create a StringVector from the list of strings passed as arguments
95 * \note All arguments MUST be CHAR* strings.
96 * The last argument MUST be NULL, as C cannot deduce the number of arguments
97 * otherwise.
98 */
100XLALCreateStringVector ( const CHAR *str1, ... )
101{
102 LALStringVector *ret;
103 const CHAR *next;
104 va_list ap;
105
106 if ( !str1 ) {
107 XLALPrintError ("%s: invalid NULL input string 'str1'\n", __func__ );
109 }
110
111 size_t len;
112
113 /* set up return vector of strings, and handle first argument */
114 len = sizeof(*ret);
115 if ( (ret = XLALCalloc ( 1, len )) == NULL )
116 goto failed;
117
118 len = sizeof(ret->data[0]);
119 if ( (ret->data = XLALCalloc ( 1, len )) == NULL)
120 goto failed;
121
122 len = strlen(str1)+1;
123 if ( (ret->data[0] = XLALCalloc ( len, sizeof(CHAR) )) == NULL )
124 goto failed;
125
126 strcpy ( ret->data[0], str1 );
127 ret->length ++;
128
129 /* handle remaining variable-length list of (assumed)string arguments */
130 va_start(ap, str1);
131
132 while ( (next = va_arg(ap, const CHAR *)) != NULL )
133 {
134 ret->length ++;
135
136 len = ret->length * sizeof(ret->data[0]);
137 if ( (ret->data = XLALRealloc ( ret->data, len)) == NULL )
138 goto failed;
139
140 len = strlen(next)+1;
141 if ( (ret->data[ret->length-1] = XLALCalloc( len, sizeof(CHAR) )) == NULL )
142 goto failed;
143
144 strcpy ( ret->data[ret->length-1], next );
145
146 } /* while more arguments */
147
148 va_end(ap);
149
150 return ret;
151
152 failed:
153 va_end(ap);
154 XLALPrintError ("%s: failed to allocate '%zu' bytes\n", __func__, len );
157
158} /* XLALCreateStringVector() */
159
160
161/**
162 * Create an empty string vector of the given length
163 */
165{
166 LALStringVector * vector;
167 vector = LALMalloc( sizeof( *vector ) );
168 if ( ! vector )
170 vector->length = length;
171 if ( ! length ) /* zero length: set data pointer to be NULL */
172 vector->data = NULL;
173 else /* non-zero length: allocate memory for data */
174 {
175 vector->data = LALCalloc( length, sizeof( *vector->data ) );
176 if ( ! vector->data )
177 {
178 LALFree( vector );
180 }
181 }
182 return vector;
183}
184
185
186/**
187 * Create a copy of a string vector
188 */
190{
191 XLAL_CHECK_NULL( vect != NULL && vect->data != NULL && vect->length > 0, XLAL_EINVAL );
192 LALStringVector *copy = XLALCreateStringVector( vect->data[0], NULL );
193 XLAL_CHECK_NULL( copy != NULL, XLAL_EFUNC );
194 for (size_t i = 1; i < vect->length; ++i) {
195 copy = XLALAppendString2Vector( copy, vect->data[i] );
196 XLAL_CHECK_NULL( copy != NULL, XLAL_EFUNC );
197 }
198 return copy;
199} /* XLALCopyStringVector() */
200
201
202/** XLAL-interface: Free a string-vector ;) */
203void
205{
206 UINT4 i;
207
208 if ( !vect )
209 return;
210
211 if ( vect->data )
212 {
213 for ( i=0; i < vect->length; i++ )
214 {
215 if ( vect->data[i] )
216 XLALFree ( vect->data[i] );
217 }
218
219 XLALFree ( vect->data );
220 }
221
222 XLALFree ( vect );
223
224 return;
225
226} /* XLALDestroyStringVector() */
227
228
229
230/* comparison function for strings */
231static int StringCompare (const void *p1, const void *p2)
232{
233 /* this formulation explicitly follows the example given in 'man qsort' for string-array sorting
234 * Quoting from there:
235 ** The actual arguments to this function are "pointers to
236 ** pointers to char", but strcmp(3) arguments are "pointers
237 ** to char", hence the following cast plus dereference
238 *
239 */
240 return strcmp ( * ( char * const *) p1, * ( char * const *) p2 );
241}
242
243///
244/// Concatenate a string vector 'strings', separated by the string 'sep', into a single string
245///
246char *XLALConcatStringVector( const LALStringVector *strings, const char *sep )
247{
248
249 // Check input
250 XLAL_CHECK_NULL( strings != NULL, XLAL_EFAULT );
251 XLAL_CHECK_NULL( sep != NULL, XLAL_EFAULT );
252
253 // Allocate a string of the required size
254 int len = 1;
255 if ( strings->length > 0 ) {
256 len += strlen( strings->data[0] );
257 for ( size_t i = 1; i < strings->length; ++i ) {
258 len += strlen( sep ) + strlen( strings->data[i] );
259 }
260 }
261 char *s = XLALCalloc( len, sizeof(*s) );
262 XLAL_CHECK_NULL( s != NULL, XLAL_ENOMEM );
263
264 // Concatenate the vector of strings into a single string
265 if ( strings->length > 0 ) {
266 strcpy( s, strings->data[0] );
267 for ( size_t i = 1; i < strings->length; ++i ) {
268 strcat( s, sep );
269 strcat( s, strings->data[i] );
270 }
271 }
272
273 return s;
274
275}
276
277///
278/// Parse 'string' into a string vector of tokens, delimited by the characters 'delim'
279///
280LALStringVector *XLALParseStringVector( const char *string, const char *delim )
281{
282
283 // Check input
284 XLAL_CHECK_NULL( string != NULL, XLAL_EFAULT );
285 XLAL_CHECK_NULL( delim != NULL, XLAL_EFAULT );
286
287 // Allocate an empty string vector
288 LALStringVector *strings = XLALCalloc( 1, sizeof(*strings) );
289 XLAL_CHECK_NULL( strings != NULL, XLAL_ENOMEM );
290
291 // Split the string into a vector of strings
292 char *s = XLALStringDuplicate( string );
293 XLAL_CHECK_NULL( s != NULL, XLAL_EFUNC );
294 char *p = s;
295 char *t = XLALStringToken( &p, delim, 1 );
296 while ( t != NULL ) {
297 XLAL_CHECK_NULL( XLALAppendString2Vector( strings, t ) != NULL, XLAL_EFUNC );
298 t = XLALStringToken( &p, delim, 1 );
299 }
300
301 // Cleanup
302 XLALFree( s );
303
304 return strings;
305
306}
307
308/**
309 * Sort string-vector alphabetically *in place*
310 */
311int
313{
314 if ( !strings || strings->length == 0 ) {
315 XLALPrintError ("%s: invalid empty or zero-length input 'strings'\n", __func__ );
317 }
318
319 qsort ( (void*)(&strings->data[0]), (size_t)(strings->length), sizeof(strings->data[0]), StringCompare );
320
321 return XLAL_SUCCESS;
322
323} /* XLALSortStringVector() */
324
325/**
326 * Copy (and allocate) string from 'start' with length 'len', removing
327 * all starting- and trailing blanks!
328 */
329char *
330XLALDeblankString ( const CHAR *start, UINT4 len )
331{
332 XLAL_CHECK_NULL ( start != NULL, XLAL_EINVAL );
333 XLAL_CHECK_NULL ( len > 0, XLAL_EDOM );
334
335 const CHAR *blank_chars = " \t\n";
336
337 /* clip from beginning */
338 const char *pos0 = start;
339 const char *pos1 = start + len - 1;
340 while ( (pos0 < pos1) && strchr ( blank_chars, (*pos0) ) ) {
341 pos0 ++;
342 }
343
344 /* clip backwards from end */
345 while ( (pos1 >= pos0) && strchr ( blank_chars, (*pos1) ) ) {
346 pos1 --;
347 }
348
349 UINT4 newlen = pos1 - pos0 + 1;
350 XLAL_CHECK_NULL ( newlen > 0, XLAL_EFAILED, "newlen==0: Something went wrong here .. probably a coding mistake.\n" );
351
352 CHAR *ret;
353 XLAL_CHECK_NULL ( (ret = XLALCalloc(1, newlen + 1)) != NULL, XLAL_ENOMEM );
354
355 strncpy ( ret, pos0, newlen );
356 ret[ newlen ] = 0;
357
358 return ret;
359
360} /* XLALDeblankString() */
361
362/**
363 * Search for string 'needle' in string-vector 'haystack', return index to
364 * first matching vector element if found, -1 outherwise.
365 *
366 * Note: function allows haystack=NULL input, in which case -1 (=not found) will be returned.
367 *
368 */
369INT4
370XLALFindStringInVector ( const char *needle, const LALStringVector *haystack )
371{
372 if ( !needle ) {
373 XLALPrintError ("%s: invalid NULL input 'needle'!\n", __func__ );
375 }
376
377 if ( !haystack || (haystack->length == 0) ) // no vector to search => not found
378 return -1;
379
380 UINT4 i;
381 for ( i=0; i < haystack->length; i ++ )
382 if ( !strcmp ( needle, haystack->data[i] ) ) // found it!
383 return i;
384
385 return -1; // didn't find matching entry
386
387} /* XLALFindStringInVector() */
#define LALCalloc(m, n)
Definition: LALMalloc.h:94
#define LALMalloc(n)
Definition: LALMalloc.h:93
#define LALFree(p)
Definition: LALMalloc.h:96
static int StringCompare(const void *p1, const void *p2)
Definition: StringVector.c:231
int XLALPrintError(const char *fmt,...)
Definition: XLALError.c:68
char CHAR
One-byte signed integer, see Headers LAL(Atomic)Datatypes.h for more details.
uint32_t UINT4
Four-byte unsigned integer.
int32_t INT4
Four-byte signed integer.
#define XLALCalloc(m, n)
Definition: LALMalloc.h:45
#define XLALFree(p)
Definition: LALMalloc.h:47
#define XLALRealloc(p, n)
Definition: LALMalloc.h:46
char * XLALStringDuplicate(const char *s)
Like strdup but uses LAL allocation routines (free with LALFree).
Definition: LALString.c:89
char * XLALStringToken(char **s, const char *delim, int empty)
Return the next token delimited by any character in 'delim' from the string 's', which is updated to ...
Definition: LALString.c:292
void XLALDestroyStringVector(LALStringVector *vect)
XLAL-interface: Free a string-vector ;)
Definition: StringVector.c:204
char * XLALDeblankString(const CHAR *start, UINT4 len)
Copy (and allocate) string from 'start' with length 'len', removing all starting- and trailing blanks...
Definition: StringVector.c:330
LALStringVector * XLALAppendString2Vector(LALStringVector *vect, const CHAR *string)
Append the given string to the string-vector (XLAL interface), return pointer to the resulting string...
Definition: StringVector.c:47
LALStringVector * XLALCreateStringVector(const CHAR *str1,...)
Create a StringVector from the list of strings passed as arguments.
Definition: StringVector.c:100
LALStringVector * XLALParseStringVector(const char *string, const char *delim)
Parse 'string' into a string vector of tokens, delimited by the characters 'delim'.
Definition: StringVector.c:280
LALStringVector * XLALCreateEmptyStringVector(UINT4 length)
Create an empty string vector of the given length.
Definition: StringVector.c:164
int XLALSortStringVector(LALStringVector *strings)
Sort string-vector alphabetically in place
Definition: StringVector.c:312
char * XLALConcatStringVector(const LALStringVector *strings, const char *sep)
Concatenate a string vector 'strings', separated by the string 'sep', into a single string.
Definition: StringVector.c:246
INT4 XLALFindStringInVector(const char *needle, const LALStringVector *haystack)
Search for string 'needle' in string-vector 'haystack', return index to first matching vector element...
Definition: StringVector.c:370
LALStringVector * XLALCopyStringVector(const LALStringVector *vect)
Create a copy of a string vector.
Definition: StringVector.c:189
#define XLAL_ERROR_NULL(...)
Macro to invoke a failure from a XLAL routine returning a pointer.
Definition: XLALError.h:713
#define XLAL_ERROR(...)
Macro to invoke a failure from a XLAL routine returning an integer.
Definition: XLALError.h:700
#define XLAL_CHECK_NULL(assertion,...)
Macro to test an assertion and invoke a failure if it is not true in a function that returns a pointe...
Definition: XLALError.h:825
@ XLAL_ENOMEM
Memory allocation error.
Definition: XLALError.h:407
@ XLAL_SUCCESS
Success return value (not an error number)
Definition: XLALError.h:401
@ XLAL_EFAULT
Invalid pointer.
Definition: XLALError.h:408
@ XLAL_EFUNC
Internal function call failed bit: "or" this with existing error number.
Definition: XLALError.h:462
@ XLAL_EDOM
Input domain error.
Definition: XLALError.h:410
@ XLAL_EINVAL
Invalid argument.
Definition: XLALError.h:409
@ XLAL_EFAILED
Generic failure.
Definition: XLALError.h:418
Vector of type CHAR*, ie 'strings', see DATATYPE-Vector types for more details.
Definition: LALDatatypes.h:82
UINT4 length
Number of elements in array.
Definition: LALDatatypes.h:86
CHAR ** data
Pointer to the data array.
Definition: LALDatatypes.h:87