#ifndef STRING_H #define STRING_H #define STRING_DEFAULT_CHUNK_SIZE 256 typedef struct { char *value; int length; int capacity; int chunk_size; } String; String *string_construct(const char *value); String *string_construct_from_int(int value); void string_destroy(String *string); void string_set_value(String *string, const char *value); void string_append_value(String *string, const char *value); void string_prepend_value(String *string, const char *value); const char *string_get_value(String *string); int string_get_length(String *string); void string_set_capacity(String *string, int capacity); int string_get_capacity(String *string); void string_set_chunk_size(String *string, int chunk_size); int string_get_chunk_size(String *string); void string_to_uppercase(String *string); void string_to_lowercase(String *string); void string_replace_character(String *string, char old_char, char new_char); void string_left_trim(String *string); void string_right_trim(String *string); void string_trim(String *string); #endif
-----------------------------------
#include "string.h" #include "logger.h" #include <math.h> #include <stdlib.h> #include <stdio.h> #include <ctype.h> #include <string.h> #ifdef DMALLOC #include "dmalloc.h" #endif /* * FIXME: The string object maintains a length field, therefore the * NUL-character is not technically needed, but most of the time * the string capacity will be more than the string length anyway, * so maybe the wasted byte isn't anything to worry about. * * FIXME: Possibly write a function (for the event loop) that goes in and * lowers the capacity to string length when the loop is idling. */ String *string_construct(const char *value) { String *string = NULL; /* * Allocate space for the object and set all fields to zero. */ string = calloc(1, sizeof(String)); if (string == NULL) { return NULL; } /* * When resizing string, allocate proportional to STRING_DEFAULT_CHUNK_SIZE * bytes. */ string_set_chunk_size(string, STRING_DEFAULT_CHUNK_SIZE); /* * Initially the string should be one chunk big */ string_set_capacity(string, string_get_chunk_size(string)); /* * Initialize the string */ string_set_value(string, value); return string; } String *string_construct_from_int(int value) { String *string = NULL; char *c_string = NULL; c_string = malloc(15); sprintf(c_string, "%d", value); string = string_construct(c_string); free(c_string); return string; } void string_destroy(String *string) { if (string == NULL) { return; } if (string->value != NULL) { free(string->value); } free(string); } void string_set_value(String *string, const char *value) { int length = 0, capacity = 0, chunk_size = 0; if (string == NULL) { return; } if (value == NULL) { value = ""; } length = strlen(value); /* * If the length of the string is bigger than the object's current * capacity, then increase the capacity of the object to be large * enough for the string. */ if (length > string_get_length(string)) { chunk_size = string_get_chunk_size(string); capacity = string_get_capacity(string); capacity += (length/chunk_size + 1) * chunk_size; string_set_capacity(string, capacity); } /* * Copy the string to the object */ strcpy(string->value, value); string->length = length; } void string_prepend_value(String *string, const char *value) { char *construct_value = NULL; int length = 0; if (string == NULL) { return; } if (value == NULL) { return; } length = strlen(value) + string_get_length(string); construct_value = malloc((length + 1) * sizeof(char)); if (construct_value == NULL) { return; } strcpy(construct_value, value); strcat(construct_value, string_get_value(string)); string_set_value(string, construct_value); free(construct_value); } void string_append_value(String *string, const char *value) { char *new_value = NULL; int length = 0; if (string == NULL) { return; } if (value == NULL) { return; } length = string_get_length(string) + strlen(value); /* * This is an optimization that is not necessary, but might have * better performance when appending small strings */ if (length < string_get_capacity(string)) { strcat(string->value, value); string->length = length; return; } new_value = malloc((length + 1) * sizeof(char)); if (new_value == NULL) { return; } strcpy(new_value, string_get_value(string)); strcat(new_value, value); string_set_value(string, new_value); free(new_value); } const char *string_get_value(String *string) { if (string == NULL) { return NULL; } return string->value; } int string_get_length(String *string) { if (string == NULL) { return 0; } return string->length; } void string_set_capacity(String *string, int capacity) { if (string == NULL) { return; } if (capacity <= 0 || capacity == string_get_capacity(string)) { return; } string->value = realloc(string->value, capacity); if (string->value == NULL) { string->length = 0; return; } string->capacity = capacity; if (string->capacity <= string->length) { string->length = string->capacity - 1; string->value[string->length] = 0; } } int string_get_capacity(String *string) { if (string == NULL) { return 0; } return string->capacity; } void string_set_chunk_size(String *string, int chunk_size) { if (string == NULL) { return; } if (chunk_size <= 0) { chunk_size = STRING_DEFAULT_CHUNK_SIZE; } string->chunk_size = chunk_size; } int string_get_chunk_size(String *string) { if (string == NULL) { return 0; } return string->chunk_size; } void string_to_uppercase(String *string) { char *p = NULL; if (string == NULL) { return; } for (p = (char *) string->value; p[0] != 0; p++) { p[0] = (char) toupper(p[0]); } } void string_to_lowercase(String *string) { char *p = NULL; if (string == NULL) { return; } for (p = (char *) string->value; p[0] != 0; p++) { p[0] = (char) tolower(p[0]); } } void string_replace_character(String *string, char old_char, char construct_char) { char *p = NULL; if (string == NULL) { return; } for (p = (char *) string->value; p[0] != 0; p++) { if (p[0] == old_char) { p[0] = construct_char; } } } void string_left_trim(String *string) { char *new_value = NULL, *head = NULL, *tail = NULL; if (string == NULL) { return; } if (string_get_length(string) == 0) { return; } new_value = strdup(string_get_value(string)); head = new_value; tail = new_value + string_get_length(string); while (head != tail && isspace(head[0])) { head++; } string_set_value(string, head); free(new_value); } void string_right_trim(String *string) { char *new_value = NULL, *tail = NULL; if (string == NULL) { return; } if (string_get_length(string) == 0) { return; } new_value = strdup(string_get_value(string)); tail = new_value + string_get_length(string) - 1; while (tail != new_value && isspace(tail[0])) { tail--; } tail[1] = 0; string_set_value(string, new_value); free(new_value); } void string_trim(String *string) { if (string == NULL) { return; } if (string_get_length(string) == 0) { return; } string_left_trim(string); string_right_trim(string); }