so://phie

buf

A utility for dealing with strings in C
git clone git://soophie.de/buf

blob: 13f152493856d6c651cda290ca410af271572553 (3947 bytes)[raw]

1/*

2 * Copyright (C) 2026 Sophie Sitzler

3 *

4 * This program is free software: you can redistribute it and/or modify

5 * it under the terms of the GNU General Public License as published by

6 * the Free Software Foundation, either version 3 of the License, or

7 * (at your option) any later version.

8 *

9 * This program is distributed in the hope that it will be useful,

10 * but WITHOUT ANY WARRANTY; without even the implied warranty of

11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

12 * GNU General Public License for more details.

13 *

14 * You should have received a copy of the GNU General Public License

15 * along with this program. If not, see <https://www.gnu.org/licenses/>.

16 */

17

18// @file buf.h

19#pragma once

20

21#include <stdio.h>

22#include <stdint.h>

23#include <stdlib.h>

24#include <stdarg.h>

25#include <stdbool.h>

26

27#ifndef BUF_CAP_BASE

28#define BUF_CAP_BASE 64

29#endif

30

31#define BUF_NULL (buf_t) { NULL, 0, 0, 0 }

32

33typedef struct {

34 uint8_t *bytes;

35 size_t len;

36 size_t cap;

37 size_t pos;

38} buf_t;

39

40void buf_init(buf_t *self, void *bytes, size_t len);

41void buf_free(buf_t *self);

42bool buf_write_len(buf_t *self, const void *bytes, size_t len);

43bool buf_write(buf_t *self, const void *bytes);

44void buf_writef(buf_t *self, const char *fmt, ...);

45bool buf_read(buf_t *self, void *bytes, size_t len);

46void buf_concat(buf_t *self, buf_t buf);

47void buf_repall_len(buf_t *self, const char *pat, const char *rep, size_t len);

48void buf_repall(buf_t *self, const char *pat, const char *rep);

49

50#ifdef BUF_IMPL

51

52#include <string.h>

53

54void buf_init(buf_t *self, void *bytes, size_t len) {

55 self->bytes = (uint8_t *)bytes;

56 self->len = len;

57 self->cap = len;

58 self->pos = 0;

59}

60

61void buf_free(buf_t *self) {

62 if (!self || !self->bytes) return;

63 free(self->bytes);

64 *self = BUF_NULL;

65}

66

67bool buf_write_len(buf_t *self, const void *bytes, size_t len) {

68 if (!self || !bytes) return false;

69 size_t needed = self->len + len;

70 if (needed > self->cap) {

71 size_t new_cap = self->cap ? self->cap * 2 : BUF_CAP_BASE;

72 while (needed > new_cap) new_cap *= 2;

73 uint8_t *tmp = (uint8_t *) realloc(self->bytes, new_cap);

74 if (!tmp) return false;

75 self->bytes = tmp;

76 self->cap = new_cap;

77 }

78 memcpy(self->bytes + self->len, bytes, len);

79 self->len += len;

80 return true;

81}

82

83bool buf_write(buf_t *self, const void *bytes) {

84 if (!bytes) return false;

85 return buf_write_len(self, bytes, strlen(bytes));

86}

87

88void buf_writef(buf_t *self, const char *fmt, ...) {

89 if (!self || !fmt) return;

90 va_list args;

91 va_start(args, fmt);

92 ssize_t data_len = vsnprintf(NULL, 0, fmt, args);

93 va_end(args);

94 if (data_len < 0) return;

95 char *data = malloc(data_len + 1);

96 if (!data) return;

97 va_start(args, fmt);

98 vsnprintf(data, data_len + 1, fmt, args);

99 va_end(args);

100 buf_write(self, data);

101 free(data);

102}

103

104bool buf_read(buf_t *self, void *bytes, size_t len) {

105 if (!self || !bytes || self->pos + len > self->len) return false;

106 memcpy(bytes, self->bytes + self->pos, len);

107 self->pos += len;

108 return true;

109}

110

111void buf_concat(buf_t *self, buf_t buf) {

112 buf_write_len(self, buf.bytes, buf.len);

113}

114

115void buf_repall_len(buf_t *self, const char *pat, const char *rep, size_t len) {

116 if (!self || !self->bytes || !pat || !rep) return;

117 const char *bytes = (const char *) self->bytes;

118 size_t pat_len = strlen(pat);

119 size_t rep_len = strlen(rep);

120 if (pat_len == 0) return;

121 buf_t out = BUF_NULL;

122 size_t idx = 0;

123 while (idx < len && *bytes) {

124 size_t rem = len - idx;

125 if (rem >= pat_len && strncmp(bytes, pat, pat_len) == 0) {

126 buf_write_len(&out, rep, rep_len);

127 bytes += pat_len;

128 idx += pat_len;

129 }

130 else {

131 buf_write_len(&out, bytes, 1);

132 bytes++;

133 idx++;

134 }

135 }

136 buf_free(self);

137 buf_write_len(self, out.bytes, out.len);

138 buf_free(&out);

139}

140

141void buf_repall(buf_t *self, const char *pat, const char *rep) {

142 buf_repall_len(self, pat, rep, self->len);

143}

144

145#endif /* BUF_IMPL */