Building XML-RPC Clients in C
by Joe Johnston
|
Pages: 1, 2, 3, 4
Listing 7 hints at the reference counting
that Kidd's XML-RPC library does. He tries to shield the user from the
details of memory management, but you must tell the system when you
are done with xmlrpc_value data (see line 73). There are
also two convenient functions (lines 76, 77) for cleaning up other
memory that was allocated behind the scenes.
Listing 7: xmlrpc_debug.c, part 6
72 /* Dispose of our result value. */
73 xmlrpc_DECREF(result);
74
75 /* Shutdown our XML-RPC client library. */
76 xmlrpc_env_clean(&env);
77 xmlrpc_client_cleanup();
78
79 free(url);
80
81 return 0;
82 }
83
|
Listing 8 shows how the six simplest data
types are decoded. The tricky part is knowing which "format" string to
pass to xmlrpc_parse_value. You can use this code as a
guide, but also look at the aforementioned overview.txt for the gory
details. Notice that after calling this conversion function, any
errors that may have occurred will be reported by
die_if_fault_occurred (which is code ripped entirely from
Eric Kidd's examples).
Listing 8: xmlrpc_debug.c, part 7
84 /*
85 subs
86 */
87 void print_values( xmlrpc_env* env, xmlrpc_value* in ){
88
89 /* What did we get back? */
90 switch (xmlrpc_value_type(in)) {
91 case (XMLRPC_TYPE_INT):
92 printf("Got an integer: %d\n", get_int(env, in));
93 break;
94 case (XMLRPC_TYPE_BOOL):
95 printf("Got a boolean: %d\n", get_boolean(env, in));
96 break;
97 case (XMLRPC_TYPE_DOUBLE):
98 printf("Got a double: %g\n", get_double(env, in));
99 break;
100 case (XMLRPC_TYPE_DATETIME):
101 printf("Got an ISO8601 timestamp: %s\n",
get_timestamp(env, in));
102 break;
103 case (XMLRPC_TYPE_STRING):
104 printf("Got a string: %s\n", get_string(env, in));
105 break;
106 case (XMLRPC_TYPE_BASE64):
107 printf("Got a base64 string: %s\n",
get_base64(env, in));
108 break;
109 case (XMLRPC_TYPE_ARRAY):
110 printf("Got an array:\n");
111 get_array(env, in);
112 break;
113 case (XMLRPC_TYPE_STRUCT):
114 printf("Got a struct\n");
115 get_struct(env, in);
116 break;
117 case (XMLRPC_TYPE_C_PTR):
118 printf("Got a C pointer?!\n");
119 break;
120 case (XMLRPC_TYPE_DEAD):
121 printf("Got a 0xDEADr?!\n");
122 break;
123 default:
124 printf("UNKNOWN XML-RPC DATATYPE\n");
125 }
126 }
|
Listing 9 is a bit long, but it's a pretty
simple switch statement. The XML-RPC library defines several constants
with which the xmlrpc_value that was passed in can be
identified. Most of these types should be self-evident. In order to
map XML-RPC values to C values, we need to call
xmlrpc_parse_value. Examples of this will be seen in the
small helper functions that begin with "get_". The last two cases are
internal datatypes that won't normally occur, but are shown for the
sake of completeness.
Listing 9: xmlrpc_debug.c, part 8
127 int get_int(xmlrpc_env* env, xmlrpc_value* in){
128 int i;
129 xmlrpc_parse_value(env, in, "i", &i);
130 die_if_fault_occurred(env);
131 return(i);
132 }
133
134
135 int get_boolean(xmlrpc_env* env, xmlrpc_value* in){
136 int i;
137 xmlrpc_parse_value(env, in, "b", &i);
138 die_if_fault_occurred(env);
139 return(i);
140 }
141
142 double get_double(xmlrpc_env* env, xmlrpc_value* in){
143 double d;
144 xmlrpc_parse_value(env, in, "d", &d);
145 die_if_fault_occurred(env);
146 return(d);
147 }
148
149
150 char* get_timestamp(xmlrpc_env* env, xmlrpc_value* in){
151 char *s;
152
153 xmlrpc_parse_value(env, in, "8", &s);
154 die_if_fault_occurred(env);
155 return(s);
156 }
157
158 char* get_string(xmlrpc_env* env, xmlrpc_value* in){
159 char* s;
160
161 xmlrpc_parse_value(env, in, "s", &s);
162 die_if_fault_occurred(env);
163 return(s);
164 }
165
166 char* get_base64(xmlrpc_env* env, xmlrpc_value* in) {
167 char *s;
168
169 xmlrpc_parse_value(env, in, "6", &s);
170 die_if_fault_occurred(env);
171 return(s);
172 }
173
|
Listing 10 shows how to handle the
simplest aggregate type, the array. Naively calling
xmlrpc_parse_value won't work here because each element
can be a different data type. Fortunately, the size of the array can
be determined with a call to xmlrpc_array_size. Then,
it's a simple matter to iterate through the array, retrieving each
element with a call to xmlrpc_array_get. In a fine
display of code reuse, this element is passed to
print_values.
Listing 10: xmlrpc_debug.c, part 9
174 void get_array(xmlrpc_env* env, xmlrpc_value* in){
175 int i, size = 0;
176 xmlrpc_value *el;
177
178 size = xmlrpc_array_size(env, in);
179 die_if_fault_occurred(env);
180
181 for(i=0; i < size; i++){
182 el = xmlrpc_array_get_item( env, in, i);
183 die_if_fault_occurred(env);
184 print_values(env, el);
185 }
186 }
187
|