00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 #include "config.h"
00039 #include "mxml.h"
00040 
00041 
00042 
00043 
00044 
00045 
00046 static int      index_compare(mxml_index_t *ind, mxml_node_t *first,
00047                               mxml_node_t *second);
00048 static int      index_find(mxml_index_t *ind, const char *element,
00049                            const char *value, mxml_node_t *node);
00050 static void     index_sort(mxml_index_t *ind, int left, int right);
00051 
00052 
00053 
00054 
00055 
00056 
00057 void
00058 mxmlIndexDelete(mxml_index_t *ind)      
00059 {
00060  
00061 
00062 
00063 
00064   if (!ind)
00065     return;
00066 
00067  
00068 
00069 
00070 
00071   if (ind->attr)
00072     free(ind->attr);
00073 
00074   if (ind->alloc_nodes)
00075     free(ind->nodes);
00076 
00077   free(ind);
00078 }
00079 
00080 
00081 
00082 
00083 
00084 
00085 
00086 
00087 mxml_node_t *                           
00088 mxmlIndexEnum(mxml_index_t *ind)        
00089 {
00090  
00091 
00092 
00093 
00094   if (!ind)
00095     return (NULL);
00096 
00097  
00098 
00099 
00100 
00101   if (ind->cur_node < ind->num_nodes)
00102     return (ind->nodes[ind->cur_node ++]);
00103   else
00104     return (NULL);
00105 }
00106 
00107 
00108 
00109 
00110 
00111 
00112 
00113 
00114 
00115 
00116 
00117 mxml_node_t *                           
00118 mxmlIndexFind(mxml_index_t *ind,        
00119               const char   *element,    
00120               const char   *value)      
00121 {
00122   int           diff,                   
00123                 current,                
00124                 first,                  
00125                 last;                   
00126 
00127 
00128 #ifdef DEBUG
00129   printf("mxmlIndexFind(ind=%p, element=\"%s\", value=\"%s\")\n",
00130          ind, element ? element : "(null)", value ? value : "(null)");
00131 #endif 
00132 
00133  
00134 
00135 
00136 
00137   if (!ind || (!ind->attr && value))
00138   {
00139 #ifdef DEBUG
00140     puts("    returning NULL...");
00141     printf("    ind->attr=\"%s\"\n", ind->attr ? ind->attr : "(null)");
00142 #endif 
00143 
00144     return (NULL);
00145   }
00146 
00147  
00148 
00149 
00150 
00151 
00152   if (!element && !value)
00153     return (mxmlIndexEnum(ind));
00154 
00155  
00156 
00157 
00158 
00159   if (!ind->num_nodes)
00160   {
00161 #ifdef DEBUG
00162     puts("    returning NULL...");
00163     puts("    no nodes!");
00164 #endif 
00165 
00166     return (NULL);
00167   }
00168 
00169  
00170 
00171 
00172 
00173   if (ind->cur_node == 0)
00174   {
00175    
00176 
00177 
00178 
00179     first = 0;
00180     last  = ind->num_nodes - 1;
00181 
00182 #ifdef DEBUG
00183     printf("    find first time, num_nodes=%d...\n", ind->num_nodes);
00184 #endif 
00185 
00186     while ((last - first) > 1)
00187     {
00188       current = (first + last) / 2;
00189 
00190 #ifdef DEBUG
00191       printf("    first=%d, last=%d, current=%d\n", first, last, current);
00192 #endif 
00193 
00194       if ((diff = index_find(ind, element, value, ind->nodes[current])) == 0)
00195       {
00196        
00197 
00198 
00199 
00200 #ifdef DEBUG
00201         puts("    match!");
00202 #endif 
00203 
00204         while (current > 0 &&
00205                !index_find(ind, element, value, ind->nodes[current - 1]))
00206           current --;
00207 
00208 #ifdef DEBUG
00209         printf("    returning first match=%d\n", current);
00210 #endif 
00211 
00212        
00213 
00214 
00215 
00216         ind->cur_node = current + 1;
00217 
00218         return (ind->nodes[current]);
00219       }
00220       else if (diff < 0)
00221         last = current;
00222       else
00223         first = current;
00224 
00225 #ifdef DEBUG
00226       printf("    diff=%d\n", diff);
00227 #endif 
00228     }
00229 
00230    
00231 
00232 
00233 
00234     for (current = first; current <= last; current ++)
00235       if (!index_find(ind, element, value, ind->nodes[current]))
00236       {
00237        
00238 
00239 
00240 
00241 #ifdef DEBUG
00242         printf("    returning only match %d...\n", current);
00243 #endif 
00244 
00245         ind->cur_node = current + 1;
00246 
00247         return (ind->nodes[current]);
00248       }
00249 
00250    
00251 
00252 
00253 
00254     ind->cur_node = ind->num_nodes;
00255 
00256 #ifdef DEBUG
00257     puts("    returning NULL...");
00258 #endif 
00259 
00260     return (NULL);
00261   }
00262   else if (ind->cur_node < ind->num_nodes &&
00263            !index_find(ind, element, value, ind->nodes[ind->cur_node]))
00264   {
00265    
00266 
00267 
00268 
00269 #ifdef DEBUG
00270     printf("    returning next match %d...\n", ind->cur_node);
00271 #endif 
00272 
00273     return (ind->nodes[ind->cur_node ++]);
00274   }
00275 
00276  
00277 
00278 
00279 
00280   ind->cur_node = ind->num_nodes;
00281 
00282 #ifdef DEBUG
00283   puts("    returning NULL...");
00284 #endif 
00285 
00286   return (NULL);
00287 }
00288 
00289 
00290 
00291 
00292 
00293 
00294 
00295 
00296 
00297 
00298 
00299 
00300 mxml_index_t *                          
00301 mxmlIndexNew(mxml_node_t *node,         
00302              const char  *element,      
00303              const char  *attr)         
00304 {
00305   mxml_index_t  *ind;                   
00306   mxml_node_t   *current,               
00307                 **temp;                 
00308 
00309 
00310  
00311 
00312 
00313 
00314 #ifdef DEBUG
00315   printf("mxmlIndexNew(node=%p, element=\"%s\", attr=\"%s\")\n",
00316          node, element ? element : "(null)", attr ? attr : "(null)");
00317 #endif 
00318 
00319   if (!node)
00320     return (NULL);
00321 
00322  
00323 
00324 
00325 
00326   if ((ind = calloc(1, sizeof(mxml_index_t))) == NULL)
00327   {
00328     mxml_error("Unable to allocate %d bytes for index - %s",
00329                sizeof(mxml_index_t), strerror(errno));
00330     return (NULL);
00331   }
00332 
00333   if (attr)
00334     ind->attr = strdup(attr);
00335 
00336   if (!element && !attr)
00337     current = node;
00338   else
00339     current = mxmlFindElement(node, node, element, attr, NULL, MXML_DESCEND);
00340 
00341   while (current)
00342   {
00343     if (ind->num_nodes >= ind->alloc_nodes)
00344     {
00345       if (!ind->alloc_nodes)
00346         temp = malloc(64 * sizeof(mxml_node_t *));
00347       else
00348         temp = realloc(ind->nodes, (ind->alloc_nodes + 64) * sizeof(mxml_node_t *));
00349 
00350       if (!temp)
00351       {
00352        
00353 
00354 
00355 
00356         mxml_error("Unable to allocate %d bytes for index: %s",
00357                    (ind->alloc_nodes + 64) * sizeof(mxml_node_t *),
00358                    strerror(errno));
00359 
00360         mxmlIndexDelete(ind);
00361         return (NULL);
00362       }
00363 
00364       ind->nodes       = temp;
00365       ind->alloc_nodes += 64;
00366     }
00367 
00368     ind->nodes[ind->num_nodes ++] = current;
00369 
00370     current = mxmlFindElement(current, node, element, attr, NULL, MXML_DESCEND);
00371   }
00372 
00373  
00374 
00375 
00376 
00377 #ifdef DEBUG
00378   {
00379     int i;                              
00380 
00381 
00382     printf("%d node(s) in index.\n\n", ind->num_nodes);
00383 
00384     if (attr)
00385     {
00386       printf("Node      Address   Element         %s\n", attr);
00387       puts("--------  --------  --------------  ------------------------------");
00388 
00389       for (i = 0; i < ind->num_nodes; i ++)
00390         printf("%8d  %-8p  %-14.14s  %s\n", i, ind->nodes[i],
00391                ind->nodes[i]->value.element.name,
00392                mxmlElementGetAttr(ind->nodes[i], attr));
00393     }
00394     else
00395     {
00396       puts("Node      Address   Element");
00397       puts("--------  --------  --------------");
00398 
00399       for (i = 0; i < ind->num_nodes; i ++)
00400         printf("%8d  %-8p  %s\n", i, ind->nodes[i],
00401                ind->nodes[i]->value.element.name);
00402     }
00403 
00404     putchar('\n');
00405   }
00406 #endif 
00407 
00408   if (ind->num_nodes > 1)
00409     index_sort(ind, 0, ind->num_nodes - 1);
00410 
00411 #ifdef DEBUG
00412   {
00413     int i;                              
00414 
00415 
00416     puts("After sorting:\n");
00417 
00418     if (attr)
00419     {
00420       printf("Node      Address   Element         %s\n", attr);
00421       puts("--------  --------  --------------  ------------------------------");
00422 
00423       for (i = 0; i < ind->num_nodes; i ++)
00424         printf("%8d  %-8p  %-14.14s  %s\n", i, ind->nodes[i],
00425                ind->nodes[i]->value.element.name,
00426                mxmlElementGetAttr(ind->nodes[i], attr));
00427     }
00428     else
00429     {
00430       puts("Node      Address   Element");
00431       puts("--------  --------  --------------");
00432 
00433       for (i = 0; i < ind->num_nodes; i ++)
00434         printf("%8d  %-8p  %s\n", i, ind->nodes[i],
00435                ind->nodes[i]->value.element.name);
00436     }
00437 
00438     putchar('\n');
00439   }
00440 #endif 
00441 
00442  
00443 
00444 
00445 
00446   return (ind);
00447 }
00448 
00449 
00450 
00451 
00452 
00453 
00454 
00455 
00456 
00457 
00458 mxml_node_t *                           
00459 mxmlIndexReset(mxml_index_t *ind)       
00460 {
00461 #ifdef DEBUG
00462   printf("mxmlIndexReset(ind=%p)\n", ind);
00463 #endif 
00464 
00465  
00466 
00467 
00468 
00469   if (!ind)
00470     return (NULL);
00471 
00472  
00473 
00474 
00475 
00476   ind->cur_node = 0;
00477 
00478  
00479 
00480 
00481 
00482   if (ind->num_nodes)
00483     return (ind->nodes[0]);
00484   else
00485     return (NULL);
00486 }
00487 
00488 
00489 
00490 
00491 
00492 
00493 static int                              
00494 index_compare(mxml_index_t *ind,        
00495               mxml_node_t  *first,      
00496               mxml_node_t  *second)     
00497 {
00498   int   diff;                           
00499 
00500 
00501  
00502 
00503 
00504 
00505   if ((diff = strcmp(first->value.element.name,
00506                      second->value.element.name)) != 0)
00507     return (diff);
00508 
00509  
00510 
00511 
00512 
00513   if (ind->attr)
00514   {
00515     if ((diff = strcmp(mxmlElementGetAttr(first, ind->attr),
00516                        mxmlElementGetAttr(second, ind->attr))) != 0)
00517       return (diff);
00518   }
00519 
00520  
00521 
00522 
00523 
00524   return (0);
00525 }
00526 
00527 
00528 
00529 
00530 
00531 
00532 static int                              
00533 index_find(mxml_index_t *ind,           
00534            const char   *element,       
00535            const char   *value,         
00536            mxml_node_t  *node)          
00537 {
00538   int   diff;                           
00539 
00540 
00541  
00542 
00543 
00544 
00545   if (element)
00546   {
00547     if ((diff = strcmp(element, node->value.element.name)) != 0)
00548       return (diff);
00549   }
00550 
00551  
00552 
00553 
00554 
00555   if (value)
00556   {
00557     if ((diff = strcmp(value, mxmlElementGetAttr(node, ind->attr))) != 0)
00558       return (diff);
00559   }
00560 
00561  
00562 
00563 
00564 
00565   return (0);
00566 }
00567 
00568 
00569 
00570 
00571 
00572 
00573 
00574 
00575 static void
00576 index_sort(mxml_index_t *ind,           
00577            int          left,           
00578            int          right)          
00579 {
00580   mxml_node_t   *pivot,                 
00581                 *temp;                  
00582   int           templ,                  
00583                 tempr;                  
00584 
00585 
00586  
00587 
00588 
00589 
00590   do
00591   {
00592    
00593 
00594 
00595 
00596     pivot = ind->nodes[left];
00597 
00598     for (templ = left, tempr = right; templ < tempr;)
00599     {
00600      
00601 
00602 
00603 
00604       while ((templ < right) &&
00605              index_compare(ind, ind->nodes[templ], pivot) <= 0)
00606         templ ++;
00607 
00608      
00609 
00610 
00611 
00612       while ((tempr > left) &&
00613              index_compare(ind, ind->nodes[tempr], pivot) > 0)
00614         tempr --;
00615 
00616      
00617 
00618 
00619 
00620       if (templ < tempr)
00621       {
00622         temp              = ind->nodes[templ];
00623         ind->nodes[templ] = ind->nodes[tempr];
00624         ind->nodes[tempr] = temp;
00625       }
00626     }
00627 
00628    
00629 
00630 
00631 
00632 
00633     if (index_compare(ind, pivot, ind->nodes[tempr]) > 0)
00634     {
00635       ind->nodes[left]  = ind->nodes[tempr];
00636       ind->nodes[tempr] = pivot;
00637     }
00638 
00639    
00640 
00641 
00642 
00643     if (left < (tempr - 1))
00644       index_sort(ind, left, tempr - 1);
00645   }
00646   while (right > (left = tempr + 1));
00647 }
00648 
00649 
00650 
00651 
00652