root/1.8.3/tags/p3/src/bufferq.c

Revision 919, 6.5 KB (checked in by shawnw, 19 months ago)

1.8.3p3

Line 
1/**
2 * \file bufferq.c
3 *
4 * \brief Code for managing queues of buffers, a handy data structure.
5 *
6 *
7 */
8
9#include "copyrite.h"
10#include "config.h"
11
12#include <stdio.h>
13#ifdef I_UNISTD
14#include <unistd.h>
15#endif
16#include <string.h>
17#include <stddef.h>
18#include <stdarg.h>
19#include <stdlib.h>
20#ifdef I_SYS_TIME
21#include <sys/time.h>
22#ifdef TIME_WITH_SYS_TIME
23#include <time.h>
24#endif
25#else
26#include <time.h>
27#endif
28#ifdef I_SYS_TYPES
29#include <sys/types.h>
30#endif
31
32#include "conf.h"
33#include "externs.h"
34#include "flags.h"
35#include "dbdefs.h"
36#include "bufferq.h"
37#include "mymalloc.h"
38#include "log.h"
39#include "confmagic.h"
40
41#define BUFFERQLINEOVERHEAD     (2*sizeof(int)+sizeof(time_t)+sizeof(dbref))
42
43static void shift_bufferq(BUFFERQ *bq, int space_needed);
44
45/** Add data to a buffer queue.
46 * \param bq pointer to buffer queue.
47 * \param type caller-specific integer
48 * \param player caller-specific dbref
49 * \param msg caller-specific string to add.
50 */
51void
52add_to_bufferq(BUFFERQ *bq, int type, dbref player, const char *msg)
53{
54  int len = strlen(msg);
55  int room = len + 1 + BUFFERQLINEOVERHEAD;
56  if (!bq)
57    return;
58  if (room > bq->buffer_size)
59    return;
60  if ((bq->buffer_end > bq->buffer) &&
61      ((bq->buffer_size - (bq->buffer_end - bq->buffer)) < room))
62    shift_bufferq(bq, room);
63  memcpy(bq->buffer_end, &len, sizeof(len));
64  bq->buffer_end += sizeof(len);
65  memcpy(bq->buffer_end, &player, sizeof(player));
66  bq->buffer_end += sizeof(player);
67  memcpy(bq->buffer_end, &type, sizeof(type));
68  bq->buffer_end += sizeof(type);
69  memcpy(bq->buffer_end, &mudtime, sizeof(time_t));
70  bq->buffer_end += sizeof(time_t);
71  memcpy(bq->buffer_end, msg, len + 1);
72  bq->buffer_end += len + 1;
73  strcpy(bq->last_string, msg);
74  bq->last_type = type;
75  bq->num_buffered++;
76}
77
78
79static void
80shift_bufferq(BUFFERQ *bq, int space_needed)
81{
82  char *p = bq->buffer;
83  int size, jump;
84  int skipped = 0;
85
86  while ((space_needed > 0) && (p < bq->buffer_end)) {
87    /* First 4 bytes is the size of the first string, not including \0 */
88    memcpy(&size, p, sizeof(size));
89    /* Jump to the start of the next string */
90    jump = size + BUFFERQLINEOVERHEAD + 1;
91    p += jump;
92    space_needed -= jump;
93    skipped++;
94  }
95
96  if ((p != bq->buffer_end) && (space_needed > 0)) {
97    /* Not good. We couldn't get the space we needed even after we
98     * emptied the buffer. This should never happen, but if it does,
99     * we'll just log a fault and do nothing.
100     */
101    do_rawlog(LT_ERR, "Unable to get enough buffer queue space");
102    return;
103  }
104
105  /* Shift everything here and after up to the front
106   * At this point, p may be pointing at the very end of the buffer,
107   * in which case, we just move it to the front with no shifting.
108   */
109  if (p < bq->buffer_end)
110    memmove(bq->buffer, p, bq->buffer_end - p);
111  bq->buffer_end -= (p - bq->buffer);
112  bq->num_buffered -= skipped;
113}
114
115/** Allocate memory for a buffer queue to hold a given number of lines.
116 * \param bq pointer to buffer queue.
117 * \param lines lines to allocate for buffer queue.
118 * \retval address of allocated buffer queue.
119 */
120BUFFERQ *
121allocate_bufferq(int lines)
122{
123  BUFFERQ *bq;
124  int bytes = lines * (BUFFER_LEN + BUFFERQLINEOVERHEAD);
125  bq = mush_malloc(sizeof(BUFFERQ), "bufferq");
126  bq->buffer = mush_malloc(bytes, "bufferq.buffer");
127  *bq->buffer = '\0';
128  bq->buffer_end = bq->buffer;
129  bq->num_buffered = 0;
130  bq->buffer_size = bytes;
131  strcpy(bq->last_string, "");
132  bq->last_type = 0;
133  return bq;
134}
135
136/** Free memory of a buffer queue.
137 * \param bq pointer to buffer queue.
138 */
139void
140free_bufferq(BUFFERQ *bq)
141{
142  if (!bq)
143    return;
144  if (bq->buffer)
145    mush_free(bq->buffer, "bufferq.buffer");
146  mush_free(bq, "bufferq");
147}
148
149/** Reallocate a buffer queue (to change its size)
150 * \param bq pointer to buffer queue.
151 * \param lines new number of lines to store in buffer queue.
152 * \retval address of reallocated buffer queue.
153 */
154BUFFERQ *
155reallocate_bufferq(BUFFERQ *bq, int lines)
156{
157  char *newbuff;
158  ptrdiff_t bufflen;
159  int bytes = lines * (BUFFER_LEN + 2 * BUFFERQLINEOVERHEAD);
160  /* If we were accidentally called without a buffer, deal */
161  if (!bq) {
162    return allocate_bufferq(lines);
163  }
164  /* Are we not changing size? */
165  if (bq->buffer_size == bytes)
166    return bq;
167  if (bq->buffer_size > bytes) {
168    /* Shrinking the buffer */
169    if ((bq->buffer_end - bq->buffer) >= bytes)
170      shift_bufferq(bq, bq->buffer_end - bq->buffer - bytes);
171  }
172  bufflen = bq->buffer_end - bq->buffer;
173  newbuff = realloc(bq->buffer, bytes);
174  if (newbuff) {
175    bq->buffer = newbuff;
176    bq->buffer_end = bq->buffer + bufflen;
177    bq->buffer_size = bytes;
178  }
179  return bq;
180}
181
182
183
184/** Iterate through messages in a bufferq.
185 * This function returns the next message in a bufferq, given
186 * a pointer to the start of entry (which is modified).
187 * It returns NULL when there are no more messages to get.
188 * Call this in a loop to get all messages; do not intersperse
189 * with calls to insert messages!
190 * \param bq pointer to buffer queue structure.
191 * \param p address of pointer to track start of next entry. If that's
192 *   the address of a null pointer, reset to beginning.
193 * \param player address of pointer to return player data in
194 * \param type address of pointer to return type value in.
195 * \param timestamp address of pointer to return timestamp in.
196 * \return next message text or NULL if no more.
197 */
198char *
199iter_bufferq(BUFFERQ *bq, char **p, dbref *player, int *type,
200             time_t * timestamp)
201{
202  static char tbuf1[BUFFER_LEN];
203  int size;
204
205  if (!p || !bq || !bq->buffer || (bq->buffer == bq->buffer_end))
206    return NULL;
207
208  if (*p == bq->buffer_end)
209    return NULL;
210
211  if (!*p)
212    *p = bq->buffer;            /* Reset to beginning */
213
214  memcpy(&size, *p, sizeof(size));
215  *p += sizeof(size);
216  memcpy(player, *p, sizeof(dbref));
217  *p += sizeof(dbref);
218  memcpy(type, *p, sizeof(int));
219  *p += sizeof(int);
220  memcpy(timestamp, *p, sizeof(time_t));
221  *p += sizeof(time_t);
222  memcpy(tbuf1, *p, size + 1);
223  *p += size + 1;
224  return tbuf1;
225}
226
227/** Size of bufferq buffer in lines.
228 * \param bq pointer to buffer queue.
229 * \return size of buffer queue in lines
230 */
231int
232bufferq_lines(BUFFERQ *bq)
233{
234  if (bq && bq->buffer)
235    return bq->buffer_size / (BUFFER_LEN + BUFFERQLINEOVERHEAD);
236  else
237    return 0;
238}
239
240/** Is a buffer queue empty?
241 * \param bq pointer to buffer queue.
242 * \retval 1 the buffer queue is empty (has no messages).
243 * \retval 0 the buffer queue is not empty (has messages).
244 */
245int
246isempty_bufferq(BUFFERQ *bq)
247{
248  if (!bq || !bq->buffer)
249    return 1;
250  if (bq->buffer == bq->buffer_end)
251    return 1;
252  return 0;
253}
Note: See TracBrowser for help on using the browser.