LCOV - code coverage report
Current view: top level - collection - collection_iter.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 132 150 88.0 %
Date: 2014-04-01 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /*
       2             :     COLLECTION LIBRARY
       3             : 
       4             :     Implementation of the collection library iterator functions.
       5             : 
       6             :     Copyright (C) Dmitri Pal <dpal@redhat.com> 2009
       7             : 
       8             :     Collection Library is free software: you can redistribute it and/or modify
       9             :     it under the terms of the GNU Lesser General Public License as published by
      10             :     the Free Software Foundation, either version 3 of the License, or
      11             :     (at your option) any later version.
      12             : 
      13             :     Collection Library is distributed in the hope that it will be useful,
      14             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :     GNU Lesser General Public License for more details.
      17             : 
      18             :     You should have received a copy of the GNU Lesser General Public License
      19             :     along with Collection Library.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "config.h"
      23             : #include <string.h>
      24             : #include <stdlib.h>
      25             : #include <errno.h>
      26             : #include <ctype.h>
      27             : #include <time.h>
      28             : #include "trace.h"
      29             : 
      30             : /* The collection should use the real structures */
      31             : #include "collection_priv.h"
      32             : #include "collection.h"
      33             : 
      34             : /* Depth for iterator depth allocation block */
      35             : #define STACK_DEPTH_BLOCK   15
      36             : 
      37             : /* Grow iteration stack */
      38         266 : static int col_grow_stack(struct collection_iterator *iterator, unsigned desired)
      39             : {
      40         266 :     int grow_by = 0;
      41             :     struct collection_item **temp;
      42             : 
      43             :     TRACE_FLOW_STRING("col_grow_stack", "Entry.");
      44             : 
      45         266 :     if (desired > iterator->stack_size) {
      46          82 :         grow_by = (((desired - iterator->stack_size) / STACK_DEPTH_BLOCK) + 1) * STACK_DEPTH_BLOCK;
      47          82 :         temp = (struct collection_item **)realloc(iterator->stack, grow_by * sizeof(struct collection_item *));
      48          82 :         if (temp == NULL) {
      49             :             TRACE_ERROR_NUMBER("Failed to allocate memory", ENOMEM);
      50           0 :             return ENOMEM;
      51             :         }
      52          82 :         iterator->stack = temp;
      53          82 :         iterator->stack_size += grow_by;
      54             :     }
      55             :     TRACE_FLOW_STRING("col_grow_stack", "Exit.");
      56         266 :     return EOK;
      57             : }
      58             : 
      59             : 
      60             : 
      61             : /* Bind iterator to a collection */
      62          82 : int col_bind_iterator(struct collection_iterator **iterator,
      63             :                       struct collection_item *ci,
      64             :                       int mode_flags)
      65             : {
      66             :     int error;
      67             :     struct collection_header *header;
      68          82 :     struct collection_iterator *iter = NULL;
      69             : 
      70             :     TRACE_FLOW_STRING("col_bind_iterator", "Entry.");
      71             : 
      72             :     /* Do some argument checking first */
      73          82 :     if ((iterator == NULL) || (ci == NULL)) {
      74             :         TRACE_ERROR_NUMBER("Invalid parameter.", EINVAL);
      75           0 :         return EINVAL;
      76             :     }
      77             : 
      78          82 :     iter = (struct collection_iterator *)malloc(sizeof(struct collection_iterator));
      79          82 :     if (iter == NULL) {
      80             :         TRACE_ERROR_NUMBER("Error allocating memory for the iterator.", ENOMEM);
      81           0 :         return ENOMEM;
      82             :     }
      83             : 
      84             :     /* Allocate memory for the stack */
      85          82 :     iter->stack = NULL;
      86          82 :     iter->stack_size = 0;
      87          82 :     iter->stack_depth = 0;
      88          82 :     iter->item_level = 0;
      89          82 :     iter->flags = mode_flags;
      90          82 :     iter->pin_level = 0;
      91          82 :     iter->can_break = 0;
      92             : 
      93             :     TRACE_INFO_NUMBER("Iterator flags", iter->flags);
      94             : 
      95             :     /* Allocate memory for stack */
      96          82 :     error = col_grow_stack(iter, 1);
      97          82 :     if(error) {
      98           0 :         free(iter);
      99             :         TRACE_ERROR_NUMBER("Error growing stack.", error);
     100           0 :         return error;
     101             :     }
     102             : 
     103             :     /* Create a special end item */
     104          82 :     error = col_allocate_item(&(iter->end_item), "", NULL, 0, COL_TYPE_END);
     105          82 :     if(error) {
     106           0 :         free(iter);
     107             :         TRACE_ERROR_NUMBER("Error allocating end item.", error);
     108           0 :         return error;
     109             :     }
     110             : 
     111             :     /* Make sure that we tie iterator to the collection */
     112          82 :     header = (struct collection_header *)ci->data;
     113          82 :     header->reference_count++;
     114          82 :     iter->top = ci;
     115          82 :     iter->pin = ci;
     116          82 :     *(iter->stack) = ci;
     117          82 :     iter->stack_depth++;
     118             : 
     119          82 :     *iterator = iter;
     120             : 
     121             :     TRACE_FLOW_STRING("col_bind_iterator", "Exit");
     122          82 :     return EOK;
     123             : }
     124             : 
     125             : /* Stop processing this subcollection and move to the next item in the
     126             :  * collection 'level' levels up.*/
     127           3 : int col_iterate_up(struct collection_iterator *iterator, unsigned level)
     128             : {
     129             :     TRACE_FLOW_STRING("iterate_up", "Entry");
     130             : 
     131           3 :     if (iterator == NULL) {
     132             :         TRACE_ERROR_NUMBER("Invalid parameter.", EINVAL);
     133           0 :         return EINVAL;
     134             :     }
     135             : 
     136             :     TRACE_INFO_NUMBER("Going up:", level);
     137             :     TRACE_INFO_NUMBER("Current stack depth:", iterator->stack_depth);
     138             : 
     139             :     /* If level is big just move to the top,
     140             :      * that will end the iteration process.
     141             :      */
     142           3 :     if (level >= iterator->stack_depth) iterator->stack_depth = 0;
     143           1 :     else iterator->stack_depth -= level;
     144             : 
     145             :     TRACE_INFO_NUMBER("Stack depth at the end:", iterator->stack_depth);
     146             :     TRACE_FLOW_STRING("col_iterate_up", "Exit");
     147           3 :     return EOK;
     148             : }
     149             : 
     150             : /* How deep are we relative to the top level.*/
     151          27 : int col_get_iterator_depth(struct collection_iterator *iterator, int *depth)
     152             : {
     153             :     TRACE_FLOW_STRING("col_get_iterator_depth", "Entry");
     154             : 
     155          27 :     if ((iterator == NULL) || (depth == NULL)) {
     156             :         TRACE_ERROR_NUMBER("Invalid parameter.", EINVAL);
     157           0 :         return EINVAL;
     158             :     }
     159             : 
     160          27 :     *depth = iterator->stack_depth - 1;
     161             : 
     162             :     TRACE_INFO_NUMBER("Stack depth at the end:", iterator->stack_depth);
     163             :     TRACE_FLOW_STRING("col_get_iterator_depth","Exit");
     164          27 :     return EOK;
     165             : }
     166             : 
     167             : /* What was the level of the last item we got? */
     168         751 : int col_get_item_depth(struct collection_iterator *iterator, int *depth)
     169             : {
     170             :     TRACE_FLOW_STRING("col_get_item_depth", "Entry");
     171             : 
     172         751 :     if ((iterator == NULL) || (depth == NULL)) {
     173             :         TRACE_ERROR_NUMBER("Invalid parameter.", EINVAL);
     174           0 :         return EINVAL;
     175             :     }
     176             : 
     177         751 :     *depth = iterator->item_level;
     178             : 
     179             :     TRACE_INFO_NUMBER("Item level at the end:", iterator->item_level);
     180             :     TRACE_FLOW_STRING("col_get_item_depth","Exit");
     181         751 :     return EOK;
     182             : }
     183             : 
     184             : 
     185             : 
     186             : /* Unbind the iterator from the collection */
     187          82 : void col_unbind_iterator(struct collection_iterator *iterator)
     188             : {
     189             :     TRACE_FLOW_STRING("col_unbind_iterator", "Entry.");
     190          82 :     if (iterator != NULL) {
     191          82 :         col_destroy_collection(iterator->top);
     192          82 :         col_delete_item(iterator->end_item);
     193          82 :         free(iterator->stack);
     194          82 :         free(iterator);
     195             :     }
     196             :     TRACE_FLOW_STRING("col_unbind_iterator", "Exit");
     197          82 : }
     198             : 
     199             : /* Get items from the collection one by one following the tree */
     200        1556 : int col_iterate_collection(struct collection_iterator *iterator,
     201             :                            struct collection_item **item)
     202             : {
     203             :     int error;
     204             :     struct collection_item *current;
     205             :     struct collection_item *other;
     206             : 
     207             :     TRACE_FLOW_STRING("col_iterate_collection", "Entry.");
     208             : 
     209             :     /* Check if we have storage for item */
     210        1556 :     if (item == NULL) {
     211             :         TRACE_ERROR_NUMBER("Invalid parameter.", EINVAL);
     212           0 :         return EINVAL;
     213             :     }
     214             : 
     215             :     while (1) {
     216             : 
     217             :         TRACE_INFO_NUMBER("Stack depth:", iterator->stack_depth);
     218             : 
     219        1758 :         if (iterator->stack_depth == 0) {
     220             :             /* Re-init so if we continue looping we start over */
     221          78 :             iterator->stack[0] = iterator->top;
     222          78 :             iterator->stack_depth++;
     223          78 :             iterator->item_level = 0;
     224             :         }
     225             : 
     226             :         /* Is current item available */
     227        1758 :         current = iterator->stack[iterator->stack_depth - 1];
     228        1758 :         iterator->item_level = iterator->stack_depth - 1;
     229             : 
     230             :         /* Are we done? */
     231        3025 :         if (((iterator->stack_depth - 1) == iterator->pin_level) &&
     232        1267 :             (iterator->pin == current)) {
     233         196 :             if (iterator->can_break) {
     234             :                 TRACE_FLOW_STRING("We are done.", "");
     235          78 :                 *item = NULL;
     236          78 :                 iterator->can_break = 0;
     237          78 :                 return EOK;
     238             :             }
     239         118 :             else iterator->can_break = 1;
     240             :         }
     241             : 
     242             :         /* We are not done so check if we have an item  */
     243        1680 :         if (current != NULL) {
     244             : 
     245             :             TRACE_INFO_STRING("Current item:", current->property);
     246             :             TRACE_INFO_NUMBER("Current item type:", current->type);
     247             : 
     248             :             /* Is this a collection reference */
     249        1465 :             if (current->type == COL_TYPE_COLLECTIONREF) {
     250             :                 /* We do follow references? */
     251             :                 TRACE_INFO_STRING("Current item:", "collection reference");
     252         184 :                 if ((iterator->flags & COL_TRAVERSE_IGNORE) == 0) {
     253             :                     /* We should not ignore - then move on */
     254             :                     TRACE_INFO_STRING("Collection references are not ignored", "");
     255         184 :                     error = col_grow_stack(iterator, iterator->stack_depth + 1);
     256         184 :                     if (error) {
     257             :                         TRACE_ERROR_NUMBER("Error growing stack.", error);
     258           0 :                         return error;
     259             :                     }
     260             :                     /* Do we need to go deeper than one level ? */
     261         184 :                     if ((iterator->flags & COL_TRAVERSE_ONELEVEL) == 0) {
     262             :                         TRACE_INFO_STRING("Need to go deeper", "");
     263             :                         /* We need to go deeper... */
     264             :                         /* Do we need to show headers but not reference? */
     265         144 :                         if ((iterator->flags & COL_TRAVERSE_ONLYSUB) != 0) {
     266             :                             TRACE_INFO_STRING("Instructed to show header not reference", "");
     267           3 :                             other = *((struct collection_item **)current->data);
     268           3 :                             iterator->stack[iterator->stack_depth] = other->next;
     269           3 :                             iterator->item_level = iterator->stack_depth;
     270           3 :                             *item = other;
     271             :                         }
     272             :                         /* Do we need to show both? */
     273         141 :                         else if ((iterator->flags & COL_TRAVERSE_SHOWSUB) != 0) {
     274             :                             TRACE_INFO_STRING("Instructed to show header and reference","");
     275           6 :                             iterator->stack[iterator->stack_depth] = *((struct collection_item **)(current->data));
     276           6 :                             *item = current;
     277             :                             /* Do not need to adjust level here */
     278             :                         }
     279             :                         /* Do not show either */
     280         135 :                         else if ((iterator->flags & COL_TRAVERSE_FLAT) != 0) {
     281             :                             TRACE_INFO_STRING("Instructed not to show header and reference","");
     282          77 :                             other = *((struct collection_item **)current->data);
     283          77 :                             iterator->stack[iterator->stack_depth] = other->next;
     284          77 :                             iterator->stack[iterator->stack_depth - 1] = current->next;
     285          77 :                             iterator->stack_depth++;
     286             :                             /* Do not need to adjust level here */
     287          77 :                             continue;
     288             :                         }
     289             :                         /* We need to show reference only */
     290             :                         else {
     291             :                             TRACE_INFO_STRING("Instructed to show reference only", "");
     292          58 :                             other = *((struct collection_item **)current->data);
     293             :                             TRACE_INFO_STRING("Sub collection:", other->property);
     294             :                             TRACE_INFO_NUMBER("Sub collection type:", other->type);
     295          58 :                             iterator->stack[iterator->stack_depth] = other->next;
     296          58 :                             if (other->next != NULL) {
     297             :                                 TRACE_INFO_STRING("Will show this item next time:", other->next->property);
     298             :                                 TRACE_INFO_NUMBER("Will show this item next time type:", other->next->type);
     299             :                             }
     300          58 :                             *item = current;
     301             :                             TRACE_INFO_NUMBER("Level of the reference:", iterator->item_level);
     302             :                             /* Do not need to adjust level here */
     303             :                         }
     304             : 
     305             :                         TRACE_INFO_STRING("We return item:", (*item)->property);
     306             :                         TRACE_INFO_NUMBER("We return item type:", (*item)->type);
     307             :                         TRACE_INFO_STRING("Moving to the next item on the previous item in stack", "");
     308          67 :                         iterator->stack[iterator->stack_depth - 1] = current->next;
     309          67 :                         iterator->stack_depth++;
     310             : 
     311             :                     }
     312             :                     else {
     313             :                         TRACE_INFO_STRING("Instructed to parse just one level", "");
     314             :                         /* On one level - just return current */
     315          40 :                         *item = current;
     316             :                         TRACE_INFO_STRING("Moving to the next item on one level", "");
     317          40 :                         iterator->stack[iterator->stack_depth - 1] = current->next;
     318             :                     }
     319         107 :                     break;
     320             :                 }
     321             :                 else {
     322             :                     /* We need to ignore references so move to the next item */
     323             :                     TRACE_INFO_STRING("Stepping over the reference", "");
     324           0 :                     iterator->stack[iterator->stack_depth - 1] = current->next;
     325           0 :                     continue;
     326             :                 }
     327             :             }
     328             :             else {
     329             :                 /* Got a normal item - return it and move to the next one */
     330        1403 :                 if ((current->type == COL_TYPE_COLLECTION) &&
     331         149 :                     ((iterator->flags & COL_TRAVERSE_FLAT) != 0) &&
     332          27 :                     (iterator->stack_depth > 1)) {
     333             :                     TRACE_INFO_STRING("Header of the sub collection in flat case ", "");
     334           0 :                     iterator->stack[iterator->stack_depth - 1] = current->next;
     335           0 :                     continue;
     336             :                 }
     337             :                 else {
     338             :                     TRACE_INFO_STRING("Simple item", "");
     339        1281 :                     *item = current;
     340        1281 :                     iterator->stack[iterator->stack_depth - 1] = current->next;
     341             :                 }
     342        1281 :                 break;
     343             :             }
     344             :         }
     345             :         else {
     346             :             /* Item is NULL */
     347             :             TRACE_INFO_STRING("Finished level", "moving to upper level");
     348         215 :             iterator->stack_depth--;
     349             :             /* Remember that item_level is zero based while depth is size
     350             :              * so we decrease and then assign. */
     351             :             TRACE_INFO_NUMBER("Stack depth at the end:", iterator->stack_depth);
     352         215 :             if ((iterator->flags & COL_TRAVERSE_END) != 0) {
     353             : 
     354             :                 /* Show end element
     355             :                  * a) If we are flattening but at the top
     356             :                  * b) We are not flattening
     357             :                  */
     358         255 :                 if ((((iterator->flags & COL_TRAVERSE_FLAT) != 0) &&
     359         232 :                      (iterator->stack_depth == 0)) ||
     360         138 :                     ((iterator->flags & COL_TRAVERSE_FLAT) == 0)) {
     361             : 
     362             :                     /* Return dummy entry to indicate the end of the collection */
     363             :                     TRACE_INFO_STRING("Finished level", "told to return END");
     364          90 :                     *item = iterator->end_item;
     365          90 :                     break;
     366             :                 }
     367             :             }
     368             :             else {
     369             :                 /* Move to next level */
     370          54 :                 continue;
     371             :             }
     372             :         }
     373         202 :     }
     374             : 
     375             :     TRACE_FLOW_STRING("col_iterate_collection", "Exit");
     376        1478 :     return EOK;
     377             : }
     378             : 
     379             : 
     380             : /* Pins down the iterator to loop around this point */
     381           2 : void col_pin_iterator(struct collection_iterator *iterator)
     382             : {
     383             :     TRACE_FLOW_STRING("col_iterator_add_pin", "Entry");
     384             : 
     385           2 :     if ((!iterator) || (!iterator->stack)) {
     386             :         TRACE_FLOW_STRING("Invalid itertor", "Ingoring");
     387           2 :         return;
     388             :     }
     389             : 
     390          10 :     while ((iterator->stack_depth) &&
     391           4 :            (iterator->stack[iterator->stack_depth - 1] == NULL)) {
     392           2 :         iterator->stack_depth--;
     393             :     }
     394             : 
     395           2 :     if (iterator->stack_depth == 0) {
     396           0 :         iterator->pin = iterator->top;
     397           0 :         iterator->pin_level = 0;
     398             :     }
     399             :     else {
     400           2 :         iterator->pin = iterator->stack[iterator->stack_depth - 1];
     401           2 :         iterator->pin_level = iterator->stack_depth - 1;
     402             :     }
     403           2 :     iterator->can_break = 0;
     404             : 
     405             :     TRACE_FLOW_STRING("col_iterator_add_pin", "Exit");
     406             : }
     407             : 
     408             : 
     409             : /* Rewinds iterator to the beginning */
     410          41 : void col_rewind_iterator(struct collection_iterator *iterator)
     411             : {
     412             :     TRACE_FLOW_STRING("col_rewind_iterator", "Entry");
     413             : 
     414          41 :     if ((!iterator) || (!iterator->stack)) {
     415             :         TRACE_FLOW_STRING("Invalid itertor", "Ingoring");
     416          41 :         return;
     417             :     }
     418             : 
     419          41 :     iterator->pin = iterator->top;
     420          41 :     iterator->stack[0] = iterator->top;
     421          41 :     iterator->stack_depth = 1;
     422          41 :     iterator->item_level = 0;
     423          41 :     iterator->pin_level = 0;
     424          41 :     iterator->can_break = 0;
     425             : 
     426             :     TRACE_FLOW_STRING("col_rewind_iterator", "Exit");
     427             : }

Generated by: LCOV version 1.10