LAL  7.5.0.1-b72065a
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  */
47 XLALAppendString2Vector (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  */
100 XLALCreateStringVector ( 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 );
155  XLALDestroyStringVector ( ret );
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 ;) */
203 void
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 */
231 static 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 ///
246 char *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 ///
280 LALStringVector *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  */
311 int
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  */
329 char *
330 XLALDeblankString ( 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  */
369 INT4
370 XLALFindStringInVector ( 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
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
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
void XLALDestroyStringVector(LALStringVector *vect)
XLAL-interface: Free a string-vector ;)
Definition: StringVector.c:204
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 * XLALCreateStringVector(const CHAR *str1,...)
Create a StringVector from the list of strings passed as arguments.
Definition: StringVector.c:100
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
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
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
#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