Main Page | Modules | Directories | File List | Globals | Related Pages

string.c

Go to the documentation of this file.
00001 #ifndef _STRING_C_ /* -*- linux-c -*- */
00002 #define _STRING_C_
00003 
00004 #include <linux/config.h>
00005 
00006 /** @file string.c
00007  * @brief Implements String type.
00008  */
00009 /** @addtogroup string String Functions
00010  *
00011  * One of the biggest restrictions the library has is that it cannot allocate things like strings off the stack.
00012  * It is also not a good idea to dynamically allocate space for strings with kmalloc().  That leaves us with 
00013  * statically allocated space for strings. This is what is implemented in the String module.  Strings use
00014  * preallocated per-cpu buffers and are safe to use (unlike C strings).
00015  * @{
00016  */
00017 
00018 /** Maximum string size allowed in Strings */
00019 #ifndef STP_STRING_SIZE
00020 #define STP_STRING_SIZE 2048
00021 #endif
00022 
00023 struct string {
00024         short len;
00025         short global;
00026         char buf[STP_STRING_SIZE];
00027 };
00028 
00029 static struct string _stp_string[STP_NUM_STRINGS][NR_CPUS];
00030 
00031 typedef struct string *String;
00032 
00033 /** Initialize a String for our use.
00034  * This grabs one of the global Strings for our use.
00035  *
00036  * @param num Number of the preallocated String to use. 
00037  * #STP_NUM_STRINGS are statically allocated for our use. The
00038  * translator (or author) should be sure to grab a free one.
00039  * @todo Global (and static) Strings not implemented yet. 
00040  */
00041 
00042 String _stp_string_init (int num)
00043 {
00044         int global = 0;
00045         String str;
00046 
00047         if (num  < 0) {
00048                 num = -num;
00049                 global = 1;
00050         }
00051         
00052         if (num >= STP_NUM_STRINGS) {
00053                 _stp_log ("_stp_string_init internal error: requested string exceeded allocated number");
00054                 return NULL;
00055         }
00056 
00057         if (global)
00058                 str = &_stp_string[num][0];
00059         else
00060                 str = &_stp_string[num][smp_processor_id()];
00061 
00062         str->global = global;
00063         str->len = 0;
00064         return str;
00065 }
00066 
00067 
00068 /** Sprintf into a String.
00069  * Like printf, except output goes into a String.
00070  * Safe because overflowing the buffer is not allowed.
00071  * Size is limited by length of String, #STP_STRING_SIZE.
00072  *
00073  * @param str String
00074  * @param fmt A printf-style format string followed by a 
00075  * variable number of args.
00076  */
00077 void _stp_sprintf (String str, const char *fmt, ...)
00078 {
00079         int num;
00080         va_list args;
00081         va_start(args, fmt);
00082         num = vscnprintf(str->buf + str->len, STP_STRING_SIZE - str->len - 1, fmt, args);
00083         va_end(args);
00084         if (num > 0)
00085                 str->len += num;
00086 }
00087 
00088 /** Vsprintf into a String
00089  * Use this if your function already has a va_list.
00090  * You probably want _stp_sprintf().
00091  */
00092 void _stp_vsprintf (String str, const char *fmt, va_list args)
00093 {
00094         int num;
00095         num = vscnprintf(str->buf + str->len, STP_STRING_SIZE - str->len - 1, fmt, args);
00096         if (num > 0)
00097                 str->len += num;
00098 }
00099 
00100 /** ConCATenate (append) a C string to a String.
00101  * Like strcat().
00102  * @param str1 String
00103  * @param str2 C string (char *)
00104  * @sa _stp_string_cat
00105  */
00106 void _stp_string_cat_cstr (String str1, const char *str2)
00107 {
00108         int num = strlen (str2);
00109         if (num > STP_STRING_SIZE - str1->len - 1)
00110                 num = STP_STRING_SIZE - str1->len - 1;
00111         strncpy (str1->buf + str1->len, str2, num+1);
00112         str1->len += num;
00113 }
00114 
00115 /** ConCATenate (append) a String to a String.
00116  * Like strcat().
00117  * @param str1 String
00118  * @param str2 String
00119  * @sa _stp_string_cat
00120  */
00121 void _stp_string_cat_string (String str1, String str2)
00122 {
00123         int num = str2->len;
00124         if (num > STP_STRING_SIZE - str1->len - 1)
00125                 num = STP_STRING_SIZE - str1->len - 1;
00126         strncpy (str1->buf + str1->len, str2->buf, num);
00127         str1->len += num;
00128 }
00129 
00130 /** Get a pointer to String's buffer
00131  * For rare cases when a C string is needed and you have a String.
00132  * One example is when you want to print a String with _stp_printf().
00133  * @param str String
00134  * @returns A C string (char *)
00135  * @note Readonly. Don't write to this pointer or it will mess up
00136  * the internal String state and probably mess up your output or crash something.
00137  */
00138 char * _stp_string_ptr (String str)
00139 {
00140         return str->buf;
00141 }
00142 
00143 
00144 /** ConCATenate (append) a String or C string to a String.
00145  * This macro selects the proper function to call.
00146  * @param str1 A String
00147  * @param str2 A String or C string (char *)
00148  * @sa _stp_string_cat_cstr _stp_string_cat_string
00149  */
00150 #define _stp_string_cat(str1, str2)                                     \
00151   ({                                                            \
00152           if (__builtin_types_compatible_p (typeof (str2), char[])) {   \
00153                   char *x = (char *)str2;                               \
00154                   _str_string_cat_cstr(str1,x);                         \
00155           } else {                                                      \
00156                   String x = (String)str2;                              \
00157                   _str_string_cat_string(str1,x);                       \
00158           }                                                             \
00159   })
00160 
00161 /** @} */
00162 #endif /* _STRING_C_ */