#ifndef STR_H #define STR_H /* STR RETURN CODE */ #define STR_RC_TYPE unsigned char extern __thread STR_RC_TYPE str_errno; #define STR_RC_OK ((STR_RC_TYPE) 0L) /* No Error */ #define STR_RC_EFM ((STR_RC_TYPE) 1L) /* Failed to malloc */ #define STR_RC_EVN ((STR_RC_TYPE) 2L) /* Value is Null */ #define STR_RC_EFMC ((STR_RC_TYPE) 3L) /* Failed to memcpy */ #include #if defined(STR_TYPEDEF) || defined(TYPEDEFS) typedef struct str str_st; #endif /* STR_TYPEDEF || TYPEDEFS */ struct str { char *data; char *_c_data; size_t size; size_t _c_size; }; struct str* str_create(const char *cstring, size_t cstring_size); struct str* str_create_ns(const char *cstring); STR_RC_TYPE str_destroy(struct str *str); STR_RC_TYPE str_to_lowercase(struct str *str); STR_RC_TYPE str_to_uppercase(struct str *str); STR_RC_TYPE str_to_titlecase(struct str *str); _Bool str_starts_with(struct str *str, struct str* start); _Bool str_starts_with_char(struct str *str, char chr); _Bool str_starts_with_cstring(struct str *str, char *cstring, size_t cstring_size); _Bool str_starts_with_cstring_ns(struct str *str, char *cstring); _Bool str_ends_with(struct str *str, struct str* end); _Bool str_ends_with_char(struct str *str, char chr); _Bool str_ends_with_cstring(struct str *str, char *cstring, size_t cstring_size); _Bool str_ends_with_cstring_ns(struct str *str, char *cstring); _Bool str_is_empty(struct str *str); size_t str_count_str(struct str *str, struct str *str2); size_t str_count_char(struct str *str, char chr); size_t str_count_cstring(struct str *str, char *cstring, size_t cstring_size); size_t str_count_cstring_ns(struct str *str, char *cstring); // reverse // append // prepend // trim_left // trim_right // trim // split // split_limit // equal // iequal // cmp // icmp // in_array // in_list // contains // to_cstring // to_char // to_short // to_int // to_long // to_float // to_double // formatted // join #if defined(STR_IMP) || defined(IMPLEMENTATIONS) #include #include #if defined(STR_LOG) || defined(LOGS) #define __LOG(OUT, PFX, TXT) fprintf(OUT, PFX" %s: %s", __func__, TXT) #define LOG_ERROR(TXT) __LOG(stderr, "[ERROR]", TXT) #define LOG_INFO(TXT) __LOG(stdout, "[INFO]", TXT) #else #define LOG_ERROR(TXT) ; #define LOG_INFO(TXT) ; #endif /* STR_LOG */ #define true ((unsigned char) 1L) #define false ((unsigned char) 0L) #define TEST_FOR_NULL(POINTER) \ if ( POINTER == NULL ) { \ LOG_ERROR("Null Pointer Not Expected"); \ str_errno = STR_RC_EVN; \ return str_errno; \ } #define TEST_FOR_NULL_SR(POINTER, STR_RC) \ if ( POINTER == NULL ) { \ LOG_ERROR("Null Pointer Not Expected"); \ str_errno = STR_RC_EVN; \ return STR_RC; \ } #define CHECK_MALLOC(POINTER, STR_RC) \ if ( POINTER == NULL ) { \ LOG_ERROR("Failed to malloc"); \ str_errno = STR_RC_EFM; \ return STR_RC; \ } #define CHECK_MALLOC_FREE(POINTER, STR_RC, FREE) \ if ( POINTER == NULL ) { \ free(FREE); \ LOG_ERROR("Failed to malloc"); \ str_errno = STR_RC_EFM; \ return STR_RC; \ } struct str* str_create(const char *cstring, size_t cstring_size) { str_errno = STR_RC_OK; struct str *ret = malloc(sizeof(struct str)); CHECK_MALLOC(ret, NULL); ret->_c_size = cstring_size; ret->size = ret->_c_size; ret->data = malloc(ret->_c_size); CHECK_MALLOC_FREE(ret, NULL, ret); *ret->data = -1; ret->_c_data = ret->data; memcpy(ret->data, cstring, ret->_c_size); if ( *ret->data == -1 ) { str_destroy(ret); str_errno = STR_RC_EFMC; return NULL; } return ret; } struct str* str_create_ns(const char *cstring) { str_errno = STR_RC_OK; #ifdef CSTRING_H return str_create(cstring, cstring_len(cstring)); #else return str_create(cstring, strlen(cstring)); #endif /* CSTRING_H */ } STR_RC_TYPE str_destroy(struct str *str) { TEST_FOR_NULL(str); str_errno = STR_RC_OK; free(str->data); free(str); return STR_RC_OK; } STR_RC_TYPE str_to_lowercase(struct str *str) { TEST_FOR_NULL(str); TEST_FOR_NULL(str->_c_data); str_errno = STR_RC_OK; for ( size_t z = 0; z < str->_c_size; ++z ) { char c = str->_c_data[z]; str->_c_data[z] += (char) ((c >= 'A' && c <= 'Z') * 32); } return STR_RC_OK; } STR_RC_TYPE str_to_uppercase(struct str *str) { TEST_FOR_NULL(str); TEST_FOR_NULL(str->_c_data); str_errno = STR_RC_OK; for ( size_t z = 0; z < str->_c_size; ++z ) { char c = str->_c_data[z]; str->_c_data[z] -= (char)((c >= 'a' && c <= 'z') * 32); } return STR_RC_OK; } STR_RC_TYPE str_to_titlecase(struct str *str) { TEST_FOR_NULL(str); TEST_FOR_NULL(str->_c_data); str_errno = STR_RC_OK; size_t limit = str->_c_size - 1; char pc = ' '; for ( size_t z = 1; z < limit; ++z ) { char c = str->_c_data[z]; char nc = str->_c_data[z+1]; str->_c_data[z] = (char) ( ((c >= 'a' && c <= 'z') && (nc != ' ' && pc == ' ')) * (c - 32) + ((c >= 'A' && c <= 'Z') && (pc != ' ' || nc == ' ')) * (c + 32)); pc = c; } return STR_RC_OK; } _Bool str_starts_with(struct str *str, struct str* start) { TEST_FOR_NULL_SR(str, false); TEST_FOR_NULL_SR(str->_c_data, false); TEST_FOR_NULL_SR(start, false); TEST_FOR_NULL_SR(start->_c_data, false); str_errno = STR_RC_OK; _Bool ret = false; return ret; } _Bool str_starts_with_char(struct str *str, char chr) { TEST_FOR_NULL_SR(str, false); TEST_FOR_NULL_SR(str->_c_data, false); str_errno = STR_RC_OK; return (*str->data == chr); } _Bool str_starts_with_cstring(struct str *str, char *cstring, size_t cstring_size); _Bool str_starts_with_cstring_ns(struct str *str, char *cstring); _Bool str_ends_with(struct str *str, struct str* end); _Bool str_ends_with_char(struct str *str, char chr); _Bool str_ends_with_cstring(struct str *str, char *cstring, size_t cstring_size); _Bool str_ends_with_cstring_ns(struct str *str, char *cstring); _Bool str_is_empty(struct str *str); size_t str_count_str(struct str *str, struct str *str2); size_t str_count_char(struct str *str, char chr); size_t str_count_cstring(struct str *str, char *cstring, size_t cstring_size); size_t str_count_cstring_ns(struct str *str, char *cstring); #undef true #undef false #undef TEST_FOR_NULL #undef TEST_FOR_NULL_SR #undef CHECK_MALLOC #undef CHECK_MALLOC_FREE #undef LOG_ERROR #undef LOG_INFO #endif /* STR_IMP || IMPLEMENTATIONS */ #endif /* STR_H */