1/*
2 * buf.c --
3 *
4 *	Implementations of functions in the platform independent public Buf API.
5 *
6 * Copyright (c) 2000 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: buf.c,v 1.1 2000/09/26 21:17:49 aku Exp $
12 */
13
14#include "buf.h"
15
16/*
17 * Codestring used to associate the
18 * initialization flag with an interpreter.
19 */
20
21#define ASSOC "memchan:buf"
22
23/* Internal declaration of buffers.
24 */
25
26typedef struct Buffer_ {
27  Buf_BufferType* type;       /* Reference to the type of the buffer */
28  ClientData      clientData; /* The information pertinent to the used type. */
29  int             refCount;   /* Number of references hold by other parts
30			       * of the application to this buffer. Initialized
31			       * to 0 by the creator procedures implemented here.
32			       */
33} Buffer;
34
35/* Internal declaration of a buffer position.
36 */
37
38typedef struct BufferPosition_ {
39  Buf_Buffer buf;    /* The buffer this position belongs to */
40  int        offset; /* The offset into the data area */
41} BufferPosition;
42
43/*
44 *------------------------------------------------------*
45 *
46 *	Buf_IsInitialized --
47 *
48 *	Check wether the buffer system is initialized for
49 *	the specified interpreter
50 *
51 *	Sideeffects:
52 *		None.
53 *
54 *	Result:
55 *		A boolean value. 0 indicates no
56 *		initialization, 1 the opposite.
57 *
58 *------------------------------------------------------*
59 */
60
61int
62Buf_IsInitialized (interp)
63     Tcl_Interp* interp;
64{
65  Tcl_InterpDeleteProc* proc = (Tcl_InterpDeleteProc*) NULL;
66  return (int) Tcl_GetAssocData (interp, ASSOC, &proc);
67}
68
69/*
70 *------------------------------------------------------*
71 *
72 *	Buf_Init --
73 *
74 *	Initializes the buffer system in the specified
75 *	interpreter.
76 *
77 *	Sideeffects:
78 *		Associates data with the specified
79 *		interpreter to remember the initialization
80 *
81 *	Result:
82 *		A standard TCL error code.
83 *
84 *------------------------------------------------------*
85 */
86
87
88int
89Buf_Init (interp)
90     Tcl_Interp* interp;
91{
92  /* There is nothing to initialize here. But we have an operation
93   * querying the state of initialization, so we have to remember
94   * at least this.
95   */
96
97  if (Buf_IsInitialized (interp)) {
98    /* catch multiple initialization of an interpreter
99     */
100    return TCL_OK;
101  }
102
103  Tcl_SetAssocData (interp, ASSOC,
104		    (Tcl_InterpDeleteProc*) NULL,
105		    (ClientData) 1);
106
107  return TCL_OK;
108}
109
110/*
111 *------------------------------------------------------*
112 *
113 *	Buf_RegisterType --
114 *
115 *	Registers a new buffer type.
116 *
117 *	Sideeffects:
118 *		None.
119 *
120 *	Result:
121 *		None.
122 *
123 *------------------------------------------------------*
124 */
125
126void
127Buf_RegisterType (bufType)
128     Buf_BufferType* bufType;
129{
130  /* There are currently no operations in the interface which require
131   * an internal list of registered buffer types, etc. So this function
132   * can and will be a no-op for now.
133   */
134}
135
136/*
137 *------------------------------------------------------*
138 *
139 *	Buf_IncrRefcount --
140 *
141 *	Tells the specified buffer that a new reference
142 *	to it is hold by someone else.
143 *
144 *	Sideeffects:
145 *		See above.
146 *
147 *	Result:
148 *		None.
149 *
150 *------------------------------------------------------*
151 */
152
153void
154Buf_IncrRefcount (buf)
155     Buf_Buffer buf;
156{
157  ((Buffer*) buf)->refCount ++;
158}
159
160/*
161 *------------------------------------------------------*
162 *
163 *	Buf_DecrRefcount --
164 *
165 *	Tells the specified buffer that a reference to it
166 *	is no longer in existence.
167 *
168 *	Sideeffects:
169 *		Deletes the buffer if the last reference
170 *		to it is released.
171 *
172 *	Result:
173 *		None.
174 *
175 *------------------------------------------------------*
176 */
177
178void
179Buf_DecrRefcount (buf)
180     Buf_Buffer buf;
181{
182  Buffer* iBuf = (Buffer*) buf;
183
184  iBuf->refCount --;
185
186  if (iBuf->refCount <= 0) {
187    /* No references are hold by anyone else anymore.
188     * So remove the buffer, we won't need it again.
189     */
190
191    iBuf->type->freeProc (buf, iBuf->clientData);
192    Tcl_Free ((char*) iBuf);
193  }
194}
195
196/*
197 *------------------------------------------------------*
198 *
199 *	Buf_IsShared --
200 *
201 *	Checks wether the buffer is shared among
202 *	different parts of the application.
203 *
204 *	Sideeffects:
205 *		None.
206 *
207 *	Result:
208 *		A boolean value. 1 indicates a shared
209 *		buffer, 0 the opposite.
210 *
211 *------------------------------------------------------*
212 */
213
214int
215Buf_IsShared (buf)
216     Buf_Buffer buf;
217{
218  return (((Buffer*) buf)->refCount > 1);
219}
220
221/*
222 *------------------------------------------------------*
223 *
224 *	Buf_GetType --
225 *
226 *	Retrieves the type structure of a buffer.
227 *
228 *	Sideeffects:
229 *		None.
230 *
231 *	Result:
232 *		A reference to the type of the buffer.
233 *
234 *------------------------------------------------------*
235 */
236
237Buf_BufferType*
238Buf_GetType (buf)
239     Buf_Buffer buf;
240{
241  return ((Buffer*) buf)->type;
242}
243
244/*
245 *------------------------------------------------------*
246 *
247 *	Buf_GetTypeName --
248 *
249 *	Retrieves the name of the type of a buffer.
250 *
251 *	Sideeffects:
252 *		None.
253 *
254 *	Result:
255 *		A reference to the string containing the
256 *		name of the type of the buffer.
257 *
258 *------------------------------------------------------*
259 */
260
261CONST char*
262Buf_GetTypeName (buf)
263     Buf_Buffer buf;
264{
265  return ((Buffer*) buf)->type->typeName;
266}
267
268/*
269 *------------------------------------------------------*
270 *
271 *	Buf_Size --
272 *
273 *	Returns the number of bytes currently stored in
274 *	the buffer.
275 *
276 *	Sideeffects:
277 *		None.
278 *
279 *	Result:
280 *		See above.
281 *
282 *------------------------------------------------------*
283 */
284
285int
286Buf_Size (buf)
287     Buf_Buffer buf;
288{
289  Buffer* iBuf = (Buffer*) buf;
290  return iBuf->type->sizeProc (buf, iBuf->clientData);
291}
292
293/*
294 *------------------------------------------------------*
295 *
296 *	Buf_GetClientData --
297 *
298 *	Retrieves the type specific client information
299 *	of a buffer.
300 *
301 *	Sideeffects:
302 *		None.
303 *
304 *	Result:
305 *		The client information of the buffer.
306 *
307 *------------------------------------------------------*
308 */
309
310ClientData
311Buf_GetClientData (buf)
312     Buf_Buffer buf;
313{
314  return ((Buffer*) buf)->clientData;
315}
316
317/*
318 *------------------------------------------------------*
319 *
320 *	Buf_Create --
321 *
322 *	Create a new buffer (refcount 0) from its type
323 *	and the asssociated type specific information
324 *
325 *	Sideeffects:
326 *		Allocates memory.
327 *
328 *	Result:
329 *		A new buffer token.
330 *
331 *------------------------------------------------------*
332 */
333
334
335Buf_Buffer
336Buf_Create (bufType, clientData)
337     Buf_BufferType* bufType;
338     ClientData      clientData;
339{
340  Buffer* iBuf     = (Buffer*) Tcl_Alloc (sizeof (Buffer));
341
342  iBuf->type       = bufType;
343  iBuf->clientData = clientData;
344  iBuf->refCount   = 0;
345
346  return (Buf_Buffer) iBuf;
347}
348
349/*
350 *------------------------------------------------------*
351 *
352 *	Buf_Dup --
353 *
354 *	Duplicates a buffer and its contents.
355 *
356 *	Sideeffects:
357 *		As of the used buffer driver.
358 *
359 *	Result:
360 *		A new buffer token.
361 *
362 *------------------------------------------------------*
363 */
364
365Buf_Buffer
366Buf_Dup (buf)
367     Buf_Buffer buf;
368{
369  Buffer* iBuf = (Buffer*) buf;
370  return iBuf->type->dupProc (buf, iBuf->clientData);
371}
372
373/*
374 *------------------------------------------------------*
375 *
376 *	Buf_Read --
377 *
378 *	Reads at most size bytes from the current location
379 *	in the buffer and stores it into outbuf.
380 *
381 *	Sideeffects:
382 *		Moves the read pointer behind the bytes
383 *		just read from the buffer.
384 *
385 *	Result:
386 *		The number of bytes actually read from
387 *		the buffer.
388 *
389 *------------------------------------------------------*
390 */
391
392int
393Buf_Read (buf, outbuf, size)
394     Buf_Buffer  buf;
395     VOID*       outbuf;
396     int         size;
397{
398  Buffer* iBuf = (Buffer*) buf;
399  return iBuf->type->readProc (buf, iBuf->clientData, outbuf, size);
400}
401
402/*
403 *------------------------------------------------------*
404 *
405 *	Buf_Write --
406 *
407 *	Writes at most size bytes from inbuf and appends
408 *	it the buffer
409 *
410 *	Sideeffects:
411 *		Moves the write pointer behind the bytes
412 *		just written into the buffer.
413 *
414 *	Result:
415 *		The number of bytes actually written
416 *		into the buffer.
417 *
418 *------------------------------------------------------*
419 */
420
421int
422Buf_Write (buf, inbuf, size)
423     Buf_Buffer  buf;
424     CONST VOID* inbuf;
425     int         size;
426{
427  Buffer* iBuf = (Buffer*) buf;
428
429  if (iBuf->type->writeProc == NULL) {
430    return 0;
431  } else {
432    return iBuf->type->writeProc (buf, iBuf->clientData, inbuf, size);
433  }
434}
435
436/*
437 *------------------------------------------------------*
438 *
439 *	Buf_PositionPtr --
440 *
441 *	Converts the logical location in the buffer into
442 *	a reference to the data area.
443 *
444 *	Sideeffects:
445 *		None.
446 *
447 *	Result:
448 *		A character pointer
449 *
450 *------------------------------------------------------*
451 */
452
453char*
454Buf_PositionPtr (loc)
455     Buf_BufferPosition loc;
456{
457  BufferPosition* bPos = (BufferPosition*) loc;
458  Buffer*         iBuf = (Buffer*) bPos->buf;
459  char*           data = iBuf->type->dataProc (bPos->buf, iBuf->clientData);
460
461  return data + bPos->offset;
462}
463
464/*
465 *------------------------------------------------------*
466 *
467 *	Buf_PositionOffset --
468 *
469 *	Converts the logical location in the buffer into
470 *	an offset relative to the start of the data area
471 *	of the underlying buffer.
472 *
473 *	Sideeffects:
474 *		None.
475 *
476 *	Result:
477 *		An integer value.
478 *
479 *------------------------------------------------------*
480 */
481
482int
483Buf_PositionOffset (loc)
484     Buf_BufferPosition loc;
485{
486  BufferPosition* bPos = (BufferPosition*) loc;
487  return bPos->offset;
488}
489
490/*
491 *------------------------------------------------------*
492 *
493 *	Buf_Tell --
494 *
495 *	Creates a logical position in the buffer pointing
496 *	to the current location of the read pointer.
497 *
498 *	Sideeffects:
499 *		Allocates memory, adds a reference to
500 *		the buffer.
501 *
502 *	Result:
503 *		A buffer position.
504 *
505 *------------------------------------------------------*
506 */
507
508Buf_BufferPosition
509Buf_Tell (buf)
510     Buf_Buffer buf;
511{
512  Buffer*         iBuf = (Buffer*) buf;
513  BufferPosition* bPos = (BufferPosition*) Tcl_Alloc (sizeof (BufferPosition));
514
515  bPos->buf    = buf;
516  bPos->offset = iBuf->type->tellProc (buf, iBuf->clientData);
517
518  /*
519   * The position holds a reference to the buffer, remember that.
520   */
521
522  Buf_IncrRefcount (buf);
523
524  return (Buf_BufferPosition) bPos;
525}
526
527/*
528 *------------------------------------------------------*
529 *
530 *	Buf_FreePosition --
531 *
532 *	Deletes a logical position in a buffer.
533 *
534 *	Sideeffects:
535 *		Deallocates memory, removes a reference to
536 *		the buffer, may free the referenced buffer.
537 *
538 *	Result:
539 *		None.
540 *
541 *------------------------------------------------------*
542 */
543
544void
545Buf_FreePosition (loc)
546     Buf_BufferPosition loc;
547{
548  BufferPosition* bPos = (BufferPosition*) loc;
549
550  Buf_DecrRefcount (bPos->buf);
551  Tcl_Free ((char*) bPos);
552}
553
554/*
555 *------------------------------------------------------*
556 *
557 *	Buf_MovePosition --
558 *
559 *	Move a logical position in a buffer.
560 *
561 *	Sideeffects:
562 *		See above.
563 *
564 *	Result:
565 *		None.
566 *
567 *------------------------------------------------------*
568 */
569
570void
571Buf_MovePosition (loc, offset)
572     Buf_BufferPosition loc;
573     int                offset;
574{
575  BufferPosition* bPos = (BufferPosition*) loc;
576
577  if ((bPos->offset + offset) < 0) {
578    Tcl_Panic ("Moved buffer location out of range");
579  }
580
581  bPos->offset += offset;
582}
583
584/*
585 *------------------------------------------------------*
586 *
587 *	Buf_DupPosition --
588 *
589 *	Duplicates a logical position in a buffer.
590 *
591 *	Sideeffects:
592 *		Allocates memory, adds another reference
593 *		to the underlying buffer.
594 *
595 *	Result:
596 *		A token for the new buffer position.
597 *
598 *------------------------------------------------------*
599 */
600
601Buf_BufferPosition
602Buf_DupPosition (loc)
603     Buf_BufferPosition loc;
604{
605  BufferPosition* bPos   = (BufferPosition*) loc;
606  BufferPosition* newPos = (BufferPosition*) Tcl_Alloc (sizeof (BufferPosition));
607
608  newPos->buf    = bPos->buf;
609  newPos->offset = bPos->offset;
610
611  Buf_IncrRefcount (bPos->buf);
612
613  return (Buf_BufferPosition) newPos;
614}
615
616/*
617 *------------------------------------------------------*
618 *
619 *	Buf_PositionFromOffset --
620 *
621 *	Creates a logical position from an offset into
622 *	the data area and a buffer.
623 *
624 *	Sideeffects:
625 *		Allocates memory, adds another reference
626 *		to the buffer.
627 *
628 *	Result:
629 *		A token for the new buffer position.
630 *
631 *------------------------------------------------------*
632 */
633
634Buf_BufferPosition
635Buf_PositionFromOffset (buf, offset)
636     Buf_Buffer buf;
637     int        offset;
638{
639  BufferPosition* newPos = (BufferPosition*) Tcl_Alloc (sizeof (BufferPosition));
640
641  newPos->buf    = buf;
642  newPos->offset = offset;
643
644  Buf_IncrRefcount (buf);
645
646  return (Buf_BufferPosition) newPos;
647}
648