fork download
  1. /********************************************************************//**
  2.  * @file s_get_dyn.c
  3.  * @brief Read a c-string of unknown length from stdin.
  4.  * @author migf1 <mig_f1@hotmail.com>
  5.  * @bug No known bugs
  6.  ************************************************************************
  7.  */
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <stdarg.h>
  11. #include <string.h>
  12.  
  13. /*********************************************************//**
  14.  * @par Prototype
  15.  * char *s_get_dyn( int len );
  16.  *
  17.  * @brief Read a c-string of unknown length form stdin.
  18.  * @param[in] len (int) Initial length to be allocated for the c-string,
  19.  * in characters, excluding the nil-terminator (see notes).
  20.  * @return The read c-string, or NULL on error. The c-string
  21.  * returned on success MUST be explicitly freed before
  22.  * program termination.
  23.  * @note The length of the c-string is dynamically doubled every
  24.  * time it is exhausted. Those reallocations automatically
  25.  * make room for one extra character: the nil-terminator.
  26.  * At the end, and only if it is needed, the length of the
  27.  * created c-string is truncated to the exact number of
  28.  * characters read, plus 1 for the nil-terminator.
  29.  *************************************************************
  30.  */
  31. char *s_get_dyn( int len )
  32. {
  33. int i = 0; /* counter of stdin chars */
  34. char *s = NULL, *try = NULL; /* try: for testing realloc() */
  35.  
  36. /* demand a valid initial length, along with its successful memory allocation */
  37. if ( len < 1 || NULL == (s = calloc( len+1, sizeof(char)) ) )
  38. goto ret_failure;
  39.  
  40. /* keep reading chars from stdin until either '\n' or EOF is typed */
  41. for (i=0; EOF != (s[i] = getchar()) && s[i] != '\n'; i++)
  42. {
  43. if ( i != 0 && i % len == 0 ) /* reallocation is needed */
  44. {
  45. len += len; /* ... increase len by itself */
  46. try = realloc(s, (len+1) * sizeof(char) );
  47. if ( !try ) /* ... reallocation failed */
  48. goto ret_failure; /* ... ... cleanup & return */
  49. s = try; /* ... realloc OK, accept it */
  50. }
  51. }
  52. s[i] = '\0'; /* nil-termnate s */
  53.  
  54. /* if needed, truncate s to its exact length, plus the nil-terminator */
  55. if ( i == len )
  56. return s;
  57. if ( NULL == (try = realloc(s, (i+1) * sizeof(char) )) )
  58. goto ret_failure;
  59.  
  60. return try;
  61.  
  62. ret_failure:
  63. /* cleanup & return failure */
  64. if ( s )
  65. free(s);
  66. return NULL;
  67. }
  68.  
  69. /*********************************************************//**
  70.  * @par Prototype
  71.  * int debug_info( const char *fmttext, ... );
  72.  *
  73.  * @brief A vfpintf() wrapper for outputing debugging info on stderr.
  74.  * @param[in] fmttext (const char *) A c-string holding the formatting template.
  75.  * @param ... A list of arguments, as specified in the formatting template.
  76.  * @return 0 (FALSE) on error, 1 (TRUE) otherwise.
  77.  *************************************************************
  78.  */
  79. int debug_info( const char *fmttext, ... )
  80. {
  81. va_list args;
  82.  
  83. if ( !fmttext )
  84. return 0; /* FALSE */
  85.  
  86. va_start( args, fmttext );
  87. if ( vfprintf( stderr, fmttext, args ) < 0 ) {
  88. fputs("*** vfprintf() failed!\n", stderr);
  89. va_end( args );
  90. return 0; /* FALSE */
  91. }
  92. va_end( args );
  93.  
  94. return 1; /* TRUE */
  95. }
  96.  
  97. /*********************************************************//**
  98.  * @par Prototype
  99.  * char *s_get_dyn_debug( const int len );
  100.  *
  101.  * @brief Same as s_get_dyn() but it ouputs debugging information on stderr.
  102.  *************************************************************
  103.  */
  104. char *s_get_dyn_debug( int len )
  105. {
  106. int i = 0; /* char counter */
  107. char *s = NULL, *try = NULL; /* try: for testing realloc() */
  108.  
  109. debug_info( "--- DBG: memory chunk = %d\n", len );
  110.  
  111. /* demand valid len and a successful allocation of memory */
  112. if ( len < 1 || NULL == (s = calloc( len+1, sizeof(char)) ) )
  113. return NULL;
  114.  
  115. debug_info( "--- DBG: s allocated successfully to %d chars\n", len+1 );
  116.  
  117. for (i=0; EOF != (s[i] = getchar()) && s[i] != '\n'; i++)
  118. {
  119. if ( i != 0 && i % len == 0 ) /* needs realloc */
  120. {
  121. len += len; /* increase len */
  122. try = realloc(s, (len+1) * sizeof(char) );
  123. if ( !try ) { /* realloc failed */
  124. free(s);
  125. return NULL;
  126. }
  127. debug_info(
  128. "--- DBG: s reallocated successfully to %d chars\n",
  129. len+1
  130. );
  131. s = try; /* accept realloc */
  132. }
  133. }
  134. s[i] = '\0';
  135.  
  136. if ( i == len ) {
  137. debug_info( "%s\n", "--- DBG: no truncation is needed!" );
  138. return s;
  139. }
  140.  
  141. debug_info(
  142. "--- DBG: before truncation: strlen = %u chars, maxlen = %d (including '\\0')\n",
  143. (unsigned)strlen(s), len+1
  144. );
  145. if ( NULL == (try = realloc(s, (i+1) * sizeof(char) )) ) {
  146. debug_info( "%s\n", "--- DBG: realloc() error, no truncation!\n" );
  147. free(s);
  148. return NULL;
  149. }
  150.  
  151. debug_info(
  152. "--- DBG: after truncation: strlen = %u, maxlen = %d (including '\\0')\n",
  153. (unsigned)strlen(s), i+1
  154. );
  155.  
  156. return try;
  157. }
  158.  
  159. /*********************************************************//**
  160.  *
  161.  *************************************************************
  162.  */
  163. int main( void )
  164. {
  165. char *s = NULL;
  166.  
  167. printf("Type a string of any length: ");
  168. if ( NULL == (s = s_get_dyn_debug(32)) ) {
  169. fputs("*** possibly out of memory, aborting program...\n", stderr);
  170. goto exit_failure;
  171. }
  172.  
  173. printf( "s: %s\n", s );
  174. free( s );
  175.  
  176. exit( EXIT_SUCCESS );
  177.  
  178. exit_failure:
  179. if ( s )
  180. free(s);
  181. exit( EXIT_FAILURE );
  182. }
  183.  
  184.  
Success #stdin #stdout 0.01s 1856KB
stdin
This is a test for the function char *s_get_dyn(int len); which reads and returns
a c-string of unknown length from the standard input. In this test it is called
with an initial length of 32 characters, excluding the nil-terminator.
stdout
Type a string of any length: s: This is a test for the function char *s_get_dyn(int len); which reads and returns