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