All of lore.kernel.org
 help / color / mirror / Atom feed
From: Pierre Habouzit <madcoder@debian.org>
To: git@vger.kernel.org
Cc: Pierre Habouzit <madcoder@debian.org>
Subject: [PATCH] Rework strbuf API and semantics.
Date: Wed,  5 Sep 2007 21:18:36 +0200	[thread overview]
Message-ID: <11890199232110-git-send-email-madcoder@debian.org> (raw)
In-Reply-To: <20070905085720.GD31750@artemis.corp>

  A strbuf can be used to store byte arrays, or as an extended string
library. The `buf' member can be passed to any C legacy string function,
because strbuf operations always ensure there is a terminating \0 at the end
of the buffer, not accounted in the `len' field of the structure.

  A strbuf can be used to generate a string/buffer whose final size is not
really known, and then "strbuf_detach" can be used to get the built buffer,
and keep the wrapping "strbuf" structure usable for further work again.

  Other interesting feature: strbuf_grow(sb, size) ensure that there is
enough allocated space in `sb' to put `size' new octets of data in the
buffer. It helps avoiding reallocating data for nothing when the problem the
strbuf helps to solve has a known typical size.

Signed-off-by: Pierre Habouzit <madcoder@debian.org>
---
 archive-tar.c |    2 +-
 fast-import.c |   15 ++++----
 mktree.c      |    4 +--
 strbuf.c      |  103 +++++++++++++++++++++++++++++++++++++++++++++++++--------
 strbuf.h      |   42 ++++++++++++++++++++++-
 5 files changed, 138 insertions(+), 28 deletions(-)

diff --git a/archive-tar.c b/archive-tar.c
index 66fe3e3..a0763c5 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -166,7 +166,7 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,
 		sprintf(header.name, "%s.paxheader", sha1_to_hex(sha1));
 	} else {
 		if (verbose)
-			fprintf(stderr, "%.*s\n", path->len, path->buf);
+			fprintf(stderr, "%.*s\n", (int)path->len, path->buf);
 		if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
 			*header.typeflag = TYPEFLAG_DIR;
 			mode = (mode | 0777) & ~tar_umask;
diff --git a/fast-import.c b/fast-import.c
index 078079d..2f7baf4 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -1595,7 +1595,7 @@ static void read_next_command(void)
 		} else {
 			struct recent_command *rc;
 
-			command_buf.buf = NULL;
+			strbuf_detach(&command_buf);
 			read_line(&command_buf, stdin, '\n');
 			if (command_buf.eof)
 				return;
@@ -1649,7 +1649,6 @@ static void *cmd_data (size_t *size)
 		size_t sz = 8192, term_len = command_buf.len - 5 - 2;
 		length = 0;
 		buffer = xmalloc(sz);
-		command_buf.buf = NULL;
 		for (;;) {
 			read_line(&command_buf, stdin, '\n');
 			if (command_buf.eof)
@@ -1657,11 +1656,11 @@ static void *cmd_data (size_t *size)
 			if (term_len == command_buf.len
 				&& !strcmp(term, command_buf.buf))
 				break;
-			ALLOC_GROW(buffer, length + command_buf.len, sz);
+			ALLOC_GROW(buffer, length + command_buf.len + 1, sz);
 			memcpy(buffer + length,
 				command_buf.buf,
-				command_buf.len - 1);
-			length += command_buf.len - 1;
+				command_buf.len);
+			length += command_buf.len;
 			buffer[length++] = '\n';
 		}
 		free(term);
@@ -2101,7 +2100,7 @@ static void cmd_new_commit(void)
 	}
 
 	/* file_change* */
-	while (!command_buf.eof && command_buf.len > 1) {
+	while (!command_buf.eof && command_buf.len > 0) {
 		if (!prefixcmp(command_buf.buf, "M "))
 			file_change_m(b);
 		else if (!prefixcmp(command_buf.buf, "D "))
@@ -2256,7 +2255,7 @@ static void cmd_reset_branch(void)
 	else
 		b = new_branch(sp);
 	read_next_command();
-	if (!cmd_from(b) && command_buf.len > 1)
+	if (!cmd_from(b) && command_buf.len > 0)
 		unread_command_buf = 1;
 }
 
@@ -2273,7 +2272,7 @@ static void cmd_checkpoint(void)
 
 static void cmd_progress(void)
 {
-	fwrite(command_buf.buf, 1, command_buf.len - 1, stdout);
+	fwrite(command_buf.buf, 1, command_buf.len, stdout);
 	fputc('\n', stdout);
 	fflush(stdout);
 	skip_optional_lf();
diff --git a/mktree.c b/mktree.c
index d86dde8..86de5eb 100644
--- a/mktree.c
+++ b/mktree.c
@@ -92,7 +92,6 @@ int main(int ac, char **av)
 
 	strbuf_init(&sb);
 	while (1) {
-		int len;
 		char *ptr, *ntr;
 		unsigned mode;
 		enum object_type type;
@@ -101,7 +100,6 @@ int main(int ac, char **av)
 		read_line(&sb, stdin, line_termination);
 		if (sb.eof)
 			break;
-		len = sb.len;
 		ptr = sb.buf;
 		/* Input is non-recursive ls-tree output format
 		 * mode SP type SP sha1 TAB name
@@ -111,7 +109,7 @@ int main(int ac, char **av)
 			die("input format error: %s", sb.buf);
 		ptr = ntr + 1; /* type */
 		ntr = strchr(ptr, ' ');
-		if (!ntr || sb.buf + len <= ntr + 41 ||
+		if (!ntr || sb.buf + sb.len <= ntr + 40 ||
 		    ntr[41] != '\t' ||
 		    get_sha1_hex(ntr + 1, sha1))
 			die("input format error: %s", sb.buf);
diff --git a/strbuf.c b/strbuf.c
index e33d06b..7866fbe 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -2,40 +2,115 @@
 #include "strbuf.h"
 
 void strbuf_init(struct strbuf *sb) {
-	sb->buf = NULL;
-	sb->eof = sb->alloc = sb->len = 0;
+	memset(sb, 0, sizeof(*sb));
 }
 
-static void strbuf_begin(struct strbuf *sb) {
+void strbuf_release(struct strbuf *sb) {
 	free(sb->buf);
+	memset(sb, 0, sizeof(*sb));
+}
+
+void strbuf_reset(struct strbuf *sb) {
+	if (sb->len)
+		sb->buf[sb->len = 0] = '\0';
+}
+
+char *strbuf_detach(struct strbuf *sb) {
+	char *res = sb->buf;
 	strbuf_init(sb);
+	return res;
+}
+
+void strbuf_grow(struct strbuf *sb, size_t extra) {
+	if (sb->len + extra + 1 < sb->len)
+		die("you want to use way too much memory");
+	ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
+}
+
+void strbuf_add(struct strbuf *sb, const void *data, size_t len) {
+	strbuf_grow(sb, len);
+	memcpy(sb->buf + sb->len, data, len);
+	sb->len += len;
+	sb->buf[sb->len] = '\0';
+}
+
+void strbuf_addvf(struct strbuf *sb, const char *fmt, va_list ap)
+{
+	size_t len;
+	va_list ap2;
+
+	va_copy(ap2, ap);
+
+	len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
+	if (len < 0) {
+		len = 0;
+	}
+	if (len >= sb->alloc - sb->len) {
+		strbuf_grow(sb, len);
+		len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap2);
+		if (len >= sb->alloc - sb->len) {
+			len = sb->alloc - sb->len - 1;
+		}
+	}
+	sb->len = sb->len + len;
+	sb->buf[sb->len] = '\0';
 }
 
-static void inline strbuf_add(struct strbuf *sb, int ch) {
-	if (sb->alloc <= sb->len) {
-		sb->alloc = sb->alloc * 3 / 2 + 16;
-		sb->buf = xrealloc(sb->buf, sb->alloc);
+size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f) {
+	size_t res;
+
+	strbuf_grow(sb, size);
+	res = fread(sb->buf + sb->len, 1, size, f);
+	if (res > 0) {
+		sb->len += res;
+		sb->buf[sb->len] = '\0';
 	}
-	sb->buf[sb->len++] = ch;
+	return res;
 }
 
-static void strbuf_end(struct strbuf *sb) {
-	strbuf_add(sb, 0);
+ssize_t strbuf_read(struct strbuf *sb, int fd)
+{
+	size_t oldlen = sb->len;
+
+	for (;;) {
+		ssize_t cnt;
+
+		strbuf_grow(sb, 8192);
+		cnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
+		if (cnt < 0) {
+			sb->buf[sb->len = oldlen] = '\0';
+			return -1;
+		}
+		if (!cnt)
+			break;
+		sb->len += cnt;
+	}
+
+	sb->buf[sb->len] = '\0';
+	return sb->len - oldlen;
 }
 
 void read_line(struct strbuf *sb, FILE *fp, int term) {
 	int ch;
-	strbuf_begin(sb);
 	if (feof(fp)) {
+		strbuf_release(sb);
 		sb->eof = 1;
 		return;
 	}
+
+	strbuf_reset(sb);
 	while ((ch = fgetc(fp)) != EOF) {
 		if (ch == term)
 			break;
-		strbuf_add(sb, ch);
+		strbuf_grow(sb, 1);
+		sb->buf[sb->len++] = ch;
 	}
-	if (ch == EOF && sb->len == 0)
+	if (ch == EOF && sb->len == 0) {
+		strbuf_release(sb);
 		sb->eof = 1;
-	strbuf_end(sb);
+	}
+
+	strbuf_grow(sb, 1);
+	sb->buf[sb->len] = '\0';
 }
+
diff --git a/strbuf.h b/strbuf.h
index 74cc012..db1e438 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -1,13 +1,51 @@
 #ifndef STRBUF_H
 #define STRBUF_H
 struct strbuf {
-	int alloc;
-	int len;
+	size_t alloc;
+	size_t len;
 	int eof;
 	char *buf;
 };
 
+#define STRBUF_INIT  { 0, 0, 0, NULL }
+
+/* strbuf life cycle */
 extern void strbuf_init(struct strbuf *);
+extern void strbuf_release(struct strbuf *);
+extern void strbuf_reset(struct strbuf *);
+extern char *strbuf_detach(struct strbuf *);
+
+
+extern void strbuf_grow(struct strbuf *, size_t);
+extern void strbuf_add(struct strbuf *, const void *, size_t);
+
+static inline void strbuf_addstr(struct strbuf *sb, const char *s) {
+	strbuf_add(sb, s, strlen(s));
+}
+static inline void strbuf_addbuf(struct strbuf *sb, struct strbuf *sb2) {
+	strbuf_add(sb, sb2->buf, sb2->len);
+}
+static inline void strbuf_addch(struct strbuf *sb, size_t c) {
+	strbuf_grow(sb, 1);
+	sb->buf[sb->len++] = c;
+	sb->buf[sb->len] = '\0';
+}
+
+__attribute__((format(printf,2,0)))
+extern void strbuf_addvf(struct strbuf *, const char *, va_list);
+
+static inline __attribute__((format(printf,2,3)))
+void strbuf_addf(struct strbuf *sb, const char *fmt, ...) {
+	va_list ap;
+	va_start(ap, fmt);
+	strbuf_addvf(sb, fmt, ap);
+	va_end(ap);
+}
+
+
+extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);
+extern ssize_t strbuf_read(struct strbuf *, int fd);
+
 extern void read_line(struct strbuf *, FILE *, int);
 
 #endif /* STRBUF_H */
-- 
1.5.3

  reply	other threads:[~2007-09-05 19:19 UTC|newest]

Thread overview: 90+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-09-02 22:42 strbuf API Pierre Habouzit
2007-09-03  5:43 ` Johan Herland
2007-09-03  8:46   ` Pierre Habouzit
2007-09-04  1:52     ` Miles Bader
2007-09-04  8:47       ` strbuf new semantics, let's give it a try Pierre Habouzit
2007-09-04  8:47       ` [PATCH] Rework strbuf API and semantics Pierre Habouzit
2007-09-04 11:11         ` Johannes Schindelin
2007-09-04 11:53           ` Pierre Habouzit
2007-09-04 13:34             ` Andreas Ericsson
2007-09-04 14:01             ` Pierre Habouzit
2007-09-04 15:44               ` Johannes Schindelin
2007-09-04 16:18                 ` Pierre Habouzit
2007-09-04 17:18                   ` Wincent Colaiuta
2007-09-04 14:01             ` [PATCH] Simplify strbuf uses in fast-import.c using the proper functions Pierre Habouzit
2007-09-04 23:46               ` René Scharfe
2007-09-04 23:46               ` René Scharfe
2007-09-05  7:48                 ` Pierre Habouzit
2007-09-05  8:05                   ` Junio C Hamano
2007-09-05  8:57                     ` Pierre Habouzit
2007-09-05 19:18                       ` Pierre Habouzit [this message]
2007-09-05 19:18                         ` [PATCH] Simplify strbuf uses in archive-tar.c " Pierre Habouzit
2007-09-05 19:18                           ` [PATCH] Simplify strbuf uses in fast-import.c " Pierre Habouzit
2007-09-05 19:18                             ` [PATCH] Use proper strbuf API, and also simplify cmd_data code Pierre Habouzit
2007-09-05 19:18                               ` [PATCH] Simplify write_tree using strbuf's Pierre Habouzit
2007-09-05 19:18                                 ` [PATCH] Further strbuf re-engineering Pierre Habouzit
2007-09-05 19:18                                   ` [PATCH] Eradicate yet-another-buffer implementation in buitin-rerere.c Pierre Habouzit
2007-09-05 19:18                                     ` [PATCH] More strbuf uses in cache-tree.c Pierre Habouzit
2007-09-19  8:05                                   ` [PATCH] Further strbuf re-engineering Junio C Hamano
2007-09-05 19:21                             ` [PATCH] Simplify strbuf uses in fast-import.c using the proper functions Pierre Habouzit
2007-09-19  8:06                           ` [PATCH] Simplify strbuf uses in archive-tar.c " Junio C Hamano
2007-09-19  8:36                             ` Pierre Habouzit
2007-09-06  9:31                         ` [PATCH] Rework strbuf API and semantics Junio C Hamano
2007-09-06  9:49                           ` Pierre Habouzit
2007-09-06 10:03                         ` Junio C Hamano
2007-09-06 10:22                           ` Pierre Habouzit
2007-09-04 14:01             ` [PATCH] Use proper strbuf API, and also simplify cmd_data code Pierre Habouzit
2007-09-05  4:44             ` [PATCH] Rework strbuf API and semantics Miles Bader
2007-09-04  8:48       ` [PATCH] Add strbuf_fread, use it in fast-import.c Pierre Habouzit
2007-09-03  8:32 ` strbuf API Matthieu Moy
2007-09-03  8:49   ` Pierre Habouzit
2007-09-03  9:02     ` Matthieu Moy
2007-09-03  9:18     ` Junio C Hamano
2007-09-03 11:53       ` Pierre Habouzit
2007-09-03 12:29       ` Johannes Schindelin
2007-09-06 11:20 ` strbuf new API, take 2 for inclusion Pierre Habouzit
2007-09-06 11:20   ` [PATCH 1/7] Rework strbuf API and semantics Pierre Habouzit
2007-09-06 11:20     ` [PATCH 2/7] Simplify strbuf uses in archive-tar.c using the proper functions Pierre Habouzit
2007-09-06 11:20       ` [PATCH 3/7] Use proper strbuf API, and also simplify cmd_data code Pierre Habouzit
2007-09-06 11:20         ` [PATCH 4/7] Simplify write_tree using strbuf's Pierre Habouzit
2007-09-06 11:20           ` [PATCH 5/7] Further strbuf re-engineering Pierre Habouzit
2007-09-06 11:20             ` [PATCH 6/7] Eradicate yet-another-buffer implementation in buitin-rerere.c Pierre Habouzit
2007-09-06 11:20               ` [PATCH 7/7] More strbuf uses in cache-tree.c Pierre Habouzit
2007-09-06 14:05               ` [PATCH 6/7] Eradicate yet-another-buffer implementation in buitin-rerere.c Johannes Schindelin
2007-09-06 17:17                 ` Pierre Habouzit
2007-09-06 20:16                   ` David Kastrup
2007-09-06 20:54                     ` Pierre Habouzit
2007-09-07  8:03                   ` Junio C Hamano
2007-09-07  9:02                     ` Pierre Habouzit
2007-09-06 17:59       ` [PATCH 2/7] Simplify strbuf uses in archive-tar.c using the proper functions Kristian Høgsberg
2007-09-06 18:08         ` Pierre Habouzit
2007-09-06 18:18           ` Kristian Høgsberg
2007-09-06 18:27             ` Pierre Habouzit
2007-09-06 22:54               ` René Scharfe
2007-09-06 14:09     ` [PATCH 1/7] Rework strbuf API and semantics Johannes Schindelin
2007-09-06 14:21       ` Jeff King
2007-09-06 14:44         ` David Kastrup
2007-09-06 14:50           ` Jeff King
2007-09-06 15:06             ` David Kastrup
2007-09-06 15:36               ` Jeff King
2007-09-06 15:53                 ` David Kastrup
2007-09-06 15:45               ` Johannes Sixt
2007-09-06 14:43       ` David Kastrup
2007-09-06 14:52         ` Jeff King
2007-09-06 17:49     ` Kristian Høgsberg
2007-09-06 12:58   ` strbuf new API, take 2 for inclusion Jeff King
2007-09-06 17:15     ` Pierre Habouzit
2007-09-06 17:16       ` Jeff King
2007-09-06 17:19         ` Pierre Habouzit
2007-09-08 11:53 ` Use strbufs in commit.c (pretty printing) Pierre Habouzit
2007-09-08 11:53   ` [PATCH 1/3] Add strbuf_rtrim (to remove trailing spaces) Pierre Habouzit
2007-09-08 11:53     ` [PATCH 2/3] Change semantics of interpolate to work like snprintf Pierre Habouzit
2007-09-08 11:53       ` [PATCH 3/3] Rework pretty_print_commit to use strbufs instead of custom buffers Pierre Habouzit
2007-09-08 11:59         ` David Kastrup
2007-09-08 12:17           ` Pierre Habouzit
2007-09-08 12:28           ` Pierre Habouzit
2007-09-08 18:40         ` René Scharfe
2007-09-08 18:49           ` Pierre Habouzit
2007-09-08 16:18     ` [PATCH 1/3] Add strbuf_rtrim (to remove trailing spaces) René Scharfe
2007-09-08 22:53       ` Pierre Habouzit
2007-09-08 23:44         ` Pierre Habouzit

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=11890199232110-git-send-email-madcoder@debian.org \
    --to=madcoder@debian.org \
    --cc=git@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.