Pastebin launched a little side project called VERYVIRAL.com, check it out ;-) Want more features on Pastebin? Sign Up, it's FREE!
Guest

SPStrinc.c - Dynamic string in C

By: a guest on Jun 13th, 2011  |  syntax: C  |  size: 11.05 KB  |  views: 196  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. /*
  2. *  C Implementation: SPString
  3. *
  4. * Description:
  5. *    This class provides a safe and convenient, albeit slower, alternative
  6. *    to C character chains.
  7. *
  8. *    One can easily create a String from a C string with newString(char *).
  9. *    String.str always returns a null-terminated C chain, and String.len
  10. *    returns its length.
  11. *    One should always avoid to manipulate the String structure members
  12. *    directly in order to prevent corruption (i.e incorrect sz and len values).
  13. *
  14. *    Most functions mirror standard C functions.
  15. *    stringcpy and stringcat can increase their buffer size if necessary in
  16. *    order to prevent buffer overflow.
  17. *
  18. * Author: Nicolas Janin <>, (C) 2009
  19. *
  20. * Copyright: LGPL
  21. *
  22. */
  23.  
  24. #include <stddef.h>
  25. #include <string.h>
  26. #include <malloc.h>
  27. #include <assert.h>
  28. #include <stdarg.h>
  29. #include <stdio.h>
  30. #include "SPString.h"
  31.  
  32. #undef  TIDY   /* Tidy up buffers by filling them with zeroes       */
  33.                            /* Slows things down a little, so uncomment this     */
  34.                            /* only if needed.                                   */
  35.  
  36. /* private (internal mechanics) */
  37. static int ST_ERR = ST_NO_ERR;
  38. static int incsz ( String *string, size_t len );
  39.  
  40. /* --- Dynamic allocation
  41.  
  42.  String can dynamically increase in size as necessary. */
  43. String * newString ( const char *chars )
  44. {
  45.         String *newS = NULL;
  46.  
  47.         if ( chars != NULL )
  48.         {
  49.                 size_t len = strlen ( chars );
  50.                 newS = ( String * ) malloc ( sizeof ( String ) );
  51.                 if ( newS != NULL )
  52.                 {
  53.                         newS->len = len;
  54.                         newS->sz = len + 1;
  55.                         newS->str = strdup ( chars );
  56.                         if ( newS->str == NULL )
  57.                         {
  58.                                 ST_ERR = ST_ALLOC_ERR;
  59.                         }
  60.                 }
  61.                 else
  62.                 {
  63.                         ST_ERR = ST_ALLOC_ERR;
  64.                 }
  65.         }
  66.         else
  67.         {
  68.                 ST_ERR = ST_NULLPARAM_ERR;
  69.         }
  70.         return newS;
  71. }
  72.  
  73. void delString ( String *string )
  74. {
  75. #ifdef NDEBUG
  76.         stringcheck ( string, __FILE__, __LINE__ );
  77. #endif
  78.         if ( string != NULL )
  79.         {
  80.                 if ( string->str != NULL )
  81.                 {
  82.                         free ( string->str );
  83.                         string->str = NULL;
  84.                 }
  85.                 else
  86.                 {
  87.                         ST_ERR = ST_NULLSTR_ERR;
  88.                 }
  89.                 free ( string );
  90.                 string = NULL;
  91.         }
  92.         else
  93.         {
  94.                 ST_ERR = ST_NULLPARAM_ERR;
  95.         }
  96. }
  97.  
  98. /* Copy - Will increase dst allocation if src is too large */
  99. size_t stringcpy ( String *dst, const String *src )
  100. {
  101. #ifdef NDEBUG
  102.         stringcheck ( src, __FILE__, __LINE__ );
  103.         stringcheck ( dst, __FILE__, __LINE__ );
  104. #endif
  105.         size_t len = src->len;
  106.         if ( dst->sz <= len )
  107.         {
  108.                 if ( incsz ( dst, len + 1 ) == ST_ALLOC_ERR )
  109.                 {
  110.                         return ST_ALLOC_ERR;
  111.                 }
  112.         }
  113.  
  114.         dst->len = len;
  115. #ifdef TIDY
  116.         strncpy ( dst->str, src->str, len );
  117. #else
  118.         strcpy ( dst->str, src->str );
  119. #endif
  120.         return len;
  121. }
  122.  
  123. /* Copy - Will increase dst allocation if src is too large */
  124. size_t stringchcpy ( String *dst, const char *src )
  125. {
  126. #ifdef NDEBUG
  127.         stringcheck ( dst, __FILE__, __LINE__ );
  128. #endif
  129.         if ( src == NULL )
  130.         {
  131.                 ST_ERR = ST_NULLPARAM_ERR;
  132.                 return ST_NULLPARAM_ERR;
  133.         }
  134.         size_t len = strlen ( src );
  135.         if ( dst->sz <= len )
  136.         {
  137.                 if ( incsz ( dst, len + 1 ) == ST_ALLOC_ERR )
  138.                 {
  139.                         return ST_ALLOC_ERR;
  140.                 }
  141.         }
  142.  
  143.         dst->len = len;
  144. #ifdef TIDY
  145.         strncpy ( dst->str, src, len );
  146. #else
  147.         strcpy ( dst->str, src );
  148. #endif
  149.         return len;
  150. }
  151.  
  152. /* Concatenation - Will increase dst allocation when necessary */
  153. size_t stringcat ( String *dst, const String *src )
  154. {
  155. #ifdef NDEBUG
  156.         stringcheck ( src, __FILE__, __LINE__ );
  157.         stringcheck ( dst, __FILE__, __LINE__ );
  158. #endif
  159.         size_t len = src->len;
  160.         size_t finallen = dst->len + len;
  161.         if ( dst->sz <= finallen )
  162.         {
  163.                 if ( incsz ( dst, finallen + 1 ) == ST_ALLOC_ERR )
  164.                 {
  165.                         return ST_ALLOC_ERR;
  166.                 }
  167.         }
  168.  
  169.         dst->len = finallen;
  170.         strcat ( dst->str, src->str );
  171. #ifdef TIDY
  172.         size_t l = dst->len;
  173.         char * end =  dst->str + l;
  174.         for ( ; l < dst->sz; l++ ) *end++ = 0;
  175. #endif
  176.         return len;
  177. }
  178.  
  179. /* Concatenation - Will increase dst allocation when necessary */
  180. size_t stringchcat ( String *dst, const char *src )
  181. {
  182. #ifdef NDEBUG
  183.         stringcheck ( dst, __FILE__, __LINE__ );
  184. #endif
  185.         if ( src == NULL )
  186.         {
  187.                 ST_ERR = ST_NULLPARAM_ERR;
  188.                 return ST_NULLPARAM_ERR;
  189.         }
  190.         size_t len = strlen ( src );
  191.         size_t finallen = dst->len + len;
  192.         if ( dst->sz <= finallen )
  193.         {
  194.                 if ( incsz ( dst, finallen + 1 ) == ST_ALLOC_ERR )
  195.                 {
  196.                         return ST_ALLOC_ERR;
  197.                 }
  198.         }
  199.  
  200.         dst->len = finallen;
  201.         strcat ( dst->str, src );
  202. #ifdef TIDY
  203.         size_t l = dst->len;
  204.         char * end =  dst->str + l;
  205.         for ( ; l < dst->sz; l++ ) *end++ = 0;
  206. #endif
  207.  
  208.         return len;
  209. }
  210.  
  211. /* Duplication - allocate a new String */
  212. String * stringdup ( const String *src )
  213. {
  214. #ifdef NDEBUG
  215.         stringcheck ( src, __FILE__, __LINE__ );
  216. #endif
  217.         String *string = NULL;
  218.         if ( src != NULL )
  219.         {
  220.                 string = newString ( src->str );
  221.         }
  222.         else
  223.         {
  224.                 ST_ERR = ST_NULLPARAM_ERR;
  225.         }
  226.         return string;
  227. }
  228.  
  229.  
  230. /* ---- Allocation on the stack (non dynamic) */
  231.  
  232. /*
  233.     Allocation on the stack
  234.     Here, szMax is a maximum size of the buffer, which is allocated
  235.     once and for all, and cannot be increased at runtime.
  236.     Furthermore, the chars array must not be deallocated before the release
  237.     of the LString (else mangling pointer).
  238.     If you need fully extensible Strings, use dynamic allocation instead.
  239. */
  240. LString localString ( char *chars, size_t szMax )
  241. {
  242.         LString newS;
  243.         if ( chars != NULL )
  244.         {
  245.                 newS = ( LString ) {szMax, strlen ( chars ), chars};
  246. #ifdef TIDY
  247.                 size_t l = newS.len;
  248.                 char * end =  chars + l;
  249.                 for ( ; l < szMax; l++ ) *end++ = 0;
  250. #endif
  251.         }
  252.         else
  253.         {
  254.                 ST_ERR = ST_NULLPARAM_ERR;
  255.                 newS = ( LString ) {0, 0, NULL};
  256.         }
  257.         return newS;
  258. }
  259.  
  260. /* Copy of LString - checks that there is no buffer overflow */
  261. size_t lstringcpy ( LString *dst, const LString *src )
  262. {
  263. #ifdef NDEBUG
  264.         stringcheck ( ( String * ) src, __FILE__, __LINE__ );
  265.         stringcheck ( ( String * ) dst, __FILE__, __LINE__ );
  266. #endif
  267.         size_t len = src->len;
  268.         if ( dst->sz <= len )
  269.         {
  270.                 ST_ERR = ST_OVERWRITE_ERR;
  271.                 return ST_OVERWRITE_ERR;
  272.         }
  273.         dst->len = len;
  274. #ifdef TIDY
  275.         strncpy ( dst->str, src->str, dst->sz );
  276. #else
  277.         strcpy ( dst->str, src->str );
  278. #endif
  279.         return len;
  280. }
  281.  
  282. /* Copy of a fixed character chain in a LString
  283.  * checks that there is no buffer overflow
  284.  */
  285. size_t lstringchcpy ( LString *dst, const char *src )
  286. {
  287. #ifdef NDEBUG
  288.         stringcheck ( ( String * ) dst, __FILE__, __LINE__ );
  289. #endif
  290.         if ( src == NULL )
  291.         {
  292.                 ST_ERR = ST_NULLPARAM_ERR;
  293.                 return ST_NULLPARAM_ERR;
  294.         }
  295.         size_t len = strlen ( src );
  296.         if ( dst->sz <= len )
  297.         {
  298.                 ST_ERR = ST_OVERWRITE_ERR;
  299.                 return ST_OVERWRITE_ERR;
  300.         }
  301.         dst->len = len;
  302. #ifdef TIDY
  303.         strncpy ( dst->str, src, dst->sz );
  304. #else
  305.         strcpy ( dst->str, src );
  306. #endif
  307.         return len;
  308. }
  309.  
  310. size_t lstringcat ( LString *dst, const LString *src )
  311. {
  312. #ifdef NDEBUG
  313.         stringcheck ( ( String * ) src, __FILE__, __LINE__ );
  314.         stringcheck ( ( String * ) dst, __FILE__, __LINE__ );
  315. #endif
  316.         size_t len = src->len;
  317.         size_t finallen = dst->len + len;
  318.         if ( finallen >= dst->sz )
  319.         {
  320.                 ST_ERR = ST_OVERWRITE_ERR;
  321.                 return ST_OVERWRITE_ERR;
  322.         }
  323.         dst->len = finallen;
  324.         strcat ( dst->str, src->str );
  325. #ifdef TIDY
  326.         size_t l = dst->len;
  327.         char * end =  dst->str + l;
  328.         for ( ; l < dst->sz; l++ ) *end++ = 0;
  329. #endif
  330.         return len;
  331. }
  332.  
  333. /* Cooncatenation of a fixed character chain to a LString */
  334. size_t lstringchcat ( LString *dst, const char *src )
  335. {
  336. #ifdef NDEBUG
  337.         stringcheck ( ( String * ) dst, __FILE__, __LINE__ );
  338. #endif
  339.         if ( src == NULL )
  340.         {
  341.                 ST_ERR = ST_NULLPARAM_ERR;
  342.                 return ST_NULLPARAM_ERR;
  343.         }
  344.         size_t len = strlen ( src );
  345.         size_t finallen = dst->len + len;
  346.         if ( finallen >= dst->sz )
  347.         {
  348.                 ST_ERR = ST_OVERWRITE_ERR;
  349.                 return ST_OVERWRITE_ERR;
  350.         }
  351.         dst->len = finallen;
  352.         strcat ( dst->str, src );
  353. #ifdef TIDY
  354.         size_t l = dst->len;
  355.         char * end =  dst->str + l;
  356.         for ( ; l < dst->sz; l++ ) *end++ = 0;
  357. #endif
  358.         return len;
  359. }
  360.  
  361. LString lstringdup ( const LString *src )
  362. {
  363. #ifdef NDEBUG
  364.         stringcheck ( ( String * ) src, __FILE__, __LINE__ );
  365. #endif
  366.         LString string;
  367.         if ( src != NULL )
  368.         {
  369.                 string = localString ( src->str, src->len );
  370.         }
  371.         else
  372.         {
  373.                 ST_ERR = ST_NULLPARAM_ERR;
  374.                 string = ( LString ) {0, 0, NULL};
  375.         }
  376.         return string;
  377. }
  378.  
  379. /* The following functions apply both on String and LString */
  380.  
  381. size_t stringlen ( const String *string )
  382. {
  383.         return string->len;
  384. }
  385.  
  386. /*
  387.     Check for an internal inconsistency in a LString.
  388.     You can use this in a debugging session.
  389. */
  390. int stringcheck ( const String *string, char *file, int line )
  391. {
  392. #ifdef NDEBUG
  393.         #define ASSERT(cond) if ( !(cond) ) { \
  394.                         printf("stringcheck error %s line %d:String(%d/%d)=\"%s\"\n", \
  395.                         file, line, string->len, string->sz, string->str); \
  396.                         assert( string != NULL ); }
  397.         ASSERT ( string != NULL );
  398.         ASSERT ( string->str != NULL );
  399.         ASSERT ( string->len < string->sz );
  400.         ASSERT ( string->len == strlen ( string->str ) );
  401.         return 0;
  402.         #undef ASSERT
  403. #else
  404.         if ( string == NULL )
  405.                 return ST_NULLPARAM_ERR;
  406.         if ( string->str == NULL )
  407.                 return ST_NULLSTR_ERR;
  408.         if ( string->len >= string->sz )
  409.                 return ST_INCONSISTENTSZ_ERR;
  410.         if ( string->len != strlen ( string->str ) )
  411.                 return ST_INCONSISTENTLEN_ERR;
  412.         return 0;
  413. #endif
  414. }
  415.  
  416. /* String comparison */
  417. int stringcmp ( const String *st1, const String *st2 )
  418. {
  419. #ifdef NDEBUG
  420.         stringcheck ( ( String * ) st1, __FILE__, __LINE__ );
  421.         stringcheck ( ( String * ) st2, __FILE__, __LINE__ );
  422. #endif
  423.         if ( st1->len != st2->len )
  424.         {
  425.                 return ( int ) ( st2->len - st1->len );
  426.         }
  427.  
  428.         return strcmp ( st1->str, st2->str );
  429. }
  430.  
  431. /* Comparison with a C chain */
  432. int stringchcmp ( const String *st1, const char *st2 )
  433. {
  434. #ifdef NDEBUG
  435.         stringcheck ( ( String * ) st1, __FILE__, __LINE__ );
  436. #endif
  437.         size_t lt2 = strlen ( st2 );
  438.         if ( st1->len != lt2 )
  439.         {
  440.                 return ( int ) ( lt2 - st1->len );
  441.         }
  442.  
  443.         return strcmp ( st1->str, st2 );
  444. }
  445.  
  446. /* Truncation to the Nth character */
  447. String * stringtrunc ( String *string, size_t N )
  448. {
  449. #ifdef NDEBUG
  450.         stringcheck ( string, __FILE__, __LINE__ );
  451. #endif
  452.         string->len = N;
  453.         string->str[N-1] = '\0';
  454. #ifdef TIDY
  455.         size_t l = string->len;
  456.         char * end =  string->str + l;
  457.         for ( ; l < string->sz; l++ ) *end++ = 0;
  458. #endif
  459.         return string;
  460. }
  461.  
  462.  
  463. /* Formatting */
  464. void stringprintf ( String *dst, const char * format, ... )
  465. {
  466. #ifdef NDEBUG
  467.         stringcheck ( dst, __FILE__, __LINE__ );
  468. #endif
  469.         va_list argp;
  470.         va_start ( argp, format );
  471.         dst->len = vsnprintf ( dst->str, dst->sz, format, argp ) ;
  472.         va_end ( argp ) ;
  473. }
  474.  
  475. /* Returns error type and resets ST_ERR */
  476. int get_stringerr()
  477. {
  478.         int err = ST_ERR;
  479.         ST_ERR = ST_NO_ERR;
  480.         return err;
  481. }
  482.  
  483. /*************************************************
  484. * PRIVATE
  485. **************************************************/
  486.  
  487. /* Increase string.sz to desired size */
  488. static int incsz ( String *string, size_t size )
  489. {
  490.         ST_ERR = ST_NO_ERR;
  491.  
  492.         if ( string->sz < size )
  493.         {
  494.             /* double as necessary */
  495.                 size_t newsz = string->sz;
  496.         do
  497.                 {
  498.                 newsz *= 2;
  499.                 } while (newsz < size);
  500.                
  501.                 char *tmp = realloc ( string->str, (size_t)newsz );
  502.  
  503.                 if ( tmp != NULL )
  504.                 {
  505. #ifdef TIDY
  506.                         size_t l = string->len;
  507.                         char * end =  tmp + l;
  508.                         for ( ; l < size; l++ ) *end++ = 0;
  509. #endif
  510.                         string->str = tmp;
  511.                         string->sz = newsz;
  512.                 }
  513.                 else
  514.                 {
  515.                         ST_ERR = ST_ALLOC_ERR;
  516.                 }
  517.         }
  518.         return ST_ERR;
  519. }
  520.  
  521. #undef TIDY