.. _safe_strings: Safe Additions to Strings ========================== As mentioned in :ref:`buff_overflow`, adding textual data to a string is dangerous. It is not very difficult to work with strings safely, but it does require extra effort and needs topics that we covered toward the end of the course. In particular, dynamic memory allocation, data structures, and file input / output need to be used along with the functions from :ref:`stringlib`. A library of functions is helpful. There are actually several open source string libraries for C. `This article `_ compares some popular string processing libraries. Many of these libraries are quite large and go well beyond safely adding data to strings. So to keep things simple, I wrote a modest set of functions to avoid string buffer overflows and truncations. The code is in the ``textstring.h`` file, which can be added to your code with an include statement. :: #include "textstring.h" Declare a pointer to a data structure along with a starting string length as follows:: txtstr *str; str = tstr_new(LINESIZE); Then use functions defined below to store data to str in various ways. To avoid conflicts with your name space, all functions in the library begin with ``tstr_``. To access the string to print it or any other char * string operations, use either:: char *ptr = tstr_str(str); - or - char *ptr = str->string; The ``tstr_str`` function resets the string to the beginning, which impacts future string appending functions. To avoid memory leaks when finished with a string, especially in a function other than main, use:: tstr_free(str); .. describe:: tstr_new Allocate an new txtstr with a given size:: txtstr *tstr_new(int); str = tstr_new(200); .. describe:: tstr_ReadLine Same as :ref:`readline`, except the lines go to a ``txtstr *`` data structure. Read a ``txtstr`` line from a file:: bool tstr_ReadLine(txtstr *, FILE *); // str is a new line from the file on each loop iteration. // End of file is reached when false is returned. while( tstr_ReadLine(str, fileptr) ) .. describe:: tstr_sprintf Safe sprintf() into a txtstr. New string starts at the beginning of the str->string. Formatting is the same as the standard ``printf`` and ``sprintf`` functions. Multiple data variables may be referenced:: int tstr_sprintf(txtstr *, const char *, ...); tstr_sprintf(str, "V = %lf, and a string\n", V, str2); .. describe:: tstr_strappend Formatted append a ``char *`` string to an existing ``txtstr``. Note, the format string may contain text, but only one string is added. Only ``tstr_sprintf`` has the formatting functionality of ``sprintf``:: int tstr_strappend(txtstr *str, const char *fmt, char *s2); tstr_strappend(str, "adding a string: %s\n", s2) .. describe:: tstr_append Formatted append ``txtstr`` to existing ``txtstr``. This function is like ``tstr_strappend`` except the string to add is in a ``txtstr *`` data structure, not a ``char *`` string:: int tstr_append(txtstr *str1, const char *fmt, txtstr *str2); .. describe:: tstr_cat Safe strcat of ``txtstr``s. Contents of ``s2`` is added to the end of ``s1``:: void tstr_cat(txtstr *s1, txtstr *s2); .. describe:: tstr_strcat Safe strcat for a ``char *`` string:: void tstr_strcat(txtstr *str, char *s2); .. describe:: tstr_cpy Safe strcpy of ``txtstr``. ``s2`` is copied to ``s1``:: void tstr_cpy(txtstr *s1, txtstr *s2); .. describe:: tstr_strcpy:: Safe copy of ``char *`` string into a ``txtstr``. The ``s2`` string is copied to the ``s1`` data structure:: void tstr_strcpy(txtstr *s, char *); .. describe:: tstr_str:: Return string for printing or other use and reset so string is empty:: char *tstr_str(txtstr *str); printf("%s\n", tstr_str(str)); .. describe:: tstr_reset:: Reset the ``txtstr`` so that the string is empty. Future appends go the beginning of the string:: void tstr_reset(txtstr *); .. describe:: tstr_free Free the memory held by a ``txtstr``. It is important to remember this to avoid memory leaks:: void tstr_free(txtstr *str); Here is the include file that may be downloaded. Testing and example code is also available for download. * :download:`textstring.h` * :download:`test_txtstr.c`