chiark / gitweb /
changelog: start 1.3.3
[chiark-tcl.git] / hbytes / hbytes.c
1 /*
2  * hbytes - hex-stringrep efficient byteblocks for Tcl
3  * Copyright 2006-2012 Ian Jackson
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this library; if not, see <http://www.gnu.org/licenses/>.
17  */
18
19
20 #include "hbytes.h"
21
22 #define COMPLEX(hb) ((HBytes_ComplexValue*)hb->begin_complex)
23 #define SIMPLE_LEN(hb) ((Byte*)(hb)->end_0 - (Byte*)(hb)->begin_complex)
24
25 /* enquirers */
26
27 int cht_hb_len(const HBytes_Value *hb) {
28   if (HBYTES_ISEMPTY(hb)) return 0;
29   else if (HBYTES_ISCOMPLEX(hb)) return COMPLEX(hb)->len;
30   else return SIMPLE_LEN(hb);
31 }
32
33 Byte *cht_hb_data(const HBytes_Value *hb) {
34   if (HBYTES_ISEMPTY(hb)) return 0;
35   else if (HBYTES_ISCOMPLEX(hb)) return COMPLEX(hb)->dstart;
36   else return hb->begin_complex;
37 }
38
39 int cht_hb_issentinel(const HBytes_Value *hb) {
40   return HBYTES_ISSENTINEL(hb);
41 }
42
43 /* constructors */
44
45 void cht_hb_empty(HBytes_Value *returns) {
46   returns->begin_complex= returns->end_0= 0;
47 }
48
49 void cht_hb_sentinel(HBytes_Value *returns) {
50   returns->begin_complex= 0;
51   returns->end_0= (void*)&cht_hbytes_type;
52 }
53
54 Byte *cht_hb_arrayspace(HBytes_Value *returns, int l) {
55   if (!l) { cht_hb_empty(returns); return 0; }
56   returns->begin_complex= TALLOC(l);
57   returns->end_0= returns->begin_complex + l;
58   return returns->begin_complex;
59 }
60   
61 void cht_hb_array(HBytes_Value *returns, const Byte *array, int l) {
62   memcpy(cht_hb_arrayspace(returns,l), array, l);
63 }
64
65 /* destructor */
66
67 void cht_hb_free(const HBytes_Value *frees) {
68   if (HBYTES_ISCOMPLEX(frees)) {
69     HBytes_ComplexValue *cx= COMPLEX(frees);
70     TFREE(cx->dstart - cx->prespace);
71   }
72   TFREE(frees->begin_complex);
73 }
74
75 /* mutators */
76
77 static HBytes_ComplexValue *complex(HBytes_Value *hb) {
78   HBytes_ComplexValue *cx;
79
80   if (HBYTES_ISCOMPLEX(hb)) return hb->begin_complex;
81
82   cx= TALLOC(sizeof(*cx));
83   cx->dstart= hb->begin_complex;
84   cx->len= cx->avail= SIMPLE_LEN(hb);
85   cx->prespace= 0;
86
87   hb->begin_complex= cx;
88   hb->end_0= 0;
89
90   return cx;
91 }
92
93 Byte *cht_hb_prepend(HBytes_Value *hb, int el) {
94   HBytes_ComplexValue *cx;
95   int new_prespace;
96   Byte *old_block, *new_block, *new_dstart;
97
98   cx= complex(hb);
99
100   assert(el < INT_MAX/4 && cx->len < INT_MAX/2);
101   
102   if (cx->prespace < el) {
103     new_prespace= el*2 + cx->len;
104     old_block= cx->dstart - cx->prespace;
105     new_block= Tcl_Realloc(old_block, new_prespace + cx->avail);
106     new_dstart= new_block + new_prespace;
107     memmove(new_dstart, new_block + cx->prespace, cx->len);
108     cx->prespace= new_prespace;
109     cx->dstart= new_dstart;
110   }
111   cx->dstart -= el;
112   cx->prespace -= el;
113   cx->len += el;
114   cx->avail += el;
115   return cx->dstart;
116 }
117
118 Byte *cht_hb_append(HBytes_Value *hb, int el) {
119   HBytes_ComplexValue *cx;
120   int new_len, new_avail;
121   Byte *newpart, *new_block, *old_block;
122
123   cx= complex(hb);
124   assert(el < INT_MAX/4 && cx->len < INT_MAX/4);
125
126   new_len= cx->len + el;
127   if (new_len > cx->avail) {
128     new_avail= new_len*2;
129     old_block= cx->dstart - cx->prespace;
130     new_block= Tcl_Realloc(old_block, cx->prespace + new_avail);
131     cx->dstart= new_block + cx->prespace;
132     cx->avail= new_avail;
133   }
134   newpart= cx->dstart + cx->len;
135   cx->len= new_len;
136   return newpart;
137 }
138
139 static HBytes_ComplexValue*
140 prechop(HBytes_Value *hb, int cl, const Byte **rv) {
141   HBytes_ComplexValue *cx;
142
143   if (cl<0) { *rv=0; return 0; }
144   if (cl==0) { *rv= (const void*)&cht_hbytes_type; return 0; }
145   
146   cx= complex(hb);
147   if (cl > cx->len) { *rv=0; return 0; }
148   return cx;
149 }
150
151 const Byte *cht_hb_unprepend(HBytes_Value *hb, int pl) {
152   const Byte *chopped;
153   HBytes_ComplexValue *cx= prechop(hb,pl,&chopped);
154   if (!cx) return chopped;
155
156   chopped= cx->dstart;
157   cx->dstart += pl;
158   cx->prespace += pl;
159   cx->len -= pl;
160   cx->avail -= pl;
161   return chopped;
162 }
163
164 const Byte *cht_hb_unappend(HBytes_Value *hb, int sl) {
165   const Byte *chopped;
166   HBytes_ComplexValue *cx= prechop(hb,sl,&chopped);
167   if (!cx) return chopped;
168
169   cx->len -= sl;
170   return cx->dstart + cx->len;
171 }
172
173 void memxor(Byte *dest, const Byte *src, int l) {
174   while (l--) *dest++ ^= *src++;
175 }