Advertisement
Nicolas_Janin

SPString

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