1/* 2 * bufExt.c -- 3 * 4 * Implementations of an extendable buffer. 5 * 6 * Copyright (c) 2000-2009 by Andreas Kupries <a.kupries@westend.com> 7 * 8 * See the file "license.terms" for information on usage and redistribution 9 * of this file, and for a DISCLAIMER OF ALL WARRANTIES. 10 * 11 * RCS: @(#) $Id: bufExt.c,v 1.3 2009/03/16 18:50:59 andreas_kupries Exp $ 12 */ 13 14#include "memchanInt.h" 15#include "buf.h" 16 17/* 18 * Forward declarations of all internal procedures. 19 */ 20 21static int ReadProc _ANSI_ARGS_ ((Buf_Buffer buf, ClientData clientData, 22 VOID* outbuf, int size)); 23static int WriteProc _ANSI_ARGS_ ((Buf_Buffer buf, ClientData clientData, 24 CONST VOID* inbuf, int size)); 25static Buf_Buffer DupProc _ANSI_ARGS_ ((Buf_Buffer buf, ClientData clientData)); 26static void FreeProc _ANSI_ARGS_ ((Buf_Buffer buf, ClientData clientData)); 27static int SizeProc _ANSI_ARGS_ ((Buf_Buffer buf, ClientData clientData)); 28static int TellProc _ANSI_ARGS_ ((Buf_Buffer buf, ClientData clientData)); 29static char* DataProc _ANSI_ARGS_ ((Buf_Buffer buf, ClientData clientData)); 30 31/* Internal structure used to hold the buffer information. 32 */ 33 34typedef struct ExtBuffer_ { 35 Buf_Buffer buf; /* The buffer token containing this structure. */ 36 int size; /* Size of the area for data, maximal amount of 37 * bytes storable in the buffer. */ 38 char* readLoc; /* The location till which data was read from the 39 * buffer. */ 40 char* writeLoc; /* The location at which new data can be appended to 41 * the buffer. */ 42 char* limit; /* A pointer behind the last character in the buffer. */ 43 char* data; /* Pointer to start of the actual container */ 44} ExtBuffer; 45 46/* Declaration of the buffer type. 47 */ 48 49static Buf_BufferType ext = { 50 "extendable-buffer", /* Buffer of varying size */ 51 ReadProc, /* Reading from a buffer */ 52 WriteProc, /* Writing to a buffer */ 53 DupProc, /* Duplicating a buffer */ 54 FreeProc, /* Freeing all allocated resources of a buffer */ 55 SizeProc, /* Number of bytes currently in the buffer. */ 56 TellProc, /* Return current location */ 57 DataProc /* Return start of data */ 58}; 59 60 61/* 62 *------------------------------------------------------* 63 * 64 * FreeProc -- 65 * 66 * Deallocates the resources of the buffer. 67 * 68 * Sideeffects: 69 * See above. 70 * 71 * Result: 72 * None. 73 * 74 *------------------------------------------------------* 75 */ 76 77void 78FreeProc (buf, clientData) 79 Buf_Buffer buf; 80 ClientData clientData; 81{ 82 ExtBuffer* iBuf = (ExtBuffer*) clientData; 83 Tcl_Free (iBuf->data); 84 Tcl_Free ((char*) iBuf); 85} 86 87/* 88 *------------------------------------------------------* 89 * 90 * SizeProc -- 91 * 92 * Returns the number of bytes currently stored in 93 * the buffer. 94 * 95 * Sideeffects: 96 * None. 97 * 98 * Result: 99 * See above. 100 * 101 *------------------------------------------------------* 102 */ 103 104int 105SizeProc (buf, clientData) 106 Buf_Buffer buf; 107 ClientData clientData; 108{ 109 ExtBuffer* iBuf = (ExtBuffer*) clientData; 110 return (iBuf->writeLoc - iBuf->readLoc); 111} 112 113/* 114 *------------------------------------------------------* 115 * 116 * TellProc -- 117 * 118 * Returns the offset of the current read location 119 * relative to the start of the data. 120 * 121 * Sideeffects: 122 * None. 123 * 124 * Result: 125 * See above. 126 * 127 *------------------------------------------------------* 128 */ 129 130int 131TellProc (buf, clientData) 132 Buf_Buffer buf; 133 ClientData clientData; 134{ 135 ExtBuffer* iBuf = (ExtBuffer*) clientData; 136 return iBuf->readLoc - iBuf->data; 137} 138 139/* 140 *------------------------------------------------------* 141 * 142 * DataProc -- 143 * 144 * Returns the start of the data area. 145 * (Here: Start of the data area in the underlying buffer) 146 * 147 * Sideeffects: 148 * None. 149 * 150 * Result: 151 * See above. 152 * 153 *------------------------------------------------------* 154 */ 155 156char* 157DataProc (buf, clientData) 158 Buf_Buffer buf; 159 ClientData clientData; 160{ 161 ExtBuffer* iBuf = (ExtBuffer*) clientData; 162 return iBuf->data; 163} 164 165/* 166 *------------------------------------------------------* 167 * 168 * DupProc -- 169 * 170 * Duplicates a buffer and its contents. 171 * 172 * Sideeffects: 173 * Allocates memory. 174 * 175 * Result: 176 * A new buffer token. 177 * 178 *------------------------------------------------------* 179 */ 180 181Buf_Buffer 182DupProc (buf, clientData) 183 Buf_Buffer buf; 184 ClientData clientData; 185{ 186 ExtBuffer* iBuf = (ExtBuffer*) clientData; 187 ExtBuffer* newBuf = (ExtBuffer*) Tcl_Alloc (sizeof(ExtBuffer) + 188 (iBuf->limit - iBuf->data)); 189 Buf_Buffer new = Buf_Create (&ext, (ClientData) newBuf); 190 191 newBuf->buf = new; 192 newBuf->data = Tcl_Alloc (iBuf->size); 193 newBuf->size = iBuf->size; 194 newBuf->readLoc = newBuf->data + (iBuf->readLoc - iBuf->data); 195 newBuf->writeLoc = newBuf->data + (iBuf->writeLoc - iBuf->data); 196 newBuf->limit = newBuf->data + newBuf->size; 197 198 if ((iBuf->writeLoc - iBuf->readLoc) > 0) { 199 /* Copy just that part of container which was not read already 200 */ 201 memcpy (newBuf->readLoc, iBuf->readLoc, iBuf->writeLoc - iBuf->readLoc); 202 } 203 204 return new; 205} 206 207/* 208 *------------------------------------------------------* 209 * 210 * ReadProc -- 211 * 212 * Reads at most size bytes from the current location 213 * in the buffer and stores it into outbuf. 214 * 215 * Sideeffects: 216 * Moves the read pointer behind the bytes 217 * just read from the buffer. 218 * 219 * Result: 220 * The number of bytes actually read from 221 * the buffer. 222 * 223 *------------------------------------------------------* 224 */ 225 226int 227ReadProc (buf, clientData, outbuf, size) 228 Buf_Buffer buf; 229 ClientData clientData; 230 VOID* outbuf; 231 int size; 232{ 233 ExtBuffer* iBuf = (ExtBuffer*) clientData; 234 int bSize = iBuf->writeLoc - iBuf->readLoc; 235 236 if ((bSize <= 0) || (size <= 0)) { 237 return 0; 238 } 239 240 if (bSize < size) { 241 size = bSize; 242 } 243 244 memcpy (outbuf, iBuf->readLoc, size); 245 iBuf->readLoc += size; 246 247 return size; 248} 249 250/* 251 *------------------------------------------------------* 252 * 253 * WriteProc -- 254 * 255 * Writes at most size bytes from inbuf and appends 256 * it the buffer 257 * 258 * Sideeffects: 259 * Moves the write pointer behind the bytes 260 * just written into the buffer. 261 * 262 * Result: 263 * The number of bytes actually written 264 * into the buffer. 265 * 266 *------------------------------------------------------* 267 */ 268 269int 270WriteProc (buf, clientData, inbuf, size) 271 Buf_Buffer buf; 272 ClientData clientData; 273 CONST void* inbuf; 274 int size; 275{ 276 ExtBuffer* iBuf = (ExtBuffer*) clientData; 277 int bSize = iBuf->limit - iBuf->writeLoc; 278 279 if (size <= 0) { 280 return 0; 281 } 282 283 if (bSize < size) { 284 /* Not enough memory to copy the whole input to the buffer. 285 * So extend it now. 286 */ 287 288 char* ndata = (char*) Tcl_Alloc (iBuf->size + size); 289 290 memcpy (ndata, iBuf->data, iBuf->size); 291 292 iBuf->size += size; 293 iBuf->readLoc = ndata + (iBuf->readLoc - iBuf->data); 294 iBuf->writeLoc = ndata + (iBuf->writeLoc - iBuf->data); 295 iBuf->limit = ndata + iBuf->size; 296 iBuf->data = ndata; 297 } 298 299 memcpy (iBuf->writeLoc, inbuf, size); 300 iBuf->writeLoc += size; 301 302 return size; 303} 304 305 306/* 307 * ------------------------------------------------------------ 308 */ 309 310Buf_Buffer 311Buf_CreateExtendableBuffer (size) 312 int size; 313{ 314 ExtBuffer* newBuf = (ExtBuffer*) Tcl_Alloc (sizeof(ExtBuffer)); 315 Buf_Buffer new = Buf_Create (&ext, (ClientData) newBuf); 316 317 newBuf->buf = new; 318 newBuf->size = size; 319 newBuf->data = Tcl_Alloc (size); 320 newBuf->readLoc = newBuf->data; 321 newBuf->writeLoc = newBuf->data; 322 newBuf->limit = newBuf->data + size; 323 324 return new; 325} 326 327