From 1d62dedf83b2a3a06c6e0d1783e37656f451931c Mon Sep 17 00:00:00 2001 From: Matthew Fernandez Date: Sat, 15 Aug 2020 13:06:43 -0700 Subject: [PATCH] add a new 'disown' API for agxbuf --- CHANGELOG.md | 6 ++++++ lib/cgraph/agxbuf.c | 34 ++++++++++++++++++++++++++++++++++ lib/cgraph/agxbuf.h | 15 ++++++++++++++- 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ed978b72..a67677542 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] + +### Added +- Cgraph's agxbuf API gained a new function agxbdisown(), for dissociating + backing memory from the managed buffer + +### Changed - Cgraph's agheap() API has been removed ### Fixed diff --git a/lib/cgraph/agxbuf.c b/lib/cgraph/agxbuf.c index 4e320670a..6c5bfeecb 100644 --- a/lib/cgraph/agxbuf.c +++ b/lib/cgraph/agxbuf.c @@ -110,3 +110,37 @@ int agxbpop(agxbuf * xb) return -1; } + +char *agxbdisown(agxbuf * xb) { + + size_t size; + char *buf; + + /* terminate the existing string */ + agxbputc(xb, '\0'); + + size = (size_t)(xb->ptr - xb->buf); + + if (!xb->dyna) { + /* the buffer is not dynamically allocated, so we need to copy its contents + * to heap memory + */ + + buf = malloc(size); + if (buf == NULL) { + return NULL; + } + + memcpy(buf, xb->buf, size); + + } else { + /* the buffer is already dynamically allocated, so take it as-is */ + buf = (char*)xb->buf; + } + + /* reset xb to a state where it is usable */ + xb->buf = xb->ptr = xb->eptr = NULL; + xb->dyna = 1; + + return buf; +} diff --git a/lib/cgraph/agxbuf.h b/lib/cgraph/agxbuf.h index 7cbb22088..6a7bada96 100644 --- a/lib/cgraph/agxbuf.h +++ b/lib/cgraph/agxbuf.h @@ -77,7 +77,10 @@ extern "C" { #define agxbputc(X,C) ((((X)->ptr >= (X)->eptr) ? agxbmore(X,1) : 0), (void)(*(X)->ptr++ = ((unsigned char)C))) /* agxbuse: - * Null-terminates buffer; resets and returns pointer to data; + * Null-terminates buffer; resets and returns pointer to data. The buffer is + * still associated with the agxbuf and will be overwritten on the next, e.g., + * agxbput. If you want to retrieve and disassociate the buffer, use agxbdisown + * instead. * char* agxbuse(agxbuf* xb) */ #define agxbuse(X) ((void)agxbputc(X,'\0'),(char*)((X)->ptr = (X)->buf)) @@ -106,6 +109,16 @@ extern "C" { */ #define agxbnext(X) ((char*)((X)->ptr)) +/* agxbdisown: + * Disassociate the backing buffer from this agxbuf and return it. The buffer is + * NUL terminated before being returned. If the agxbuf is using stack memory, + * this will first copy the data to a new heap buffer to then return. If failure + * occurs, NULL is returned. If you want to temporarily access the string in the + * buffer, but have it overwritten and reused the next time, e.g., agxbput is + * called, use agxbuse instead of agxbdisown. + */ + AGXBUF_API char *agxbdisown(agxbuf * xb); + #endif #ifdef __cplusplus -- 2.50.1