#ifndef _STRING_C_ /* -*- linux-c -*- */ #define _STRING_C_ #include /** @file string.c * @brief Implements String type. */ /** @addtogroup string String Functions * * One of the biggest restrictions the library has is that it cannot allocate things like strings off the stack. * It is also not a good idea to dynamically allocate space for strings with kmalloc(). That leaves us with * statically allocated space for strings. This is what is implemented in the String module. Strings use * preallocated per-cpu buffers and are safe to use (unlike C strings). * @{ */ /** Maximum string size allowed in Strings */ #ifndef STP_STRING_SIZE #define STP_STRING_SIZE 2048 #endif struct string { short len; short global; char buf[STP_STRING_SIZE]; }; static struct string _stp_string[STP_NUM_STRINGS][NR_CPUS]; typedef struct string *String; /** Initialize a String for our use. * This grabs one of the global Strings for our use. * * @param num Number of the preallocated String to use. * #STP_NUM_STRINGS are statically allocated for our use. The * translator (or author) should be sure to grab a free one. * @todo Global (and static) Strings not implemented yet. */ String _stp_string_init (int num) { int global = 0; String str; if (num < 0) { num = -num; global = 1; } if (num >= STP_NUM_STRINGS) { _stp_log ("_stp_string_init internal error: requested string exceeded allocated number"); return NULL; } if (global) str = &_stp_string[num][0]; else str = &_stp_string[num][smp_processor_id()]; str->global = global; str->len = 0; return str; } /** Sprintf into a String. * Like printf, except output goes into a String. * Safe because overflowing the buffer is not allowed. * Size is limited by length of String, #STP_STRING_SIZE. * * @param str String * @param fmt A printf-style format string followed by a * variable number of args. */ void _stp_sprintf (String str, const char *fmt, ...) { int num; va_list args; va_start(args, fmt); num = vscnprintf(str->buf + str->len, STP_STRING_SIZE - str->len - 1, fmt, args); va_end(args); if (num > 0) str->len += num; } /** Vsprintf into a String * Use this if your function already has a va_list. * You probably want _stp_sprintf(). */ void _stp_vsprintf (String str, const char *fmt, va_list args) { int num; num = vscnprintf(str->buf + str->len, STP_STRING_SIZE - str->len - 1, fmt, args); if (num > 0) str->len += num; } /** ConCATenate (append) a C string to a String. * Like strcat(). * @param str1 String * @param str2 C string (char *) * @sa _stp_string_cat */ void _stp_string_cat_cstr (String str1, const char *str2) { int num = strlen (str2); if (num > STP_STRING_SIZE - str1->len - 1) num = STP_STRING_SIZE - str1->len - 1; strncpy (str1->buf + str1->len, str2, num+1); str1->len += num; } /** ConCATenate (append) a String to a String. * Like strcat(). * @param str1 String * @param str2 String * @sa _stp_string_cat */ void _stp_string_cat_string (String str1, String str2) { int num = str2->len; if (num > STP_STRING_SIZE - str1->len - 1) num = STP_STRING_SIZE - str1->len - 1; strncpy (str1->buf + str1->len, str2->buf, num); str1->len += num; } /** Get a pointer to String's buffer * For rare cases when a C string is needed and you have a String. * One example is when you want to print a String with _stp_printf(). * @param str String * @returns A C string (char *) * @note Readonly. Don't write to this pointer or it will mess up * the internal String state and probably mess up your output or crash something. */ char * _stp_string_ptr (String str) { return str->buf; } /** ConCATenate (append) a String or C string to a String. * This macro selects the proper function to call. * @param str1 A String * @param str2 A String or C string (char *) * @sa _stp_string_cat_cstr _stp_string_cat_string */ #define _stp_string_cat(str1, str2) \ ({ \ if (__builtin_types_compatible_p (typeof (str2), char[])) { \ char *x = (char *)str2; \ _str_string_cat_cstr(str1,x); \ } else { \ String x = (String)str2; \ _str_string_cat_string(str1,x); \ } \ }) /** @} */ #endif /* _STRING_C_ */