00001 /* just some information about this file */ 00002 #define STRINGARRAY_VERSION "1.3.1" 00003 #define STRINGARRAY_DATE "19-Dec-2003" 00004 00005 /* structures and typedefs */ 00006 00007 /** @file 00008 * @anchor StringArray 00009 * Fault-tolerant structure to store one or more strings. 00010 * 00011 * This structure provides a fault-tolerant way to store several strings. Strings are stored in sequential 00012 * order with the function @ref StringArray_addElement. The individual elements are accessed via their 00013 * index @b starting @b from @b zero. Therefore, the index of the element with the highest index number 00014 * is one less than @c numberOfElements. 00015 * 00016 * The structure is created with @ref StringArray_create, destroyed with @ref StringArray_destroy and 00017 * displayed with @ref StringArray_display. The number of elements of a structure is returned by the 00018 * function @ref StringArray_getNumberOfElements, the size of the array @c arrayOfStrings is returned 00019 * by the function @ref StringArray_getSizeOfArray. Strings are added by @ref StringArray_addElement and 00020 * the value of an element is obtained by @ref StringArray_getElement. Elements that are identical to 00021 * a given string can be removed with @ref StringArray_removeElement. 00022 * 00023 * If an element is accessed via @ref StringArray_getElement and the index is higher than @c 00024 * numberOfElements - 1 (number of elements of this structure) the define @ref IndexOutOfBoundsError is 00025 * called and the program aborts. 00026 * 00027 * The size of @c arrayOfStrings can grow during the lifetime of a structure @ref StringArray. When a 00028 * structure @ref StringArray is created with @ref StringArray_create the initial size of @c 00029 * arrayOfStrings is set to @ref STRINGARRAY_STARTSIZEOFARRAY. @ref StringArray_addElement checks if @c 00030 * numberOfElements exceeds @c sizeOfArray and, if necessary, resizes the string array automatically via 00031 * @ref StringArray_extend. As there is currently no function to remove elements @c arrayOfStrings can 00032 * not shrink during the lifetime of an instance of @ref StringArray! 00033 * 00034 * @attention 00035 * Function @ref StringArray_addElement just links the given char* to @c arrayOfStrings. The char* is not 00036 * copied and therefore must not be freed after the assignment! If @ref StringArray_destroy is called the 00037 * memory of all elements in @c arrayOfStrings is freed automatically. 00038 * 00039 * <B>Description of the members:</B><BR><BR> 00040 * @c arrayOfStrings - array of char*<BR> 00041 * @c numberOfElements - number of elements in the structure<BR> 00042 * @c sizeOfArray - size of the array @c arrayOfStrings<BR> 00043 * @author Uli Fechner 00044 * @version 01/09/2003 - v1.0.0 - Uli Fechner - initial release 00045 * @version 02/09/2003 - v1.1.0 - Uli Fechner - major change: the size of the string array (@c arrayOfStrings) can 00046 * now grow during the lifetime of a structure @ref StringArray; this is handled automatically by @ref 00047 * StringArray_addElement if @c numberOfElements exceeds @c sizeOfArray; added @ref 00048 * STRINGARRAY_STARTSIZEOFARRAY, @ref StringArray_createWithSpecifiedArraySize and @ref 00049 * StringArray_extend; changes in @ref StringArray_create and StringArray_addElement 00050 * @version 08/09/2003 - v1.1.1 - Uli Fechner - small modification in the output format of @ref 00051 * StringArray_display 00052 * @version 08/09/2003 - v1.2.0 - Uli Fechner - bugfix related to the extension of the array (@ref 00053 * StringArray_addElement and @ref StringArray_extend); modified the headers of both functions 00054 * @version 15/10/2003 - v1.2.1 - Uli Fechner - changed the define @ref STRINGARRAY_STARTSIZEOFARRAY 00055 * @version 10/12/2003 - v1.2.2 - Uli Fechner - added function @ref StringArray_concatenate 00056 * @version 17/12/2003 - v1.3.0 - Uli Fechner - added function @ref StringArray_copy and @ref 00057 * StringArray_mapConcatenate 00058 * @version 19/12/2003 - v1.3.1 - Uli Fechner - added function @ref StringArray_removeElement 00059 * @@code 00060 */ 00061 typedef struct 00062 { 00063 char** arrayOfStrings; 00064 int numberOfElements; 00065 int sizeOfArray; 00066 } StringArray; 00067 /** @endcode */ 00068 00069 00070 /** A pointer to structure @ref StringArray is assigned the name @c StringArrayPtr. */ 00071 typedef StringArray* StringArray_Ptr; 00072 00073 /* defines */ 00074 00075 /** This value sets the size of @c arrayOfStrings if a new structure @ref StringArray is created. 00076 * 00077 * @author Uli Fechner 00078 * @version 02/09/2003 - Uli Fechner - initial release 00079 */ 00080 #ifndef STRINGARRAY_STARTSIZEOFARRAY 00081 #define STRINGARRAY_STARTSIZEOFARRAY 50 00082 #endif 00083 00084 /* function prototypes */ 00085 00086 StringArray_Ptr StringArray_create( void ); 00087 00088 StringArray_Ptr StringArray_createWithSpecifiedArraySize( const int sizeOfArray ); 00089 00090 void StringArray_destroy( StringArray_Ptr sAPtr ); 00091 00092 void StringArray_extend( const StringArray_Ptr sAPtr ); 00093 00094 void StringArray_display( StringArray_Ptr sAPtr, FILE* outputStream ); 00095 00096 StringArray_Ptr StringArray_copy( const StringArray_Ptr sAPtr ); 00097 00098 void StringArray_concatenate( const StringArray_Ptr sAPtrTarget, const StringArray_Ptr sAPtrSource ); 00099 00100 void StringArray_mapConcatenate( const StringArray_Ptr sAPtr, const char* source ); 00101 00102 int StringArray_getNumberOfElements( const StringArray_Ptr sAPtr ); 00103 00104 int StringArray_getSizeOfArray( const StringArray_Ptr sAPtr ); 00105 00106 void StringArray_addElement( const StringArray_Ptr sAPtr, char* string ); 00107 00108 char* StringArray_getElement( const StringArray_Ptr sAPtr, const int index ); 00109 00110 int StringArray_removeElement( StringArray_Ptr sAPtr, const char* string ); 00111 00112 /* functions */ 00113 00114 /** Creates a @ref StringArray structure. 00115 * 00116 * A @ref StringArray structure is created. The size of the array @c arrayOfStrings of the structure is 00117 * @ref STRINGARRAY_STARTSIZEOFARRAY and is dynamically adjusted during the lifetime of the structure. 00118 * 00119 * @attention 00120 * This function is only a wrapper for @ref StringArray_createWithSpecifiedArraySize 00121 * 00122 * @retval StringArray_Ptr pointer on the newly created structure @ref StringArray 00123 * @author Uli Fechner 00124 * @version 01/09/2003 - Uli Fechner - initial release 00125 * @version 02/09/2003 - Uli Fechner - major change: now, this function is a wrapper for @ref 00126 * StringArray_createWithSpecifiedArraySize; therefore, all instructions moved to 00127 * @ref StringArray_createWithSpecifiedArraySize 00128 */ 00129 StringArray_Ptr StringArray_create( void ) 00130 { 00131 return StringArray_createWithSpecifiedArraySize( STRINGARRAY_STARTSIZEOFARRAY ); 00132 } 00133 00134 /** Creates a @ref StringArray structure. 00135 * 00136 * A @ref StringArray structure is created. The size of the array @c arrayOfStrings of the structure is 00137 * given as an argument. 00138 * 00139 * @param sizeOfArray the size of the array @c arrayOfStrings of the newly created structure 00140 * @retval StringArray_Ptr pointer on the newly created structure @ref StringArray 00141 * @author Uli Fechner 00142 * @version 02/09/2003 - Uli Fechner - initial release 00143 */ 00144 StringArray_Ptr StringArray_createWithSpecifiedArraySize( const int sizeOfArray ) 00145 { 00146 StringArray_Ptr sAPtr; 00147 00148 if( !( sAPtr = calloc( 1, sizeof( StringArray ) ) ) ) 00149 MemoryError( "sAPtr", "StringArray_createWithSpecifiedArraySize" ); 00150 00151 sAPtr->sizeOfArray = sizeOfArray; 00152 sAPtr->numberOfElements = 0; 00153 00154 if( sizeOfArray == 0 ) 00155 sAPtr->arrayOfStrings = NULL; 00156 00157 else 00158 { 00159 if( !( sAPtr->arrayOfStrings = calloc( sizeOfArray, sizeof( char* ) ) ) ) 00160 MemoryError( "sAPtr->arrayOfStrings", "StringArray_createWithSpecifiedArraySize" ); 00161 } 00162 00163 return sAPtr; 00164 } 00165 00166 /** Destroys a structure @ref StringArray. 00167 * 00168 * The structure @ref StringArray the pointer @c sAPtr refers to is destroyed. All allocated memory of 00169 * the structure is automatically freed; this includes the memory of the char* of @c arrayOfStrings. 00170 * 00171 * @param sAPtr pointer on the structure @ref StringArray that should be destroyed 00172 * @author Uli Fechner 00173 * @version 01/09/2003 - Uli Fechner - initial release 00174 */ 00175 void StringArray_destroy( StringArray_Ptr sAPtr ) 00176 { 00177 int counter; 00178 00179 if( sAPtr != NULL ) 00180 { 00181 if( sAPtr->arrayOfStrings != NULL ) 00182 { 00183 for( counter = 0; counter < sAPtr->numberOfElements; counter++ ) 00184 { 00185 if( (sAPtr->arrayOfStrings)[counter] != NULL ) 00186 free ( (sAPtr->arrayOfStrings)[counter] ); 00187 } 00188 free( sAPtr->arrayOfStrings ); 00189 } 00190 free( sAPtr ); 00191 } 00192 else 00193 { 00194 fprintf( stderr, "\n\nERROR: Function 'StringArray_destroy' can not destroy a structure\n" ); 00195 fprintf( stderr, "'StringArray' that has not been created before!\n" ); 00196 AbortProgram; 00197 } 00198 } 00199 00200 00201 /** Extends the array size of a structure @ref StringArray. 00202 * 00203 * The array size of the structure @ref StringArray is enlarged (more exactly: its size is doubled). This 00204 * function is automatically called by @ref StringArray_addElement if @c numberOfElements exceeds @c 00205 * sizeOfArray. 00206 * 00207 * @param sAPtr pointer on the structure @ref StringArray containing the array that is extended 00208 * @author Uli Fechner 00209 * @version 02/09/2003 - Uli Fechner - initial release 00210 * @version 08/09/2003 - Uli Fechner - function rewritten from scratch; function header modified 00211 */ 00212 void StringArray_extend( const StringArray_Ptr sAPtr ) 00213 { 00214 int counter; /* counter to enumerate the elements of arrayOfIntegers */ 00215 char** newArrayOfStrings; /* replaces iAPtr->arrayOfStrings */ 00216 00217 /* create new integer array with doubled size compared to iAPtr->arrayOfString */ 00218 if( !( newArrayOfStrings = calloc( 2 * sAPtr->sizeOfArray, sizeof( char* ) ) ) ) 00219 MemoryError( "newArrayOfStrings", "StringArray_extend" ); 00220 00221 /* copy information from sAPtr->arrayOfStrings to newArrayOfStrings */ 00222 for( counter = 0; counter < sAPtr->numberOfElements; counter++ ) 00223 newArrayOfStrings[counter] = (sAPtr->arrayOfStrings)[counter]; 00224 sAPtr->sizeOfArray *= 2; 00225 00226 /* destroy sAPtr->arrayOfStrings */ 00227 if( sAPtr->arrayOfStrings != NULL ) 00228 free( sAPtr->arrayOfStrings ); 00229 00230 sAPtr->arrayOfStrings = newArrayOfStrings; 00231 } 00232 00233 /** Displays a structure @ref StringArray. 00234 * 00235 * The structure @ref StringArray the pointer @c sAPtr refers to is displayed on the FILE* @c 00236 * outputStream. 00237 * 00238 * @param sAPtr pointer on the structure @ref StringArray that is displayed 00239 * @param outputStream FILE* on the stream the output is sent to 00240 * @author Uli Fechner 00241 * @version 01/09/2003 - Uli Fechner - initial release 00242 * @version 08/09/2003 - Uli Fechner - small modifications in the output format 00243 */ 00244 void StringArray_display( StringArray_Ptr sAPtr, FILE* outputStream ) 00245 { 00246 int counter; /* simple counter variable in for loop */ 00247 00248 if( sAPtr == NULL ) 00249 { 00250 fprintf( outputStream, "The Structure 'StringArray' (pointer: %p) does not exist.\n\n", sAPtr ); 00251 return; 00252 } 00253 00254 if( sAPtr->numberOfElements == 0 ) 00255 { 00256 fprintf( outputStream, "The Structure 'StringArray' (pointer: %p) is empty.\n\n", sAPtr ); 00257 return; 00258 } 00259 00260 for( counter = 0; counter < sAPtr->numberOfElements; counter++ ) 00261 fprintf( outputStream, "%s\t", (sAPtr->arrayOfStrings)[counter] ); 00262 //fprintf( outputStream, "\n" ); 00263 } 00264 00265 /** A deepcopy of @c sAPtr is returned. 00266 * 00267 * @attention 00268 * Empty strings (NULL) are not copied. The number of elements of the @b copy of @c sAPtr may 00269 * therefore be less than the number of elements of @c sAPtr. 00270 * 00271 * @param sAPtr a deepcopy of the strings of @c sAPtr is returned 00272 * @retval StringArray_Ptr deepcopy of @c sAPtr 00273 * @author Uli Fechner 00274 * @version 17/12/2003 - Uli Fechner - initial release 00275 */ 00276 StringArray_Ptr StringArray_copy( const StringArray_Ptr sAPtr ) 00277 { 00278 int counter; 00279 char* currentSourceElement; 00280 char* tempString; 00281 StringArray_Ptr copyOfSAPtr; 00282 00283 copyOfSAPtr = StringArray_create( ); 00284 00285 for( counter = 0; counter < sAPtr->numberOfElements; counter++ ) 00286 { 00287 currentSourceElement = StringArray_getElement( sAPtr, counter ); 00288 if( currentSourceElement != NULL ) 00289 { 00290 if( !( tempString = calloc( strlen( currentSourceElement ) + 1, sizeof( char ) ) ) ) 00291 MemoryError( "tempString", "StringArray_copy" ); 00292 strncpy( tempString, currentSourceElement, strlen( currentSourceElement ) + 1 ); 00293 StringArray_addElement( copyOfSAPtr, tempString ); 00294 } 00295 } 00296 return copyOfSAPtr; 00297 } 00298 00299 /** A copy of each string in @c sAPtrSource is added to @c sAPtrTarget. 00300 * 00301 * @attention 00302 * Empty strings (NULL) are not copied. The number of elements that are added to @c sAPtrTarget may 00303 * therefore be less than the number of elements that are added to @c sAPtrSource. 00304 * 00305 * @param sAPtrTarget copies of the strings of @c sAPtrSource are added to this structure @ref StringArray 00306 * @param sAPtrSource copies of the strings of this structure @ref StringArray are added to @c sAPtrSource 00307 * @author Uli Fechner 00308 * @version 10/12/2003 - Uli Fechner - initial release 00309 */ 00310 void StringArray_concatenate( const StringArray_Ptr sAPtrTarget, const StringArray_Ptr sAPtrSource ) 00311 { 00312 int counter; 00313 char* currentSourceElement; 00314 char* tempString; 00315 00316 for( counter = 0; counter < sAPtrSource->numberOfElements; counter++ ) 00317 { 00318 currentSourceElement = StringArray_getElement( sAPtrSource, counter ); 00319 if( currentSourceElement != NULL ) 00320 { 00321 if( !( tempString = calloc( strlen( currentSourceElement ) + 1, sizeof( char ) ) ) ) 00322 MemoryError( "tempString", "StringArray_concatenate" ); 00323 strncpy( tempString, currentSourceElement, strlen( currentSourceElement ) + 1 ); 00324 StringArray_addElement( sAPtrTarget, tempString ); 00325 } 00326 } 00327 } 00328 00329 /** @c source is added to each element (char*) of @c sAPtr. 00330 * 00331 * @attention 00332 * Notrhing is added to empty strings (NULL). 00333 * 00334 * @param sAPtr each element of @c sAPtr is modified 00335 * @param source this char* is concatenated to each element of @c sAPtr 00336 * @author Uli Fechner 00337 * @version 17/12/2003 - Uli Fechner - initial release 00338 */ 00339 void StringArray_mapConcatenate( const StringArray_Ptr sAPtr, const char* source ) 00340 { 00341 int counter; 00342 char* currentElement; 00343 char* tempTargetString; 00344 00345 for( counter = 0; counter < sAPtr->numberOfElements; counter++ ) 00346 { 00347 currentElement = StringArray_getElement( sAPtr, counter ); 00348 if( currentElement != NULL ) 00349 { 00350 if( !( tempTargetString = calloc( strlen( currentElement ) + strlen( source ) + 1, \ 00351 sizeof( char ) ) ) ) 00352 MemoryError( "tempTargetString", "StringArray_mapConcatenate" ); 00353 strncpy( tempTargetString, currentElement, strlen( currentElement ) + 1 ); 00354 strncat( tempTargetString, source, strlen( source ) + 1 ); 00355 (sAPtr->arrayOfStrings)[ counter ] = tempTargetString; 00356 free( currentElement ); 00357 } 00358 } 00359 } 00360 00361 /** Returns the number of elements of a structure @ref StringArray. 00362 * 00363 * The number of elements of the structure @ref StringArray the pointer @c sAPtr refers to is returned. 00364 * 00365 * @param sAPtr pointer on the structure @ref StringArray of which the number of elements is returned 00366 * @retval int number of elements of the structure @ref StringArray 00367 * @author Uli Fechner 00368 * @version 01/09/2003 - Uli Fechner - initial release 00369 */ 00370 int StringArray_getNumberOfElements( const StringArray_Ptr sAPtr ) 00371 { 00372 return sAPtr->numberOfElements; 00373 } 00374 00375 /** Returns the size of the array @c arrayOfStrings of a structure @ref StringArray. 00376 * 00377 * The size of the array @c arrayOfStrings of the structure @ref StringArray is returned. 00378 * 00379 * @param sAPtr pointer on the structure @ref StringArray of which the size of the array is returned 00380 * @retval int size of the array @c arrayOfStrings of the structure @ref StringArray 00381 * @author Uli Fechner 00382 * @version 01/09/2003 - Uli Fechner - initial release 00383 */ 00384 int StringArray_getSizeOfArray( const StringArray_Ptr sAPtr ) 00385 { 00386 return sAPtr->sizeOfArray; 00387 } 00388 00389 /** A char* is added to the structure @ref StringArray. 00390 * 00391 * The char* is added to the array @c arrayOfStrings of structure @ref StringArray. 00392 * If the array @c arrayOfStrings is already full (i.e. @c numberOfElements >= @c sizeOfArray) 00393 * it is extended by calling the function @ref StringArray_extend. 00394 * 00395 * @param sAPtr pointer on the structure @ref StringArray the char* is added to 00396 * @param string char* that is added to @ref StringArray 00397 * @author Uli Fechner 00398 * @version 01/09/2003 - Uli Fechner - initial release 00399 * @version 02/09/2003 - Uli Fechner - added the capability to extend @c arrayOfStrings if necessary; 00400 * therefore, @b const of @c sAPtr had to be removed 00401 * @version 08/09/2003 - Uli Fechner - fixed a bug related to the function call @ref StringArray_extend; 00402 * function header modified (const added) 00403 */ 00404 void StringArray_addElement( const StringArray_Ptr sAPtr, char* string ) 00405 { 00406 if( sAPtr->numberOfElements >= sAPtr->sizeOfArray ) 00407 StringArray_extend( sAPtr ); 00408 00409 (sAPtr->arrayOfStrings)[(sAPtr->numberOfElements)] = string; 00410 (sAPtr->numberOfElements)++; 00411 } 00412 00413 /** The char* of the element with index @c index of structure @ref StringArray is returned. 00414 * 00415 * The value of the element with index @c index of the structure @ref StringArray @c sAPtr points on is 00416 * returned. If the index @c index is greater than (@c numberOfElements - 1 ), the program aborts with 00417 * the call of the define @ref IndexOutOfBoundsError. 00418 * 00419 * @param sAPtr pointer on the structure @ref StringArray that contains the char* 00420 * @param index index of the char* that is returned 00421 * @retval char* the char* with index @c index 00422 * @author Uli Fechner 00423 * @version 01/09/2003 - Uli Fechner - initial release 00424 */ 00425 char* StringArray_getElement( const StringArray_Ptr sAPtr, const int index ) 00426 { 00427 if( index < sAPtr->numberOfElements ) 00428 return (sAPtr->arrayOfStrings)[ index ]; 00429 else 00430 IndexOutOfBoundsError( "StringArray", sAPtr->numberOfElements, index ); 00431 } 00432 00433 /** All elements of @c sAPtr that are identical to @c string are removed. 00434 * 00435 * Elements that are identical to @c string are removed from @c sAPtr. The return value is the number 00436 * of times @c string is found in @c sAPtr. 00437 * 00438 * @param sAPtr @c string is removed from the structure @ref StringArray that is referred to by @c sAPtr 00439 * @param string all occurrences of string are removed from @c sAPtr 00440 * @retval int number of times @c string was removed from @c sAPtr 00441 * @author Uli Fechner 00442 * @version 19/12/2003 - Uli Fechner - initial release 00443 */ 00444 int StringArray_removeElement( StringArray_Ptr sAPtr, const char* string ) 00445 { 00446 StringArray_Ptr newSAPtr; /* new StringArray: all elements that equal string are removed */ 00447 int counter; /* simple counter in for loop */ 00448 int stringFound = 0; /* stores the number of times string is found within sAPtr */ 00449 00450 for( counter = 0; counter < sAPtr->numberOfElements; counter++ ) 00451 { 00452 if( strcmp( sAPtr->arrayOfStrings[ counter ], string ) == 0 ) 00453 { 00454 stringFound++; 00455 free( sAPtr->arrayOfStrings[ counter ] ); 00456 sAPtr->arrayOfStrings[ counter ] = NULL; 00457 } 00458 } 00459 newSAPtr = StringArray_copy( sAPtr ); 00460 StringArray_destroy( sAPtr ); 00461 sAPtr = newSAPtr; 00462 00463 return stringFound; 00464 }