1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621
|
/* ------------------------------------------------------------------------- */
/* "symbols" : The symbols table; creating stock of reserved words */
/* */
/* Part of Inform 6.21 */
/* copyright (c) Graham Nelson 1993, 1994, 1995, 1996, 1997, 1998, 1999 */
/* */
/* ------------------------------------------------------------------------- */
#include "header.h"
/* ------------------------------------------------------------------------- */
/* This section of Inform is a service detached from the rest. */
/* Only two variables are accessible from the outside: */
/* ------------------------------------------------------------------------- */
int no_symbols; /* Total number of symbols defined */
int no_named_constants; /* Copied into story file */
/* ------------------------------------------------------------------------- */
/* Plus four arrays. Each symbol has its own index n (an int32) and */
/* */
/* svals[n] is its value (must be 32 bits wide, i.e. an int32, tho' */
/* it is used to hold an unsigned 16 bit Z-machine value) */
/* sflags[n] holds flags (see "header.h" for a list) */
/* stypes[n] is the "type", distinguishing between the data type of */
/* different kinds of constants/variables. */
/* (See the "typename()" below.) */
/* symbs[n] (needs to be cast to (char *) to be used) is the name */
/* of the symbol, in the same case form as when created. */
/* slines[n] is the source line on which the symbol value was first */
/* assigned */
/* */
/* Comparison is case insensitive. */
/* Note that local variable names are not entered into the symbols table, */
/* as their numbers and scope are too limited for this to be efficient. */
/* ------------------------------------------------------------------------- */
/* Caveat editor: some array types are set up to work even on machines */
/* where sizeof(int32 *) differs from, e.g., sizeof(char *): so do not */
/* alter the types unless you understand what is going on! */
/* ------------------------------------------------------------------------- */
int32 **symbs;
int32 *svals;
int32 *slines;
int *sflags;
#ifdef VAX
char *stypes; /* In VAX C, insanely, "signed char" is illegal */
#else
signed char *stypes;
#endif
/* ------------------------------------------------------------------------- */
/* Memory to hold the text of symbol names: note that this memory is */
/* allocated as needed in chunks of size SYMBOLS_CHUNK_SIZE. */
/* ------------------------------------------------------------------------- */
static uchar *symbols_free_space, /* Next byte free to hold new names */
*symbols_ceiling; /* Pointer to the end of the current
allocation of memory for names */
static char** symbol_name_space_chunks; /* For chunks of memory used to hold
the name strings of symbols */
static int no_symbol_name_space_chunks;
/* ------------------------------------------------------------------------- */
/* The symbols table is "hash-coded" into a disjoint union of linked */
/* lists, so that for any symbol i, next_entry[i] is either -1 (meaning */
/* that it's the last in its list) or the next in the list. */
/* */
/* Each list contains, in alphabetical order, all the symbols which share */
/* the same "hash code" (a numerical function of the text of the symbol */
/* name, designed with the aim that roughly equal numbers of symbols are */
/* given each possible hash code). The hash codes are 0 to HASH_TAB_SIZE */
/* (which is a memory setting) minus 1: start_of_list[h] gives the first */
/* symbol with hash code h, or -1 if no symbol exists with hash code h. */
/* */
/* Note that the running time of the symbol search algorithm is about */
/* */
/* O ( n^2 / HASH_TAB_SIZE ) */
/* */
/* (where n is the number of symbols in the program) so that it is a good */
/* idea to choose HASH_TAB_SIZE as large as conveniently possible. */
/* ------------------------------------------------------------------------- */
static int *next_entry;
static int32 *start_of_list;
/* ------------------------------------------------------------------------- */
/* Initialisation. */
/* ------------------------------------------------------------------------- */
static void init_symbol_banks(void)
{ int i;
for (i=0; i<HASH_TAB_SIZE; i++) start_of_list[i] = -1;
}
/* ------------------------------------------------------------------------- */
/* The hash coding we use is quite standard; the variable hashcode is */
/* expected to overflow a good deal. (The aim is to produce a number */
/* so that similar names do not produce the same number.) Note that */
/* 30011 is prime. It doesn't matter if the unsigned int to int cast */
/* behaves differently on different ports. */
/* ------------------------------------------------------------------------- */
int case_conversion_grid[128];
static void make_case_conversion_grid(void)
{
/* Assumes that A to Z are contiguous in the host OS character set:
true for ASCII but not for EBCDIC, for instance. */
int i;
for (i=0; i<128; i++) case_conversion_grid[i] = i;
for (i=0; i<26; i++) case_conversion_grid['A'+i]='a'+i;
}
extern int hash_code_from_string(char *p)
{ uint32 hashcode=0;
for (; *p; p++) hashcode=hashcode*30011 + case_conversion_grid[*p];
return (int) (hashcode % HASH_TAB_SIZE);
}
extern int strcmpcis(char *p, char *q)
{
/* Case insensitive strcmp */
int i, j, pc, qc;
for (i=0;p[i] != 0;i++)
{ pc = p[i]; if (isupper(pc)) pc = tolower(pc);
qc = q[i]; if (isupper(qc)) qc = tolower(qc);
j = pc - qc;
if (j!=0) return j;
}
qc = q[i]; if (isupper(qc)) qc = tolower(qc);
return -qc;
}
/* ------------------------------------------------------------------------- */
/* Symbol finding/creating. */
/* ------------------------------------------------------------------------- */
extern int symbol_index(char *p, int hashcode)
{
/* Return the index in the symbs/svals/sflags/stypes arrays of symbol
"p", creating a new symbol with that name if it isn't already there.
New symbols are created with fundamental type UNKNOWN_CONSTANT_FT,
value 0x100 (a 2-byte quantity in Z-machine terms) and type
CONSTANT_T.
The string "p" is undamaged. */
int32 new_entry, this, last; char *r;
if (hashcode == -1) hashcode = hash_code_from_string(p);
this = start_of_list[hashcode]; last = -1;
do
{ if (this == -1) break;
r = (char *)symbs[this];
new_entry = strcmpcis(r, p);
if (new_entry == 0) return this;
if (new_entry > 0) break;
last = this;
this = next_entry[this];
} while (this != -1);
if (no_symbols >= MAX_SYMBOLS)
memoryerror("MAX_SYMBOLS", MAX_SYMBOLS);
if (last == -1)
{ next_entry[no_symbols]=start_of_list[hashcode];
start_of_list[hashcode]=no_symbols;
}
else
{ next_entry[no_symbols]=this;
next_entry[last]=no_symbols;
}
if (symbols_free_space+strlen(p)+1 >= symbols_ceiling)
{ symbols_free_space
= my_malloc(SYMBOLS_CHUNK_SIZE, "symbol names chunk");
symbols_ceiling = symbols_free_space + SYMBOLS_CHUNK_SIZE;
symbol_name_space_chunks[no_symbol_name_space_chunks++]
= (char *) symbols_free_space;
}
strcpy((char *) symbols_free_space, p);
symbs[no_symbols] = (int32 *) symbols_free_space;
symbols_free_space += strlen((char *)symbols_free_space) + 1;
svals[no_symbols] = 0x100;
sflags[no_symbols] = UNKNOWN_SFLAG;
stypes[no_symbols] = CONSTANT_T;
slines[no_symbols] = ErrorReport.line_number
+ 0x10000*ErrorReport.file_number;
return(no_symbols++);
}
/* ------------------------------------------------------------------------- */
/* Printing diagnostics */
/* ------------------------------------------------------------------------- */
extern char *typename(int type)
{ switch(type)
{
/* These are the possible symbol types. Note that local variables
do not reside in the symbol table (for scope and efficiency
reasons) and actions have their own name-space (via routine
names with "Sub" appended). */
case ROUTINE_T: return("Routine");
case LABEL_T: return("Label");
case GLOBAL_VARIABLE_T: return("Global variable");
case ARRAY_T: return("Array");
case CONSTANT_T: return("Defined constant");
case ATTRIBUTE_T: return("Attribute");
case PROPERTY_T: return("Property");
case INDIVIDUAL_PROPERTY_T: return("Individual property");
case OBJECT_T: return("Object");
case CLASS_T: return("Class");
case FAKE_ACTION_T: return("Fake action");
default: return("(Unknown type)");
}
}
static void describe_flags(int flags)
{ if (flags & UNKNOWN_SFLAG) printf("(?) ");
if (flags & USED_SFLAG) printf("(used) ");
if (flags & REPLACE_SFLAG) printf("(Replaced) ");
if (flags & DEFCON_SFLAG) printf("(Defaulted) ");
if (flags & STUB_SFLAG) printf("(Stubbed) ");
if (flags & CHANGE_SFLAG) printf("(value will change) ");
if (flags & IMPORT_SFLAG) printf("(Imported) ");
if (flags & EXPORT_SFLAG) printf("(Exported) ");
if (flags & SYSTEM_SFLAG) printf("(System) ");
if (flags & INSF_SFLAG) printf("(created in sys file) ");
if (flags & UERROR_SFLAG) printf("('Unknown' error issued) ");
if (flags & ALIASED_SFLAG) printf("(aliased) ");
if (flags & ACTION_SFLAG) printf("(Action name) ");
if (flags & REDEFINABLE_SFLAG) printf("(Redefinable) ");
}
extern void describe_symbol(int k)
{ printf("%4d %-16s %2d:%04d %04x %s ",
k, (char *) (symbs[k]), slines[k]/0x10000, slines[k]%0x10000,
svals[k], typename(stypes[k]));
describe_flags(sflags[k]);
}
extern void list_symbols(int level)
{ int k;
for (k=0; k<no_symbols; k++)
{ if ((level==2) ||
((sflags[k] & (SYSTEM_SFLAG + UNKNOWN_SFLAG + INSF_SFLAG)) == 0))
{ describe_symbol(k); printf("\n");
}
}
}
extern void issue_unused_warnings(void)
{ int32 i;
if (module_switch) return;
i = symbol_index("Main", -1);
if (!(sflags[i] & UNKNOWN_SFLAG)) sflags[i] |= USED_SFLAG;
for (i=0;i<no_symbols;i++)
{ if (((sflags[i]
& (SYSTEM_SFLAG + UNKNOWN_SFLAG + EXPORT_SFLAG
+ INSF_SFLAG + USED_SFLAG + REPLACE_SFLAG)) == 0)
&& (stypes[i] != OBJECT_T))
dbnu_warning(typename(stypes[i]), (char *) symbs[i], slines[i]);
}
}
/* ------------------------------------------------------------------------- */
/* These are arrays used only during story file (never module) creation, */
/* and not allocated until then. */
int32 *individual_name_strings; /* Packed addresses of Z-encoded
strings of the names of the
properties: this is an array
indexed by the property ID */
int32 *action_name_strings; /* Ditto for actions */
int32 *attribute_name_strings; /* Ditto for attributes */
int32 *array_name_strings; /* Ditto for arrays */
extern void write_the_identifier_names(void)
{ int i, j, k, t, null_value; char idname_string[256];
for (i=0; i<no_individual_properties; i++)
individual_name_strings[i] = 0;
if (module_switch) return;
veneer_mode = TRUE;
null_value = compile_string("<unknown attribute>", FALSE, FALSE);
for (i=0; i<48; i++) attribute_name_strings[i] = null_value;
for (i=0; i<no_symbols; i++)
{ t=stypes[i];
if ((t == INDIVIDUAL_PROPERTY_T) || (t == PROPERTY_T))
{ if (sflags[i] & ALIASED_SFLAG)
{ if (individual_name_strings[svals[i]] == 0)
{ sprintf(idname_string, "%s", (char *) symbs[i]);
for (j=i+1, k=0; (j<no_symbols && k<3); j++)
{ if ((stypes[j] == stypes[i])
&& (svals[j] == svals[i]))
{ sprintf(idname_string+strlen(idname_string),
"/%s", (char *) symbs[j]);
k++;
}
}
if (debugfile_switch)
{ write_debug_byte(PROP_DBR);
write_debug_byte(svals[i]/256);
write_debug_byte(svals[i]%256);
write_debug_string(idname_string);
}
individual_name_strings[svals[i]]
= compile_string(idname_string, FALSE, FALSE);
}
}
else
{ sprintf(idname_string, "%s", (char *) symbs[i]);
if (debugfile_switch)
{ write_debug_byte(PROP_DBR);
write_debug_byte(svals[i]/256);
write_debug_byte(svals[i]%256);
write_debug_string(idname_string);
}
individual_name_strings[svals[i]]
= compile_string(idname_string, FALSE, FALSE);
}
}
if (t == ATTRIBUTE_T)
{ if (sflags[i] & ALIASED_SFLAG)
{ if (attribute_name_strings[svals[i]] == null_value)
{ sprintf(idname_string, "%s", (char *) symbs[i]);
for (j=i+1, k=0; (j<no_symbols && k<3); j++)
{ if ((stypes[j] == stypes[i])
&& (svals[j] == svals[i]))
{ sprintf(idname_string+strlen(idname_string),
"/%s", (char *) symbs[j]);
k++;
}
}
if (debugfile_switch)
{ write_debug_byte(ATTR_DBR);
write_debug_byte(svals[i]/256);
write_debug_byte(svals[i]%256);
write_debug_string(idname_string);
}
attribute_name_strings[svals[i]]
= compile_string(idname_string, FALSE, FALSE);
}
}
else
{ sprintf(idname_string, "%s", (char *) symbs[i]);
if (debugfile_switch)
{ write_debug_byte(ATTR_DBR);
write_debug_byte(svals[i]/256);
write_debug_byte(svals[i]%256);
write_debug_string(idname_string);
}
attribute_name_strings[svals[i]]
= compile_string(idname_string, FALSE, FALSE);
}
}
if (sflags[i] & ACTION_SFLAG)
{ sprintf(idname_string, "%s", (char *) symbs[i]);
idname_string[strlen(idname_string)-3] = 0;
if (debugfile_switch)
{ write_debug_byte(ACTION_DBR);
write_debug_byte(svals[i]/256);
write_debug_byte(svals[i]%256);
write_debug_string(idname_string);
}
action_name_strings[svals[i]]
= compile_string(idname_string, FALSE, FALSE);
}
}
for (i=0; i<no_symbols; i++)
{ if (stypes[i] == FAKE_ACTION_T)
{ sprintf(idname_string, "%s", (char *) symbs[i]);
idname_string[strlen(idname_string)-3] = 0;
if (debugfile_switch)
{ write_debug_byte(ACTION_DBR);
write_debug_byte(svals[i]/256);
write_debug_byte(svals[i]%256);
write_debug_string(idname_string);
}
action_name_strings[svals[i]
- ((grammar_version_number==1)?256:4096) + no_actions]
= compile_string(idname_string, FALSE, FALSE);
}
}
for (j=0; j<no_arrays; j++)
{ i = array_symbols[j];
sprintf(idname_string, "%s", (char *) symbs[i]);
if (debugfile_switch)
{ write_debug_byte(ARRAY_DBR);
write_debug_byte(svals[i]/256);
write_debug_byte(svals[i]%256);
write_debug_string(idname_string);
}
array_name_strings[j]
= compile_string(idname_string, FALSE, FALSE);
}
if (define_INFIX_switch)
{ for (i=0; i<no_symbols; i++)
{ if (stypes[i] == GLOBAL_VARIABLE_T)
{ sprintf(idname_string, "%s", (char *) symbs[i]);
array_name_strings[no_arrays + svals[i] -16]
= compile_string(idname_string, FALSE, FALSE);
}
}
for (i=0; i<no_named_routines; i++)
{ sprintf(idname_string, "%s", (char *) symbs[named_routine_symbols[i]]);
array_name_strings[no_arrays + no_globals + i]
= compile_string(idname_string, FALSE, FALSE);
}
for (i=0, no_named_constants=0; i<no_symbols; i++)
{ if (((stypes[i] == OBJECT_T) || (stypes[i] == CLASS_T)
|| (stypes[i] == CONSTANT_T))
&& ((sflags[i] & (UNKNOWN_SFLAG+ACTION_SFLAG))==0))
{ sprintf(idname_string, "%s", (char *) symbs[i]);
array_name_strings[no_arrays + no_globals + no_named_routines
+ no_named_constants++]
= compile_string(idname_string, FALSE, FALSE);
}
}
}
veneer_mode = FALSE;
}
/* ------------------------------------------------------------------------- */
/* Creating symbols */
/* ------------------------------------------------------------------------- */
extern int32 variable_tokens[256];
extern void assign_symbol(int index, int32 value, int type)
{ svals[index] = value;
stypes[index] = type;
if (sflags[index] & UNKNOWN_SFLAG)
{ sflags[index] &= (~UNKNOWN_SFLAG);
if (is_systemfile()) sflags[index] |= INSF_SFLAG;
slines[index] = ErrorReport.line_number
+ 0x10000*ErrorReport.file_number;
}
}
static void create_symbol(char *p, int value, int type)
{ int i = symbol_index(p, -1);
svals[i] = value; stypes[i] = type; slines[i] = 0;
sflags[i] = USED_SFLAG + SYSTEM_SFLAG;
}
static void create_rsymbol(char *p, int value, int type)
{ int i = symbol_index(p, -1);
svals[i] = value; stypes[i] = type; slines[i] = 0;
sflags[i] = USED_SFLAG + SYSTEM_SFLAG + REDEFINABLE_SFLAG;
}
static void stockup_symbols(void)
{
create_symbol("nothing", 0, OBJECT_T);
create_symbol("name", 1, PROPERTY_T);
create_symbol("true", 1, CONSTANT_T);
create_symbol("false", 0, CONSTANT_T);
create_rsymbol("Grammar__Version", 1, CONSTANT_T);
grammar_version_symbol = symbol_index("Grammar__Version", -1);
if (module_switch)
create_rsymbol("MODULE_MODE",0, CONSTANT_T);
if (runtime_error_checking_switch)
create_rsymbol("STRICT_MODE",0, CONSTANT_T);
if (define_DEBUG_switch)
create_rsymbol("DEBUG", 0, CONSTANT_T);
if (define_USE_MODULES_switch)
create_rsymbol("USE_MODULES",0, CONSTANT_T);
if (define_INFIX_switch)
{ create_rsymbol("INFIX", 0, CONSTANT_T);
create_symbol("infix__watching", 0, ATTRIBUTE_T);
}
create_symbol("temp_global", 255, GLOBAL_VARIABLE_T);
create_symbol("temp__global2", 254, GLOBAL_VARIABLE_T);
create_symbol("temp__global3", 253, GLOBAL_VARIABLE_T);
create_symbol("temp__global4", 252, GLOBAL_VARIABLE_T);
create_symbol("self", 251, GLOBAL_VARIABLE_T);
create_symbol("sender", 250, GLOBAL_VARIABLE_T);
create_symbol("sw__var", 249, GLOBAL_VARIABLE_T);
create_symbol("sys__glob0", 16, GLOBAL_VARIABLE_T);
create_symbol("sys__glob1", 17, GLOBAL_VARIABLE_T);
create_symbol("sys__glob2", 18, GLOBAL_VARIABLE_T);
create_symbol("create", 64, INDIVIDUAL_PROPERTY_T);
create_symbol("recreate", 65, INDIVIDUAL_PROPERTY_T);
create_symbol("destroy", 66, INDIVIDUAL_PROPERTY_T);
create_symbol("remaining", 67, INDIVIDUAL_PROPERTY_T);
create_symbol("copy", 68, INDIVIDUAL_PROPERTY_T);
create_symbol("call", 69, INDIVIDUAL_PROPERTY_T);
create_symbol("print", 70, INDIVIDUAL_PROPERTY_T);
create_symbol("print_to_array",71, INDIVIDUAL_PROPERTY_T);
}
/* ========================================================================= */
/* Data structure management routines */
/* ------------------------------------------------------------------------- */
extern void init_symbols_vars(void)
{
symbs = NULL;
svals = NULL;
stypes = NULL;
sflags = NULL;
next_entry = NULL;
start_of_list = NULL;
symbol_name_space_chunks = NULL;
no_symbol_name_space_chunks = 0;
symbols_free_space=NULL;
symbols_ceiling=symbols_free_space;
no_symbols = 0;
make_case_conversion_grid();
}
extern void symbols_begin_pass(void) { }
extern void symbols_allocate_arrays(void)
{
symbs = my_calloc(sizeof(char *), MAX_SYMBOLS, "symbols");
svals = my_calloc(sizeof(int32), MAX_SYMBOLS, "symbol values");
slines = my_calloc(sizeof(int32), MAX_SYMBOLS, "symbol lines");
stypes = my_calloc(sizeof(char), MAX_SYMBOLS, "symbol types");
sflags = my_calloc(sizeof(int), MAX_SYMBOLS, "symbol flags");
next_entry = my_calloc(sizeof(int), MAX_SYMBOLS,
"symbol linked-list forward links");
start_of_list = my_calloc(sizeof(int32), HASH_TAB_SIZE,
"hash code list beginnings");
symbol_name_space_chunks
= my_calloc(sizeof(char *), 100, "symbol names chunk addresses");
init_symbol_banks();
stockup_symbols();
/* Allocated during story file construction, not now */
individual_name_strings = NULL;
attribute_name_strings = NULL;
action_name_strings = NULL;
array_name_strings = NULL;
}
extern void symbols_free_arrays(void)
{ int i;
for (i=0; i<no_symbol_name_space_chunks; i++)
my_free(&(symbol_name_space_chunks[i]),
"symbol names chunk");
my_free(&symbol_name_space_chunks, "symbol names chunk addresses");
my_free(&symbs, "symbols");
my_free(&svals, "symbol values");
my_free(&slines, "symbol lines");
my_free(&stypes, "symbol types");
my_free(&sflags, "symbol flags");
my_free(&next_entry, "symbol linked-list forward links");
my_free(&start_of_list, "hash code list beginnings");
if (individual_name_strings != NULL)
my_free(&individual_name_strings, "property name strings");
if (action_name_strings != NULL)
my_free(&action_name_strings, "action name strings");
if (attribute_name_strings != NULL)
my_free(&attribute_name_strings, "attribute name strings");
if (array_name_strings != NULL)
my_free(&array_name_strings, "array name strings");
}
/* ========================================================================= */
|