Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / support / x-struct-str.c
1 /*
2  * A helper routine to copy the strings between differing structures.
3  */
4
5 #include <stdlib.h>
6 #include <string.h>
7 #include <limits.h>
8
9 #include "mph.h"
10
11 #define MAX_OFFSETS 10
12
13 #define OFFSET_SHIFT 1
14
15 #define lstr_at(p, n) (*(char**)(((char*)(p))+(n >> OFFSET_SHIFT)))
16
17 #define str_at(p, n) (                                          \
18                 (((n) & MPH_STRING_OFFSET_MASK) == MPH_STRING_OFFSET_ARRAY) \
19                 ? (char*)(p) + (n >> OFFSET_SHIFT)                          \
20                 : lstr_at(p, n)                                             \
21 )
22
23 char*
24 _mph_copy_structure_strings (
25         void *to,         const mph_string_offset_t *to_offsets, 
26         const void *from, const mph_string_offset_t *from_offsets, 
27         size_t num_strings)
28 {
29         int i;
30         size_t buflen;
31         int len[MAX_OFFSETS];
32         char *buf, *cur = NULL;
33
34         g_assert (num_strings < MAX_OFFSETS);
35
36         for (i = 0; i < num_strings; ++i) {
37                 lstr_at (to, to_offsets[i]) = NULL;
38         }
39
40         buflen = num_strings;
41         for (i = 0; i < num_strings; ++i) {
42                 const char* s = str_at(from, from_offsets[i]);
43                 len [i] = s ? strlen (s) : 0;
44                 if (len[i] < INT_MAX - buflen)
45                         buflen += len[i];
46                 else
47                         len[i] = -1;
48         }
49
50         cur = buf = malloc (buflen);
51         if (buf == NULL) {
52                 return NULL;
53         }
54
55         for (i = 0; i < num_strings; ++i) {
56                 if (len[i] > 0) {
57                         lstr_at (to, to_offsets[i]) = 
58                                 strcpy (cur, str_at (from, from_offsets[i]));
59                         cur += (len[i] +1);
60                 }
61         }
62
63         return buf;
64 }
65
66 #ifdef TEST
67
68 /*
69  * To run the tests:
70  * $ gcc -DTEST -I.. `pkg-config --cflags --libs glib-2.0` x-struct-str.c
71  * $ ./a.out
72  */
73
74 #include <stdio.h>
75
76 struct foo {
77         char *a;
78         int   b;
79         char *c;
80         char d[10];
81 };
82
83 struct bar {
84         int    b;
85         char  *a;
86         double d;
87         char  *c;
88         char  *e;
89 };
90
91 int
92 main ()
93 {
94         /* test copying foo to bar */
95         struct foo f = {"hello", 42, "world", "!!"};
96         struct bar b;
97         mph_string_offset_t foo_offsets[] = {
98                 MPH_STRING_OFFSET(struct foo, a, MPH_STRING_OFFSET_PTR),
99                 MPH_STRING_OFFSET(struct foo, c, MPH_STRING_OFFSET_PTR),
100                 MPH_STRING_OFFSET(struct foo, d, MPH_STRING_OFFSET_ARRAY)
101         };
102         mph_string_offset_t bar_offsets[] = {
103                 MPH_STRING_OFFSET(struct bar, a, MPH_STRING_OFFSET_PTR), 
104                 MPH_STRING_OFFSET(struct bar, c, MPH_STRING_OFFSET_PTR), 
105                 MPH_STRING_OFFSET(struct bar, e, MPH_STRING_OFFSET_PTR)
106         };
107         char *buf;
108
109         buf = _mph_copy_structure_strings (&b, bar_offsets, 
110                         &f, foo_offsets, 3);
111         printf ("b.a=%s\n", b.a);
112         printf ("b.c=%s\n", b.c);
113         printf ("b.e=%s\n", b.e);
114
115         f.c = NULL;
116         buf = _mph_copy_structure_strings (&b, bar_offsets, 
117                         &f, foo_offsets, 3);
118         printf ("b.a=%s\n", b.a);
119         printf ("b.c=%s\n", b.c);
120         printf ("b.e=%s\n", b.e);
121
122         return 0;
123 }
124 #endif
125