Nilorea Library

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

All Data Structures Files Functions Variables Typedefs Macros Groups
n_str.c
Go to the documentation of this file.
1
9 #include "n_str.h"
10
11 #ifndef NO_NSTR
12
13
18 int empty_nstr( N_STR *nstr )
19 {
20 _assert( nstr , return FALSE );
21 _assert( nstr -> data , return FALSE );
22
23 nstr -> written = 0 ;
24 memset( nstr -> data , 0 , nstr -> length );
25
26 return TRUE ;
27 }
28
34 N_STR *new_nstr( NSTRBYTE size )
35 {
36 N_STR *str = NULL ;
37
38 Malloc( str , N_STR , 1 );
39 _assert( str , return NULL );
40
41 str -> written = 0 ;
42
43 if( size == 0 )
44 {
45 str -> data = NULL ;
46 str -> length = 0 ;
47 }
48 else
49 {
50 Malloc( str -> data , char , size + 1 );
51 _assert( str -> data , Free(str) ; return NULL );
52 str -> length = size ;
53 }
54 return str ;
55 } /* new_nstr(...) */
56
57
58
66 int char_to_nstr_ex( char *from , NSTRBYTE nboct , N_STR **to )
67 {
68 if( (*to) )
69 {
70 n_log( LOG_ERR , "destination N_STR **str is not NULL, you must provide an empty destination" );
71 return FALSE ;
72 };
73
74 Malloc( (*to) , N_STR , 1 );
75 _assert( (*to) , return FALSE );
76
77 Malloc( (*to) -> data , char , nboct + 2 );
78 _assert( (*to) -> data , Free( (*to) );return FALSE );
79
80 memcpy( (*to) -> data , from , nboct );
81 (*to) -> length = nboct + 1 ;
82 (*to) -> written = nboct ;
83
84 return TRUE;
85 } /* char_to_nstr(...) */
86
87
88
94 N_STR *char_to_nstr( char *src )
95 {
96 N_STR *strptr = NULL ;
97 char_to_nstr_ex( src , strlen( src ) , &strptr ) ;
98 return strptr ;
99 } /* char_to_str(...) */
100
101
102
103
109 N_STR *file_to_nstr( char *filename )
110 {
111 N_STR *tmpstr = NULL ;
112 struct stat filestat ;
113 FILE *in = NULL ;
114
115 _assert( filename , return NULL );
116
117 if( stat( filename , &filestat ) != 0 )
118 {
119 #ifdef LINUX
120 if( errno == EOVERFLOW )
121 {
122 n_log( LOG_ERR , "%s size is too big (>4GB,EOVERFLOW)" , filename );
123 }
124 else
125 {
126 #endif
127 n_log( LOG_ERR , "Couldn't stat %s. Errno: %s" , filename , strerror( errno ) );
128 #ifdef LINUX
129 }
130 #endif
131 return NULL ;
132 }
133 if( ( filestat . st_size + 1 ) >= ( pow( 2 , 32 ) - 1 ) )
134 {
135 n_log( LOG_ERR , "Sending file size >= 2GB is not possible yet. %s is %lld oct" , filename , filestat . st_size );
136 return NULL ;
137 }
138
139 n_log( LOG_DEBUG , "File size is: %ld", filestat . st_size );
140
141 in = fopen( filename , "rb" );
142 _assert( in , return NULL );
143
144 tmpstr = new_nstr( filestat . st_size + 1 );
145 _assert( tmpstr , fclose( in );return NULL );
146 tmpstr -> written = filestat . st_size ;
147
148 if( fread( tmpstr -> data , sizeof( char ) , tmpstr -> written , in ) == 0 )
149 {
150 n_log( LOG_ERR , "Couldn't read file, fread return 0" );
151 free_nstr( &tmpstr );
152 fclose( in );
153 return NULL ;
154 }
155 if( ferror( in ) )
156 {
157 n_log( LOG_ERR , "There were some errors when reading %s" , filename );
158 free_nstr( &tmpstr );
159 fclose( in );
160 return NULL ;
161 }
162
163 fclose( in );
164
165 return tmpstr ;
166 } /*file_to_nstr */
167
168
169
170
177 int nstr_to_file( N_STR *str , char *filename )
178 {
179 FILE *out = NULL ;
180
181 _assert( str , return FALSE );
182 _assert( filename , return FALSE );
183
184 out = fopen( filename , "wb" );
185 _assert( out , return FALSE );
186
187 if( fwrite( str -> data , sizeof( char ) , str -> written , out ) == 0 )
188 {
189 n_log( LOG_ERR , "Couldn't write file, fwrite return 0" );
190 fclose( out );
191 return FALSE ;
192 }
193 if( ferror( out ) )
194 {
195 n_log( LOG_ERR , "There were some errors when writing %s" , filename );
196 fclose( out );
197 return FALSE ;
198 }
199 fclose( out );
200
201 return TRUE ;
202 } /* str_to_file( ... ) */
203
204
205
217 int str_to_int_ex( const char *s , NSTRBYTE start , NSTRBYTE end , int *i, const int base )
218 {
219 char *tmpstr = NULL ;
220 char *endstr = NULL ;
221 long l = 0;
222
223 _assert( s , return FALSE );
224
225 Malloc( tmpstr , char , 4 + end - start );
226 _assert( tmpstr , n_log( LOG_ERR , "Unable to Malloc( tmpstr , char , 4 + %d - %d )" , end , start ); return FALSE );
227
228 memcpy( tmpstr , s + start , end - start );
229
230 errno = 0;
231 l = strtol(tmpstr, &endstr, base);
232 if( ( errno == ERANGE && l == LONG_MAX) || l > INT_MAX )
233 {
234 n_log( LOG_ERR , "OVERFLOW reached when converting %s to int" , tmpstr );
235 Free( tmpstr );
236 return FALSE;
237 }
238 if( ( errno == ERANGE && l == LONG_MIN) || l < INT_MIN )
239 {
240 n_log( LOG_ERR , "UNDERFLOW reached when converting %s to int" , tmpstr );
241 Free( tmpstr );
242 return FALSE;
243 }
244 if( *endstr != '\0' && *endstr != '\n' )
245 {
246 n_log( LOG_ERR , "Impossible conversion for %s" , tmpstr );
247 Free( tmpstr );
248 return FALSE;
249 }
250 Free( tmpstr );
251 *i = l;
252 return TRUE;
253 }/* str_to_int_ex( ... ) */
254
255
256
257
265 int str_to_int( const char *s , int *i, const int base )
266 {
267 int ret = FALSE ;
268 if( s )
269 {
270 ret = str_to_int_ex( s , 0 , strlen( s ) , i , base );
271 }
272 return ret ;
273 } /* str_to_int(...) */
274
275
276
277
283 int free_nstr( N_STR **ptr )
284 {
285 _assert( (*ptr) , return FALSE );
286
287 Free( (*ptr) -> data );
288 Free( (*ptr) );
289
290 return TRUE ;
291 } /* free_nstr( ... ) */
292
293
294
299 void free_nstr_ptr( void *ptr )
300 {
301 N_STR *strptr = (N_STR *)ptr ;
302 if( strptr )
303 {
304 Free( strptr -> data );
305 Free( strptr );
306 }
307 } /* free_nstr_ptr( ... ) */
308
309
310
311
317 N_STR *nstrdup( N_STR *str )
318 {
319 N_STR *new_str = NULL ;
320
321 _assert( str , return NULL );
322 _assert( str -> data , return NULL );
323
324 Malloc( new_str , N_STR , 1 );
325 if( new_str )
326 {
327 Malloc( new_str -> data , char , str -> length + 1 );
328 if( new_str -> data )
329 {
330 memcpy( new_str -> data , str -> data , str -> written );
331 new_str -> length = str -> length ;
332 new_str -> written = str -> written ;
333 }
334 else
335 {
336 Free( new_str );
337 n_log( LOG_ERR , "Error duplicating N_STR %p -> data" , str );
338 }
339 }
340 else
341 {
342 n_log( LOG_ERR , "Error duplicating N_STR %p" , str );
343 }
344 return new_str ;
345 } /* nstrdup(...) */
346
347
348
358 int skipw( char *string , char toskip , NSTRBYTE *iterator , int inc )
359 {
360 int error_flag = 0 ;
361 NSTRBYTE previous = 0 ;
362
363 _assert( string , return FALSE );
364
365 previous = *iterator;
366 if( toskip == ' ' )
367 {
368 while( *iterator <= (NSTRBYTE)strlen ( string ) && isspace( string[ *iterator ] ) )
369 {
370 if( inc < 0 && *iterator == 0 )
371 {
372 error_flag = 1 ;
373 break ;
374 }
375 else
376 *iterator = *iterator + inc;
377 }
378 }
379 else
380 {
381 while( *iterator <= (NSTRBYTE)strlen( string ) && string[ *iterator ] == toskip )
382 {
383 if( inc < 0 && *iterator == 0 )
384 {
385 error_flag = 1 ;
386 break ;
387 }
388 else
389 *iterator = *iterator + inc;
390 }
391 }
392 if( error_flag == 1 || *iterator > (NSTRBYTE)strlen ( string ) )
393 {
394 *iterator = previous ;
395 return FALSE;
396 }
397
398 return TRUE;
399 } /*skipw(...)*/
400
401
402
412 int skipu( char *string , char toskip , NSTRBYTE *iterator , int inc )
413 {
414 int error_flag = 0 ;
415 NSTRBYTE previous = 0 ;
416
417 _assert( string , return FALSE );
418
419 previous = *iterator;
420 if( toskip == ' ' )
421 {
422 while( *iterator <= (NSTRBYTE)strlen ( string ) && !isspace( string[ *iterator ] ) )
423 {
424 if( inc < 0 && *iterator == 0 )
425 {
426 error_flag = 1 ;
427 break ;
428 }
429 else
430 *iterator = *iterator + inc;
431 }
432 }
433 else
434 {
435 while( *iterator <= (NSTRBYTE)strlen( string ) && string[ *iterator ] != toskip )
436 {
437 if( inc < 0 && *iterator == 0 )
438 {
439 error_flag = 1 ;
440 break ;
441 }
442 else
443 *iterator = *iterator + inc;
444 }
445 }
446
447 if( error_flag == 1 || *iterator > (NSTRBYTE)strlen ( string ) )
448 {
449 *iterator = previous ;
450 return FALSE;
451 }
452
453 return TRUE;
454 } /*Skipu(...)*/
455
456
457
465 int strup( char *string , char *dest )
466 {
467
468 NSTRBYTE it = 0 ;
469
470 _assert( string , return FALSE );
471 _assert( dest , return FALSE );
472
473 for( it = 0 ; it < (NSTRBYTE)strlen( string ) ; it++ )
474 dest[ it ] = toupper ( string[ it ] );
475
476 return TRUE;
477 } /*strup(...)*/
478
479
480
488 int strlo( char *string , char *dest )
489 {
490
491 NSTRBYTE it = 0 ;
492
493 _assert( string , return FALSE );
494 _assert( dest , return FALSE );
495
496 for( it = 0 ; it < (NSTRBYTE)strlen( string ) ; it++ )
497 dest[ it ] = tolower ( string[ it ] );
498
499 return TRUE;
500 } /*strlo(...)*/
501
502
503
513 int strcpy_u( char *from , char *to , NSTRBYTE to_size , char split , NSTRBYTE *it )
514 {
515 NSTRBYTE _it = 0;
516
517 _assert( from , return FALSE );
518 _assert( to , return FALSE );
519 _assert( (*it) , return FALSE );
520
521 while( _it < to_size && from[ (*it) ] != '\0' && from[ (*it) ] != split )
522 {
523 to[ _it ] = from[ (*it) ] ;
524 (*it) = (*it) + 1 ;
525 _it = _it +1 ;
526 }
527
528 if( _it >= to_size )
529 {
530 n_log( LOG_ERR ,
531 "strcpy_u: not enough space to write %d octet to dest (%d max) , %s: %d \n" , _it , to_size ,
532 __FILE__ , __LINE__ );
533 to[ to_size - 1 ] = '\0' ;
534 return FALSE;
535 }
536
537 to[ _it ] = '\0' ;
538
539 if( _it == 0 )
540 _it = FALSE ;
541
542 return TRUE ;
543 } /* strcpy_u(...) */
544
545
546
554 char** split( char* str , const char* delim , int empty ){
555
556 char** tab=NULL; /* result array */
557 char *ptr = NULL ; /* tmp pointer */
558 int sizeStr;
559 int sizeTab=0; /* array size */
560 char* largestring = NULL; /* pointer to start of string */
561
562 int sizeDelim=strlen(delim);
563
564 _assert( str , return NULL );
565 _assert( delim , return NULL );
566
567 largestring = str;
568
569 while( ( ptr = strstr( largestring , delim ) ) != NULL )
570 {
571 sizeStr=ptr-largestring;
572 if( empty == 1 || sizeStr != 0 )
573 {
574 sizeTab++;
575 tab= (char**) realloc(tab,sizeof(char*)*sizeTab);
576
577 Malloc( tab[sizeTab-1] , char , (int)(sizeof(char)*(sizeStr+1)) );
578 _assert( tab[ sizeTab - 1 ] , goto error );
579
580 strncpy(tab[sizeTab-1],largestring,sizeStr);
581 tab[sizeTab-1][sizeStr]='\0';
582 }
583 ptr=ptr+sizeDelim;
584 largestring=ptr;
585 }
586
587 if(strlen(largestring)!=0)
588 {
589 sizeStr=strlen(largestring);
590 sizeTab++;
591
592 tab= (char**) realloc(tab,sizeof(char*)*sizeTab);
593
594 Malloc( tab[sizeTab-1] , char ,(int)( sizeof(char)*(sizeStr+1) ) );
595 _assert( tab[ sizeTab - 1 ] , goto error );
596
597 strncpy(tab[sizeTab-1],largestring,sizeStr);
598 tab[sizeTab-1][sizeStr]='\0';
599 }
600 else
601 {
602 if( empty == 1 )
603 {
604 sizeTab++;
605 tab= (char**) realloc(tab,sizeof(char*)*sizeTab);
606
607 Malloc( tab[sizeTab-1] , char , (int)(sizeof(char)*1) );
608 _assert( tab[ sizeTab - 1 ] , goto error );
609
610 tab[sizeTab-1][0]='\0';
611 }
612 }
613
614 //on ajoute une case à null pour finir le tableau
615 sizeTab++;
616 tab= (char**) realloc(tab,sizeof(char*)*sizeTab);
617 tab[sizeTab-1]=NULL;
618
619 return tab;
620
621 error:
622 free_split_result( &tab );
623 return NULL;
624 } /* split( ... ) */
625
626
627
633 int split_count( char **split_result )
634 {
635 _assert( split_result , return -1 );
636 _assert( split_result[ 0 ] , return -1 );
637
638 int it = 0 ;
639 while( split_result[ it ] )
640 {
641 it ++ ;
642 }
643 return it ;
644 } /* split_count(...) */
645
646
647
653 int free_split_result( char ***tab )
654 {
655 char **tmptab = (*tab);
656
657 if( !tmptab )
658 return FALSE ;
659
660 int it = 0 ;
661
662 while( tmptab[ it ] )
663 {
664 Free( tmptab[ it ] );
665 it++;
666 }
667 Free( tmptab );
668 (*tab) = NULL ;
669
670 return TRUE ;
671 }/* free_split_result(...)*/
672
673
674
684 int nstrcat_ex( N_STR *dest , void *src , NSTRBYTE size , NSTRBYTE blk_size , int resize_flag )
685 {
686 char *ptr = NULL ;
687 int realloc_flag = 0 ;
688
689 if( ( dest -> written + size >= dest -> length ) && resize_flag == 0 )
690 {
691 n_log( LOG_ERR , "%p to %p: not enough space. Resize forbidden. %lld needed, %lld available" , dest , src , dest -> written + size , dest -> length );
692 return FALSE ;
693 }
694
695 while( ( dest -> written + size ) >= ( dest -> length ) )
696 {
697 dest -> length += blk_size ;
698 realloc_flag = 1 ;
699 }
700 if( realloc_flag == 1 )
701 {
702 Reallocz( dest -> data , char , dest -> written , dest -> length );
703 _assert( dest -> data , Free( dest ); return FALSE );
704 }
705
706 ptr = dest -> data + dest -> written ;
707 memcpy( ptr , src , size );
708 dest -> written += size ;
709
710 return TRUE ;
711 } /* nstrcat_ex( ... ) */
712
713
714
721 int nstrcat( N_STR *dst , N_STR *src )
722 {
723 return nstrcat_ex( dst , src -> data , src -> written , src -> written + 1 , 1 );
724 } /* nstrcat( ... ) */
725
726
727
735 int nstrcat_bytes_ex( N_STR *dest , void *data , NSTRBYTE size )
736 {
737 _assert( dest , return FALSE );
738 _assert( data , return FALSE );
739
740 if( size <= 0 )
741 {
742 n_log( LOG_ERR , "Could not copy 0 or less (%ld) octet!" , size );
743 return FALSE ;
744 }
745
746 return nstrcat_ex( dest , data , size , size + 1 , 1 );
747 } /* nstrcat_bytes_ex( ... )*/
748
749
756 int nstrcat_bytes( N_STR *dest , void *data )
757 {
758 _assert( dest , return FALSE );
759 _assert( data , return FALSE );
760
761 NSTRBYTE size = strlen( (char *)data );
762 if( size <= 0 )
763 {
764 n_log( LOG_ERR , "Could not copy 0 or less (%ld) octet!" , size );
765 return FALSE ;
766 }
767 return nstrcat_bytes_ex( dest , data , size );
768 } /* nstrcat_bytes( ... )*/
769
770
771
779 int write_and_fit( char **dest , NSTRBYTE *size , NSTRBYTE *written , char *src )
780 {
781 char *ptr = NULL ;
782 NSTRBYTE src_size = 0 ;
783 int realloc_flag = 0 ;
784
785 src_size = strlen( src ) ;
786 while( ( (*written) + src_size ) >= (*size) )
787 {
788 (*size) = (*size) + 1024 ;
789 realloc_flag = 1 ;
790 }
791
792 if( realloc_flag == 1 )
793 {
794 (*dest) =(char *)realloc( (*dest) , (*size) * sizeof( char ) );
795 if( !(*dest) )
796 {
797 n_log( LOG_ERR , "reallocation error !!!!" );
798 return FALSE ;
799 }
800 }
801 ptr = (*dest) + (*written) ;
802 snprintf( ptr , (*size) - (*written) , "%s" , src );
803 (*written) += src_size ;
804
805 return TRUE ;
806 } /* write_and_fit( ...) */
807
808
809
810
818 int scan_dir( const char *dir, LIST *result , const int recurse )
819 {
820 DIR *dp = NULL ;
821 struct dirent *entry = NULL;
822 struct stat statbuf;
823 char tmpstr[ PATH_MAX + 11 ] = "" ;
824
825 if( !result )
826 return FALSE ;
827
828 if( ( dp = opendir( dir ) ) == NULL)
829 {
830 n_log( LOG_ERR , "cannot open directory: %s" , dir );
831 return FALSE ;
832 }
833 chdir( dir );
834 while( ( entry = readdir( dp ) ) != NULL )
835 {
836 stat( entry -> d_name , &statbuf );
837 if( S_ISDIR( statbuf . st_mode ) )
838 {
839 if( strcmp( "." , entry -> d_name ) == 0 || strcmp( ".." , entry -> d_name ) == 0 )
840 continue;
841
842 /* Recurse */
843 if( recurse != FALSE )
844 scan_dir( entry -> d_name , result, recurse );
845 }
846 if( S_ISREG( statbuf . st_mode ) )
847 {
848 sprintf( tmpstr , "%s%s" , dir , entry -> d_name );
849 char *file = strdup( tmpstr );
850 if( file )
851 {
852 list_push( result , file , free );
853 }
854 else
855 {
856 n_log( LOG_ERR , "Error loading %s%s" , dir , entry -> d_name );
857 }
858 }
859 }
860
861 chdir( ".." );
862 closedir( dp );
863 return TRUE ;
864 } /*scan_dir(...) */
865
866
867
874 int wildmat(register const char *text, register const char *p)
875 {
876 register int last = 0 ;
877 register int matched = 0;
878 register int reverse = 0;
879
880 for ( ; *p; text++, p++)
881 {
882 if (*text == '\0' && *p != '*')
883 return WILDMAT_ABORT;
884 switch (*p) {
885 case '\\':
886 /* Literal match with following character. */
887 p++;
888 /* FALLTHROUGH */
889 default:
890 if (*text != *p)
891 return FALSE;
892 continue;
893 case '?':
894 /* Match anything. */
895 continue;
896 case '*':
897 while (*++p == '*')
898 /* Consecutive stars act just like one. */
899 continue;
900 if (*p == '\0')
901 /* Trailing star matches everything. */
902 return TRUE;
903 while (*text)
904 if ((matched = wildmat(text++, p)) != FALSE)
905 return matched;
906 return WILDMAT_ABORT;
907 case '[':
908 reverse = p[1] == WILDMAT_NEGATE_CLASS ? TRUE : FALSE;
909 if (reverse)
910 /* Inverted character class. */
911 p++;
912 matched = FALSE;
913 if (p[1] == ']' || p[1] == '-')
914 if (*++p == *text)
915 matched = TRUE;
916 for (last = *p; *++p && *p != ']'; last = *p)
917 /* This next line requires a good C compiler. */
918 if (*p == '-' && p[1] != ']'
919 ? *text <= *++p && *text >= last : *text == *p)
920 matched = TRUE;
921 if (matched == reverse)
922 return FALSE;
923 continue;
924 }
925 }
926 #ifdef WILDMAT_MATCH_TAR_PATTERN
927 if (*text == '/')
928 return TRUE;
929 #endif /* MATCH_TAR_ATTERN */
930 return *text == '\0';
931 } /* wildmatch(...) */
932
933
934
941 int wildmatcase(register const char *text, register const char *p)
942 {
943 register int last;
944 register int matched;
945 register int reverse;
946
947 for ( ; *p; text++, p++) {
948 if (*text == '\0' && *p != '*')
949 return WILDMAT_ABORT;
950 switch (*p) {
951 case '\\':
952 /* Literal match with following character. */
953 p++;
954 /* FALLTHROUGH */
955 default:
956 if (toupper(*text) != toupper(*p))
957 return FALSE;
958 continue;
959 case '?':
960 /* Match anything. */
961 continue;
962 case '*':
963 while (*++p == '*')
964 /* Consecutive stars act just like one. */
965 continue;
966 if (*p == '\0')
967 /* Trailing star matches everything. */
968 return TRUE;
969 while (*text)
970 if ((matched = wildmatcase(text++, p)) != FALSE)
971 return matched;
972 return WILDMAT_ABORT;
973 case '[':
974 reverse = p[1] == WILDMAT_NEGATE_CLASS ? TRUE : FALSE;
975 if (reverse)
976 /* Inverted character class. */
977 p++;
978 matched = FALSE;
979 if (p[1] == ']' || p[1] == '-')
980 if (toupper(*++p) == toupper(*text))
981 matched = TRUE;
982 for (last = toupper(*p); *++p && *p != ']'; last = toupper(*p))
983 if (*p == '-' && p[1] != ']'
984 ? toupper(*text) <= toupper(*++p) && toupper(*text) >= last : toupper(*text) == toupper(*p))
985 matched = TRUE;
986 if (matched == reverse)
987 return FALSE;
988 continue;
989 }
990 }
991 #ifdef WILDMAT_MATCH_TAR_PATTERN
992 if (*text == '/')
993 return TRUE;
994 #endif /* MATCH_TAR_ATTERN */
995 return *text == '\0';
996 } /* wildmatcase(...) */
997
998
999
1000
1010 char *str_replace ( const char *string, const char *substr, const char *replacement )
1011 {
1012 char *tok = NULL;
1013 char *newstr = NULL;
1014 char *oldstr = NULL;
1015 char *head = NULL;
1016
1017 /* if either substr or replacement is NULL, duplicate string a let caller handle it */
1018 if ( substr == NULL || replacement == NULL ) return strdup (string);
1019 newstr = strdup (string);
1020 head = newstr;
1021 while ( (tok = strstr ( head, substr ))){
1022 oldstr = newstr;
1023 newstr = malloc ( strlen ( oldstr ) - strlen ( substr ) + strlen ( replacement ) + 1 );
1024 /*failed to alloc mem, free old string and return NULL */
1025 if ( newstr == NULL ){
1026 free (oldstr);
1027 return NULL;
1028 }
1029 memcpy ( newstr, oldstr, tok - oldstr );
1030 memcpy ( newstr + (tok - oldstr), replacement, strlen ( replacement ) );
1031 memcpy ( newstr + (tok - oldstr) + strlen( replacement ), tok + strlen ( substr ), strlen ( oldstr ) - strlen ( substr ) - ( tok - oldstr ) );
1032 memset ( newstr + strlen ( oldstr ) - strlen ( substr ) + strlen ( replacement ) , 0, 1 );
1033 /* move back head right after the last replacement */
1034 head = newstr + (tok - oldstr) + strlen( replacement );
1035 free (oldstr);
1036 }
1037 return newstr;
1038 }
1039
1040 #endif /* #ifndef NOSTR */
1041