aboutsummaryrefslogtreecommitdiffstats
path: root/core/membuffer.h
blob: 821b0cecbd0fb8a62125a1f4cb43e40eaca71339 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// 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

#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>
#include "units.h"

struct membuffer {
	unsigned int len, alloc;
	char *buffer;
};

#ifdef __cplusplus

// In C++ code use this - it automatically frees the buffer, when going out of scope.
struct membufferpp : public membuffer {
	membufferpp();
	~membufferpp();
};

extern "C" {
#endif

#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 *);

/* The pointer obtained by mb_cstring is invalidated by any modifictation to the 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