source: azure_iot_hub/trunk/azure_iohub/c-utility/src/string_token.c@ 388

Last change on this file since 388 was 388, checked in by coas-nagasima, 5 years ago

Azure IoT Hub Device C SDK を使ったサンプルの追加

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csrc
File size: 14.0 KB
Line 
1// Copyright (c) Microsoft. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
4#include <stdlib.h>
5#include <stdbool.h>
6#include <stdarg.h>
7#include "azure_c_shared_utility/gballoc.h"
8#include "azure_c_shared_utility/optimize_size.h"
9#include "azure_c_shared_utility/xlogging.h"
10#include "azure_c_shared_utility/crt_abstractions.h"
11#include "azure_c_shared_utility/string_token.h"
12
13typedef struct STRING_TOKEN_TAG
14{
15 const char* source;
16 size_t length;
17
18 const char* token_start;
19 const char* delimiter_start;
20 const char* delimiter;
21} STRING_TOKEN;
22
23static size_t* get_delimiters_lengths(const char** delimiters, size_t n_delims)
24{
25 size_t* result;
26
27 if ((result = malloc(sizeof(size_t) * n_delims)) == NULL)
28 {
29 LogError("Failed to allocate array for delimiters lengths");
30 }
31 else
32 {
33 size_t i;
34 for (i = 0; i < n_delims; i++)
35 {
36 if (delimiters[i] == NULL)
37 {
38 // Codes_SRS_STRING_TOKENIZER_09_002: [ If any of the strings in delimiters are NULL, the function shall return NULL ]
39 LogError("Invalid argument (delimiter %lu is NULL)", (unsigned long)i);
40 free(result);
41 result = NULL;
42 break;
43 }
44 else
45 {
46 result[i] = strlen(delimiters[i]);
47 }
48 }
49 }
50
51 return result;
52}
53
54static int get_next_token(STRING_TOKEN* token, const char** delimiters, size_t n_delims)
55{
56 int result;
57
58 if (token->token_start != NULL && token->delimiter_start == NULL)
59 {
60 // The parser reached the end of the input string.
61 result = MU_FAILURE;
62 }
63 else
64 {
65 size_t* delimiters_lengths;
66
67 if ((delimiters_lengths = get_delimiters_lengths(delimiters, n_delims)) == NULL)
68 {
69 LogError("Failed to get delimiters lengths");
70 result = MU_FAILURE;
71 }
72 else
73 {
74 const char* new_token_start;
75 const char* current_pos;
76 const char* stop_pos = (char*)token->source + token->length;
77 size_t j; // iterator for the delimiters.
78
79 if (token->delimiter_start == NULL)
80 {
81 // Codes_SRS_STRING_TOKENIZER_09_005: [ The source string shall be split in a token starting from the beginning of source up to occurrence of any one of the demiliters, whichever occurs first in the order provided ]
82 new_token_start = (char*)token->source;
83 }
84 else
85 {
86 // Codes_SRS_STRING_TOKENIZER_09_010: [ The next token shall be selected starting from the position in source right after the previous delimiter up to occurrence of any one of demiliters, whichever occurs first in the order provided ]
87 new_token_start = token->delimiter_start + strlen(token->delimiter);
88 }
89
90 current_pos = new_token_start;
91 result = 0;
92
93 while (current_pos < stop_pos)
94 {
95 for (j = 0; j < n_delims; j++)
96 {
97 if (*current_pos == *delimiters[j])
98 {
99 size_t k;
100 for (k = 1; k < delimiters_lengths[j] && (current_pos + k) < stop_pos; k++)
101 {
102 if (*(current_pos + k) != *(delimiters[j] + k))
103 {
104 break;
105 }
106 }
107
108 if (k == delimiters_lengths[j])
109 {
110 token->delimiter_start = current_pos;
111 token->delimiter = delimiters[j];
112
113 if (token->delimiter_start == token->source)
114 {
115 // Delimiter occurs in the beginning of the source string.
116 token->token_start = NULL;
117 }
118 else
119 {
120 token->token_start = new_token_start;
121 }
122 goto SCAN_COMPLETED;
123 }
124 }
125 }
126
127 current_pos++;
128 }
129
130 // Codes_SRS_STRING_TOKENIZER_09_006: [ If the source string does not have any of the demiliters, the resulting token shall be the entire source string ]
131 // Codes_SRS_STRING_TOKENIZER_09_011: [ If the source string, starting right after the position of the last delimiter found, does not have any of the demiliters, the resulting token shall be the entire remaining of the source string ]
132 if (current_pos == stop_pos)
133 {
134 token->token_start = new_token_start;
135 token->delimiter_start = NULL;
136 // Codes_SRS_STRING_TOKENIZER_09_019: [ If the current token extends to the end of source, the function shall return NULL ]
137 token->delimiter = NULL;
138 }
139
140SCAN_COMPLETED:
141 free(delimiters_lengths);
142 }
143 }
144
145 return result;
146}
147
148STRING_TOKEN_HANDLE StringToken_GetFirst(const char* source, size_t length, const char** delimiters, size_t n_delims)
149{
150 STRING_TOKEN* result;
151
152 // Codes_SRS_STRING_TOKENIZER_09_001: [ If source or delimiters are NULL, or n_delims is zero, the function shall return NULL ]
153 if (source == NULL || delimiters == NULL || n_delims == 0)
154 {
155 LogError("Invalid argument (source=%p, delimiters=%p, n_delims=%lu)", source, delimiters, (unsigned long)n_delims);
156 result = NULL;
157 }
158 else
159 {
160 // Codes_SRS_STRING_TOKENIZER_09_003: [ A STRING_TOKEN structure shall be allocated to hold the token parameters ]
161 if ((result = (STRING_TOKEN*)malloc(sizeof(STRING_TOKEN))) == NULL)
162 {
163 // Codes_SRS_STRING_TOKENIZER_09_004: [ If the STRING_TOKEN structure fails to be allocated, the function shall return NULL ]
164 LogError("Failed allocating STRING_TOKEN");
165 }
166 else
167 {
168 (void)memset(result, 0, sizeof(STRING_TOKEN));
169 result->source = source;
170 result->length = length;
171
172 if (get_next_token(result, delimiters, n_delims) != 0)
173 {
174 LogError("Failed to get first token");
175 // Codes_SRS_STRING_TOKENIZER_09_007: [ If any failure occurs, all memory allocated by this function shall be released ]
176 free(result);
177 result = NULL;
178 }
179 }
180 }
181
182 return result;
183}
184
185bool StringToken_GetNext(STRING_TOKEN_HANDLE token, const char** delimiters, size_t n_delims)
186{
187 bool result;
188
189 // Codes_SRS_STRING_TOKENIZER_09_008: [ If token or delimiters are NULL, or n_delims is zero, the function shall return false ]
190 if (token == NULL || delimiters == NULL || n_delims == 0)
191 {
192 LogError("Invalid argument (token=%p, delimiters=%p, n_delims=%lu)", token, delimiters, (unsigned long)n_delims);
193 result = false;
194 }
195 else if (get_next_token(token, delimiters, n_delims) != 0)
196 {
197 // Codes_SRS_STRING_TOKENIZER_09_009: [ If the previous token already extended to the end of source, the function shall return false ]
198 result = false;
199 }
200 else
201 {
202 // Codes_SRS_STRING_TOKENIZER_09_012: [ If a token was identified, the function shall return true ]
203 result = true;
204 }
205
206 return result;
207}
208
209const char* StringToken_GetValue(STRING_TOKEN_HANDLE token)
210{
211 const char* result;
212
213 // Codes_SRS_STRING_TOKENIZER_09_013: [ If token is NULL the function shall return NULL ]
214 if (token == NULL)
215 {
216 LogError("Invalig argument (token is NULL)");
217 result = NULL;
218 }
219 // Beyond the length of the source string.
220 else if (token->token_start == (token->source + token->length))
221 {
222 result = NULL;
223 }
224 // Two delimiters side by side (empty token).
225 else if (token->token_start == token->delimiter_start)
226 {
227 result = NULL;
228 }
229 else
230 {
231 // Codes_SRS_STRING_TOKENIZER_09_014: [ The function shall return the pointer to the position in source where the current token starts. ]
232 result = token->token_start;
233 }
234
235 return result;
236}
237
238size_t StringToken_GetLength(STRING_TOKEN_HANDLE token)
239{
240 size_t result;
241
242 // Codes_SRS_STRING_TOKENIZER_09_015: [ If token is NULL the function shall return zero ]
243 if (token == NULL)
244 {
245 LogError("Invalig argument (token is NULL)");
246 result = 0;
247 }
248 // Codes_SRS_STRING_TOKENIZER_09_016: [ The function shall return the length of the current token ]
249 else if (token->token_start == NULL)
250 {
251 result = 0;
252 }
253 else if (token->delimiter_start == NULL)
254 {
255 result = token->source + token->length - token->token_start;
256 }
257 else
258 {
259 result = token->delimiter_start - token->token_start;
260 }
261
262 return result;
263}
264
265const char* StringToken_GetDelimiter(STRING_TOKEN_HANDLE token)
266{
267 const char* result;
268
269 if (token == NULL)
270 {
271 // Codes_SRS_STRING_TOKENIZER_09_017: [ If token is NULL the function shall return NULL ]
272 LogError("Invalig argument (token is NULL)");
273 result = NULL;
274 }
275 else
276 {
277 // Codes_SRS_STRING_TOKENIZER_09_018: [ The function shall return a pointer to the delimiter that defined the current token, as passed to the previous call to StringToken_GetNext() or StringToken_GetFirst() ]
278 result = token->delimiter;
279 }
280
281 return result;
282}
283
284int StringToken_Split(const char* source, size_t length, const char** delimiters, size_t n_delims, bool include_empty, char*** tokens, size_t* token_count)
285{
286 int result;
287
288 // Codes_SRS_STRING_TOKENIZER_09_022: [ If source, delimiters, token or token_count are NULL, or n_delims is zero the function shall return a non-zero value ]
289 if (source == NULL || delimiters == NULL || n_delims == 0 || tokens == NULL || token_count == NULL)
290 {
291 LogError("Invalid argument (source=%p, delimiters=%p, n_delims=%lu, tokens=%p, token_count=%p)", source, delimiters, (unsigned long)n_delims, tokens, token_count);
292 result = MU_FAILURE;
293 }
294 else
295 {
296 STRING_TOKEN_HANDLE tokenizer;
297
298 // Codes_SRS_STRING_TOKENIZER_09_023: [ source (up to length) shall be split into individual tokens separated by any of delimiters ]
299 tokenizer = StringToken_GetFirst(source, length, delimiters, n_delims);
300
301 *token_count = 0;
302 *tokens = NULL;
303 // Codes_SRS_STRING_TOKENIZER_09_027: [ If no failures occur the function shall return zero ]
304 result = 0;
305
306 if (tokenizer != NULL)
307 {
308 do
309 {
310 const char* tokenValue;
311 size_t tokenLength;
312
313 tokenValue = StringToken_GetValue(tokenizer);
314 tokenLength = StringToken_GetLength(tokenizer);
315
316 if ((tokenValue != NULL && tokenLength == 0) || (tokenValue == NULL && tokenLength > 0))
317 {
318 LogError("Unexpected token value (%p) or length (%lu)", tokenValue, (unsigned long)tokenLength);
319 result = MU_FAILURE;
320 break;
321 }
322 // Codes_SRS_STRING_TOKENIZER_09_024: [ All NULL tokens shall be ommited if include_empty is not TRUE ]
323 else if (tokenValue != NULL || include_empty)
324 {
325 char** temp_token;
326 // Codes_SRS_STRING_TOKENIZER_09_025: [ The tokens shall be stored in tokens, and their count stored in token_count ]
327 *token_count = (*token_count) + 1;
328
329 if ((temp_token = (char**)realloc(*tokens, sizeof(char*) * (*token_count))) == NULL)
330 {
331 // Codes_SRS_STRING_TOKENIZER_09_026: [ If any failures splitting or storing the tokens occur the function shall return a non-zero value ]
332 LogError("Failed re-allocating the token array");
333 (*token_count)--;
334 result = MU_FAILURE;
335 break;
336 }
337 else
338 {
339 *tokens = temp_token;
340 if (tokenLength == 0)
341 {
342 (*tokens)[(*token_count) - 1] = NULL;
343 }
344 else if (((*tokens)[(*token_count) - 1] = (char*)malloc(sizeof(char) * (tokenLength + 1))) == NULL)
345 {
346 // Codes_SRS_STRING_TOKENIZER_09_026: [ If any failures splitting or storing the tokens occur the function shall return a non-zero value ]
347 LogError("Failed copying token into array");
348 *token_count = (*token_count) - 1;
349 result = MU_FAILURE;
350 break;
351 }
352 else
353 {
354 (void)memcpy((*tokens)[(*token_count) - 1], tokenValue, tokenLength);
355 (*tokens)[(*token_count) - 1][tokenLength] = '\0';
356 }
357 }
358 }
359 } while (StringToken_GetNext(tokenizer, delimiters, n_delims));
360
361 StringToken_Destroy(tokenizer);
362
363 if (result != 0)
364 {
365 while ((*token_count) > 0 && *tokens != NULL)
366 {
367 *token_count = (*token_count) - 1;
368 free((*tokens)[*token_count]);
369 }
370 free(*tokens);
371 }
372 }
373 }
374
375 return result;
376}
377
378void StringToken_Destroy(STRING_TOKEN_HANDLE token)
379{
380 if (token == NULL)
381 {
382 // Codes_SRS_STRING_TOKENIZER_09_020: [ If token is NULL the function shall return ]
383 LogError("Invalig argument (token is NULL)");
384 }
385 else
386 {
387 // Codes_SRS_STRING_TOKENIZER_09_021: [ Otherwise the memory allocated for STRING_TOKEN shall be released ]
388 free(token);
389 }
390}
Note: See TracBrowser for help on using the repository browser.