1 /* 2 * Copyright 2002 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * prof_tree.c --- these routines maintain the parse tree of the 10 * config file. 11 * 12 * All of the details of how the tree is stored is abstracted away in 13 * this file; all of the other profile routines build, access, and 14 * modify the tree via the accessor functions found in this file. 15 * 16 * Each node may represent either a relation or a section header. 17 * 18 * A section header must have its value field set to 0, and may a one 19 * or more child nodes, pointed to by first_child. 20 * 21 * A relation has as its value a pointer to allocated memory 22 * containing a string. Its first_child pointer must be null. 23 * 24 */ 25 26 #include <stdio.h> 27 #include <string.h> 28 #ifdef HAVE_STDLIB_H 29 #include <stdlib.h> 30 #endif 31 #include <errno.h> 32 #include <ctype.h> 33 34 #include "prof_int.h" 35 36 struct profile_node { 37 errcode_t magic; 38 char *name; 39 char *value; 40 int group_level; 41 int final:1; /* Indicate don't search next file */ 42 struct profile_node *first_child; 43 struct profile_node *parent; 44 struct profile_node *next, *prev; 45 }; 46 47 #define CHECK_MAGIC(node) \ 48 if ((node)->magic != PROF_MAGIC_NODE) \ 49 return PROF_MAGIC_NODE; 50 51 /* 52 * Free a node, and any children 53 */ 54 void profile_free_node(node) 55 struct profile_node *node; 56 { 57 struct profile_node *child, *next; 58 59 if (node->magic != PROF_MAGIC_NODE) 60 return; 61 62 if (node->name) 63 free(node->name); 64 if (node->value) 65 free(node->value); 66 67 for (child=node->first_child; child; child = next) { 68 next = child->next; 69 profile_free_node(child); 70 } 71 node->magic = 0; 72 73 free(node); 74 } 75 76 /* 77 * Create a node 78 */ 79 errcode_t profile_create_node(name, value, ret_node) 80 const char *name, *value; 81 struct profile_node **ret_node; 82 { 83 struct profile_node *new; 84 85 new = (struct profile_node *)malloc(sizeof(struct profile_node)); 86 if (!new) 87 return ENOMEM; 88 memset(new, 0, sizeof(struct profile_node)); 89 new->name = (char *) malloc(strlen(name)+1); 90 if (new->name == 0) { 91 profile_free_node(new); 92 return ENOMEM; 93 } 94 strcpy(new->name, name); 95 if (value) { 96 new->value = (char *) malloc(strlen(value)+1); 97 if (new->value == 0) { 98 profile_free_node(new); 99 return ENOMEM; 100 } 101 strcpy(new->value, value); 102 } 103 new->magic = PROF_MAGIC_NODE; 104 105 *ret_node = new; 106 return 0; 107 } 108 109 /* 110 * This function verifies that all of the representation invarients of 111 * the profile are true. If not, we have a programming bug somewhere, 112 * probably in this file. 113 */ 114 errcode_t profile_verify_node(node) 115 struct profile_node *node; 116 { 117 struct profile_node *p, *last; 118 errcode_t retval; 119 120 CHECK_MAGIC(node); 121 122 if (node->value && node->first_child) 123 return PROF_SECTION_WITH_VALUE; 124 125 last = 0; 126 for (p = node->first_child; p; last = p, p = p->next) { 127 if (p->prev != last) 128 return PROF_BAD_LINK_LIST; 129 if (last && (last->next != p)) 130 return PROF_BAD_LINK_LIST; 131 if (node->group_level+1 != p->group_level) 132 return PROF_BAD_GROUP_LVL; 133 if (p->parent != node) 134 return PROF_BAD_PARENT_PTR; 135 retval = profile_verify_node(p); 136 if (retval) 137 return retval; 138 } 139 return 0; 140 } 141 142 /* 143 * Add a node to a particular section 144 */ 145 errcode_t profile_add_node(section, name, value, ret_node) 146 struct profile_node *section; 147 const char *name, *value; 148 struct profile_node **ret_node; 149 { 150 errcode_t retval; 151 struct profile_node *p, *last, *new; 152 int cmp = -1; 153 154 CHECK_MAGIC(section); 155 156 if (section->value) 157 return PROF_ADD_NOT_SECTION; 158 159 /* 160 * Find the place to insert the new node. We look for the 161 * place *after* the last match of the node name, since 162 * order matters. 163 */ 164 for (p=section->first_child, last = 0; p; last = p, p = p->next) { 165 cmp = strcmp(p->name, name); 166 if (cmp > 0) 167 break; 168 } 169 retval = profile_create_node(name, value, &new); 170 if (retval) 171 return retval; 172 new->group_level = section->group_level+1; 173 new->parent = section; 174 new->prev = last; 175 new->next = p; 176 if (p) 177 p->prev = new; 178 if (last) 179 last->next = new; 180 else 181 section->first_child = new; 182 if (ret_node) 183 *ret_node = new; 184 return 0; 185 } 186 187 /* 188 * Set the final flag on a particular node. 189 */ 190 errcode_t profile_make_node_final(node) 191 struct profile_node *node; 192 { 193 CHECK_MAGIC(node); 194 195 node->final = 1; 196 return 0; 197 } 198 199 /* 200 * Check the final flag on a node 201 */ 202 int profile_is_node_final(node) 203 struct profile_node *node; 204 { 205 return (node->final != 0); 206 } 207 208 /* 209 * Return the name of a node. (Note: this is for internal functions 210 * only; if the name needs to be returned from an exported function, 211 * strdup it first!) 212 */ 213 const char *profile_get_node_name(node) 214 struct profile_node *node; 215 { 216 return node->name; 217 } 218 219 /* 220 * Return the value of a node. (Note: this is for internal functions 221 * only; if the name needs to be returned from an exported function, 222 * strdup it first!) 223 */ 224 const char *profile_get_node_value(node) 225 struct profile_node *node; 226 { 227 return node->value; 228 } 229 230 /* 231 * Iterate through the section, returning the nodes which match 232 * the given name. If name is NULL, then interate through all the 233 * nodes in the section. If section_flag is non-zero, only return the 234 * section which matches the name; don't return relations. If value 235 * is non-NULL, then only return relations which match the requested 236 * value. (The value argument is ignored if section_flag is non-zero.) 237 * 238 * The first time this routine is called, the state pointer must be 239 * null. When this profile_find_node_relation() returns, if the state 240 * pointer is non-NULL, then this routine should be called again. 241 * (This won't happen if section_flag is non-zero, obviously.) 242 * 243 */ 244 errcode_t profile_find_node(section, name, value, section_flag, state, node) 245 struct profile_node *section; 246 const char *name; 247 const char *value; 248 int section_flag; 249 void **state; 250 struct profile_node **node; 251 { 252 struct profile_node *p; 253 254 CHECK_MAGIC(section); 255 p = *state; 256 if (p) { 257 CHECK_MAGIC(p); 258 } else 259 p = section->first_child; 260 261 for (; p; p = p->next) { 262 if (name && (strcmp(p->name, name))) 263 continue; 264 if (section_flag) { 265 if (p->value) 266 continue; 267 } else { 268 if (!p->value) 269 continue; 270 if (value && (strcmp(p->value, value))) 271 continue; 272 } 273 /* A match! */ 274 if (node) 275 *node = p; 276 break; 277 } 278 if (p == 0) { 279 *state = 0; 280 return section_flag ? PROF_NO_SECTION : PROF_NO_RELATION; 281 } 282 /* 283 * OK, we've found one match; now let's try to find another 284 * one. This way, if we return a non-zero state pointer, 285 * there's guaranteed to be another match that's returned. 286 */ 287 for (p = p->next; p; p = p->next) { 288 if (name && (strcmp(p->name, name))) 289 continue; 290 if (section_flag) { 291 if (p->value) 292 continue; 293 } else { 294 if (!p->value) 295 continue; 296 if (value && (strcmp(p->value, value))) 297 continue; 298 } 299 /* A match! */ 300 break; 301 } 302 *state = p; 303 return 0; 304 } 305 306 307 /* 308 * Iterate through the section, returning the relations which match 309 * the given name. If name is NULL, then interate through all the 310 * relations in the section. The first time this routine is called, 311 * the state pointer must be null. When this profile_find_node_relation() 312 * returns, if the state pointer is non-NULL, then this routine should 313 * be called again. 314 * 315 * The returned character string in value points to the stored 316 * character string in the parse string. Before this string value is 317 * returned to a calling application (profile_find_node_relation is not an 318 * exported interface), it should be strdup()'ed. 319 */ 320 errcode_t profile_find_node_relation(section, name, state, ret_name, value) 321 struct profile_node *section; 322 const char *name; 323 void **state; 324 char **ret_name, **value; 325 { 326 struct profile_node *p; 327 errcode_t retval; 328 329 retval = profile_find_node(section, name, 0, 0, state, &p); 330 if (retval) 331 return retval; 332 333 if (p) { 334 if (value) 335 *value = p->value; 336 if (ret_name) 337 *ret_name = p->name; 338 } 339 return 0; 340 } 341 342 /* 343 * Iterate through the section, returning the subsections which match 344 * the given name. If name is NULL, then interate through all the 345 * subsections in the section. The first time this routine is called, 346 * the state pointer must be null. When this profile_find_node_subsection() 347 * returns, if the state pointer is non-NULL, then this routine should 348 * be called again. 349 * 350 * This is (plus accessor functions for the name and value given a 351 * profile node) makes this function mostly syntactic sugar for 352 * profile_find_node. 353 */ 354 errcode_t profile_find_node_subsection(section, name, state, ret_name, 355 subsection) 356 struct profile_node *section; 357 const char *name; 358 void **state; 359 char **ret_name; 360 struct profile_node **subsection; 361 { 362 struct profile_node *p; 363 errcode_t retval; 364 365 if (section == (struct profile_node *)NULL) 366 return (PROF_NO_PROFILE); 367 368 retval = profile_find_node(section, name, 0, 1, state, &p); 369 if (retval) 370 return retval; 371 372 if (p) { 373 if (subsection) 374 *subsection = p; 375 if (ret_name) 376 *ret_name = p->name; 377 } 378 return 0; 379 } 380 381 /* 382 * This function returns the parent of a particular node. 383 */ 384 errcode_t profile_get_node_parent(section, parent) 385 struct profile_node *section, **parent; 386 { 387 *parent = section->parent; 388 return 0; 389 } 390 391 /* 392 * This is a general-purpose iterator for returning all nodes that 393 * match the specified name array. 394 */ 395 struct profile_iterator { 396 prf_magic_t magic; 397 profile_t profile; 398 int flags; 399 const char **names; 400 const char *name; 401 prf_file_t file; 402 int file_serial; 403 int done_idx; 404 struct profile_node *node; 405 int num; 406 }; 407 408 errcode_t profile_node_iterator_create(profile, names, flags, ret_iter) 409 profile_t profile; 410 const char **names; 411 int flags; 412 void **ret_iter; 413 { 414 struct profile_iterator *iter; 415 int done_idx = 0; 416 417 if (profile == 0) 418 return PROF_NO_PROFILE; 419 if (profile->magic != PROF_MAGIC_PROFILE) 420 return PROF_MAGIC_PROFILE; 421 if (!names) 422 return PROF_BAD_NAMESET; 423 if (!(flags & PROFILE_ITER_LIST_SECTION)) { 424 if (!names[0]) 425 return PROF_BAD_NAMESET; 426 done_idx = 1; 427 } 428 429 if ((iter = (struct profile_iterator *) 430 malloc(sizeof(struct profile_iterator))) == NULL) 431 return ENOMEM; 432 433 iter->magic = PROF_MAGIC_ITERATOR; 434 iter->profile = profile; 435 iter->names = names; 436 iter->flags = flags; 437 iter->file = profile->first_file; 438 iter->done_idx = done_idx; 439 iter->node = 0; 440 iter->num = 0; 441 *ret_iter = iter; 442 return 0; 443 } 444 445 void profile_node_iterator_free(iter_p) 446 void **iter_p; 447 { 448 struct profile_iterator *iter; 449 450 if (!iter_p) 451 return; 452 iter = *iter_p; 453 if (!iter || iter->magic != PROF_MAGIC_ITERATOR) 454 return; 455 free(iter); 456 *iter_p = 0; 457 } 458 459 /* 460 * Note: the returned character strings in ret_name and ret_value 461 * points to the stored character string in the parse string. Before 462 * this string value is returned to a calling application 463 * (profile_node_iterator is not an exported interface), it should be 464 * strdup()'ed. 465 */ 466 errcode_t profile_node_iterator(iter_p, ret_node, ret_name, ret_value) 467 void **iter_p; 468 struct profile_node **ret_node; 469 char **ret_name, **ret_value; 470 { 471 struct profile_iterator *iter = *iter_p; 472 struct profile_node *section, *p; 473 const char **cpp; 474 errcode_t retval; 475 int skip_num = 0; 476 477 if (!iter || iter->magic != PROF_MAGIC_ITERATOR) 478 return PROF_MAGIC_ITERATOR; 479 /* 480 * If the file has changed, then the node pointer is invalid, 481 * so we'll have search the file again looking for it. 482 */ 483 if (iter->node && (iter->file->upd_serial != iter->file_serial)) { 484 iter->flags &= ~PROFILE_ITER_FINAL_SEEN; 485 skip_num = iter->num; 486 iter->node = 0; 487 } 488 get_new_file: 489 if (iter->node == 0) { 490 if (iter->file == 0 || 491 (iter->flags & PROFILE_ITER_FINAL_SEEN)) { 492 profile_node_iterator_free(iter_p); 493 if (ret_node) 494 *ret_node = 0; 495 if (ret_name) 496 *ret_name = 0; 497 if (ret_value) 498 *ret_value =0; 499 return 0; 500 } 501 if ((retval = profile_update_file(iter->file))) { 502 profile_node_iterator_free(iter_p); 503 return retval; 504 } 505 iter->file_serial = iter->file->upd_serial; 506 /* 507 * Find the section to list if we are a LIST_SECTION, 508 * or find the containing section if not. 509 */ 510 section = iter->file->root; 511 for (cpp = iter->names; cpp[iter->done_idx]; cpp++) { 512 for (p=section->first_child; p; p = p->next) 513 if (!strcmp(p->name, *cpp) && !p->value) 514 break; 515 if (!p) { 516 section = 0; 517 break; 518 } 519 section = p; 520 if (p->final) 521 iter->flags |= PROFILE_ITER_FINAL_SEEN; 522 } 523 if (!section) { 524 iter->file = iter->file->next; 525 skip_num = 0; 526 goto get_new_file; 527 } 528 iter->name = *cpp; 529 iter->node = section->first_child; 530 } 531 /* 532 * OK, now we know iter->node is set up correctly. Let's do 533 * the search. 534 */ 535 for (p = iter->node; p; p = p->next) { 536 if (iter->name && strcmp(p->name, iter->name)) 537 continue; 538 if ((iter->flags & PROFILE_ITER_SECTIONS_ONLY) && 539 p->value) 540 continue; 541 if ((iter->flags & PROFILE_ITER_RELATIONS_ONLY) && 542 !p->value) 543 continue; 544 if (skip_num > 0) { 545 skip_num--; 546 continue; 547 } 548 break; 549 } 550 iter->num++; 551 if (!p) { 552 iter->file = iter->file->next; 553 iter->node = 0; 554 skip_num = 0; 555 goto get_new_file; 556 } 557 if ((iter->node = p->next) == NULL) 558 iter->file = iter->file->next; 559 if (ret_node) 560 *ret_node = p; 561 if (ret_name) 562 *ret_name = p->name; 563 if (ret_value) 564 *ret_value = p->value; 565 return 0; 566 } 567 568 /* 569 * Remove a particular node. 570 * 571 * TYT, 2/25/99 572 */ 573 errcode_t profile_remove_node(node) 574 struct profile_node *node; 575 { 576 CHECK_MAGIC(node); 577 578 if (node->parent == 0) 579 return PROF_EINVAL; /* Can't remove the root! */ 580 581 if (node->prev) 582 node->prev->next = node->next; 583 else 584 node->parent->first_child = node->next; 585 586 if (node->next) 587 node->next->prev = node->prev; 588 589 profile_free_node(node); 590 591 return 0; 592 } 593 594 /* 595 * Set the value of a specific node containing a relation. 596 * 597 * TYT, 2/25/99 598 */ 599 errcode_t profile_set_relation_value(node, new_value) 600 struct profile_node *node; 601 const char *new_value; 602 { 603 char *cp; 604 605 CHECK_MAGIC(node); 606 607 if (!node->value) 608 return PROF_SET_SECTION_VALUE; 609 610 cp = (char *) malloc(strlen(new_value)+1); 611 if (!cp) 612 return ENOMEM; 613 614 strcpy(cp, new_value); 615 free(node->value); 616 node->value = cp; 617 618 return 0; 619 } 620 621 /* 622 * Rename a specific node 623 * 624 * TYT 2/25/99 625 */ 626 errcode_t profile_rename_node(node, new_name) 627 struct profile_node *node; 628 const char *new_name; 629 { 630 char *new_string; 631 struct profile_node *p, *last; 632 633 CHECK_MAGIC(node); 634 635 if (strcmp(new_name, node->name) == 0) 636 return 0; /* It's the same name, return */ 637 638 /* 639 * Make sure we can allocate memory for the new name, first! 640 */ 641 new_string = (char *) malloc(strlen(new_name)+1); 642 if (!new_string) 643 return ENOMEM; 644 strcpy(new_string, new_name); 645 646 /* 647 * Find the place to where the new node should go. We look 648 * for the place *after* the last match of the node name, 649 * since order matters. 650 */ 651 for (p=node->parent->first_child, last = 0; p; last = p, p = p->next) { 652 if (strcmp(p->name, new_name) > 0) 653 break; 654 } 655 656 /* 657 * If we need to move the node, do it now. 658 */ 659 if ((p != node) && (last != node)) { 660 /* 661 * OK, let's detach the node 662 */ 663 if (node->prev) 664 node->prev->next = node->next; 665 else 666 node->parent->first_child = node->next; 667 if (node->next) 668 node->next->prev = node->prev; 669 670 /* 671 * Now let's reattach it in the right place. 672 */ 673 if (p) 674 p->prev = node; 675 if (last) 676 last->next = node; 677 else 678 node->parent->first_child = node; 679 node->next = p; 680 node->prev = last; 681 } 682 683 free(node->name); 684 node->name = new_string; 685 return 0; 686 } 687