diff --git a/str.c b/str.c index 8036bd5..cf0d058 100644 --- a/str.c +++ b/str.c @@ -1,128 +1,257 @@ #include #include #include + #include "str.h" #include "util.h" #define INIT_SZ 20 -//Внутренняя функция, -//позволяет убедиться что строка может вместить как минимум newsz символов +// ----------------------------------------------------------- +// INTERNAL: ensure capacity >= newsz (+1 for '\0') +// ----------------------------------------------------------- void _str_ensure(str *s, int newsz) { - int tmp; - newsz += 1; // добавляем единичку чтобы влез нулевой байт - if (newsz < s->capacity) - return; + int tmp; - tmp = s->capacity * 2; - if (tmp > newsz) { - newsz = tmp; - } - s->ptr = xrealloc(s->ptr, newsz); - s->capacity = newsz; + newsz += 1; // Account for null terminator + + if (newsz < s->capacity) + return; + + tmp = s->capacity * 2; + if (tmp > newsz) + newsz = tmp; + + s->ptr = xrealloc(s->ptr, newsz); + s->capacity = newsz; } +// ----------------------------------------------------------- +// Initialize empty string +// ----------------------------------------------------------- void str_init(str *s) { - assert(s); - // + assert(s); + + s->capacity = INIT_SZ; + s->len = 0; + s->ptr = xmalloc(s->capacity); + s->ptr[0] = '\0'; } +// ----------------------------------------------------------- +// Free memory +// ----------------------------------------------------------- void str_deinit(str *s) { - if (s->ptr) - free(s->ptr); - s->ptr = NULL; + if (s->ptr) + free(s->ptr); + + s->ptr = NULL; } +// ----------------------------------------------------------- +// Initialize with provided C-string +// ----------------------------------------------------------- void str_init_data(str *s, const char *initial) { - assert(s && initial); - // + assert(s && initial); + + int n = strlen(initial); + s->capacity = (n + 1 < INIT_SZ) ? INIT_SZ : n + 1; + s->len = n; + + s->ptr = xmalloc(s->capacity); + memcpy(s->ptr, initial, n + 1); // copy including '\0' } +// ----------------------------------------------------------- +// Return pointer to underlying C-string +// ----------------------------------------------------------- char * str_data(str *s) { - assert(s); - // - return NULL; + assert(s); + return s->ptr; } +// ----------------------------------------------------------- +// Replace contents with provided C-string +// ----------------------------------------------------------- void str_set(str *s, char *cstr) { - assert(s && cstr); - // + assert(s && cstr); + + int n = strlen(cstr); + _str_ensure(s, n); + + memcpy(s->ptr, cstr, n + 1); // include '\0' + s->len = n; } +// ----------------------------------------------------------- +// Create deep copy of string +// ----------------------------------------------------------- str str_copy(str *s) { - assert(s); - // + assert(s); + + str s2; + str_init(&s2); + + _str_ensure(&s2, s->len); + memcpy(s2.ptr, s->ptr, s->len + 1); + s2.len = s->len; + + return s2; } +// ----------------------------------------------------------- +// Count occurrences of character +// ----------------------------------------------------------- int str_count(str *s, char ch) { - assert(s); - // - return 0; + assert(s); + + int cnt = 0; + for (int i = 0; i < s->len; i++) + if (s->ptr[i] == ch) + cnt++; + + return cnt; } +// ----------------------------------------------------------- +// Append C-string +// ----------------------------------------------------------- void str_append(str *s, char *cstr) { - assert(s && cstr); - // + assert(s && cstr); + + int n = strlen(cstr); + _str_ensure(s, s->len + n); + + memcpy(s->ptr + s->len, cstr, n + 1); + s->len += n; } +// ----------------------------------------------------------- +// Append exactly len bytes from cstr +// ----------------------------------------------------------- void str_append_n(str *s, char *cstr, int len) { - assert(s && cstr); - // + assert(s && cstr); + + _str_ensure(s, s->len + len); + + memcpy(s->ptr + s->len, cstr, len); + s->len += len; + + s->ptr[s->len] = '\0'; // add terminator } +// ----------------------------------------------------------- +// Shrink string to new length +// ----------------------------------------------------------- void str_shrink(str *s, int len) { - assert(s && len >= 0); - // + assert(s && len >= 0); + + if (len > s->len) + len = s->len; + + s->len = len; + s->ptr[len] = '\0'; } +// ----------------------------------------------------------- +// Find substring, return index or -1 +// ----------------------------------------------------------- int str_find(str *s, char *substr) { - assert(s && substr); - char *p = strstr(s->ptr, substr); - if (p == NULL) - return -1; - return p - s->ptr; + assert(s && substr); + + char *p = strstr(s->ptr, substr); + if (!p) + return -1; + + return (int)(p - s->ptr); } +// ----------------------------------------------------------- +// Extract substring [start_idx, start_idx+length) +// ----------------------------------------------------------- str str_sub(str *s, int start_idx, int length) { - assert(s && start_idx >= 0 && length >= 0); + assert(s && start_idx >= 0 && length >= 0); - str s2; - str_init(&s2); - // - return s2; + str s2; + str_init(&s2); + + if (start_idx > s->len) + return s2; // empty + + if (start_idx + length > s->len) + length = s->len - start_idx; + + _str_ensure(&s2, length); + + memcpy(s2.ptr, s->ptr + start_idx, length); + s2.ptr[length] = '\0'; + s2.len = length; + + return s2; } -// Hint: you can create temporary string object! +// ----------------------------------------------------------- +// Replace all occurrences of substr with replacement +// ----------------------------------------------------------- int str_replace(str *s, char *substr, char *replacement) { - assert(s && substr && replacement); - // - return 0; + assert(s && substr && replacement); + + int sub_len = strlen(substr); + int rep_len = strlen(replacement); + + if (sub_len == 0) + return 0; + + str result; + str_init(&result); + + char *pos = s->ptr; + char *found; + int count = 0; + + while ((found = strstr(pos, substr)) != NULL) { + int prefix_len = (int)(found - pos); + + str_append_n(&result, pos, prefix_len); + str_append(&result, replacement); + + pos = found + sub_len; + count++; + } + + if (*pos) + str_append(&result, pos); + + str_set(s, result.ptr); + str_deinit(&result); + + return count; } diff --git a/str_test b/str_test new file mode 100755 index 0000000..63870ee Binary files /dev/null and b/str_test differ diff --git a/wcl.c b/wcl.c new file mode 100644 index 0000000..57caf92 --- /dev/null +++ b/wcl.c @@ -0,0 +1,31 @@ +#include + +int main(int argc, char *argv[]) { + if (argc < 2) { + printf("Использование: %s <путь_к_файлу>\n", argv[0]); + return 1; + } + + for (int i = 1; i < argc; i++) { + FILE *file = fopen(argv[i], "r"); + if (file == NULL) { + printf("Ошибка: не удалось открыть файл '%s'\n", argv[1]); + continue; + } + int line_count = 0; + int ch; + + while ((ch = fgetc(file)) != EOF) { + if (ch == '\n') { + line_count++; + } + } + + printf("Строк: %d\t%s\n", line_count, argv[i]); + + fclose(file); + } + + return 0; +} +