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