]> git.saurik.com Git - apple/security.git/blob - SecuritySNACCRuntime/c-lib/src/exp-buf.c
Security-54.1.3.tar.gz
[apple/security.git] / SecuritySNACCRuntime / c-lib / src / exp-buf.c
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 #if defined (USE_EXP_BUF) || defined (USE_GEN_BUF)
20 /*
21 * .../c-lib/src/exp-buf.c - buffer routines for the buffer structure
22 *
23 *
24 * --------- ----------
25 * | ExpBuf |<------>| ExpBuf |<------> ...ExpBufs
26 * | |--- | |---
27 * ---------- | ---------- |
28 * V V
29 * -------- --------
30 * | DATA | | DATA |
31 * | BLK | | BLK |
32 * -------- --------
33 *
34 *
35 * ExpBuf
36 * --------------
37 * | readError |
38 * | writeError |
39 * | dataStart |-----------
40 * | dataEnd |-------- |
41 * | curr |------ | |
42 * | next | | | |
43 * | prev | | | | data
44 * | blkStart |=====|=|==|==>--------------------------
45 * | blkEnd |--- | | | | | (each line
46 * -------------- | | | | | | reps a byte
47 * | | | |-->| - - - - - - - - - - - -| diff in addr)
48 * | | | | valid |
49 * | |-|----->| |
50 * | | | data |
51 * | | | |
52 * | | | - - - - - - - - - - - -|
53 * | |----->|(one byte after last valid data byte)
54 * | | |
55 * | --------------------------
56 * |-----------> (one byte after last byte in data blk)
57 *
58 *
59 * readError - set to non-zero to indicate attempt to read past end of
60 * of data
61 * writeError- set to non-zero to indicate write error.
62 * Set if Alloc of new buf fails
63 * dataStart - pts to first VALID data byte ie *dataStart is first byte
64 * dataEnd - pts to byte AFTER last VALID byte *dataEnd is not in the data
65 * but *(dataEnd -1) is in the data
66 * curr - used for current read ptr - points to next byte to be read
67 * so *curr is the next byte to be read.
68 * next - pts to next BUF in list, NULL for last BUF in list
69 * prev - pts to prev BUF in list, NULL for first BUF in list
70 * blkStart - pts to start of the data blk. *blkStart is first byte
71 * in the buffer's data blk.
72 * blkEnd - pts to byte AFTER last writable byte of the dataBlk.
73 * *(blkEnd-1) is the last byte in the buffer's data blk.
74 *
75 * NOTES:
76 * - dataEnd is currently always the same as blkEnd
77 * - at End Of Data (EOD) (no more data to be read)
78 * if (curr == dataEnd)
79 * - buffer has no valid data if (dataStart == dataEnd)
80 * - number of valid data bytes = (dataEnd - dataStart)
81 * - size of the data block = (blkEnd - blkStart)
82 *
83 * - the write reverse routines modify dataStart
84 * - the read routines modify the curr ptr.
85 * - there are no 'forward' write routines at the moment
86 * (if there were they would adjust dataEnd)
87 *
88 *
89 * Copyright (C) 1992 Michael Sample and the University of British Columbia
90 *
91 * This library is free software; you can redistribute it and/or
92 * modify it provided that this copyright/license information is retained
93 * in original form.
94 *
95 * If you modify this file, you must clearly indicate your changes.
96 *
97 * This source code is distributed in the hope that it will be
98 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
99 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
100 *
101 * $Header: /cvs/Darwin/src/live/Security/SecuritySNACCRuntime/c-lib/src/exp-buf.c,v 1.1.1.1 2001/05/18 23:14:08 mb Exp $
102 * $Log: exp-buf.c,v $
103 * Revision 1.1.1.1 2001/05/18 23:14:08 mb
104 * Move from private repository to open source repository
105 *
106 * Revision 1.2 2001/05/05 00:59:25 rmurphy
107 * Adding darwin license headers
108 *
109 * Revision 1.1.1.1 1999/03/16 18:06:32 aram
110 * Originals from SMIME Free Library.
111 *
112 * Revision 1.2 1995/07/27 09:05:29 rj
113 * merged type table routines and code used by its gen-bufs.
114 *
115 * changed `_' to `-' in file names.
116 *
117 * Revision 1.1 1994/08/28 09:46:05 rj
118 * first check-in. for a list of changes to the snacc-1.1 distribution please refer to the ChangeLog.
119 *
120 */
121
122 #include "asn-config.h"
123 #include "gen-buf.h"
124 #include "exp-buf.h"
125
126
127 /* default buffer data block size (used when allocating) */
128 unsigned long expBufDataBlkSizeG = 1024;
129
130
131 #if defined (DEBUG) || defined (USE_GEN_BUF) /* otherwise macros */
132
133 #ifdef USE_GEN_BUF
134
135 /*
136 * casts are used to overcome void * - ExpBuf * conflict
137 * be careful if you modify param lists etc.
138 */
139 static struct GenBuf expBufOpsG =
140 {
141 (BufGetByteFcn) ExpBufGetByte,
142 (BufGetSegFcn) ExpBufGetSeg,
143 (BufCopyFcn) ExpBufCopy,
144 (BufSkipFcn) ExpBufSkip,
145 (BufPeekByteFcn) ExpBufPeekByte,
146 (BufPeekSegFcn) ExpBufPeekSeg,
147 (BufPeekCopyFcn) ExpBufPeekCopy,
148 (BufPutByteRvsFcn) ExpBufPutByteRvs,
149 (BufPutSegRvsFcn) ExpBufPutSegRvs,
150 (BufReadErrorFcn) ExpBufReadError,
151 (BufWriteErrorFcn) ExpBufWriteError,
152 NULL,
153 NULL
154 };
155
156 #endif
157
158 /*
159 * remember: ExpBufs are used via a handle (double ptr)
160 * in the standardized buffer routines. This allows
161 * the 'current' expbuf in the list of expbuf to be the arg.
162 * The list is doubly linked so you can always find
163 * the head or tail given any expbuf in the list
164 */
165 void
166 PutExpBufInGenBuf PARAMS ((eb, gb),
167 ExpBuf *eb _AND_
168 GenBuf *gb)
169 {
170 *gb = expBufOpsG; /* structure assignemnt */
171 gb->bufInfo = &gb->spare; /* handle to expbuf */
172 gb->spare = eb;
173 } /* PutExpBufInGenBuf */
174
175 /*
176 * sets the size of the data block to attach to
177 * an ExpBuf when allocating a new one
178 */
179 void
180 ExpBufInit PARAMS ((dataBlkSize),
181 unsigned long dataBlkSize)
182 {
183 expBufDataBlkSizeG = dataBlkSize;
184 } /* InitBuffers */
185
186 /*
187 * Allocates and returns an uninitialized ExpBuf with
188 * no a data attached.
189 */
190 ExpBuf*
191 ExpBufAllocBuf()
192 {
193 return (ExpBuf*)malloc (sizeof (ExpBuf));
194 }
195
196 void
197 ExpBufFreeBuf PARAMS ((ptr),
198 ExpBuf *ptr)
199 {
200 free (ptr);
201 }
202
203 char*
204 ExpBufAllocData()
205 {
206 return (char*)malloc (expBufDataBlkSizeG);
207 }
208
209 void
210 ExpBufFreeData PARAMS ((ptr),
211 char *ptr)
212 {
213 free (ptr);
214 }
215
216 void
217 ExpBufFreeBufAndData PARAMS ((b),
218 ExpBuf *b)
219 {
220 ExpBufFreeData ((b)->blkStart);
221 ExpBufFreeBuf (b);
222 } /* ExpBufFreeBufAndData */
223
224 ExpBuf*
225 ExpBufNext PARAMS ((b),
226 ExpBuf *b)
227 {
228 return b->next;
229 }
230
231 ExpBuf*
232 ExpBufPrev PARAMS ((b),
233 ExpBuf *b)
234 {
235 return b->prev;
236 }
237
238 int
239 ExpBufReadError PARAMS ((b),
240 ExpBuf **b)
241 {
242 return (*b)->readError;
243 } /* ExpBufReadError */
244
245 int
246 ExpBufWriteError PARAMS ((b),
247 ExpBuf **b)
248 {
249 return (*b)->writeError;
250 } /* ExpBufWriteError */
251
252 /*
253 * set curr ptr used in reads to the first byte
254 * to be read
255 */
256 void
257 ExpBufResetInReadMode PARAMS ((b),
258 ExpBuf *b)
259 {
260 b->curr = b->dataStart;
261 b->readError = 0;
262 b->writeError = 1; /* catch wrong mode errors */
263 }
264
265 /*
266 * sets dataStart to end of buffer
267 * so following writes (backward)
268 * over-write any existing data associated with
269 * the buffer
270 */
271 void
272 ExpBufResetInWriteRvsMode PARAMS ((b),
273 ExpBuf *b)
274 {
275 b->dataEnd = b->dataStart = b->blkEnd;
276 b->writeError = 0;
277 b->readError = 1; /* catch wrong mode errors */
278 }
279
280
281 /*
282 * returns true if no more data can be read from
283 * the given buffer. only valid when buffer in read (fwd)
284 * mode.
285 */
286 int
287 ExpBufAtEod PARAMS ((b),
288 ExpBuf *b)
289 {
290 return b->curr == b->dataEnd;
291 }
292
293
294 /*
295 * returns true if no more reverse writes can be done
296 * to the buffer. Only valid when buffers in reverse
297 * write mode
298 */
299 int
300 ExpBufFull PARAMS ((b),
301 ExpBuf *b)
302 {
303 return (b)->dataStart == (b)->blkStart;
304 }
305
306
307 /*
308 * returns true if the given buffer has no
309 * valid data in it's data block
310 */
311 int
312 ExpBufHasNoData PARAMS ((b),
313 ExpBuf *b)
314 {
315 return b->dataStart == b->dataEnd;
316 }
317
318
319 /*
320 * returns the number of valid data bytes in the
321 * given buffer's data block
322 */
323 unsigned long
324 ExpBufDataSize PARAMS ((b),
325 ExpBuf *b)
326 {
327 return b->dataEnd - b->dataStart;
328 }
329
330 /*
331 * returns size of data block that is attached to
332 * the given buffer.
333 */
334 unsigned long
335 ExpBufDataBlkSize PARAMS ((b),
336 ExpBuf *b)
337 {
338 return b->blkEnd - b->blkStart;
339 }
340
341 /*
342 * returns a ptr the beginning of the valid data of
343 * the given buffer.
344 * returns NULL is there is no valid data.
345 */
346 char*
347 ExpBufDataPtr PARAMS ((b),
348 ExpBuf *b)
349 {
350 if (ExpBufHasNoData (b))
351 return NULL;
352 else
353 return b->dataStart;
354 }
355
356 #endif /* DEBUG || USE_EXP_BUF */
357
358
359 /*
360 * returns last ExpBuf in a list of bufs.
361 * The given buf can be any buf in the list.
362 */
363 ExpBuf*
364 ExpBufListLastBuf PARAMS ((b),
365 ExpBuf *b)
366 {
367 for (; b->next != NULL; b = b->next)
368 ;
369 return b;
370 }
371
372 /*
373 * returns first buf in a list of bufs .
374 * The given buf can be any buf in the list
375 */
376 ExpBuf*
377 ExpBufListFirstBuf PARAMS ((b),
378 ExpBuf *b)
379 {
380 for (; b->prev != NULL; b = b->prev)
381 ;
382 return b;
383 }
384
385 /*
386 * Allocates a Buf and allocates an attaches a
387 * data block of expBufDataBlkSizeG to that buffer.
388 * sets up the blk for writing in that the data start
389 * and data end point to the byte after the data blk.
390 */
391 ExpBuf*
392 ExpBufAllocBufAndData()
393 {
394 ExpBuf *retVal;
395
396 retVal = ExpBufAllocBuf();
397
398 if (retVal == NULL)
399 return NULL;
400
401 retVal->readError = 0;
402 retVal->writeError = 0;
403 retVal->blkStart = ExpBufAllocData();
404
405 if (retVal->blkStart == NULL)
406 {
407 ExpBufFreeBuf (retVal);
408 return NULL;
409 }
410
411 retVal->next = NULL;
412 retVal->prev = NULL;
413 retVal->curr = retVal->blkEnd = retVal->dataStart = retVal->dataEnd =
414 retVal->blkStart + expBufDataBlkSizeG;
415
416 return retVal;
417 } /* ExpBufAllocBufAndData */
418
419
420 /*
421 * Frees ExpBuf's and associated data blocks after
422 * after (next ptr) and including the given buffer, b.
423 */
424 void
425 ExpBufFreeBufAndDataList PARAMS ((b),
426 ExpBuf *b)
427 {
428 ExpBuf *tmp;
429
430 for (; b != NULL;)
431 {
432 tmp = b->next;
433 ExpBufFreeBufAndData (b);
434 b = tmp;
435 }
436 } /* ExpBufFreeBufAndDataList */
437
438
439 /*
440 * puts the given data in a buffer and sets it up for reading
441 * the data. This results in a "full" buffer with a data
442 * blk size of given data's len
443 */
444 void
445 ExpBufInstallDataInBuf PARAMS ((buf, data, len),
446 ExpBuf *buf _AND_
447 char *data _AND_
448 unsigned long int len)
449 {
450 buf->readError = 0;
451 buf->writeError = 0;
452 buf->blkStart = buf->dataStart = buf->curr = data;
453 buf->next = NULL;
454 buf->prev = NULL;
455 buf->blkEnd = buf->dataEnd = data + len;
456 } /* ExpBufInstallDataInBuf */
457
458
459
460 /* Buf reading and writing routines follow */
461
462 /* READ
463 * returns the next byte to be read without
464 * advancing the pointer. No check for end of
465 * data - this is lame
466 */
467 unsigned char
468 ExpBufPeekByte PARAMS ((b),
469 ExpBuf **b)
470 {
471 if ((*b)->curr == (*b)->dataEnd)
472 (*b)->readError = 1;
473 return *(*b)->curr;
474 } /* ExpBufPeek */
475
476 #if TTBL
477
478 /* READ
479 * returns a ptr to the next "len" bytes (contiguous).
480 * if "len" is greater than the available contiguous bytes
481 * len is set the the number of contig. bytes the returned
482 * ptr references. The next call to ExpBufGetSeg or other ExpBufGet
483 * routines will return a ptrsto the SAME bytes (ie curr is NOT advanced).
484 *
485 * Does not change the buffer
486 *
487 * if the value returned in the len param is zero or the
488 * returned char * is NULL then at end of data.
489 *
490 */
491 char*
492 ExpBufPeekSeg PARAMS ((b, len),
493 ExpBuf **b _AND_
494 unsigned long int *len)
495 {
496 int bytesLeft;
497
498 if (ExpBufAtEod (*b))
499 {
500 *len = 0;
501 return NULL;
502 }
503
504 /* check for "buffer fault" and adjust "peeked" len */
505 if (((*b)->dataEnd - (*b)->curr) <= *len)
506 *len = bytesLeft;
507
508 return (*b)->curr;
509
510 } /* ExpBufPeekSeg */
511
512
513 /* READ
514 * copy the next len chars in the buffer to the given
515 * dst char string. The curr ptr in the buffer is
516 * NOT advanced so the next read will get the same bytes.
517 */
518 int
519 ExpBufPeekCopy PARAMS ((dst, b, len),
520 char *dst _AND_
521 ExpBuf **b _AND_
522 unsigned long int len)
523 {
524 unsigned long int gotLen;
525 int totalGotLen = 0;
526 char *srcPtr;
527 ExpBuf *origBuf;
528
529 origBuf = *b;
530
531 gotLen = len;
532 while (1) /* optimize std path - eg only one ExpBufGetPeekSeg needed */
533 {
534 srcPtr = ExpBufPeekSeg (b, &gotLen);
535 memcpy (dst + totalGotLen, srcPtr, gotLen);
536
537 totalGotLen += gotLen;
538
539 if ((totalGotLen >= len) || ((*b)->next == NULL))
540 {
541 *b = origBuf;
542 return totalGotLen;
543 }
544
545 if (gotLen == 0) /* eod */
546 {
547 (*b)->readError = 1;
548 *b = origBuf;
549 return totalGotLen;
550 }
551
552 *b = (*b)->next;
553 /* get next buffer with valid data */
554 while (((*b)->next != NULL) && ExpBufHasNoData (*b))
555 *b = (*b)->next;
556
557 /* reset current pointer to beggining of data if nec */
558 (*b)->curr = (*b)->dataStart;
559
560 gotLen = len - totalGotLen;
561 }
562
563 /* not reached */
564
565 } /* ExpBufPeekCopy */
566
567 #endif /* TTBL */
568
569 /* READ
570 * copy the next len chars in the buffer to the given
571 * dst char string. The curr ptr in the buffer is advanced
572 * appropriately
573 */
574 int
575 ExpBufCopy PARAMS ((dst, b, len),
576 char *dst _AND_
577 ExpBuf **b _AND_
578 unsigned long int len)
579 {
580 unsigned long int gotLen;
581 int totalGotLen = 0;
582 char *srcPtr;
583
584 gotLen = len;
585 while (1) /* optimize std path - eg only one ExpBufGetSeg needed */
586 {
587 srcPtr = ExpBufGetSeg (b, &gotLen);
588 memcpy (dst + totalGotLen, srcPtr, gotLen);
589
590 totalGotLen += gotLen;
591
592 if (totalGotLen >= len)
593 return totalGotLen;
594
595 if (gotLen == 0) /* eod */
596 {
597 (*b)->readError = 1;
598 return totalGotLen;
599 }
600
601 gotLen = len - totalGotLen;
602 }
603
604 /* not reached */
605
606 } /* ExpBufCopy */
607
608
609 /*
610 * advance the curr ptr in the given buffer over the next
611 * len bytes
612 */
613 void
614 ExpBufSkip PARAMS ((b, len),
615 ExpBuf **b _AND_
616 unsigned long int len)
617 {
618 unsigned long int lenRemaining;
619
620 lenRemaining = len;
621 while ((len > 0) && ExpBufGetSeg (b, &lenRemaining))
622 {
623 len -= lenRemaining;
624
625 if (lenRemaining == 0)
626 {
627 (*b)->readError = 1;
628 return;
629 }
630
631 lenRemaining = len;
632 }
633 } /* ExpBufSkip */
634
635
636 /* READ
637 * returns a ptr to the next "len" bytes (contiguous).
638 * if "len" is greater than the available contiguous bytes
639 * len is set the the number of contig. bytes the returned
640 * ptr references. Subsequent call to ExpBufGetSeg or other ExpBufGet
641 * routines will return ptrs to the following bytes (ie curr is advanced).
642 * Changes *b to pt to the next buffer and sets curr for the
643 * that buffer to dataStart if the current one has been totally read.
644 *
645 * if the value returned in the len param is zero or the
646 * returned char * is NULL then at end of data (eod)
647 *
648 */
649
650 char*
651 ExpBufGetSeg PARAMS ((b, len),
652 ExpBuf **b _AND_
653 unsigned long int *len)
654 {
655 int bytesLeft;
656 char *retVal;
657
658 if (ExpBufAtEod (*b))
659 {
660 *len = 0;
661 return NULL;
662 }
663
664 bytesLeft = (*b)->dataEnd - (*b)->curr;
665 retVal = (*b)->curr;
666
667 /* check for "buffer fault" */
668 if (bytesLeft <= *len)
669 {
670 *len = bytesLeft;
671
672 if ((*b)->next != NULL)
673 {
674 *b = (*b)->next;
675
676 /* get next buffer with valid data */
677 while (((*b)->next != NULL) && ExpBufHasNoData (*b))
678 *b = (*b)->next;
679
680 /* reset current pointer to beggining of data if nec */
681 (*b)->curr = (*b)->dataStart;
682 }
683 else
684 (*b)->curr += *len;
685 }
686 else
687 (*b)->curr += *len;
688
689 return retVal;
690
691 } /* ExpBufGetSeg */
692
693
694
695 /*
696 * WRITE
697 * Copies len bytes from the data pointer into the given buffer
698 *
699 * FILLS EXP_BUFFERS BACKWARDS! from the end of the data to the beginning
700 * LINKS BUFFERS BACKWARDS! if a buf is full it allocs another an
701 * puts it at the HEAD of the buffer list
702 *
703 * changes *b to pt to the new "prev" buffer if the current one
704 * has been totally filled
705 * Rvs is for REVERSE!
706 *
707 * modifies the dataStart pointer to reflect the new data
708 */
709
710 void
711 ExpBufPutSegRvs PARAMS ((b, data, len),
712 ExpBuf **b _AND_
713 char *data _AND_
714 unsigned long int len)
715 {
716 int bytesLeft;
717 ExpBuf *buf;
718 char *dataPtr;
719
720 buf = *b;
721
722 if (buf->writeError)
723 return;
724
725 bytesLeft = buf->dataStart - buf->blkStart;
726 dataPtr = data + len; /* pts to end of data to be written */
727
728 /* optimize fast path */
729
730 do
731 {
732 if (bytesLeft > len) /* enough room in this buffer for write */
733 {
734 buf->dataStart -= len;
735 memcpy (buf->dataStart, data, len);
736 break; /* this is the normal exit from this loop */
737 }
738 else
739 {
740 /*
741 * going to fill this buffer completely,
742 * so alloc other one (only if one is not
743 * already linked in)
744 */
745 dataPtr = dataPtr - bytesLeft;
746 buf->dataStart = buf->blkStart;
747 memcpy (buf->dataStart, dataPtr, bytesLeft);
748
749 len -= bytesLeft;
750
751 if (buf->prev == NULL)
752 {
753 /* alloc & insert new buf at head of buffer list */
754 buf = ExpBufAllocBufAndData();
755
756 if (buf == NULL)
757 {
758 (*b)->writeError = 1;
759 return;
760 }
761
762 buf->next = *b;
763 (*b)->prev = buf;
764 }
765 else
766 buf = buf->prev;
767
768 *b = buf; /* update head of list */
769
770 bytesLeft = buf->dataStart - buf->blkStart;
771 }
772 }
773 while (1);
774
775 /* not reached */
776
777 } /* ExpBufPutSegRvs */
778
779
780
781 /*
782 * returns the next byte and advances the curr ptr by one.
783 * sets the readError flag if there is no byte to read
784 * (ie at end of data)
785 */
786 unsigned char
787 ExpBufGetByte PARAMS ((b),
788 ExpBuf **b)
789 {
790 unsigned char retVal;
791
792
793 if (ExpBufAtEod (*b))
794 {
795 (*b)->readError = 1;
796 return (unsigned char)0;
797 }
798
799 retVal = *(*b)->curr++;
800
801 /* "buffer fault" - if end of this buf, go on to next, if any */
802 if (ExpBufAtEod (*b) && ((*b)->next != NULL))
803 {
804 *b = (*b)->next;
805
806 /* get next buffer with valid data */
807 while (((*b)->next != NULL) && ExpBufHasNoData (*b))
808 *b = (*b)->next;
809
810 /* reset current pointer to beggining of data if nec */
811 (*b)->curr = (*b)->dataStart;
812 }
813
814 return retVal;
815
816 } /* ExpBufGetByte */
817
818
819 /* WRITE
820 * Puts a single octet into the buffer
821 * writes in reverse.
822 * allocates new buffers as nec - may change
823 * (*b) to new buffer since writing backwards
824 */
825 void
826 ExpBufPutByteRvs PARAMS ((b, byte),
827 ExpBuf **b _AND_
828 unsigned char byte)
829 {
830 ExpBuf *new;
831
832 if ((*b)->writeError)
833 return;
834
835 *(--(*b)->dataStart) = byte;
836
837 /*
838 * check if buffer is full and alloc new one if nec
839 * and insert it before this one since writing backwards
840 */
841 if (ExpBufFull (*b))
842 {
843 if ((*b)->prev == NULL)
844 {
845 /*
846 * no prev buf so alloc & insert
847 * new buf as head of buffer list
848 */
849 new = ExpBufAllocBufAndData();
850 if (new == NULL)
851 {
852 (*b)->writeError = 1;
853 return;
854 }
855
856 new->next = *b;
857 (*b)->prev = new;
858 *b = new;
859 }
860 else
861 {
862 (*b) = (*b)->prev;
863 ExpBufResetInWriteRvsMode (*b);
864 }
865
866 }
867 } /* ExpBufPutByteRvs */
868
869
870 void
871 ExpBufCopyToFile PARAMS ((b, f),
872 ExpBuf *b _AND_
873 FILE *f)
874 {
875 long int writeLen;
876
877 b = ExpBufListFirstBuf (b);
878
879 for ( ; b != NULL; b = ExpBufNext (b))
880 {
881 writeLen = fwrite (ExpBufDataPtr (b), sizeof (char), ExpBufDataSize (b), f);
882
883 if (writeLen != ExpBufDataSize (b))
884 fprintf (stderr, "ExpBufCopyToFile: error during writing\n");
885 }
886 }
887
888 #else /* !USE_EXP_BUF */
889
890 #ifdef __alpha
891 static void dummy()
892 {
893 }
894 #endif
895
896 #endif /* USE_EXP_BUF */