4
* \brief Code for managing queues of buffers, a handy data structure.
25
#include <sys/types.h>
35
#include "confmagic.h"
37
#define BUFFERQLINEOVERHEAD (2*sizeof(int)+sizeof(time_t)+sizeof(dbref))
39
static void shift_bufferq(BUFFERQ * bq, int space_needed);
41
/** Add data to a buffer queue.
42
* \param bq pointer to buffer queue.
43
* \param type caller-specific integer
44
* \param player caller-specific dbref
45
* \param msg caller-specific string to add.
48
add_to_bufferq(BUFFERQ * bq, int type, dbref player, const char *msg)
50
int len = strlen(msg);
51
int room = len + 1 + BUFFERQLINEOVERHEAD;
54
if (room > bq->buffer_size)
56
if ((bq->buffer_end > bq->buffer) &&
57
((bq->buffer_size - (bq->buffer_end - bq->buffer)) < room))
58
shift_bufferq(bq, room);
59
memcpy(bq->buffer_end, &len, sizeof(len));
60
bq->buffer_end += sizeof(len);
61
memcpy(bq->buffer_end, &player, sizeof(player));
62
bq->buffer_end += sizeof(player);
63
memcpy(bq->buffer_end, &type, sizeof(type));
64
bq->buffer_end += sizeof(type);
65
memcpy(bq->buffer_end, &mudtime, sizeof(time_t));
66
bq->buffer_end += sizeof(time_t);
67
memcpy(bq->buffer_end, msg, len + 1);
68
bq->buffer_end += len + 1;
69
strcpy(bq->last_string, msg);
76
shift_bufferq(BUFFERQ * bq, int space_needed)
82
while ((space_needed > 0) && (p < bq->buffer_end)) {
83
/* First 4 bytes is the size of the first string, not including \0 */
84
memcpy(&size, p, sizeof(size));
85
/* Jump to the start of the next string */
86
jump = size + BUFFERQLINEOVERHEAD + 1;
92
if ((p != bq->buffer_end) && (space_needed > 0)) {
93
/* Not good. We couldn't get the space we needed even after we
94
* emptied the buffer. This should never happen, but if it does,
95
* we'll just log a fault and do nothing.
97
do_rawlog(LT_ERR, "Unable to get enough buffer queue space");
101
/* Shift everything here and after up to the front
102
* At this point, p may be pointing at the very end of the buffer,
103
* in which case, we just move it to the front with no shifting.
105
if (p < bq->buffer_end)
106
memmove(bq->buffer, p, bq->buffer_end - p);
107
bq->buffer_end -= (p - bq->buffer);
108
bq->num_buffered -= skipped;
111
/** Allocate memory for a buffer queue to hold a given number of lines.
112
* \param bq pointer to buffer queue.
113
* \param lines lines to allocate for buffer queue.
114
* \retval address of allocated buffer queue.
117
allocate_bufferq(int lines)
120
int bytes = lines * (BUFFER_LEN + BUFFERQLINEOVERHEAD);
121
bq = mush_malloc(sizeof(BUFFERQ), "bufferq");
122
bq->buffer = mush_malloc(bytes, "bufferq.buffer");
124
bq->buffer_end = bq->buffer;
125
bq->num_buffered = 0;
126
bq->buffer_size = bytes;
127
strcpy(bq->last_string, "");
132
/** Free memory of a buffer queue.
133
* \param bq pointer to buffer queue.
136
free_bufferq(BUFFERQ * bq)
141
mush_free(bq->buffer, "bufferq.buffer");
142
mush_free(bq, "bufferq");
145
/** Reallocate a buffer queue (to change its size)
146
* \param bq pointer to buffer queue.
147
* \param lines new number of lines to store in buffer queue.
148
* \retval address of reallocated buffer queue.
151
reallocate_bufferq(BUFFERQ * bq, int lines)
155
int bytes = lines * (BUFFER_LEN + 2 * BUFFERQLINEOVERHEAD);
156
/* If we were accidentally called without a buffer, deal */
158
return allocate_bufferq(lines);
160
/* Are we not changing size? */
161
if (bq->buffer_size == bytes)
163
if (bq->buffer_size > bytes) {
164
/* Shrinking the buffer */
165
if ((bq->buffer_end - bq->buffer) >= bytes)
166
shift_bufferq(bq, bq->buffer_end - bq->buffer - bytes);
168
bufflen = bq->buffer_end - bq->buffer;
169
newbuff = realloc(bq->buffer, bytes);
171
bq->buffer = newbuff;
172
bq->buffer_end = bq->buffer + bufflen;
173
bq->buffer_size = bytes;
180
/** Iterate through messages in a bufferq.
181
* This function returns the next message in a bufferq, given
182
* a pointer to the start of entry (which is modified).
183
* It returns NULL when there are no more messages to get.
184
* Call this in a loop to get all messages; do not intersperse
185
* with calls to insert messages!
186
* \param bq pointer to buffer queue structure.
187
* \param p address of pointer to track start of next entry. If that's
188
* the address of a null pointer, reset to beginning.
189
* \param player address of pointer to return player data in
190
* \param type address of pointer to return type value in.
191
* \param timestamp address of pointer to return timestamp in.
192
* \return next message text or NULL if no more.
195
iter_bufferq(BUFFERQ * bq, char **p, dbref *player, int *type,
198
static char tbuf1[BUFFER_LEN];
201
if (!p || !bq || !bq->buffer || (bq->buffer == bq->buffer_end))
204
if (*p == bq->buffer_end)
208
*p = bq->buffer; /* Reset to beginning */
210
memcpy(&size, *p, sizeof(size));
212
memcpy(player, *p, sizeof(dbref));
214
memcpy(type, *p, sizeof(int));
216
memcpy(timestamp, *p, sizeof(time_t));
217
*p += sizeof(time_t);
218
memcpy(tbuf1, *p, size + 1);
223
/** Size of bufferq buffer in lines.
224
* \param bq pointer to buffer queue.
225
* \return size of buffer queue in lines
228
bufferq_lines(BUFFERQ * bq)
230
if (bq && bq->buffer)
231
return bq->buffer_size / (BUFFER_LEN + BUFFERQLINEOVERHEAD);
236
/** Is a buffer queue empty?
237
* \param bq pointer to buffer queue.
238
* \retval 1 the buffer queue is empty (has no messages).
239
* \retval 0 the buffer queue is not empty (has messages).
242
isempty_bufferq(BUFFERQ * bq)
244
if (!bq || !bq->buffer)
246
if (bq->buffer == bq->buffer_end)