1 /*
2
3 Package: dyncall
4 Library: dyncall
5 File: dyncall/dyncall_struct.c
6 Description: C interface to compute struct size
7 License:
8
9 Copyright (c) 2010-2015 Olivier Chafik <olivier.chafik@centraliens.net>
10
11 Permission to use, copy, modify, and distribute this software for any
12 purpose with or without fee is hereby granted, provided that the above
13 copyright notice and this permission notice appear in all copies.
14
15 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23 */
24
25
26
27 #include "dyncall.h"
28 #include "dyncall_signature.h"
29 #include "dyncall_struct.h"
30 #include "dyncall_alloc.h"
31 #include <stdio.h>
32 #include <assert.h>
33
34
dcNewStruct(DCsize fieldCount,DCint alignment)35 DCstruct* dcNewStruct(DCsize fieldCount, DCint alignment)
36 {
37 DCstruct* s = (DCstruct*)dcAllocMem(sizeof(DCstruct));
38 s->pCurrentStruct = s;
39 s->pLastStruct = NULL;
40 s->nextField = 0;
41 s->fieldCount = fieldCount;
42 s->alignment = alignment;
43 s->size = 0;
44 s->pFields = (DCfield*)dcAllocMem(fieldCount * sizeof(DCfield));
45 return s;
46 }
47
48
dcStructField(DCstruct * s,DCint type,DCint alignment,DCsize arrayLength)49 void dcStructField(DCstruct* s, DCint type, DCint alignment, DCsize arrayLength)
50 {
51 DCfield *f;
52 if (type == DC_SIGCHAR_STRING) {
53 assert(!"Use dcSubStruct instead !!!");
54 return;
55 }
56 assert(s && s->pCurrentStruct);
57 assert(s->pCurrentStruct->nextField < (DCint)s->pCurrentStruct->fieldCount);
58 f = s->pCurrentStruct->pFields + (s->pCurrentStruct->nextField++);
59 f->type = type;
60 f->alignment = alignment;
61 f->arrayLength = arrayLength;
62 f->pSubStruct = NULL;
63 switch (type) {
64 case DC_SIGCHAR_BOOL: f->size = sizeof(DCbool); break;
65 case DC_SIGCHAR_CHAR:
66 case DC_SIGCHAR_UCHAR: f->size = sizeof(DCchar); break;
67 case DC_SIGCHAR_SHORT:
68 case DC_SIGCHAR_USHORT: f->size = sizeof(DCshort); break;
69 case DC_SIGCHAR_INT:
70 case DC_SIGCHAR_UINT: f->size = sizeof(DCint); break;
71 case DC_SIGCHAR_LONG:
72 case DC_SIGCHAR_ULONG: f->size = sizeof(DClong); break;
73 case DC_SIGCHAR_LONGLONG:
74 case DC_SIGCHAR_ULONGLONG: f->size = sizeof(DClonglong); break;
75 case DC_SIGCHAR_FLOAT: f->size = sizeof(DCfloat); break;
76 case DC_SIGCHAR_DOUBLE: f->size = sizeof(DCdouble); break;
77 case DC_SIGCHAR_POINTER:
78 case DC_SIGCHAR_STRING: f->size = sizeof(DCpointer); break;
79 default: assert(0);
80 }
81 }
82
83
dcSubStruct(DCstruct * s,DCsize fieldCount,DCint alignment,DCsize arrayLength)84 void dcSubStruct(DCstruct* s, DCsize fieldCount, DCint alignment, DCsize arrayLength)
85 {
86 DCfield *f = s->pCurrentStruct->pFields + (s->pCurrentStruct->nextField++);
87 f->type = DC_SIGCHAR_STRUCT;
88 f->arrayLength = arrayLength;
89 f->alignment = alignment;
90 f->pSubStruct = dcNewStruct(fieldCount, alignment);
91 f->pSubStruct->pLastStruct = s->pCurrentStruct;
92 s->pCurrentStruct = f->pSubStruct;
93 }
94
95
dcAlign(DCsize * size,DCsize alignment)96 static void dcAlign(DCsize *size, DCsize alignment)
97 {
98 DCsize mod = (*size) % alignment;
99 if (mod) {
100 DCsize rest = alignment - mod;
101 (*size) += rest;
102 }
103 }
104
105
dcComputeStructSize(DCstruct * s)106 static void dcComputeStructSize(DCstruct* s)
107 {
108 DCsize i;
109 assert(s);
110
111 /* compute field sizes and alignments, recurse if needed */
112 for (i = 0; i < s->fieldCount; i++) {
113 DCfield *f = s->pFields + i;
114 DCsize fieldAlignment;
115 if (f->type == DC_SIGCHAR_STRUCT) {
116 dcComputeStructSize(f->pSubStruct);
117 f->size = f->pSubStruct->size;
118 fieldAlignment = f->pSubStruct->alignment;
119 } else
120 fieldAlignment = f->size;
121
122 if (!f->alignment)
123 f->alignment = fieldAlignment;
124
125 /* if field alignment > struct alignment, choose former */
126 if (f->alignment > s->alignment)
127 s->alignment = f->alignment;
128
129 /* if array, it's x times the size */
130 f->size *= f->arrayLength;
131
132 /*printf("FIELD %d, size = %d, alignment = %d\n", (int)i, (int)f->size, (int)f->alignment);@@@*/
133 }
134
135 /* compute overall struct size */
136 for (i = 0; i < s->fieldCount; i++) {
137 DCfield *f = s->pFields + i;
138 dcAlign(&s->size, f->alignment);
139 s->size += f->size;
140 }
141 dcAlign(&s->size, s->alignment);
142
143 /*printf("STRUCT size = %d, alignment = %d\n", (int)s->size, (int)s->alignment);@@@*/
144 }
145
146
dcCloseStruct(DCstruct * s)147 void dcCloseStruct(DCstruct* s)
148 {
149 assert(s);
150 assert(s->pCurrentStruct);
151 assert(s->pCurrentStruct->nextField == s->pCurrentStruct->fieldCount);
152 if (!s->pCurrentStruct->pLastStruct) {
153 dcComputeStructSize(s->pCurrentStruct);
154 }
155 s->pCurrentStruct = s->pCurrentStruct->pLastStruct;
156 }
157
158
dcFreeStruct(DCstruct * s)159 void dcFreeStruct(DCstruct* s)
160 {
161 DCsize i;
162 assert(s);
163 for (i = 0; i < s->fieldCount; i++) {
164 DCfield *f = s->pFields + i;
165 if (f->type == DC_SIGCHAR_STRUCT)
166 dcFreeStruct(f->pSubStruct);
167 }
168 free(s->pFields);
169 free(s);
170 }
171
172
dcStructSize(DCstruct * s)173 DCsize dcStructSize(DCstruct* s)
174 {
175 assert(!s->pCurrentStruct && "Struct was not closed");
176 return s->size;
177 }
178
dcStructAlignment(DCstruct * s)179 DCsize dcStructAlignment(DCstruct* s)
180 {
181 assert(!s->pCurrentStruct && "Struct was not closed");
182 return s->alignment;
183 }
184
185
dcArgStructUnroll(DCCallVM * vm,DCstruct * s,DCpointer value)186 void dcArgStructUnroll(DCCallVM* vm, DCstruct* s, DCpointer value)
187 {
188 DCsize i;
189 /*printf("UNROLLING STRUCT !\n");@@@*/
190 assert(s && value);
191 for (i = 0; i < s->fieldCount; i++) {
192 DCfield *f = s->pFields + i;
193 DCpointer p = (char*)value + f->offset;
194 switch(f->type) {
195 case DC_SIGCHAR_STRUCT:
196 dcArgStruct(vm, f->pSubStruct, p);
197 break;
198 case DC_SIGCHAR_BOOL:
199 dcArgBool (vm, *(DCbool*)p);
200 break;
201 case DC_SIGCHAR_CHAR:
202 case DC_SIGCHAR_UCHAR:
203 dcArgChar (vm, *(DCchar*)p);
204 break;
205 case DC_SIGCHAR_SHORT:
206 case DC_SIGCHAR_USHORT:
207 dcArgShort (vm, *(DCshort*)p);
208 break;
209 case DC_SIGCHAR_INT:
210 case DC_SIGCHAR_UINT:
211 dcArgInt (vm, *(DCint*)p);
212 break;
213 case DC_SIGCHAR_LONG:
214 case DC_SIGCHAR_ULONG:
215 dcArgLong (vm, *(DCulong*)p);
216 break;
217 case DC_SIGCHAR_LONGLONG:
218 case DC_SIGCHAR_ULONGLONG:
219 dcArgLongLong (vm, *(DCulonglong*)p);
220 break;
221 case DC_SIGCHAR_FLOAT:
222 dcArgFloat (vm, *(DCfloat*)p);
223 break;
224 case DC_SIGCHAR_DOUBLE:
225 dcArgDouble (vm, *(DCdouble*)p);
226 break;
227 case DC_SIGCHAR_POINTER:
228 case DC_SIGCHAR_STRING:
229 dcArgPointer (vm, *(DCpointer**)p);
230 break;
231 default:
232 assert(0);
233 }
234 }
235 }
236
237
readInt(const char ** ptr)238 static DCint readInt(const char** ptr)
239 {
240 return strtol(*ptr, (char**)ptr, 10);/*@@@ enough*/
241 }
242
243
dcDefineStruct(const char * signature)244 DCstruct* dcDefineStruct(const char* signature)
245 {
246 DCstruct* s;
247 const char* ptr = signature;
248 DCint fieldCount = readInt(&ptr);
249 s = dcNewStruct(fieldCount, DEFAULT_ALIGNMENT);
250
251 while (*ptr) {
252 char type = *(ptr++);
253 if (type == DC_SIGCHAR_STRUCT) {
254 /*dcSubStruct( @@@*/
255 } else {
256 dcStructField(s, type, DEFAULT_ALIGNMENT, readInt(&ptr));
257 }
258 }
259 dcCloseStruct(s);
260 return s;
261 }
262
263