]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/common/hw-properties.c
Update copyright year range in header of all files managed by GDB
[thirdparty/binutils-gdb.git] / sim / common / hw-properties.c
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 = &regs[i];
681 /* copy the address */
682 cell = unit_address_to_cells (&reg->address, cell,
683 hw_unit_nr_address_cells (hw_parent (me)));
684 /* copy the size */
685 cell = unit_address_to_cells (&reg->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, &reg->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, &reg->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 }