1 // Copyright (c) 2014-2020 Josh Blum
2 // SPDX-License-Identifier: BSL-1.0
3 
4 #include "ErrorHelpers.hpp"
5 #include "TypeHelpers.hpp"
6 #include <SoapySDR/Types.h>
7 #include <cstdlib>
8 #include <cstring>
9 
10 extern "C" {
11 
SoapySDRKwargs_fromString(const char * markup)12 SoapySDRKwargs SoapySDRKwargs_fromString(const char *markup)
13 {
14     __SOAPY_SDR_C_TRY
15     return toKwargs(SoapySDR::KwargsFromString(markup));
16     __SOAPY_SDR_C_CATCH_RET(SoapySDRKwargs());
17 }
18 
SoapySDRKwargs_toString(const SoapySDRKwargs * args)19 char *SoapySDRKwargs_toString(const SoapySDRKwargs *args)
20 {
21     __SOAPY_SDR_C_TRY
22     return toCString(SoapySDR::KwargsToString(toKwargs(args)));
23     __SOAPY_SDR_C_CATCH_RET(nullptr);
24 }
25 
SoapySDR_free(void * ptr)26 void SoapySDR_free(void *ptr)
27 {
28     std::free(ptr);
29 }
30 
SoapySDRStrings_clear(char *** elems,const size_t length)31 void SoapySDRStrings_clear(char ***elems, const size_t length)
32 {
33     for (size_t i = 0; i < length; i++)
34     {
35         SoapySDR_free((*elems)[i]);
36     }
37     SoapySDR_free(*elems);
38     *elems = NULL;
39 }
40 
SoapySDRKwargs_set(SoapySDRKwargs * args,const char * key,const char * val)41 int SoapySDRKwargs_set(SoapySDRKwargs *args, const char *key, const char *val)
42 {
43     for (size_t i = 0; i < args->size; i++)
44     {
45         if (std::strcmp(args->keys[i], key) == 0)
46         {
47             auto new_val = strdup(val);
48             if (new_val == nullptr) return -1;
49             SoapySDR_free(args->vals[i]);
50             args->vals[i] = new_val;
51             return 0;
52         }
53     }
54 
55     //increase the memory size by 1 element and assign the new pointer on success
56     //the container will continue to be in a good state even after realloc failure
57     auto new_keys = (char **)std::realloc(args->keys, sizeof(char *)*(args->size+1));
58     auto new_vals = (char **)std::realloc(args->vals, sizeof(char *)*(args->size+1));
59     if (new_keys != nullptr) args->keys = new_keys;
60     if (new_vals != nullptr) args->vals = new_vals;
61 
62     //error: the current allocation has no space for the new element
63     if (new_keys == nullptr or new_vals == nullptr) return -1;
64 
65     //make copies of the key and value to store
66     auto new_key = strdup(key);
67     auto new_val = strdup(val);
68 
69     //error: could not make a copy of the key or value string
70     //free both pointers in case one of them was allocated
71     if (new_key == nullptr or new_val == nullptr)
72     {
73         SoapySDR_free(new_key);
74         SoapySDR_free(new_val);
75         return -1;
76     }
77 
78     //assign the new entry
79     args->keys[args->size] = new_key;
80     args->vals[args->size] = new_val;
81     args->size++;
82     return 0;
83 }
84 
SoapySDRKwargs_get(const SoapySDRKwargs * args,const char * key)85 const char *SoapySDRKwargs_get(const SoapySDRKwargs *args, const char *key)
86 {
87     for (size_t i = 0; i < args->size; i++)
88     {
89         if (strcmp(args->keys[i], key) == 0)
90         {
91             return args->vals[i];
92         }
93     }
94     return NULL;
95 }
96 
SoapySDRKwargs_clear(SoapySDRKwargs * args)97 void SoapySDRKwargs_clear(SoapySDRKwargs *args)
98 {
99     SoapySDRStrings_clear(&args->keys, args->size);
100     SoapySDRStrings_clear(&args->vals, args->size);
101     args->size = 0;
102 }
103 
SoapySDRKwargsList_clear(SoapySDRKwargs * args,const size_t length)104 void SoapySDRKwargsList_clear(SoapySDRKwargs *args, const size_t length)
105 {
106     for (size_t i = 0; i < length; i++) SoapySDRKwargs_clear(args+i);
107     SoapySDR_free(args);
108 }
109 
SoapySDRArgInfo_clear(SoapySDRArgInfo * info)110 void SoapySDRArgInfo_clear(SoapySDRArgInfo *info)
111 {
112     //clear strings
113     SoapySDR_free(info->key);
114     info->key = NULL;
115 
116     SoapySDR_free(info->value);
117     info->value = NULL;
118 
119     SoapySDR_free(info->name);
120     info->name = NULL;
121 
122     SoapySDR_free(info->description);
123     info->description = NULL;
124 
125     SoapySDR_free(info->units);
126     info->units = NULL;
127 
128     //clear options
129     SoapySDRStrings_clear(&info->options, info->numOptions);
130     SoapySDRStrings_clear(&info->optionNames, info->numOptions);
131     info->numOptions = 0;
132 }
133 
SoapySDRArgInfoList_clear(SoapySDRArgInfo * info,const size_t length)134 void SoapySDRArgInfoList_clear(SoapySDRArgInfo *info, const size_t length)
135 {
136     for (size_t i = 0; i < length; i++) SoapySDRArgInfo_clear(info+i);
137     SoapySDR_free(info);
138 }
139 
140 }
141