/********************************************************************//**
* @file s_get_dyn.c
* @brief Read a c-string of unknown length from stdin.
* @author migf1 <mig_f1@hotmail.com>
* @bug No known bugs
************************************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
/*********************************************************//**
* @par Prototype
* char *s_get_dyn( int len );
*
* @brief Read a c-string of unknown length form stdin.
* @param[in] len (int) Initial length to be allocated for the c-string,
* in characters, excluding the nil-terminator (see notes).
* @return The read c-string, or NULL on error. The c-string
* returned on success MUST be explicitly freed before
* program termination.
* @note The length of the c-string is dynamically doubled every
* time it is exhausted. Those reallocations automatically
* make room for one extra character: the nil-terminator.
* At the end, and only if it is needed, the length of the
* created c-string is truncated to the exact number of
* characters read, plus 1 for the nil-terminator.
*************************************************************
*/
char *s_get_dyn( int len )
{
int i = 0; /* counter of stdin chars */
char *s = NULL, *try = NULL; /* try: for testing realloc() */
/* demand a valid initial length, along with its successful memory allocation */
if ( len
< 1 || NULL
== (s
= calloc( len
+1, sizeof(char)) ) ) goto ret_failure;
/* keep reading chars from stdin until either '\n' or EOF is typed */
for (i
=0; EOF
!= (s
[i
] = getchar()) && s
[i
] != '\n'; i
++) {
if ( i != 0 && i % len == 0 ) /* reallocation is needed */
{
len += len; /* ... increase len by itself */
try
= realloc(s
, (len
+1) * sizeof(char) ); if ( !try ) /* ... reallocation failed */
goto ret_failure; /* ... ... cleanup & return */
s = try; /* ... realloc OK, accept it */
}
}
s[i] = '\0'; /* nil-termnate s */
/* if needed, truncate s to its exact length, plus the nil-terminator */
if ( i == len )
return s;
if ( NULL
== (try
= realloc(s
, (i
+1) * sizeof(char) )) ) goto ret_failure;
return try;
ret_failure:
/* cleanup & return failure */
if ( s )
return NULL;
}
/*********************************************************//**
* @par Prototype
* int debug_info( const char *fmttext, ... );
*
* @brief A vfpintf() wrapper for outputing debugging info on stderr.
* @param[in] fmttext (const char *) A c-string holding the formatting template.
* @param ... A list of arguments, as specified in the formatting template.
* @return 0 (FALSE) on error, 1 (TRUE) otherwise.
*************************************************************
*/
int debug_info( const char *fmttext, ... )
{
va_list args;
if ( !fmttext )
return 0; /* FALSE */
if ( vfprintf( stderr
, fmttext
, args
) < 0 ) { fputs("*** vfprintf() failed!\n", stderr
); return 0; /* FALSE */
}
return 1; /* TRUE */
}
/*********************************************************//**
* @par Prototype
* char *s_get_dyn_debug( const int len );
*
* @brief Same as s_get_dyn() but it ouputs debugging information on stderr.
*************************************************************
*/
char *s_get_dyn_debug( int len )
{
int i = 0; /* char counter */
char *s = NULL, *try = NULL; /* try: for testing realloc() */
debug_info( "--- DBG: memory chunk = %d\n", len );
/* demand valid len and a successful allocation of memory */
if ( len
< 1 || NULL
== (s
= calloc( len
+1, sizeof(char)) ) ) return NULL;
debug_info( "--- DBG: s allocated successfully to %d chars\n", len+1 );
for (i
=0; EOF
!= (s
[i
] = getchar()) && s
[i
] != '\n'; i
++) {
if ( i != 0 && i % len == 0 ) /* needs realloc */
{
len += len; /* increase len */
try
= realloc(s
, (len
+1) * sizeof(char) ); if ( !try ) { /* realloc failed */
return NULL;
}
debug_info(
"--- DBG: s reallocated successfully to %d chars\n",
len+1
);
s = try; /* accept realloc */
}
}
s[i] = '\0';
if ( i == len ) {
debug_info( "%s\n", "--- DBG: no truncation is needed!" );
return s;
}
debug_info(
"--- DBG: before truncation: strlen = %u chars, maxlen = %d (including '\\0')\n",
);
if ( NULL
== (try
= realloc(s
, (i
+1) * sizeof(char) )) ) { debug_info( "%s\n", "--- DBG: realloc() error, no truncation!\n" );
return NULL;
}
debug_info(
"--- DBG: after truncation: strlen = %u, maxlen = %d (including '\\0')\n",
);
return try;
}
/*********************************************************//**
*
*************************************************************
*/
int main( void )
{
char *s = NULL;
printf("Type a string of any length: "); if ( NULL == (s = s_get_dyn_debug(32)) ) {
fputs("*** possibly out of memory, aborting program...\n", stderr
); goto exit_failure;
}
exit_failure:
if ( s )
}