Branch data Line data Source code
1 : : /*
2 : : Copyright (c) 2010-2014 Jeremiah Martell
3 : : All rights reserved.
4 : :
5 : : Redistribution and use in source and binary forms, with or without modification,
6 : : are permitted provided that the following conditions are met:
7 : :
8 : : - Redistributions of source code must retain the above copyright notice,
9 : : this list of conditions and the following disclaimer.
10 : : - Redistributions in binary form must reproduce the above copyright notice,
11 : : this list of conditions and the following disclaimer in the documentation
12 : : and/or other materials provided with the distribution.
13 : : - Neither the name of Jeremiah Martell nor the name of GeekHorse nor the
14 : : name of Trot nor the names of its contributors may be used to endorse or
15 : : promote products derived from this software without specific prior written
16 : : permission.
17 : :
18 : : THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 : : ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 : : WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 : : DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
22 : : ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 : : (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 : : LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 : : ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 : : (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 : : SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 : : */
29 : :
30 : : /******************************************************************************/
31 : : /*!
32 : : \file
33 : : Decodes textual format to trot list.
34 : : */
35 : : #define TROT_FILE_NUMBER 5
36 : :
37 : : /******************************************************************************/
38 : : #include "trot.h"
39 : : #include "trotInternal.h"
40 : :
41 : : /******************************************************************************/
42 : : static TROT_RC skipWhitespace( TrotList *lCharacters, TROT_INT charactersCount, TROT_INT *index, s32 mustBeOne );
43 : : static TROT_RC getWord( TrotList *lCharacters, TROT_INT charactersCount, TROT_INT *index, TrotList **lWord_A );
44 : : static TROT_RC wordToNumber( TrotList *lWord, TROT_INT *number );
45 : : static TROT_RC splitList( TrotList *listToSplit, TROT_INT separator, TrotList **lPartList_A );
46 : : static TROT_RC getReferenceList( TrotList *lTop, TrotList *lPartList, TrotList **lReference_A );
47 : :
48 : : /******************************************************************************/
49 : : /*!
50 : : \brief Decodes a list of characters into a list.
51 : : \param[in] lCharacters Characters to decode.
52 : : \param[out] lDecodedList_A On success, the decoded list.
53 : : \return TROT_RC
54 : :
55 : : lCharacters is not modified.
56 : : lDecodedList_A is created, and caller is responsible for freeing.
57 : : */
58 : 17433 : TROT_RC trotDecode( TrotList *lCharacters, TrotList **lDecodedList_A )
59 : : {
60 : : /* DATA */
61 : 17433 : TROT_RC rc = TROT_RC_SUCCESS;
62 : :
63 : 17433 : TROT_INT charactersCount = 0;
64 : 17433 : TROT_INT index = 1;
65 : :
66 : 17433 : TrotList *lTop = NULL;
67 : 17433 : TrotList *lCurrent = NULL;
68 : 17433 : TrotList *lChild = NULL;
69 : :
70 : 17433 : TrotList *lWord = NULL;
71 : 17433 : TROT_INT ch = 0;
72 : :
73 : 17433 : TROT_INT number = 0;
74 : :
75 : 17433 : TrotList *lStack = NULL;
76 : 17433 : TROT_INT stackCount = 0;
77 : :
78 : 17433 : TrotList *lPartList = NULL;
79 : :
80 : :
81 : : /* PRECOND */
82 [ + + ]: 17433 : ERR_IF( lCharacters == NULL, TROT_RC_ERROR_PRECOND );
83 [ + + ]: 17432 : ERR_IF( lDecodedList_A == NULL, TROT_RC_ERROR_PRECOND );
84 [ + + ]: 17431 : ERR_IF( (*lDecodedList_A) != NULL, TROT_RC_ERROR_PRECOND );
85 : :
86 : :
87 : : /* CODE */
88 : : /* get count of characters */
89 : 17430 : rc = trotListGetCount( lCharacters, &charactersCount );
90 : : PARANOID_ERR_IF( rc != TROT_RC_SUCCESS );
91 : :
92 : : /* create "top" list */
93 : 17430 : rc = trotListInit( &lTop );
94 [ + + ]: 17430 : ERR_IF_PASSTHROUGH;
95 : :
96 : : /* create current list */
97 : 17254 : rc = trotListTwin( lTop, &lCurrent );
98 [ + + ]: 17254 : ERR_IF_PASSTHROUGH;
99 : :
100 : : /* create our stack */
101 : 17232 : rc = trotListInit( &lStack );
102 [ + + ]: 17232 : ERR_IF_PASSTHROUGH;
103 : :
104 : :
105 : : /* skip whitespace */
106 : 17056 : rc = skipWhitespace( lCharacters, charactersCount, &index, 0 );
107 [ + + ]: 17056 : ERR_IF_PASSTHROUGH;
108 : :
109 : :
110 : : /* get first character */
111 : 17055 : rc = trotListGetInt( lCharacters, index, &ch );
112 [ + + ]: 17055 : ERR_IF_PASSTHROUGH;
113 : :
114 : : /* must be [ */
115 [ + + ]: 17053 : ERR_IF_1( ch != '[', TROT_RC_ERROR_DECODE, ch );
116 : :
117 : : /* skip past [ */
118 : 17051 : index += 1;
119 : :
120 : :
121 : : /* decode rest of characters */
122 : : while ( 1 )
123 : : {
124 : : /* skip whitespace */
125 : 546637 : rc = skipWhitespace( lCharacters, charactersCount, &index, 1 );
126 [ + + ]: 546637 : ERR_IF_PASSTHROUGH;
127 : :
128 : : /* get next character */
129 : 546617 : rc = trotListGetInt( lCharacters, index, &ch );
130 [ + + ]: 546617 : ERR_IF_PASSTHROUGH;
131 : :
132 : : /* if double quote, decode text format */
133 [ + + ]: 546614 : if ( ch == '\"' )
134 : : {
135 : : /* skip double quote */
136 : 10398 : index += 1;
137 : :
138 : : /* go through text */
139 : : while ( 1 )
140 : : {
141 : : /* get character */
142 : 29100 : rc = trotListGetInt( lCharacters, index, &ch );
143 [ + + ]: 29100 : ERR_IF_PASSTHROUGH;
144 : :
145 : : /* if double quote, we're at end of text format */
146 [ + + ]: 29099 : if ( ch == '\"' )
147 : : {
148 : : /* skip double quote */
149 : 10369 : index += 1;
150 : :
151 : 10369 : break;
152 : : }
153 : :
154 : : /* add to lCurrent */
155 : 18730 : rc = trotListAppendInt( lCurrent, ch );
156 [ + + ]: 18730 : ERR_IF_PASSTHROUGH;
157 : :
158 : : /* increment */
159 : 18702 : index += 1;
160 : 29071 : }
161 : : }
162 : : /* if left bracket, create new child list and "go down" into it */
163 [ + + ]: 536216 : else if ( ch == '[' )
164 : : {
165 : : /* skip bracket */
166 : 75391 : index += 1;
167 : :
168 : : /* create new list */
169 : 75391 : trotListFree( &lChild );
170 : 75391 : rc = trotListInit( &lChild );
171 [ + + ]: 75391 : ERR_IF_PASSTHROUGH;
172 : :
173 : : /* add new list to current list */
174 : 74607 : rc = trotListAppendList( lCurrent, lChild );
175 [ + + ]: 74607 : ERR_IF_PASSTHROUGH;
176 : :
177 : : /* push current list */
178 : 74485 : rc = trotListAppendList( lStack, lCurrent );
179 [ + + ]: 74485 : ERR_IF_PASSTHROUGH;
180 : :
181 : : /* switchup lCurrent and lChild ... "go down" */
182 : 74191 : trotListFree( &lCurrent );
183 : 74191 : lCurrent = lChild;
184 : 74191 : lChild = NULL;
185 : : }
186 : : /* if right bracket, "go up" to parent */
187 [ + + ]: 460825 : else if ( ch == ']' )
188 : : {
189 : : /* skip bracket */
190 : 82053 : index += 1;
191 : :
192 : : /* is stack empty? */
193 : 82053 : rc = trotListGetCount( lStack, &stackCount );
194 : : PARANOID_ERR_IF( rc != TROT_RC_SUCCESS );
195 : :
196 [ + + ]: 82053 : if ( stackCount == 0 )
197 : : {
198 : 8872 : break;
199 : : }
200 : :
201 : : /* pop off stack ... "go up" */
202 : 73181 : trotListFree( &lCurrent );
203 : 73181 : rc = trotListRemoveList( lStack, -1, &lCurrent );
204 : : PARANOID_ERR_IF( rc != TROT_RC_SUCCESS );
205 : : }
206 : : /* if tilde, set tag */
207 [ + + ]: 378772 : else if ( ch == '~' )
208 : : {
209 : : /* skip tilde */
210 : 22225 : index += 1;
211 : :
212 : : /* get word */
213 : 22225 : trotListFree( &lWord );
214 : 22225 : rc = getWord( lCharacters, charactersCount, &index, &lWord );
215 [ + + ]: 22225 : ERR_IF_PASSTHROUGH;
216 : :
217 : : /* word to number */
218 : 21845 : rc = wordToNumber( lWord, &number );
219 [ + + ]: 21845 : ERR_IF_PASSTHROUGH;
220 : :
221 : : /* set tag */
222 : 21839 : rc = trotListSetTag( lCurrent, number );
223 [ + + ]: 21839 : ERR_IF_PASSTHROUGH;
224 : : }
225 : : /* if backtick, set user tag */
226 [ + + ]: 356547 : else if ( ch == '`' )
227 : : {
228 : : /* skip backtick */
229 : 20832 : index += 1;
230 : :
231 : : /* get word */
232 : 20832 : trotListFree( &lWord );
233 : 20832 : rc = getWord( lCharacters, charactersCount, &index, &lWord );
234 [ + + ]: 20832 : ERR_IF_PASSTHROUGH;
235 : :
236 : : /* word to number */
237 : 20532 : rc = wordToNumber( lWord, &number );
238 [ + + ]: 20532 : ERR_IF_PASSTHROUGH;
239 : :
240 : : /* set user tag */
241 : 20527 : rc = trotListSetUserTag( lCurrent, number );
242 : : PARANOID_ERR_IF( rc != TROT_RC_SUCCESS );
243 : : }
244 : : /* if @, read in reference, and twin a previously-seen list */
245 [ + + ]: 335715 : else if ( ch == '@' )
246 : : {
247 : : /* get word */
248 : 145510 : trotListFree( &lWord );
249 : 145510 : rc = getWord( lCharacters, charactersCount, &index, &lWord );
250 [ + + ]: 145510 : ERR_IF_PASSTHROUGH;
251 : :
252 : : /* split */
253 : 144567 : trotListFree( &lPartList );
254 : 144567 : rc = splitList( lWord, '.', &lPartList );
255 [ + + ]: 144567 : ERR_IF_PASSTHROUGH;
256 : :
257 : : /* get reference */
258 : 142153 : trotListFree( &lChild );
259 : 142153 : rc = getReferenceList( lTop, lPartList, &lChild );
260 [ + + ]: 142153 : ERR_IF_PASSTHROUGH;
261 : :
262 : : /* add to current */
263 : 141875 : rc = trotListAppendList( lCurrent, lChild );
264 [ + + ]: 141875 : ERR_IF_PASSTHROUGH;
265 : : }
266 : : /* else, must be number */
267 : : else
268 : : {
269 : : /* get word */
270 : 190205 : trotListFree( &lWord );
271 : 190205 : rc = getWord( lCharacters, charactersCount, &index, &lWord );
272 [ + + ]: 190205 : ERR_IF_PASSTHROUGH;
273 : :
274 : : /* word to number */
275 : 188164 : rc = wordToNumber( lWord, &number );
276 [ + + ]: 188164 : ERR_IF_PASSTHROUGH;
277 : :
278 : : /* add number to current list */
279 : 188144 : rc = trotListAppendInt( lCurrent, number );
280 [ + + ]: 188144 : ERR_IF_PASSTHROUGH;
281 : : }
282 : 529586 : }
283 : :
284 : : /* skip whitespace */
285 : 8872 : rc = skipWhitespace( lCharacters, charactersCount, &index, 0 );
286 [ + + ]: 8872 : ERR_IF_PASSTHROUGH;
287 : :
288 : : /* we must be at end of characters */
289 [ + + ]: 8871 : ERR_IF( index != (charactersCount + 1), TROT_RC_ERROR_DECODE );
290 : :
291 : :
292 : : /* give back */
293 : 8869 : (*lDecodedList_A) = lTop;
294 : 8869 : lTop = NULL;
295 : :
296 : :
297 : : /* CLEANUP */
298 : : cleanup:
299 : :
300 : 17433 : trotListFree( &lTop );
301 : 17433 : trotListFree( &lCurrent );
302 : 17433 : trotListFree( &lWord );
303 : 17433 : trotListFree( &lStack );
304 : 17433 : trotListFree( &lPartList );
305 : 17433 : trotListFree( &lChild );
306 : :
307 : 17433 : return rc;
308 : : }
309 : :
310 : : /******************************************************************************/
311 : : /*!
312 : : \brief Skips whitespace characters.
313 : : \param[in] lCharacters List of characters.
314 : : \param[in] charactersCount Count of characters.
315 : : \param[in,out] index Current index into lCharacters.
316 : : \param[in] mustBeOne Whether there must be at least 1 whitespace character.
317 : : \return TROT_RC
318 : :
319 : : index will be incremented to first non-whitespace character, or 1 past end of list.
320 : : */
321 : 572565 : static TROT_RC skipWhitespace( TrotList *lCharacters, TROT_INT charactersCount, TROT_INT *index, s32 mustBeOne )
322 : : {
323 : : /* DATA */
324 : 572565 : TROT_RC rc = TROT_RC_SUCCESS;
325 : :
326 : 572565 : TROT_INT ch = 0;
327 : :
328 : :
329 : : /* PRECOND */
330 : : PARANOID_ERR_IF( lCharacters == NULL );
331 : : PARANOID_ERR_IF( index == NULL );
332 : :
333 : :
334 : : /* CODE */
335 [ + + ]: 572565 : if ( mustBeOne )
336 : : {
337 : 546637 : rc = trotListGetInt( lCharacters, (*index), &ch );
338 [ + + ]: 546637 : ERR_IF_PASSTHROUGH;
339 : :
340 [ + + ]: 546633 : ERR_IF( ! trotUnicodeIsWhitespace( ch ), TROT_RC_ERROR_DECODE );
341 : :
342 : 546622 : (*index) += 1;
343 : : }
344 : :
345 [ + + ]: 574223 : while ( (*index) <= charactersCount )
346 : : {
347 : 565349 : rc = trotListGetInt( lCharacters, (*index), &ch );
348 [ + + ]: 565349 : ERR_IF_PASSTHROUGH;
349 : :
350 [ + + ]: 565342 : if ( ! trotUnicodeIsWhitespace( ch ) )
351 : : {
352 : 563669 : break;
353 : : }
354 : :
355 : 1673 : (*index) += 1;
356 : : }
357 : :
358 : :
359 : : /* CLEANUP */
360 : : cleanup:
361 : :
362 : 572565 : return rc;
363 : : }
364 : :
365 : : /******************************************************************************/
366 : : /*!
367 : : \brief Gets the next word in lCharacters.
368 : : \param[in] lCharacters List of characters.
369 : : \param[in] charactersCount Count of characters.
370 : : \param[in,out] index Current index into lCharacters.
371 : : \param[out] lWord_A The next word.
372 : : \return TROT_RC
373 : :
374 : : index will be incremented.
375 : : lWord_A will be created. Caller is responsible for freeing.
376 : : */
377 : 378772 : static TROT_RC getWord( TrotList *lCharacters, TROT_INT charactersCount, TROT_INT *index, TrotList **lWord_A )
378 : : {
379 : : /* DATA */
380 : 378772 : TROT_RC rc = TROT_RC_SUCCESS;
381 : :
382 : 378772 : TrotList *newLWord = NULL;
383 : 378772 : TROT_INT ch = 0;
384 : :
385 : :
386 : : /* PRECOND */
387 : : PARANOID_ERR_IF( lCharacters == NULL );
388 : : PARANOID_ERR_IF( index == NULL );
389 : : PARANOID_ERR_IF( lWord_A == NULL );
390 : : PARANOID_ERR_IF( (*lWord_A) != NULL );
391 : :
392 : :
393 : : /* CODE */
394 : 378772 : rc = trotListInit( &newLWord );
395 [ + + ]: 378772 : ERR_IF_PASSTHROUGH;
396 : :
397 [ + + ]: 1075190 : while ( (*index) <= charactersCount )
398 : : {
399 : 1075189 : rc = trotListGetInt( lCharacters, (*index), &ch );
400 [ + + ]: 1075189 : ERR_IF_PASSTHROUGH;
401 : :
402 [ + + ]: 1075185 : if ( trotUnicodeIsWhitespace( ch ) )
403 : : {
404 : 375107 : break;
405 : : }
406 : :
407 : 700078 : rc = trotListAppendInt( newLWord, ch );
408 [ + + ]: 700078 : ERR_IF_PASSTHROUGH;
409 : :
410 : 699346 : (*index) += 1;
411 : : }
412 : :
413 : :
414 : : /* give back */
415 : 375108 : (*lWord_A) = newLWord;
416 : 375108 : newLWord = NULL;
417 : :
418 : :
419 : : /* CLEANUP */
420 : : cleanup:
421 : :
422 : 378772 : trotListFree( &newLWord );
423 : :
424 : 378772 : return rc;
425 : : }
426 : :
427 : : /******************************************************************************/
428 : : /*!
429 : : \brief Converts a word into a number.
430 : : \param[in] lWord The list to convert
431 : : \param[out] number On success, the number.
432 : : \return TROT_RC
433 : :
434 : : lWord must not contain lists, only ints.
435 : :
436 : : Example:
437 : : If lWord is ["123"] number would be 123.
438 : : */
439 : 291485 : static TROT_RC wordToNumber( TrotList *lWord, TROT_INT *number )
440 : : {
441 : : /* DATA */
442 : 291485 : TROT_RC rc = TROT_RC_SUCCESS;
443 : :
444 : 291485 : TROT_INT index = 0;
445 : 291485 : TROT_INT count = 0;
446 : :
447 : 291485 : TROT_INT character = 0;
448 : 291485 : TROT_INT newNumber = 0;
449 : :
450 : 291485 : TROT_INT i = 0;
451 : :
452 : :
453 : : /* PRECOND */
454 : : PARANOID_ERR_IF( lWord == NULL );
455 : : PARANOID_ERR_IF( number == NULL );
456 : :
457 : :
458 : : /* CODE */
459 : : /* get count */
460 : 291485 : rc = trotListGetCount( lWord, &count );
461 : : PARANOID_ERR_IF( rc != TROT_RC_SUCCESS );
462 : :
463 : : /* get first character */
464 : 291485 : rc = trotListGetInt( lWord, 1, &character );
465 [ + + ]: 291485 : ERR_IF_PASSTHROUGH;
466 : :
467 : : /* make sure it's a good format */
468 : 291480 : index = 1;
469 [ + + ]: 291480 : if ( character == '-' )
470 : : {
471 : 26 : index += 1;
472 : : }
473 : :
474 : 291480 : rc = trotListGetInt( lWord, index, &character );
475 [ + + ]: 291480 : ERR_IF_PASSTHROUGH;
476 : :
477 [ + + ][ + + ]: 291479 : ERR_IF_1( ( ! ( character >= '0' && character <= '9' ) ), TROT_RC_ERROR_DECODE, character );
478 : :
479 [ + + ][ + + ]: 291470 : ERR_IF_1( character == '0' && count != 1, TROT_RC_ERROR_DECODE, count );
480 : :
481 : 291467 : index += 1;
482 : :
483 [ + + ]: 490946 : while ( index <= count )
484 : : {
485 : 199487 : rc = trotListGetInt( lWord, index, &character );
486 : : PARANOID_ERR_IF( rc != TROT_RC_SUCCESS );
487 : :
488 [ + + ][ + + ]: 199487 : ERR_IF_1( ( ! ( character >= '0' && character <= '9' ) ), TROT_RC_ERROR_DECODE, character );
489 : :
490 : 199479 : index += 1;
491 : : }
492 : :
493 : : /* make sure number can fit into our TROT_INT */
494 : 291459 : index = 1;
495 : :
496 : 291459 : rc = trotListGetInt( lWord, index, &character );
497 : : PARANOID_ERR_IF( rc != TROT_RC_SUCCESS );
498 : :
499 [ + + ]: 291459 : if ( character == '-' )
500 : : {
501 [ + + ]: 23 : ERR_IF_1( count > TROT_INT_MIN_STRING_LENGTH, TROT_RC_ERROR_DECODE, count );
502 : :
503 [ + + ]: 22 : if ( count == TROT_INT_MIN_STRING_LENGTH )
504 : : {
505 : 12 : index += 1;
506 : 12 : i = 1; /* to skip the '-' at the beginning of TROT_INT_MIN */
507 : :
508 [ + + ]: 92 : while ( index <= count )
509 : : {
510 : 74 : rc = trotListGetInt( lWord, index, &character );
511 : : PARANOID_ERR_IF( rc != TROT_RC_SUCCESS );
512 : :
513 [ + + ]: 74 : ERR_IF ( character > TROT_INT_MIN_STRING[ i ], TROT_RC_ERROR_DECODE );
514 : :
515 [ + + ]: 70 : if ( character < TROT_INT_MIN_STRING[ i ] )
516 : : {
517 : 6 : break;
518 : : }
519 : :
520 : 64 : index += 1;
521 : 64 : i += 1;
522 : : }
523 : : }
524 : : }
525 : : else
526 : : {
527 [ + + ]: 291436 : ERR_IF_1( count > TROT_INT_MAX_STRING_LENGTH, TROT_RC_ERROR_DECODE, count );
528 : :
529 [ + + ]: 291435 : if ( count == TROT_INT_MAX_STRING_LENGTH )
530 : : {
531 : 12 : i = 0;
532 : :
533 [ + + ]: 76 : while ( index <= count )
534 : : {
535 : 74 : rc = trotListGetInt( lWord, index, &character );
536 : : PARANOID_ERR_IF( rc != TROT_RC_SUCCESS );
537 : :
538 [ + + ]: 74 : ERR_IF_1( character > TROT_INT_MAX_STRING[ i ], TROT_RC_ERROR_DECODE, character );
539 : :
540 [ + + ]: 70 : if ( character < TROT_INT_MAX_STRING[ i ] )
541 : : {
542 : 6 : break;
543 : : }
544 : :
545 : 64 : index += 1;
546 : 64 : i += 1;
547 : : }
548 : : }
549 : : }
550 : :
551 : : /* get our number started */
552 : 291449 : index = 1;
553 : :
554 : 291449 : rc = trotListGetInt( lWord, index, &character );
555 : : PARANOID_ERR_IF( rc != TROT_RC_SUCCESS );
556 : :
557 : : /* if negative, get real first number */
558 [ + + ]: 291449 : if ( character == '-' )
559 : : {
560 : 18 : index += 1;
561 : :
562 : 18 : rc = trotListGetInt( lWord, index, &character );
563 : : PARANOID_ERR_IF( rc != TROT_RC_SUCCESS );
564 : :
565 : 18 : newNumber = character - '0';
566 : 18 : newNumber *= -1;
567 : :
568 : : /* build rest of number */
569 : 18 : index += 1;
570 : :
571 [ + + ]: 100 : while ( index <= count )
572 : : {
573 : 82 : rc = trotListGetInt( lWord, index, &character );
574 : : PARANOID_ERR_IF( rc != TROT_RC_SUCCESS );
575 : :
576 : 82 : newNumber *= 10;
577 : 82 : newNumber -= character - '0';
578 : :
579 : 82 : index += 1;
580 : : }
581 : : }
582 : : else
583 : : {
584 : 291431 : newNumber = character - '0';
585 : :
586 : : /* build rest of number */
587 : 291431 : index += 1;
588 : :
589 [ + + ]: 490736 : while ( index <= count )
590 : : {
591 : 199305 : rc = trotListGetInt( lWord, index, &character );
592 : : PARANOID_ERR_IF( rc != TROT_RC_SUCCESS );
593 : :
594 : 199305 : newNumber *= 10;
595 : 199305 : newNumber += character - '0';
596 : :
597 : 199305 : index += 1;
598 : : }
599 : : }
600 : :
601 : : /* give back */
602 : 291449 : (*number) = newNumber;
603 : :
604 : :
605 : : /* CLEANUP */
606 : : cleanup:
607 : :
608 : 291485 : return rc;
609 : : }
610 : :
611 : : /******************************************************************************/
612 : : /*!
613 : : \brief Creates a new list of parts that were separated out of l.
614 : : \param[in] listToSplit List that contains parts.
615 : : \param[in] separator Separating character
616 : : \param[out] lPartList_A On success, contains the parts.
617 : : \return TROT_RC
618 : :
619 : : listToSplit is not modified.
620 : : listToSplit must only contain characters, not lists.
621 : :
622 : : lPartList_A is created, and caller is responsible for freeing.
623 : :
624 : : Example:
625 : : IN:
626 : : listToSplit = ["abc.def.ghi"]
627 : : separator = '.'
628 : : OUT:
629 : : listToSplit = ["abc.def.ghi"]
630 : : lPartList_A will be [["abc"]["def"]["ghi"]]
631 : : */
632 : 144567 : static TROT_RC splitList( TrotList *listToSplit, TROT_INT separator, TrotList **lPartList_A )
633 : : {
634 : : /* DATA */
635 : 144567 : TROT_RC rc = TROT_RC_SUCCESS;
636 : :
637 : 144567 : TROT_INT count = 0;
638 : 144567 : TROT_INT index = 0;
639 : 144567 : TROT_INT character = 0;
640 : :
641 : 144567 : TrotList *newLPartList = NULL;
642 : 144567 : TrotList *lPart = NULL;
643 : :
644 : :
645 : : /* PRECOND */
646 : : PARANOID_ERR_IF( listToSplit == NULL );
647 : : PARANOID_ERR_IF( lPartList_A == NULL );
648 : : PARANOID_ERR_IF( (*lPartList_A) != NULL );
649 : :
650 : :
651 : : /* CODE */
652 : : /* create giveback */
653 : 144567 : rc = trotListInit( &newLPartList );
654 [ + + ]: 144567 : ERR_IF_PASSTHROUGH;
655 : :
656 : 143815 : rc = trotListInit( &lPart );
657 [ + + ]: 143815 : ERR_IF_PASSTHROUGH;
658 : :
659 : 143063 : rc = trotListAppendList( newLPartList, lPart );
660 [ + + ]: 143063 : ERR_IF_PASSTHROUGH;
661 : :
662 : : /* get count */
663 : 142781 : rc = trotListGetCount( listToSplit, &count );
664 : : PARANOID_ERR_IF( rc != TROT_RC_SUCCESS );
665 : :
666 : : /* foreach character */
667 : 142781 : index = 1;
668 [ + + ]: 407590 : while ( index <= count )
669 : : {
670 : : /* get next character */
671 : 265437 : rc = trotListGetInt( listToSplit, index, &character );
672 : : PARANOID_ERR_IF( rc != TROT_RC_SUCCESS );
673 : :
674 : : /* if separator */
675 [ + + ]: 265437 : if ( character == separator )
676 : : {
677 : 61507 : trotListFree( &lPart );
678 : :
679 : 61507 : rc = trotListInit( &lPart );
680 [ + + ]: 61507 : ERR_IF_PASSTHROUGH;
681 : :
682 : 61187 : rc = trotListAppendList( newLPartList, lPart );
683 [ + + ]: 61187 : ERR_IF_PASSTHROUGH;
684 : : }
685 : : /* else add to current part */
686 : : else
687 : : {
688 : 203930 : rc = trotListAppendInt( lPart, character );
689 [ + + ]: 203930 : ERR_IF_PASSTHROUGH;
690 : : }
691 : :
692 : : /* increment index */
693 : 264809 : index += 1;
694 : : }
695 : :
696 : : /* give back */
697 : 142153 : (*lPartList_A) = newLPartList;
698 : 142153 : newLPartList = NULL;
699 : :
700 : :
701 : : /* CLEANUP */
702 : : cleanup:
703 : :
704 : 144567 : trotListFree( &newLPartList );
705 : 144567 : trotListFree( &lPart );
706 : :
707 : 144567 : return rc;
708 : : }
709 : :
710 : : /******************************************************************************/
711 : : /*!
712 : : \brief Takes a textual-reference and retrieves the correct list out of lTop
713 : : \param[in] lTop The top list.
714 : : \param[in] lPartList List that contains the parts of the textual-reference
715 : : \param[out] lReference_A On success, the list that the textual-reference
716 : : specified
717 : : \return TROT_RC
718 : :
719 : : Example:
720 : : If lTop is [ 85 [ 86 ] [ [ 87 ] ] ]
721 : : and lPartList is [ [ "@" ] [ "3" ] [ "1" ] ]
722 : : then lReference_A would the the list that's [ 87 ].
723 : : */
724 : 142153 : static TROT_RC getReferenceList( TrotList *lTop, TrotList *lPartList, TrotList **lReference_A )
725 : : {
726 : : /* DATA */
727 : 142153 : TROT_RC rc = TROT_RC_SUCCESS;
728 : :
729 : 142153 : TROT_INT partListCount = 0;
730 : 142153 : TROT_INT partListIndex = 0;
731 : :
732 : 142153 : TrotList *lPart = NULL;
733 : 142153 : TROT_INT partNumber = 0;
734 : 142153 : TROT_INT partCount = 0;
735 : :
736 : 142153 : TrotList *lParent = NULL;
737 : 142153 : TrotList *lChild = NULL;
738 : :
739 : :
740 : : /* PRECOND */
741 : : PARANOID_ERR_IF( lTop == NULL );
742 : : PARANOID_ERR_IF( lPartList == NULL );
743 : : PARANOID_ERR_IF( lReference_A == NULL );
744 : : PARANOID_ERR_IF( (*lReference_A) != NULL );
745 : :
746 : :
747 : : /* CODE */
748 : : /* get partListCount */
749 : 142153 : rc = trotListGetCount( lPartList, &partListCount );
750 : : PARANOID_ERR_IF( rc != TROT_RC_SUCCESS );
751 : :
752 : : /* get first part */
753 : 142153 : rc = trotListGetList( lPartList, 1, &lPart );
754 [ + + ]: 142153 : ERR_IF_PASSTHROUGH;
755 : :
756 : : /* first part must be '@'
757 : : we already know it starts with '@', so just make sure there's nothing
758 : : else in the part */
759 : 142059 : rc = trotListGetCount( lPart, &partCount );
760 : : PARANOID_ERR_IF( rc != TROT_RC_SUCCESS );
761 : :
762 [ + + ]: 142059 : ERR_IF_1( partCount != 1, TROT_RC_ERROR_DECODE, partCount );
763 : :
764 : : /* start parent */
765 : 142056 : rc = trotListTwin( lTop, &lParent );
766 [ + + ]: 142056 : ERR_IF_PASSTHROUGH;
767 : :
768 : : /* for each part, starting at 2 */
769 : 141962 : partListIndex = 2;
770 [ + + ]: 202859 : while ( partListIndex <= partListCount )
771 : : {
772 : : /* get part */
773 : 60984 : trotListFree( &lPart );
774 : 60984 : rc = trotListGetList( lPartList, partListIndex, &lPart );
775 [ + + ]: 60984 : ERR_IF_PASSTHROUGH;
776 : :
777 : : /* part into number */
778 : 60944 : rc = wordToNumber( lPart, &partNumber );
779 [ + + ]: 60944 : ERR_IF_PASSTHROUGH;
780 : :
781 : : /* must be positive */
782 [ + + ]: 60939 : ERR_IF_1( partNumber <= 0, TROT_RC_ERROR_DECODE, partNumber );
783 : :
784 : : /* get child of parent */
785 : 60937 : trotListFree( &lChild );
786 : 60937 : rc = trotListGetList( lParent, partNumber, &lChild );
787 [ + + ]: 60937 : ERR_IF_PASSTHROUGH;
788 : :
789 : : /* switchup parent and child, "go down" */
790 : 60897 : trotListFree( &lParent );
791 : 60897 : lParent = lChild;
792 : 60897 : lChild = NULL;
793 : :
794 : : /* increment */
795 : 60897 : partListIndex += 1;
796 : : }
797 : :
798 : :
799 : : /* give back */
800 : 141875 : (*lReference_A) = lParent;
801 : 141875 : lParent = NULL;
802 : :
803 : :
804 : : /* CLEANUP */
805 : : cleanup:
806 : :
807 : 142153 : trotListFree( &lPart );
808 : 142153 : trotListFree( &lParent );
809 : 142153 : trotListFree( &lChild );
810 : :
811 : 142153 : return rc;
812 : : }
813 : :
|