x-struct-str.c 2.5 KB

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