1 /* The common simulator framework for GDB, the GNU Debugger. 2 3 Copyright 2002-2024 Free Software Foundation, Inc. 4 5 Contributed by Andrew Cagney and Red Hat. 6 7 This file is part of GDB. 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 3 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 21 22 /* This must come before any other includes. */ 23 #include "defs.h" 24 25 #include <string.h> 26 27 #include "hw-main.h" 28 #include "hw-base.h" 29 30 #include "sim-io.h" 31 #include "sim-assert.h" 32 33 /* property entries */ 34 35 struct hw_property_data 36 { 37 struct hw_property_data *next; 38 struct hw_property *property; 39 const void *init_array; 40 unsigned sizeof_init_array; 41 }; 42 43 void 44 create_hw_property_data (struct hw *me) 45 { 46 } 47 48 void 49 delete_hw_property_data (struct hw *me) 50 { 51 } 52 53 54 /* Device Properties: */ 55 56 static struct hw_property_data * 57 find_property_data (struct hw *me, 58 const char *property) 59 { 60 struct hw_property_data *entry; 61 ASSERT (property != NULL); 62 entry = me->properties_of_hw; 63 while (entry != NULL) 64 { 65 if (strcmp (entry->property->name, property) == 0) 66 return entry; 67 entry = entry->next; 68 } 69 return NULL; 70 } 71 72 73 static void 74 hw_add_property (struct hw *me, 75 const char *property, 76 hw_property_type type, 77 const void *init_array, 78 unsigned sizeof_init_array, 79 const void *array, 80 unsigned sizeof_array, 81 const struct hw_property *original, 82 object_disposition disposition) 83 { 84 struct hw_property_data *new_entry = NULL; 85 struct hw_property *new_value = NULL; 86 87 /* find the list end */ 88 struct hw_property_data **insertion_point = &me->properties_of_hw; 89 while (*insertion_point != NULL) 90 { 91 if (strcmp ((*insertion_point)->property->name, property) == 0) 92 return; 93 insertion_point = &(*insertion_point)->next; 94 } 95 96 /* create a new value */ 97 new_value = HW_ZALLOC (me, struct hw_property); 98 new_value->name = (char *) strdup (property); 99 new_value->type = type; 100 if (sizeof_array > 0) 101 { 102 void *new_array = hw_zalloc (me, sizeof_array); 103 memcpy (new_array, array, sizeof_array); 104 new_value->array = new_array; 105 new_value->sizeof_array = sizeof_array; 106 } 107 new_value->owner = me; 108 new_value->original = original; 109 new_value->disposition = disposition; 110 111 /* insert the value into the list */ 112 new_entry = HW_ZALLOC (me, struct hw_property_data); 113 *insertion_point = new_entry; 114 if (sizeof_init_array > 0) 115 { 116 void *new_init_array = hw_zalloc (me, sizeof_init_array); 117 memcpy (new_init_array, init_array, sizeof_init_array); 118 new_entry->init_array = new_init_array; 119 new_entry->sizeof_init_array = sizeof_init_array; 120 } 121 new_entry->property = new_value; 122 } 123 124 125 static void 126 hw_set_property (struct hw *me, 127 const char *property, 128 hw_property_type type, 129 const void *array, 130 int sizeof_array) 131 { 132 /* find the property */ 133 struct hw_property_data *entry = find_property_data (me, property); 134 if (entry != NULL) 135 { 136 /* existing property - update it */ 137 void *new_array = 0; 138 struct hw_property *value = entry->property; 139 /* check the type matches */ 140 if (value->type != type) 141 hw_abort (me, "conflict between type of new and old value for property %s", property); 142 /* replace its value */ 143 if (value->array != NULL) 144 hw_free (me, (void*)value->array); 145 new_array = (sizeof_array > 0 146 ? hw_zalloc (me, sizeof_array) 147 : (void*)0); 148 value->array = new_array; 149 value->sizeof_array = sizeof_array; 150 if (sizeof_array > 0) 151 memcpy (new_array, array, sizeof_array); 152 return; 153 } 154 else 155 { 156 /* new property - create it */ 157 hw_add_property (me, property, type, 158 NULL, 0, array, sizeof_array, 159 NULL, temporary_object); 160 } 161 } 162 163 164 #if 0 165 static void 166 clean_hw_properties (struct hw *me) 167 { 168 struct hw_property_data **delete_point = &me->properties_of_hw; 169 while (*delete_point != NULL) 170 { 171 struct hw_property_data *current = *delete_point; 172 switch (current->property->disposition) 173 { 174 case permanent_object: 175 /* zap the current value, will be initialized later */ 176 ASSERT (current->init_array != NULL); 177 if (current->property->array != NULL) 178 { 179 hw_free (me, (void*)current->property->array); 180 current->property->array = NULL; 181 } 182 delete_point = &(*delete_point)->next; 183 break; 184 case temporary_object: 185 /* zap the actual property, was created during simulation run */ 186 ASSERT (current->init_array == NULL); 187 *delete_point = current->next; 188 if (current->property->array != NULL) 189 hw_free (me, (void*)current->property->array); 190 hw_free (me, current->property); 191 hw_free (me, current); 192 break; 193 } 194 } 195 } 196 #endif 197 198 #if 0 199 void 200 hw_init_static_properties (SIM_DESC sd, 201 struct hw *me, 202 void *data) 203 { 204 struct hw_property_data *property; 205 for (property = me->properties_of_hw; 206 property != NULL; 207 property = property->next) 208 { 209 ASSERT (property->init_array != NULL); 210 ASSERT (property->property->array == NULL); 211 ASSERT (property->property->disposition == permanent_object); 212 switch (property->property->type) 213 { 214 case array_property: 215 case boolean_property: 216 case range_array_property: 217 case reg_array_property: 218 case string_property: 219 case string_array_property: 220 case integer_property: 221 /* delete the property, and replace it with the original */ 222 hw_set_property (me, property->property->name, 223 property->property->type, 224 property->init_array, 225 property->sizeof_init_array); 226 break; 227 #if 0 228 case ihandle_property: 229 break; 230 #endif 231 } 232 } 233 } 234 #endif 235 236 237 #if 0 238 void 239 hw_init_runtime_properties (SIM_DESC sd, 240 struct hw *me, 241 void *data) 242 { 243 struct hw_property_data *property; 244 for (property = me->properties_of_hw; 245 property != NULL; 246 property = property->next) 247 { 248 switch (property->property->disposition) 249 { 250 case permanent_object: 251 switch (property->property->type) 252 { 253 #if 0 254 case ihandle_property: 255 { 256 struct hw_instance *ihandle; 257 ihandle_runtime_property_spec spec; 258 ASSERT (property->init_array != NULL); 259 ASSERT (property->property->array == NULL); 260 hw_find_ihandle_runtime_property (me, property->property->name, &spec); 261 ihandle = tree_instance (me, spec.full_path); 262 hw_set_ihandle_property (me, property->property->name, ihandle); 263 break; 264 } 265 #endif 266 case array_property: 267 case boolean_property: 268 case range_array_property: 269 case integer_property: 270 case reg_array_property: 271 case string_property: 272 case string_array_property: 273 ASSERT (property->init_array != NULL); 274 ASSERT (property->property->array != NULL); 275 break; 276 } 277 break; 278 case temporary_object: 279 ASSERT (property->init_array == NULL); 280 ASSERT (property->property->array != NULL); 281 break; 282 } 283 } 284 } 285 #endif 286 287 288 289 const struct hw_property * 290 hw_next_property (const struct hw_property *property) 291 { 292 /* find the property in the list */ 293 struct hw *owner = property->owner; 294 struct hw_property_data *entry = owner->properties_of_hw; 295 while (entry != NULL && entry->property != property) 296 entry = entry->next; 297 /* now return the following property */ 298 ASSERT (entry != NULL); /* must be a member! */ 299 if (entry->next != NULL) 300 return entry->next->property; 301 else 302 return NULL; 303 } 304 305 306 const struct hw_property * 307 hw_find_property (struct hw *me, 308 const char *property) 309 { 310 if (me == NULL) 311 { 312 return NULL; 313 } 314 else if (property == NULL || strcmp (property, "") == 0) 315 { 316 if (me->properties_of_hw == NULL) 317 return NULL; 318 else 319 return me->properties_of_hw->property; 320 } 321 else 322 { 323 struct hw_property_data *entry = find_property_data (me, property); 324 if (entry != NULL) 325 return entry->property; 326 } 327 return NULL; 328 } 329 330 331 void 332 hw_add_array_property (struct hw *me, 333 const char *property, 334 const void *array, 335 int sizeof_array) 336 { 337 hw_add_property (me, property, array_property, 338 array, sizeof_array, array, sizeof_array, 339 NULL, permanent_object); 340 } 341 342 void 343 hw_set_array_property (struct hw *me, 344 const char *property, 345 const void *array, 346 int sizeof_array) 347 { 348 hw_set_property (me, property, array_property, array, sizeof_array); 349 } 350 351 const struct hw_property * 352 hw_find_array_property (struct hw *me, 353 const char *property) 354 { 355 const struct hw_property *node; 356 node = hw_find_property (me, property); 357 if (node == NULL) 358 hw_abort (me, "property \"%s\" not found", property); 359 if (node->type != array_property) 360 hw_abort (me, "property \"%s\" of wrong type (array)", property); 361 return node; 362 } 363 364 365 366 void 367 hw_add_boolean_property (struct hw *me, 368 const char *property, 369 int boolean) 370 { 371 int32_t new_boolean = (boolean ? -1 : 0); 372 hw_add_property (me, property, boolean_property, 373 &new_boolean, sizeof (new_boolean), 374 &new_boolean, sizeof (new_boolean), 375 NULL, permanent_object); 376 } 377 378 int 379 hw_find_boolean_property (struct hw *me, 380 const char *property) 381 { 382 const struct hw_property *node; 383 unsigned_cell boolean; 384 node = hw_find_property (me, property); 385 if (node == NULL) 386 hw_abort (me, "property \"%s\" not found", property); 387 if (node->type != boolean_property) 388 hw_abort (me, "property \"%s\" of wrong type (boolean)", property); 389 ASSERT (sizeof (boolean) == node->sizeof_array); 390 memcpy (&boolean, node->array, sizeof (boolean)); 391 return boolean; 392 } 393 394 395 396 #if 0 397 void 398 hw_add_ihandle_runtime_property (struct hw *me, 399 const char *property, 400 const ihandle_runtime_property_spec *ihandle) 401 { 402 /* enter the full path as the init array */ 403 hw_add_property (me, property, ihandle_property, 404 ihandle->full_path, strlen (ihandle->full_path) + 1, 405 NULL, 0, 406 NULL, permanent_object); 407 } 408 #endif 409 410 #if 0 411 void 412 hw_find_ihandle_runtime_property (struct hw *me, 413 const char *property, 414 ihandle_runtime_property_spec *ihandle) 415 { 416 struct hw_property_data *entry = find_property_data (me, property); 417 if (entry == NULL) 418 hw_abort (me, "property \"%s\" not found", property); 419 if (entry->property->type != ihandle_property 420 || entry->property->disposition != permanent_object) 421 hw_abort (me, "property \"%s\" of wrong type", property); 422 ASSERT (entry->init_array != NULL); 423 /* the full path */ 424 ihandle->full_path = entry->init_array; 425 } 426 #endif 427 428 429 430 #if 0 431 void 432 hw_set_ihandle_property (struct hw *me, 433 const char *property, 434 hw_instance *ihandle) 435 { 436 unsigned_cell cells; 437 cells = H2BE_cell (hw_instance_to_external (ihandle)); 438 hw_set_property (me, property, ihandle_property, 439 &cells, sizeof (cells)); 440 441 } 442 #endif 443 444 #if 0 445 hw_instance * 446 hw_find_ihandle_property (struct hw *me, 447 const char *property) 448 { 449 const hw_property_data *node; 450 unsigned_cell ihandle; 451 hw_instance *instance; 452 453 node = hw_find_property (me, property); 454 if (node == NULL) 455 hw_abort (me, "property \"%s\" not found", property); 456 if (node->type != ihandle_property) 457 hw_abort (me, "property \"%s\" of wrong type (ihandle)", property); 458 if (node->array == NULL) 459 hw_abort (me, "runtime property \"%s\" not yet initialized", property); 460 461 ASSERT (sizeof (ihandle) == node->sizeof_array); 462 memcpy (&ihandle, node->array, sizeof (ihandle)); 463 instance = external_to_hw_instance (me, BE2H_cell (ihandle)); 464 ASSERT (instance != NULL); 465 return instance; 466 } 467 #endif 468 469 470 void 471 hw_add_integer_property (struct hw *me, 472 const char *property, 473 signed_cell integer) 474 { 475 H2BE (integer); 476 hw_add_property (me, property, integer_property, 477 &integer, sizeof (integer), 478 &integer, sizeof (integer), 479 NULL, permanent_object); 480 } 481 482 signed_cell 483 hw_find_integer_property (struct hw *me, 484 const char *property) 485 { 486 const struct hw_property *node; 487 signed_cell integer; 488 node = hw_find_property (me, property); 489 if (node == NULL) 490 hw_abort (me, "property \"%s\" not found", property); 491 if (node->type != integer_property) 492 hw_abort (me, "property \"%s\" of wrong type (integer)", property); 493 ASSERT (sizeof (integer) == node->sizeof_array); 494 memcpy (&integer, node->array, sizeof (integer)); 495 return BE2H_cell (integer); 496 } 497 498 int 499 hw_find_integer_array_property (struct hw *me, 500 const char *property, 501 unsigned index, 502 signed_cell *integer) 503 { 504 const struct hw_property *node; 505 int sizeof_integer = sizeof (*integer); 506 signed_cell *cell; 507 508 /* check things sane */ 509 node = hw_find_property (me, property); 510 if (node == NULL) 511 hw_abort (me, "property \"%s\" not found", property); 512 if (node->type != integer_property 513 && node->type != array_property) 514 hw_abort (me, "property \"%s\" of wrong type (integer or array)", property); 515 if ((node->sizeof_array % sizeof_integer) != 0) 516 hw_abort (me, "property \"%s\" contains an incomplete number of cells", property); 517 if (node->sizeof_array <= sizeof_integer * index) 518 return 0; 519 520 /* Find and convert the value */ 521 cell = ((signed_cell*)node->array) + index; 522 *integer = BE2H_cell (*cell); 523 524 return node->sizeof_array / sizeof_integer; 525 } 526 527 528 static unsigned_cell * 529 unit_address_to_cells (const hw_unit *unit, 530 unsigned_cell *cell, 531 int nr_cells) 532 { 533 int i; 534 ASSERT (nr_cells == unit->nr_cells); 535 for (i = 0; i < unit->nr_cells; i++) 536 { 537 *cell = H2BE_cell (unit->cells[i]); 538 cell += 1; 539 } 540 return cell; 541 } 542 543 544 static const unsigned_cell * 545 cells_to_unit_address (const unsigned_cell *cell, 546 hw_unit *unit, 547 int nr_cells) 548 { 549 int i; 550 memset (unit, 0, sizeof (*unit)); 551 unit->nr_cells = nr_cells; 552 for (i = 0; i < unit->nr_cells; i++) 553 { 554 unit->cells[i] = BE2H_cell (*cell); 555 cell += 1; 556 } 557 return cell; 558 } 559 560 561 static unsigned 562 nr_range_property_cells (struct hw *me, 563 int nr_ranges) 564 { 565 return ((hw_unit_nr_address_cells (me) 566 + hw_unit_nr_address_cells (hw_parent (me)) 567 + hw_unit_nr_size_cells (me)) 568 ) * nr_ranges; 569 } 570 571 void 572 hw_add_range_array_property (struct hw *me, 573 const char *property, 574 const range_property_spec *ranges, 575 unsigned nr_ranges) 576 { 577 unsigned sizeof_cells = (nr_range_property_cells (me, nr_ranges) 578 * sizeof (unsigned_cell)); 579 unsigned_cell *cells = hw_zalloc (me, sizeof_cells); 580 unsigned_cell *cell; 581 int i; 582 583 /* copy the property elements over */ 584 cell = cells; 585 for (i = 0; i < nr_ranges; i++) 586 { 587 const range_property_spec *range = &ranges[i]; 588 /* copy the child address */ 589 cell = unit_address_to_cells (&range->child_address, cell, 590 hw_unit_nr_address_cells (me)); 591 /* copy the parent address */ 592 cell = unit_address_to_cells (&range->parent_address, cell, 593 hw_unit_nr_address_cells (hw_parent (me))); 594 /* copy the size */ 595 cell = unit_address_to_cells (&range->size, cell, 596 hw_unit_nr_size_cells (me)); 597 } 598 ASSERT (cell == &cells[nr_range_property_cells (me, nr_ranges)]); 599 600 /* add it */ 601 hw_add_property (me, property, range_array_property, 602 cells, sizeof_cells, 603 cells, sizeof_cells, 604 NULL, permanent_object); 605 606 hw_free (me, cells); 607 } 608 609 int 610 hw_find_range_array_property (struct hw *me, 611 const char *property, 612 unsigned index, 613 range_property_spec *range) 614 { 615 const struct hw_property *node; 616 unsigned sizeof_entry = (nr_range_property_cells (me, 1) 617 * sizeof (unsigned_cell)); 618 const unsigned_cell *cells; 619 620 /* locate the property */ 621 node = hw_find_property (me, property); 622 if (node == NULL) 623 hw_abort (me, "property \"%s\" not found", property); 624 if (node->type != range_array_property) 625 hw_abort (me, "property \"%s\" of wrong type (range array)", property); 626 627 /* aligned ? */ 628 if ((node->sizeof_array % sizeof_entry) != 0) 629 hw_abort (me, "property \"%s\" contains an incomplete number of entries", 630 property); 631 632 /* within bounds? */ 633 if (node->sizeof_array < sizeof_entry * (index + 1)) 634 return 0; 635 636 /* find the range of interest */ 637 cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index); 638 639 /* copy the child address out - converting as we go */ 640 cells = cells_to_unit_address (cells, &range->child_address, 641 hw_unit_nr_address_cells (me)); 642 643 /* copy the parent address out - converting as we go */ 644 cells = cells_to_unit_address (cells, &range->parent_address, 645 hw_unit_nr_address_cells (hw_parent (me))); 646 647 /* copy the size - converting as we go */ 648 cells = cells_to_unit_address (cells, &range->size, 649 hw_unit_nr_size_cells (me)); 650 651 return node->sizeof_array / sizeof_entry; 652 } 653 654 655 static unsigned 656 nr_reg_property_cells (struct hw *me, 657 int nr_regs) 658 { 659 return (hw_unit_nr_address_cells (hw_parent (me)) 660 + hw_unit_nr_size_cells (hw_parent (me)) 661 ) * nr_regs; 662 } 663 664 void 665 hw_add_reg_array_property (struct hw *me, 666 const char *property, 667 const reg_property_spec *regs, 668 unsigned nr_regs) 669 { 670 unsigned sizeof_cells = (nr_reg_property_cells (me, nr_regs) 671 * sizeof (unsigned_cell)); 672 unsigned_cell *cells = hw_zalloc (me, sizeof_cells); 673 unsigned_cell *cell; 674 int i; 675 676 /* copy the property elements over */ 677 cell = cells; 678 for (i = 0; i < nr_regs; i++) 679 { 680 const reg_property_spec *reg = ®s[i]; 681 /* copy the address */ 682 cell = unit_address_to_cells (®->address, cell, 683 hw_unit_nr_address_cells (hw_parent (me))); 684 /* copy the size */ 685 cell = unit_address_to_cells (®->size, cell, 686 hw_unit_nr_size_cells (hw_parent (me))); 687 } 688 ASSERT (cell == &cells[nr_reg_property_cells (me, nr_regs)]); 689 690 /* add it */ 691 hw_add_property (me, property, reg_array_property, 692 cells, sizeof_cells, 693 cells, sizeof_cells, 694 NULL, permanent_object); 695 696 hw_free (me, cells); 697 } 698 699 int 700 hw_find_reg_array_property (struct hw *me, 701 const char *property, 702 unsigned index, 703 reg_property_spec *reg) 704 { 705 const struct hw_property *node; 706 unsigned sizeof_entry = (nr_reg_property_cells (me, 1) 707 * sizeof (unsigned_cell)); 708 const unsigned_cell *cells; 709 710 /* locate the property */ 711 node = hw_find_property (me, property); 712 if (node == NULL) 713 hw_abort (me, "property \"%s\" not found", property); 714 if (node->type != reg_array_property) 715 hw_abort (me, "property \"%s\" of wrong type (reg array)", property); 716 717 /* aligned ? */ 718 if ((node->sizeof_array % sizeof_entry) != 0) 719 hw_abort (me, "property \"%s\" contains an incomplete number of entries", 720 property); 721 722 /* within bounds? */ 723 if (node->sizeof_array < sizeof_entry * (index + 1)) 724 return 0; 725 726 /* find the range of interest */ 727 cells = (unsigned_cell*)((char*)node->array + sizeof_entry * index); 728 729 /* copy the address out - converting as we go */ 730 cells = cells_to_unit_address (cells, ®->address, 731 hw_unit_nr_address_cells (hw_parent (me))); 732 733 /* copy the size out - converting as we go */ 734 cells = cells_to_unit_address (cells, ®->size, 735 hw_unit_nr_size_cells (hw_parent (me))); 736 737 return node->sizeof_array / sizeof_entry; 738 } 739 740 741 void 742 hw_add_string_property (struct hw *me, 743 const char *property, 744 const char *string) 745 { 746 hw_add_property (me, property, string_property, 747 string, strlen (string) + 1, 748 string, strlen (string) + 1, 749 NULL, permanent_object); 750 } 751 752 const char * 753 hw_find_string_property (struct hw *me, 754 const char *property) 755 { 756 const struct hw_property *node; 757 const char *string; 758 node = hw_find_property (me, property); 759 if (node == NULL) 760 hw_abort (me, "property \"%s\" not found", property); 761 if (node->type != string_property) 762 hw_abort (me, "property \"%s\" of wrong type (string)", property); 763 string = node->array; 764 ASSERT (strlen (string) + 1 == node->sizeof_array); 765 return string; 766 } 767 768 void 769 hw_add_string_array_property (struct hw *me, 770 const char *property, 771 const string_property_spec *strings, 772 unsigned nr_strings) 773 { 774 int sizeof_array; 775 int string_nr; 776 char *array; 777 char *chp; 778 if (nr_strings == 0) 779 hw_abort (me, "property \"%s\" must be non-null", property); 780 /* total up the size of the needed array */ 781 for (sizeof_array = 0, string_nr = 0; 782 string_nr < nr_strings; 783 string_nr ++) 784 { 785 sizeof_array += strlen (strings[string_nr]) + 1; 786 } 787 /* create the array */ 788 array = (char*) hw_zalloc (me, sizeof_array); 789 chp = array; 790 for (string_nr = 0; 791 string_nr < nr_strings; 792 string_nr++) 793 { 794 strcpy (chp, strings[string_nr]); 795 chp += strlen (chp) + 1; 796 } 797 ASSERT (chp == array + sizeof_array); 798 /* now enter it */ 799 hw_add_property (me, property, string_array_property, 800 array, sizeof_array, 801 array, sizeof_array, 802 NULL, permanent_object); 803 } 804 805 int 806 hw_find_string_array_property (struct hw *me, 807 const char *property, 808 unsigned index, 809 string_property_spec *string) 810 { 811 const struct hw_property *node; 812 node = hw_find_property (me, property); 813 if (node == NULL) 814 hw_abort (me, "property \"%s\" not found", property); 815 switch (node->type) 816 { 817 default: 818 hw_abort (me, "property \"%s\" of wrong type", property); 819 break; 820 case string_property: 821 if (index == 0) 822 { 823 *string = node->array; 824 ASSERT (strlen (*string) + 1 == node->sizeof_array); 825 return 1; 826 } 827 break; 828 case array_property: 829 if (node->sizeof_array == 0 830 || ((char*)node->array)[node->sizeof_array - 1] != '\0') 831 hw_abort (me, "property \"%s\" invalid for string array", property); 832 ATTRIBUTE_FALLTHROUGH; 833 case string_array_property: 834 ASSERT (node->sizeof_array > 0); 835 ASSERT (((char*)node->array)[node->sizeof_array - 1] == '\0'); 836 { 837 const char *chp = node->array; 838 int nr_entries = 0; 839 /* count the number of strings, keeping an eye out for the one 840 we're looking for */ 841 *string = chp; 842 do 843 { 844 if (*chp == '\0') 845 { 846 /* next string */ 847 nr_entries++; 848 chp++; 849 if (nr_entries == index) 850 *string = chp; 851 } 852 else 853 { 854 chp++; 855 } 856 } while (chp < (char*)node->array + node->sizeof_array); 857 if (index < nr_entries) 858 return nr_entries; 859 else 860 { 861 *string = NULL; 862 return 0; 863 } 864 } 865 break; 866 } 867 return 0; 868 } 869 870 void 871 hw_add_duplicate_property (struct hw *me, 872 const char *property, 873 const struct hw_property *original) 874 { 875 struct hw_property_data *master; 876 if (original->disposition != permanent_object) 877 hw_abort (me, "Can only duplicate permanent objects"); 878 /* find the original's master */ 879 master = original->owner->properties_of_hw; 880 while (master->property != original) 881 { 882 master = master->next; 883 ASSERT (master != NULL); 884 } 885 /* now duplicate it */ 886 hw_add_property (me, property, 887 original->type, 888 master->init_array, master->sizeof_init_array, 889 original->array, original->sizeof_array, 890 original, permanent_object); 891 } 892