1%%	options
2
3copyright owner	=	Dirk Krause
4copyright year	=	2015-xxxx
5SPDX-License-Identifier:	BSD-3-Clause
6
7
8
9%%	header
10
11/**	@file	dk4bf.h	Bit fields.
12*/
13
14#ifndef	DK4CONF_H_INCLUDED
15#if	DK4_BUILDING_DKTOOLS4
16#include "dk4conf.h"
17#else
18#include <dktools-4/dk4conf.h>
19#endif
20#endif
21
22#ifndef DK4ERROR_H_INCLUDED
23#if	DK4_BUILDING_DKTOOLS4
24#include <libdk4base/dk4error.h>
25#else
26#include <dktools-4/dk4error.h>
27#endif
28#endif
29
30
31/**	Bit field structure.
32*/
33typedef struct {
34  unsigned char	*d;	/**< Data buffer. */
35  size_t	 s;	/**< Number of bits in the array. */
36} dk4_bit_field_t;
37
38#ifdef __cplusplus
39extern "C" {
40#endif
41
42/**	Open bit field.
43	@param	sz	Size of the bit field (number of bits).
44	@param	erp	Error report, may be NULL.
45	@return	Pointer to new bit field on success, NULL on error.
46
47	Error codes:
48	- DK4_E_INVALID_ARGUMENTS<br>
49	  if sz is 0,
50	- DK4_E_MEMORY_ALLOCATION_FAILED<br>
51	  if not enough memory was available.
52*/
53dk4_bit_field_t *
54
55dk4bf_open(size_t sz, dk4_er_t *erp);
56
57/**	Set one bit in a bit field.
58	@param	dptr	Bit field.
59	@param	bitno	Index of bit to modify.
60	@param	val	Bit value.
61	@param	erp	Error report, may be NULL.
62	@return	1 on success, 0 on error.
63
64	Error codes:
65	- DK4_E_INVALID_ARGUMENTS<br>
66	  if dptr is 0 or bitno is outside the bit field size.
67*/
68int
69
70dk4bf_set(dk4_bit_field_t *dptr, size_t bitno, int val, dk4_er_t *erp);
71
72/**	Retrieve one value from bit field.
73	@param	dptr	Address of result variable.
74	@param	bfptr	Bit field.
75	@param	bitno	Number of bit to obtain.
76	@param	erp	Error report, may be NULL.
77	@return	1 on success (dptr set), 0 on error (dptr unchanged).
78
79	Error codes:
80	- DK4_E_INVALID_ARGUMENTS<br>
81	  if dptr or bfptr is NULL or bitno is outside the bit field size.
82*/
83int
84
85dk4bf_get(int *dptr, dk4_bit_field_t const *bfptr, size_t bitno, dk4_er_t *erp);
86
87/**	Close bit field.
88	@param	ptr	Pointer to bit field previously opened using
89			dk4bf_open().
90*/
91void
92
93dk4bf_close(dk4_bit_field_t *ptr);
94
95#ifdef __cplusplus
96}
97#endif
98
99
100
101%%	module
102
103#include "dk4conf.h"
104
105#if	DK4_HAVE_ASSERT_H
106#ifndef	ASSERT_H_INCLUDED
107#include <assert.h>
108#define	ASSERT_H_INCLUDED 1
109#endif
110#endif
111
112#include <libdk4c/dk4bf.h>
113#include <libdk4base/dk4mem.h>
114
115
116
117$!trace-include
118
119
120
121/**	Position of single bits within a byte.
122*/
123static const unsigned char dk4bf_bits_in_byte[] = {
124  0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01
125};
126
127
128
129dk4_bit_field_t *
130
131dk4bf_open(size_t sz, dk4_er_t *erp)
132{
133  dk4_bit_field_t	*back	=	NULL;
134  size_t		 bsz;
135#if	DK4_USE_ASSERT
136  assert(0 < sz);
137#endif
138  if (0 < sz) {
139    back = dk4mem_new(dk4_bit_field_t,1,erp);
140    if (NULL != back) {
141      back->s = sz;
142      bsz = sz / 8;
143      if (0 != (sz % 8)) {
144        bsz++;
145      }
146      back->d = dk4mem_new(unsigned char,bsz,erp);
147      if (NULL == back->d) {
148        dk4bf_close(back);
149	back = NULL;
150      }
151    }
152  } else {
153    dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
154  }
155  return back;
156}
157
158
159
160int
161
162dk4bf_set(dk4_bit_field_t *dptr, size_t bitno, int val, dk4_er_t *erp)
163{
164  size_t	 bytei;			/* Byte index */
165  size_t	 biti;			/* Bit index */
166  int		 back	=	0;
167#if	DK4_USE_ASSERT
168  assert(NULL != dptr);
169#endif
170  if (NULL != dptr) {
171    if (bitno < dptr->s) {
172      bytei = bitno / 8;
173      biti  = bitno % 8;
174      if (0 != val) {
175        (dptr->d)[bytei] |= dk4bf_bits_in_byte[biti];
176      } else {
177#if VERSION_BEFORE_20210729
178        (dptr->d)[bytei] &= (~(dk4bf_bits_in_byte[biti]));
179#else
180	(dptr->d)[bytei] = (unsigned char)(
181	  ((dptr->d)[bytei]) & (~(dk4bf_bits_in_byte[biti]))
182	);
183#endif
184      }
185      back = 1;
186    } else {
187      dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
188    }
189  } else {
190    dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
191  }
192  return back;
193}
194
195
196
197int
198
199dk4bf_get(int *dptr, dk4_bit_field_t const *bfptr, size_t bitno, dk4_er_t *erp)
200{
201  size_t	 bytei;			/* Byte index */
202  size_t	 biti;			/* Bit index within byte */
203  int		 back	=	0;
204#if	DK4_USE_ASSERT
205  assert(NULL != dptr);
206  assert(NULL != bfptr);
207#endif
208  if ((NULL != dptr) && (NULL != bfptr)) {
209    if (bitno < bfptr->s) {
210      bytei = bitno / 8;
211      biti  = bitno % 8;
212      if (0x00 != (((bfptr->d)[bytei]) & (dk4bf_bits_in_byte[biti]))) {
213        *dptr = 1;
214      } else {
215        *dptr = 0;
216      }
217      back = 1;
218    } else {
219      dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
220    }
221  } else {
222    dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
223  }
224  return back;
225}
226
227
228
229void
230
231dk4bf_close(dk4_bit_field_t *ptr)
232{
233#if	DK4_USE_ASSERT
234  assert(NULL != ptr);
235#endif
236  if (NULL != ptr) {
237    dk4mem_release(ptr->d);
238    dk4mem_free(ptr);
239  }
240}
241
242