GnuCash  5.6-150-g038405b370+
gnc-kvp-guile.cpp
1 #include <guid.hpp>
2 #include <kvp-frame.hpp>
3 #include <libguile.h>
4 #include <numeric>
5 #include <cstdint>
6 
7 #include <config.h>
8 
9 #include <qof.h>
10 #include "swig-runtime.h"
11 #include "guile-mappings.h"
12 #include "gnc-engine-guile.h"
13 #include "gnc-guile-utils.h"
14 #include "gnc-kvp-guile.h"
15 
16 /* NOTE: There are some problems with this approach. Currently,
17  * guids are stored simply as strings in scheme, so some
18  * strings could be mistaken for guids, although that is
19  * unlikely. The general problem is distinguishing kvp
20  * types based only on the scheme type.
21  */
22 
23 static bool scm_is_list_of_string_pairs (SCM val)
24 {
25  for (; !scm_is_null (val); val = scm_cdr (val))
26  {
27  if (!(scm_is_pair (val) && scm_is_pair (scm_car (val)) &&
28  scm_is_string (scm_caar (val))))
29  return false;
30  }
31  return true;
32 }
33 
34 KvpValue *
35 gnc_scm_to_kvp_value_ptr(SCM val)
36 {
37  if (scm_is_rational(val))
38  {
39  if (scm_is_exact(val) &&
40  (scm_is_signed_integer(val, INT64_MIN, INT64_MAX) ||
41  scm_is_unsigned_integer(val, INT64_MIN, INT64_MAX)))
42  {
43  return new KvpValue{scm_to_int64(val)};
44  }
45  else if (scm_is_exact(val) &&
46  (scm_is_signed_integer(scm_numerator(val),
47  INT64_MIN, INT64_MAX) ||
48  scm_is_unsigned_integer(scm_numerator(val),
49  INT64_MIN, INT64_MAX)) &&
50  (scm_is_signed_integer(scm_denominator(val),
51  INT64_MIN, INT64_MAX) ||
52  (scm_is_unsigned_integer(scm_denominator(val),
53  INT64_MIN, INT64_MAX))))
54  {
55  return new KvpValue{gnc_scm_to_numeric(val)};
56  }
57  else
58  {
59  return new KvpValue{scm_to_double(val)};
60  }
61  }
62  else if (gnc_guid_p(val))
63  {
64  auto guid = gnc_scm2guid(val);
65  auto tmpguid = guid_copy(&guid);
66  return new KvpValue{tmpguid};
67  }
68  else if (scm_is_string(val))
69  {
70  return new KvpValue{gnc_scm_to_utf8_string(val)};
71  }
72  else if (!scm_is_null (val) && scm_is_list_of_string_pairs (val))
73  {
74  auto frame = new KvpFrame;
75  for (; !scm_is_null (val); val = scm_cdr (val))
76  {
77  auto key_str = scm_to_utf8_stringn (scm_caar (val), nullptr);
78  auto val_scm = scm_cdar (val);
79  auto prev = frame->set ({key_str}, gnc_scm_to_kvp_value_ptr (val_scm));
80  g_free (key_str);
81  // there is a pre-existing key-value
82  if (prev)
83  delete prev;
84  }
85  return new KvpValue (frame);
86  }
87  else if (!scm_is_null (val) && scm_is_list (val))
88  {
89  GList *kvplist = nullptr;
90  for (; !scm_is_null (val); val = scm_cdr (val))
91  {
92  auto elt = gnc_scm_to_kvp_value_ptr (scm_car (val));
93  kvplist = g_list_prepend (kvplist, elt);
94  }
95  return new KvpValue (g_list_reverse (kvplist));
96  }
97  return NULL;
98 }
99 
100 SCM
101 gnc_kvp_value_ptr_to_scm(KvpValue* val)
102 {
103  if (val == nullptr) return SCM_BOOL_F;
104 
105  switch (val->get_type())
106  {
107  case KvpValue::Type::INT64:
108  return scm_from_int64(val->get<int64_t>());
109  break;
110  case KvpValue::Type::DOUBLE:
111  return scm_from_double (val->get<double>());
112  break;
113  case KvpValue::Type::NUMERIC:
114  return gnc_numeric_to_scm(val->get<gnc_numeric>());
115  break;
116  case KvpValue::Type::STRING:
117  {
118  auto string = val->get<const char*>();
119  return string ? scm_from_utf8_string(string) : SCM_BOOL_F;
120  break;
121  }
122  case KvpValue::Type::GUID:
123  {
124  auto tempguid = val->get<GncGUID*>();
125  return tempguid ? gnc_guid2scm(*tempguid) : SCM_BOOL_F;
126  }
127  break;
128  case KvpValue::Type::FRAME:
129  {
130  auto frame { val->get<KvpFrame*>() };
131  auto acc = [](const auto& rv, const auto& iter)
132  {
133  auto key_scm { scm_from_utf8_string (iter.first) };
134  auto val_scm { gnc_kvp_value_ptr_to_scm (iter.second) };
135  return scm_acons (key_scm, val_scm, rv);
136  };
137  return frame ? scm_reverse (std::accumulate (frame->begin(), frame->end(), SCM_EOL, acc)) : SCM_BOOL_F;
138  }
139  break;
140  case KvpValue::Type::GLIST:
141  {
142  SCM lst = SCM_EOL;
143  for (GList *n = val->get<GList*>(); n; n = n->next)
144  {
145  auto elt = gnc_kvp_value_ptr_to_scm (static_cast<KvpValue*>(n->data));
146  lst = scm_cons (elt, lst);
147  }
148  return scm_reverse (lst);
149  }
150  default:
151  break;
152  }
153  return SCM_BOOL_F;
154 }
GncGUID * guid_copy(const GncGUID *guid)
Returns a newly allocated GncGUID that matches the passed-in GUID.
Definition: guid.cpp:120
The type used to store guids in C.
Definition: guid.h:75