mirror of
https://github.com/subsurface/subsurface.git
synced 2024-11-30 22:20:21 +00:00
a9b1fbdcc5
The native buffer of a membuffer is not NUL-terminated, so when you want to detach it and use it as a C string, you had to first do 'mb_cstring()' that adds the proper termination/ This was all documented in the header files, and all but two users did it correctly. But there were those two users, and the exported interface was unnecessarily hard to use. We do want the "just detach the raw buffer" internally in the membuffer code, but let's not make the exported interface be that hard to use. So this switches the exported interface to be 'detach_cstring()', which does that 'mb_cstring()' for you, and avoids the possibility that you'd use a non-terminated memory buffer as a C string. The old 'detach_buffer()' is now purely the internal membuffer implementation, and not used by others. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
116 lines
3.9 KiB
C
116 lines
3.9 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Helper functions used to deal with string manipulation
|
|
* 'membuffer' functions will manage memory allocation avoiding performance
|
|
* issues related to superfluous re-allocation. See 'make_room' function
|
|
*
|
|
* Before using it membuffer struct should be properly initialized
|
|
*
|
|
* struct membuffer mb = { 0 };
|
|
*
|
|
* Internal membuffer buffer will not by default contain null terminator,
|
|
* adding it should be done using 'mb_cstring' function
|
|
*
|
|
* mb_cstring(&mb);
|
|
*
|
|
* String concatenation is done with consecutive calls to put_xxx functions
|
|
*
|
|
* put_string(&mb, "something");
|
|
* put_string(&mb, ", something else");
|
|
* printf("%s", mb_cstring(&mb));
|
|
*
|
|
* Will result in
|
|
*
|
|
* "something, something else"
|
|
*
|
|
* Unless ownership to the buffer is given away by using "detach_cstring()":
|
|
*
|
|
* ptr = detach_cstring();
|
|
*
|
|
* where the caller now has a C string and is supposed to free it.
|
|
*
|
|
* Otherwise allocated memory should be freed
|
|
*
|
|
* free_buffer(&mb);
|
|
*/
|
|
#ifndef MEMBUFFER_H
|
|
#define MEMBUFFER_H
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include "units.h"
|
|
|
|
struct membuffer {
|
|
unsigned int len, alloc;
|
|
char *buffer;
|
|
};
|
|
|
|
#ifdef __GNUC__
|
|
#define __printf(x, y) __attribute__((__format__(__printf__, x, y)))
|
|
#else
|
|
#define __printf(x, y)
|
|
#endif
|
|
|
|
extern char *detach_cstring(struct membuffer *b);
|
|
extern void free_buffer(struct membuffer *);
|
|
extern void make_room(struct membuffer *b, unsigned int size);
|
|
extern void flush_buffer(struct membuffer *, FILE *);
|
|
extern void put_bytes(struct membuffer *, const char *, int);
|
|
extern void put_string(struct membuffer *, const char *);
|
|
extern void put_quoted(struct membuffer *, const char *, int, int);
|
|
extern void strip_mb(struct membuffer *);
|
|
extern const char *mb_cstring(struct membuffer *);
|
|
extern __printf(2, 0) void put_vformat(struct membuffer *, const char *, va_list);
|
|
extern __printf(2, 0) void put_vformat_loc(struct membuffer *, const char *, va_list);
|
|
extern __printf(2, 3) void put_format(struct membuffer *, const char *fmt, ...);
|
|
extern __printf(2, 3) void put_format_loc(struct membuffer *, const char *fmt, ...);
|
|
extern __printf(2, 0) char *add_to_string_va(char *old, const char *fmt, va_list args);
|
|
extern __printf(2, 3) char *add_to_string(char *old, const char *fmt, ...);
|
|
|
|
/* Helpers that use membuffers internally */
|
|
extern __printf(1, 0) char *vformat_string(const char *, va_list);
|
|
extern __printf(1, 2) char *format_string(const char *, ...);
|
|
|
|
|
|
/* Output one of our "milli" values with type and pre/post data */
|
|
extern void put_milli(struct membuffer *, const char *, int, const char *);
|
|
|
|
/*
|
|
* Helper functions for showing particular types. If the type
|
|
* is empty, nothing is done, and the function returns false.
|
|
* Otherwise, it returns true.
|
|
*
|
|
* The two "const char *" at the end are pre/post data.
|
|
*
|
|
* The reason for the pre/post data is so that you can easily
|
|
* prepend and append a string without having to test whether the
|
|
* type is empty. So
|
|
*
|
|
* put_temperature(b, temp, "Temp=", " C\n");
|
|
*
|
|
* writes nothing to the buffer if there is no temperature data,
|
|
* but otherwise would a string that looks something like
|
|
*
|
|
* "Temp=28.1 C\n"
|
|
*
|
|
* to the memory buffer (typically the post/pre will be some XML
|
|
* pattern and unit string or whatever).
|
|
*/
|
|
extern void put_temperature(struct membuffer *, temperature_t, const char *, const char *);
|
|
extern void put_depth(struct membuffer *, depth_t, const char *, const char *);
|
|
extern void put_duration(struct membuffer *, duration_t, const char *, const char *);
|
|
extern void put_pressure(struct membuffer *, pressure_t, const char *, const char *);
|
|
extern void put_salinity(struct membuffer *, int, const char *, const char *);
|
|
extern void put_degrees(struct membuffer *b, degrees_t value, const char *, const char *);
|
|
extern void put_location(struct membuffer *b, const location_t *, const char *, const char *);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|