PennMUSH Community

root/1.8.3/trunk/src/bufferq.c

Revision 1230, 6.8 kB (checked in by shawnw, 5 months ago)

Fix @chan/what to show actual line count

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
43 static 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  */
51 void
52 add_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
79 static void
80 shift_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  */
120 BUFFERQ *
121 allocate_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  */
139 void
140 free_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  */
154 BUFFERQ *
155 reallocate_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  */
198 char *
199 iter_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 blocks.
228  * \param bq pointer to buffer queue.
229  * \return size of buffer queue in 8k blocks
230  */
231 int
232 bufferq_blocks(BUFFERQ *bq)
233 {
234   if (bq && bq->buffer)
235     return bq->buffer_size / (BUFFER_LEN + BUFFERQLINEOVERHEAD);
236   else
237     return 0;
238 }
239
240 /** Number of lines stored in queue.
241  * \param bq pointer to buffer queue.
242  * \return line count
243  */
244 int
245 bufferq_lines(BUFFERQ *bp)
246 {
247   int lines = 0;
248   char *p = NULL;
249   dbref player;
250   int type;
251   time_t t;
252
253
254   if (isempty_bufferq(bp))
255     return 0;
256
257   while (iter_bufferq(bp, &p, &player, &type, &t))
258     lines++;
259
260   return lines;
261 }
262
263 /** Is a buffer queue empty?
264  * \param bq pointer to buffer queue.
265  * \retval 1 the buffer queue is empty (has no messages).
266  * \retval 0 the buffer queue is not empty (has messages).
267  */
268 bool
269 isempty_bufferq(BUFFERQ *bq)
270 {
271   if (!bq || !bq->buffer)
272     return 1;
273   if (bq->buffer == bq->buffer_end)
274     return 1;
275   return 0;
276 }
Note: See TracBrowser for help on using the browser.