Revert "Use a variable on the stack to not have a temporary in the call"
[ACE_TAO.git] / ACE / apps / gperf / src / Key_List.cpp
blob28e82b6447eace21b20eea54816b9badd752c8a7
1 // -*- C++ -*-
3 /**
4 * Copyright (C) 1989 Free Software Foundation, Inc.
5 * written by Douglas C. Schmidt (d.schmidt@vanderbilt.edu)
7 * This file is part of GNU GPERF.
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
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.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "Key_List.h"
25 #include "Hash_Table.h"
26 #include "ace/Read_Buffer.h"
27 #include "ace/OS_Memory.h"
28 #include "ace/OS_NS_stdio.h"
29 #include "ace/OS_NS_string.h"
30 #include <memory>
32 /// Default type for generated code.
33 const char *const Key_List::default_array_type = "char *";
35 /// in_word_set return type, by default.
36 const char *const Key_List::default_return_type = "char *";
38 namespace
40 char *
41 dup_string (const char *const str)
43 char *buf = 0;
44 ACE_NEW_RETURN (buf,
45 char [ACE_OS::strlen (str) + 1],
46 0);
47 ACE_OS::strcpy (buf, str);
49 return buf;
52 } // unnamed namespace
54 /// How wide the printed field width must be to contain the maximum
55 /// hash value.
56 int Key_List::field_width = 0;
57 int Key_List::determined_[ACE_STANDARD_CHARACTER_SET_SIZE];
59 /// Destructor dumps diagnostics during debugging.
60 Key_List::~Key_List ()
62 if (option[DEBUGGING])
63 this->dump ();
65 // Free up all the nodes in the list.
66 while (this->head != 0)
68 List_Node *temp = 0;
70 // Make sure to delete the linked nodes, as well.
71 for (List_Node *ptr = this->head->link;
72 ptr != 0;
73 ptr = temp)
75 temp = ptr->link;
76 delete ptr;
79 temp = this->head->next;
80 delete this->head;
81 this->head = temp;
84 delete [] this->array_type_;
85 delete [] this->return_type;
86 delete [] this->struct_tag;
89 /// Gathers the input stream into a buffer until one of two things occur:
90 ///
91 /// 1. We read a '%' followed by a '%'
92 /// 2. We read a '%' followed by a '}'
93 ///
94 /// The first symbolizes the beginning of the keyword list proper, The
95 /// second symbolizes the end of the C source code to be generated
96 /// verbatim in the output file.
97 ///
98 /// I assume that the keys are separated from the optional preceding
99 /// struct declaration by a consecutive % followed by either % or }
100 /// starting in the first column. The code below uses an expandible
101 /// buffer to scan off and return a pointer to all the code (if any)
102 /// appearing before the delimiter.
103 char *
104 Key_List::special_input (char delimiter)
106 int size = 80;
107 char *buf = 0;
108 ACE_NEW_RETURN (buf,
109 char[size],
111 int c;
113 for (int i = 0; (c = getchar ()) != EOF; i++)
115 if (c == '%')
117 c = getchar ();
118 if (c == delimiter)
120 // Discard newline...
121 while ((c = getchar ()) != '\n')
122 continue;
124 if (i == 0)
126 buf[0] = '\0';
127 return buf;
129 else
131 buf[delimiter == '%' && buf[i - 2] == ';'
132 ? i - 2
133 : i - 1] = '\0';
134 return buf;
137 else
138 buf[i++] = '%';
140 else if (i >= size)
142 // Yikes, time to grow the buffer!
144 char *temp = 0;
145 ACE_NEW_RETURN (temp,
146 char[size *= 2],
148 for (int j = 0; j < i; j++)
149 temp[j] = buf[j];
151 delete [] buf;
152 buf = temp;
154 buf[i] = static_cast<char> (c);
157 delete [] buf;
158 return 0;
161 /// Stores any C/C++ source code that must be included verbatim into
162 /// the generated code output.
163 char *
164 Key_List::save_include_src ()
166 int c = getchar ();
168 if (c != '%')
169 ACE_OS::ungetc (c, stdin);
170 else if ((c = getchar ()) != '{')
171 ACE_ERROR_RETURN ((LM_ERROR,
172 "internal error, %c != '{' on line %l in file %N",
175 else
176 return special_input ('}');
177 return (char *) "";
180 /// Determines from the input file whether the user wants to build a
181 /// table from a user-defined struct, or whether the user is content to
182 /// simply use the default array of keys.
183 char *
184 Key_List::array_type ()
186 return special_input ('%');
189 /// Sets up the Return_Type, the Struct_Tag type and the Array_Type
190 /// based upon various user Options.
192 Key_List::output_types ()
194 if (option[TYPE])
196 delete [] array_type_;
197 array_type_ = array_type ();
198 if (array_type_ == 0)
199 // Something's wrong, but we'll catch it later on....
200 return -1;
201 else
203 // Yow, we've got a user-defined type...
204 size_t struct_tag_length = ACE_OS::strcspn (array_type_,
205 "{\n\0");
206 if (option[POINTER]) // And it must return a pointer...
208 delete [] return_type;
209 ACE_NEW_RETURN (return_type,
210 char[struct_tag_length + 2],
211 -1);
212 ACE_OS::strncpy (return_type,
213 array_type_,
214 struct_tag_length);
215 return_type[struct_tag_length] = '*';
216 return_type[struct_tag_length + 1] = '\0';
219 delete [] struct_tag;
220 ACE_NEW_RETURN (struct_tag,
221 char[struct_tag_length + 2],
222 -1);
223 ACE_OS::strncpy (struct_tag,
224 array_type_,
225 struct_tag_length);
226 if (struct_tag[struct_tag_length - 1] != ' ')
228 struct_tag[struct_tag_length] = ' ';
229 ++struct_tag_length;
231 struct_tag[struct_tag_length] = '\0';
234 else if (option[POINTER]) // Return a char *.
236 delete [] return_type;
237 return_type = dup_string (Key_List::default_array_type);
239 return 0;
242 /// Reads in all keys from standard input and creates a linked list
243 /// pointed to by Head. This list is then quickly checked for
244 /// ``links,'' i.e., unhashable elements possessing identical key sets
245 /// and lengths.
247 Key_List::read_keys ()
249 this->include_src = this->save_include_src ();
250 if (this->include_src == 0)
251 return -1;
252 else if (this->output_types () == -1)
253 return -1;
254 else
256 ACE_Read_Buffer input (stdin);
258 char *buffer = input.read ('\n');
260 if (buffer == 0)
261 ACE_ERROR_RETURN ((LM_ERROR,
262 "No words in input file, did you forget to prepend %%%%"
263 " or use -t accidentally?\n"),
264 -1);
265 // Read in all the keywords from the input file.
266 else
268 List_Node *temp = 0;
269 const char *delimiter = option.delimiter ();
270 ACE_NEW_RETURN (this->head,
271 List_Node (buffer,
272 static_cast<int> (ACE_OS::strcspn (buffer,
273 delimiter))),
274 -1);
275 for (temp = this->head;
276 (0 != (buffer = input.read ('\n')))
277 && ACE_OS::strcmp (buffer, "%%");
278 temp = temp->next)
280 ACE_NEW_RETURN (temp->next,
281 List_Node (buffer,
282 static_cast<int> (ACE_OS::strcspn (buffer,
283 delimiter))),
284 -1);
285 ++this->total_keys;
288 // See if any additional source code is included at end of
289 // this file.
290 if (buffer)
291 additional_code = 1;
293 this->list_len = this->total_keys;
295 // Make large hash table for efficiency.
296 Hash_Table table (this->list_len * Key_List::TABLE_MULTIPLE);
297 List_Node *trail = 0;
299 // Test whether there are any links and also set the maximum
300 // length an identifier in the keyword list.
302 for (temp = head;
303 temp != 0;
304 temp = temp->next)
306 List_Node *ptr = table.find (temp, option[NOLENGTH]);
308 // Check for static key links. We deal with these by
309 // building an equivalence class of all duplicate values
310 // (i.e., links) so that only 1 keyword is
311 // representative of the entire collection. This
312 // *greatly* simplifies processing during later stages
313 // of the program.
315 if (ptr == 0)
316 trail = temp;
317 else
319 ++total_duplicates;
320 --list_len;
321 trail->next = temp->next;
322 temp->link = ptr->link;
323 ptr->link = temp;
325 // Complain if user hasn't enabled the duplicate
326 // option.
327 if (!option[DUP] || option[DEBUGGING])
328 ACE_ERROR ((LM_ERROR,
329 "Static key link: \"%C\" = \"%C\", with key set \"%C\".\n",
330 temp->key,
331 ptr->key,
332 temp->keysig));
335 // Update minimum and maximum keyword length, if needed.
336 if (max_key_len < temp->length)
337 max_key_len = temp->length;
338 if (min_key_len > temp->length)
339 min_key_len = temp->length;
343 // Exit program if links exists and option[DUP] not set, since
344 // we can't continue.
345 if (total_duplicates)
347 if (option[DUP])
349 if (!option[MUTE])
350 ACE_ERROR_RETURN ((LM_ERROR,
351 "%d input keysigs have identical hash values, examine output carefully...\n",
352 total_duplicates),
355 else
356 ACE_ERROR_RETURN ((LM_ERROR,
357 "%d input keysigs have identical hash values,\ntry different key positions or use option -D.\n",
358 total_duplicates),
359 -1);
361 if (option[ALLCHARS])
362 option.keysig_size (max_key_len);
365 return 0;
368 /// Recursively merges two sorted lists together to form one sorted
369 /// list. The ordering criteria is by frequency of occurrence of
370 /// elements in the key set or by the hash value. This is a kludge,
371 /// but permits nice sharing of almost identical code without incurring
372 /// the overhead of a function call comparison.
373 List_Node *
374 Key_List::merge (List_Node *list1, List_Node *list2)
376 if (list1 == 0)
378 return list2;
380 else if (list2 == 0)
382 return list1;
384 else if ((occurrence_sort && list1->occurrence < list2->occurrence)
385 || (hash_sort && list1->hash_value > list2->hash_value)
386 || (key_sort && ACE_OS::strcmp (list1->key, list2->key) >= 0))
388 list2->next = merge (list2->next, list1);
389 return list2;
391 else
393 list1->next = merge (list1->next, list2);
394 return list1;
398 // Applies the merge sort algorithm to recursively sort the key list
399 // by frequency of occurrence of elements in the key set.
400 List_Node *
401 Key_List::merge_sort (List_Node *a_head)
403 if (!a_head || !a_head->next)
404 return a_head;
405 else
407 List_Node *middle = a_head;
408 List_Node *temp = a_head->next->next;
410 while (temp)
412 temp = temp->next;
413 middle = middle->next;
414 if (temp)
415 temp = temp->next;
418 temp = middle->next;
419 middle->next = 0;
420 return merge (merge_sort (a_head), merge_sort (temp));
424 // Returns the frequency of occurrence of elements in the key set.
425 inline int
426 Key_List::occurrence (List_Node *ptr)
428 int value = 0;
430 for (char *temp = ptr->keysig; *temp; temp++)
431 value += Vectors::occurrences[(int) *temp];
433 return value;
436 // Sets the index location for all keysig characters that are now
437 // determined.
438 inline void
439 Key_List::determined (List_Node *ptr)
441 for (char *temp = ptr->keysig; *temp; temp++)
442 Key_List::determined_[(int) *temp] = 1;
445 // Returns TRUE if PTR's key set is already completely determined.
446 inline int
447 Key_List::already_determined (List_Node *ptr)
449 int is_determined = 1;
451 for (char *temp = ptr->keysig; is_determined && *temp; temp++)
452 is_determined = determined_[(int) *temp];
454 return is_determined;
456 // Reorders the table by first sorting the list so that frequently
457 // occurring keys appear first, and then the list is reorded so that
458 // keys whose values are already determined will be placed towards the
459 // front of the list. This helps prune the search time by handling
460 // inevitable collisions early in the search process. See Cichelli's
461 // paper from Jan 1980 JACM for details....
463 void
464 Key_List::reorder ()
466 List_Node *ptr = 0;
468 for (ptr = head; ptr; ptr = ptr->next)
469 ptr->occurrence = occurrence (ptr);
471 // Switch to sorting by occurrence.
472 hash_sort = 0;
473 occurrence_sort = 1;
475 for (ptr = head = merge_sort (head); ptr->next; ptr = ptr->next)
477 determined (ptr);
479 if (already_determined (ptr->next))
480 continue;
481 else
483 List_Node *trail_ptr = ptr->next;
484 List_Node *run_ptr = trail_ptr->next;
486 for (; run_ptr; run_ptr = trail_ptr->next)
488 if (already_determined (run_ptr))
490 trail_ptr->next = run_ptr->next;
491 run_ptr->next = ptr->next;
492 ptr = ptr->next = run_ptr;
494 else
495 trail_ptr = run_ptr;
501 // Outputs the maximum and minimum hash values. Since the list is
502 // already sorted by hash value all we need to do is find the final
503 // item!
504 void
505 Key_List::output_min_max ()
507 List_Node *temp = 0;
508 for (temp = head; temp->next; temp = temp->next)
509 continue;
511 min_hash_value = head->hash_value;
512 max_hash_value = temp->hash_value;
514 if (!option[ENUM])
515 ACE_OS::printf ("\n#define TOTAL_KEYWORDS %d\n#define MIN_WORD_LENGTH %d"
516 "\n#define MAX_WORD_LENGTH %d\n#define MIN_HASH_VALUE %d"
517 "\n#define MAX_HASH_VALUE %d\n#define HASH_VALUE_RANGE %d"
518 "\n#define DUPLICATES %d\n#define WORDLIST_SIZE %d\n\n",
519 total_keys, min_key_len, max_key_len, min_hash_value,
520 max_hash_value, max_hash_value - min_hash_value + 1,
521 total_duplicates ? total_duplicates + 1 : 0, total_keys + min_hash_value);
522 else if (option[GLOBAL])
523 ACE_OS::printf ("enum\n{\n"
524 " TOTAL_KEYWORDS = %d,\n"
525 " MIN_WORD_LENGTH = %d,\n"
526 " MAX_WORD_LENGTH = %d,\n"
527 " MIN_HASH_VALUE = %d,\n"
528 " MAX_HASH_VALUE = %d,\n"
529 " HASH_VALUE_RANGE = %d,\n"
530 " DUPLICATES = %d\n"
531 " WORDLIST_SIZE = %d};\n\n",
532 total_keys, min_key_len, max_key_len, min_hash_value,
533 max_hash_value, max_hash_value - min_hash_value + 1,
534 total_duplicates ? total_duplicates + 1 : 0, total_keys + min_hash_value);
537 // Generates the output using a C switch. This trades increased
538 // search time for decreased table space (potentially *much* less
539 // space for sparse tables). It the user has specified their own
540 // struct in the keyword file *and* they enable the POINTER option we
541 // have extra work to do. The solution here is to maintain a local
542 // static array of user defined struct's, as with the
543 // Output_Lookup_Function. Then we use for switch statements to
544 // perform either a strcmp or strncmp, returning 0 if the str fails to
545 // match, and otherwise returning a pointer to appropriate index
546 // location in the local static array.
548 void
549 Key_List::output_switch (int use_keyword_table)
551 if (!option[GLOBAL] && use_keyword_table == 0)
553 if (option[LENTABLE] && option[DUP])
554 output_keylength_table ();
555 if (option[POINTER] && option[TYPE])
556 output_keyword_table ();
559 std::unique_ptr<char[]> safe_comp_buffer;
560 char * comp_buffer;
562 List_Node *curr = head;
563 int pointer_and_type_enabled = option[POINTER] && option[TYPE];
564 int total_switches = option.total_switches ();
565 int switch_size = keyword_list_length () / total_switches;
567 if (pointer_and_type_enabled)
569 // Keep track of the longest string we'll need!
570 const char *s = "charmap[*str] == *resword->%s && !ACE_OS::strncasecmp (str + 1, resword->%s + 1, len - 1)";
572 char * const tmp =
573 new char[ACE_OS::strlen (s)
574 + 2 * ACE_OS::strlen (option.key_name ()) + 1];
575 safe_comp_buffer.reset (tmp);
577 comp_buffer = safe_comp_buffer.get ();
579 if (option[COMP])
580 ACE_OS::sprintf (comp_buffer, "%s == *resword->%s && !ACE_OS::%s (str + 1, resword->%s + 1, len - 1)",
581 option[STRCASECMP] ? "charmap[*str]" : "*str", option.key_name (),
582 option[STRCASECMP] ? "strncasecmp" : "strncmp", option.key_name ());
583 else
584 ACE_OS::sprintf (comp_buffer, "%s == *resword->%s && !ACE_OS::%s (str + 1, resword->%s + 1)",
585 option[STRCASECMP] ? "charmap[*str]" : "*str", option.key_name (),
586 option[STRCASECMP] ? "strcasecmp" : "strcmp", option.key_name ());
588 else
590 if (option[COMP])
591 comp_buffer = option[STRCASECMP]
592 ? (char *) "charmap[*str] == *resword && !ACE_OS::strncasecmp (str + 1, resword + 1, len - 1)"
593 : (char *) "*str == *resword && !ACE_OS::strncmp (str + 1, resword + 1, len - 1)";
594 else
595 comp_buffer = option[STRCASECMP]
596 ? (char *) "charmap[*str] == *resword && !ACE_OS::strncasecmp (str + 1, resword + 1, len - 1)"
597 : (char *) "*str == *resword && !ACE_OS::strcmp (str + 1, resword + 1)";
599 if (!option[OPTIMIZE])
600 ACE_OS::printf (" if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)\n {\n");
601 ACE_OS::printf (" unsigned int const key = %s (str, len);\n\n", option.hash_name ());
602 if (!option[OPTIMIZE])
603 ACE_OS::printf (" if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)\n");
605 ACE_OS::printf (" {\n");
607 // Properly deal with user's who request multiple switch statements.
609 while (curr)
611 List_Node *temp = curr;
612 int lowest_case_value = curr->hash_value;
613 int number_of_cases = 0;
615 // Figure out a good cut point to end this switch.
617 for (; temp && ++number_of_cases < switch_size; temp = temp->next)
618 if (temp->next && temp->hash_value == temp->next->hash_value)
619 while (temp->next && temp->hash_value == temp->next->hash_value)
620 temp = temp->next;
622 if (temp && total_switches != 1)
623 ACE_OS::printf (" if (key <= %d)\n {\n", temp->hash_value);
624 else
625 ACE_OS::printf (" {\n");
627 // Output each keyword as part of a switch statement indexed by
628 // hash value.
630 if (option[POINTER] || option[DUP] || use_keyword_table)
632 int i = 0;
634 ACE_OS::printf (" %s%s *resword; %s\n\n",
635 option[CONSTANT] || pointer_and_type_enabled == 0 ? "const " : "",
636 pointer_and_type_enabled ? struct_tag : "char",
637 option[LENTABLE] && !option[DUP] ? "unsigned int key_len;" : "");
638 if (total_switches == 1)
640 ACE_OS::printf (" switch (key)\n {\n");
641 lowest_case_value = 0;
643 else
644 ACE_OS::printf (" switch (key - %d)\n {\n", lowest_case_value);
646 for (temp = curr; temp && ++i <= number_of_cases; temp = temp->next)
648 ACE_OS::printf (" case %*d:\n",
649 Key_List::field_width,
650 temp->hash_value - lowest_case_value);
652 // Handle `static links,' i.e., those that occur during
653 // the initial preprocessing.
655 if (temp->link == 0)
657 if (option[DEBUGGING])
658 ACE_OS::printf (" /* hash value = %4d, keyword = \"%s\" */\n",
659 temp->hash_value,
660 temp->key);
662 else
664 List_Node *links = 0;
666 for (links = temp; links; links = links->link)
668 if (option[DEBUGGING])
669 ACE_OS::printf (" /* hash value = %4d, keyword = \"%s\" */\n",
670 temp->hash_value,
671 links->key);
672 if (pointer_and_type_enabled)
673 ACE_OS::printf (" resword = &wordlist[%d];\n", links->slot);
674 else if (use_keyword_table)
675 ACE_OS::printf (" resword = wordlist[%d];\n", links->slot);
676 else
677 ACE_OS::printf (" resword = \"%s\";\n", links->key);
678 ACE_OS::printf (" if (%s) return resword;\n", comp_buffer);
682 // Handle unresolved duplicate hash values. These are
683 // guaranteed to be adjacent since we sorted the keyword
684 // list by increasing hash values.
685 if (temp->next && temp->hash_value == temp->next->hash_value)
687 for ( ; temp->next && temp->hash_value == temp->next->hash_value;
688 temp = temp->next)
690 if (pointer_and_type_enabled)
691 ACE_OS::printf (" resword = &wordlist[%d];\n", temp->slot);
692 else if (use_keyword_table)
693 ACE_OS::printf (" resword = wordlist[%d];", temp->slot);
694 else
695 ACE_OS::printf (" resword = \"%s\";\n", temp->key);
696 ACE_OS::printf (" if (%s) return resword;\n", comp_buffer);
698 if (pointer_and_type_enabled)
699 ACE_OS::printf (" resword = &wordlist[%d];\n", temp->slot);
700 else if (use_keyword_table)
701 ACE_OS::printf (" resword = wordlist[%d];", temp->slot);
702 else
703 ACE_OS::printf (" resword = \"%s\";\n", temp->key);
704 ACE_OS::printf (" return %s ? resword : 0;\n", comp_buffer);
706 else if (temp->link)
707 ACE_OS::printf (" return 0;\n");
708 else
710 if (pointer_and_type_enabled)
711 ACE_OS::printf (" resword = &wordlist[%d];", temp->slot);
712 else if (use_keyword_table)
713 ACE_OS::printf (" resword = wordlist[%d];", temp->slot);
714 else
715 ACE_OS::printf (" resword = \"%s\";", temp->key);
716 if (option[LENTABLE] && !option[DUP])
717 ACE_OS::printf (" key_len = %d;", temp->length);
718 ACE_OS::printf (" break;\n");
721 ACE_OS::printf (" default: return 0;\n }\n");
722 if (option[OPTIMIZE])
723 ACE_OS::printf (" return resword;\n");
724 else
726 ACE_OS::printf (option[LENTABLE] && !option[DUP]
727 ? " if (len == key_len && %s)\n return resword;\n"
728 : " if (%s)\n return resword;\n", comp_buffer);
729 ACE_OS::printf (" return 0;\n");
731 ACE_OS::printf (" }\n");
732 curr = temp;
734 else // Nothing special required here.
736 int i = 0;
737 ACE_OS::printf (" char *s;\n\n switch (key - %d)\n {\n",
738 lowest_case_value);
740 for (temp = curr; temp && ++i <= number_of_cases; temp = temp->next)
741 if (option[LENTABLE])
742 ACE_OS::printf (" case %*d: if (len == %d) s = \"%s\"; else return 0; break;\n",
743 Key_List::field_width,
744 temp->hash_value - lowest_case_value,
745 temp->length,
746 temp->key);
747 else
748 ACE_OS::printf (" case %*d: s = \"%s\"; break;\n",
749 Key_List::field_width,
750 temp->hash_value - lowest_case_value,
751 temp->key);
753 ACE_OS::printf (" default: return 0;\n }\n ");
754 if (option[COMP])
755 ACE_OS::printf ("return %s == *s && !ACE_OS::%s;\n }\n",
756 option[STRCASECMP] ? "charmap[*str]" : "*str",
757 option[STRCASECMP] ? "strncasecmp (s + 1, str + 1, len - 1)" : "strcmp (s + 1, str + 1)");
758 else
759 ACE_OS::printf ("return %s == *s && !ACE_OS::%s;\n }\n",
760 option[STRCASECMP] ? "charmap[*str]" : "*str",
761 option[STRCASECMP] ? "strcasecmp (s + 1, str + 1, len - 1)" : "strcmp (s + 1, str + 1)");
762 curr = temp;
765 ACE_OS::printf (" }\n %s\n}\n", option[OPTIMIZE] ? "" : "}\n return 0;");
768 // Prints out a table of keyword lengths, for use with the comparison
769 // code in generated function ``in_word_set.''
771 void
772 Key_List::output_keylength_table ()
774 const int max_column = 15;
775 int slot = 0;
776 int column = 0;
777 const char *indent = option[GLOBAL] ? "" : " ";
778 List_Node *temp;
780 if (!option[DUP] && !option[SWITCH])
782 ACE_OS::printf ("\n%sstatic %sunsigned %s lengthtable[] =\n%s%s{\n ",
783 indent,
784 option[CONSTANT] ? "const " : "",
785 max_key_len <= ((int) UCHAR_MAX) ? "char" : (max_key_len <= ((int) USHRT_MAX) ? "short" : "long"),
786 indent,
787 indent);
789 for (temp = head; temp; temp = temp->next, slot++)
791 if (slot < temp->hash_value)
792 for ( ; slot < temp->hash_value; slot++)
793 ACE_OS::printf ("%3d,%s", 0, ++column % (max_column - 1) ? "" : "\n ");
795 ACE_OS::printf ("%3d,%s", temp->length, ++column % (max_column - 1 ) ? "" : "\n ");
798 ACE_OS::printf ("\n%s%s};\n",
799 indent,
800 indent);
804 // Prints out the array containing the key words for the Gen_Perf hash
805 // function.
807 void
808 Key_List::output_keyword_table ()
810 const char *l_brace = *head->rest ? "{" : "";
811 const char *r_brace = *head->rest ? "}," : "";
812 const char *indent = option[GLOBAL] ? "" : " ";
813 int slot = 0;
814 List_Node *temp;
816 int pointer_and_type_enabled = option[POINTER] && option[TYPE];
817 ACE_OS::printf ("%sstatic %s%swordlist[] =\n%s%s{\n",
818 indent,
819 option[CONSTANT] || pointer_and_type_enabled == 0 ? "const " : "",
820 struct_tag,
821 indent,
822 indent);
824 // Skip over leading blank entries if there are no duplicates.
826 if (0 < head->hash_value)
827 ACE_OS::printf (" ");
830 int column;
832 for (column = 1; slot < head->hash_value; column++)
834 ACE_OS::printf ("%s\"\",%s%s%s",
835 l_brace,
836 option.fill_default (),
837 r_brace,
838 column % 9 ? "" : "\n ");
839 slot++;
842 if (0 < head->hash_value && column % 10)
843 ACE_OS::printf ("\n");
845 // Generate an array of reserved words at appropriate locations.
847 for (temp = head ; temp; temp = temp->next, slot++)
849 temp->slot = slot;
851 if (!option[SWITCH] && (total_duplicates == 0 || !option[DUP]) && slot < temp->hash_value)
853 int column;
855 ACE_OS::printf (" ");
857 for (column = 1; slot < temp->hash_value; slot++, column++)
858 ACE_OS::printf ("%s\"\",%s%s%s",
859 l_brace,
860 option.fill_default (),
861 r_brace,
862 column % 9 ? "" : "\n ");
864 if (column % 10)
865 ACE_OS::printf ("\n");
866 else
868 ACE_OS::printf ("%s\"%s\", %s%s", l_brace, temp->key, temp->rest, r_brace);
869 if (option[DEBUGGING])
870 ACE_OS::printf (" /* hash value = %d, slot = %d */",
871 temp->hash_value,
872 temp->slot);
873 putchar ('\n');
874 continue;
878 ACE_OS::printf (" %s\"%s\", %s%s", l_brace, temp->key, temp->rest, r_brace);
879 if (option[DEBUGGING])
880 ACE_OS::printf (" /* hash value = %d, slot = %d */",
881 temp->hash_value,
882 temp->slot);
883 putchar ('\n');
885 // Deal with links specially.
886 if (temp->link)
887 for (List_Node *links = temp->link; links; links = links->link)
889 links->slot = ++slot;
890 ACE_OS::printf (" %s\"%s\", %s%s", l_brace, links->key, links->rest, r_brace);
891 if (option[DEBUGGING])
892 ACE_OS::printf (" /* hash value = %d, slot = %d */",
893 links->hash_value,
894 links->slot);
895 putchar ('\n');
899 ACE_OS::printf ("%s%s};\n\n", indent, indent);
902 // Generates C code for the binary search algorithm that returns
903 // the proper encoding for each key word
906 Key_List::output_binary_search_function ()
908 ACE_OS::printf ("%s\n", include_src);
910 // Get prototype for strncmp() and strcmp().
911 if (!option[SKIPSTRINGH])
912 ACE_OS::printf ("#include \"ace/OS_NS_string.h\"\n");
914 // Output type declaration now, reference it later on....
915 if (option[TYPE] && !option[NOTYPE])
916 ACE_OS::printf ("%s;\n",
917 array_type_);
919 output_min_max ();
921 if (option[STRCASECMP])
922 output_strcasecmp ();
924 // Class definition if -M is *not* enabled.
925 if (option[CPLUSPLUS] && !option[SKIPCLASS])
926 ACE_OS::printf ("class %s {\npublic:\n"
927 " static %s%s%s (const char *str);\n};\n\n",
928 option.class_name (),
929 option[CONSTANT] ? "const " : "",
930 return_type,
931 option.function_name ());
933 // Use the inline keyword to remove function overhead.
934 if (option[INLINE])
935 ACE_OS::printf ("inline\n");
937 ACE_OS::printf ("%s%s\n", option[CONSTANT] ? "const " : "", return_type);
938 if (option[CPLUSPLUS])
939 ACE_OS::printf ("%s::", option.class_name ());
941 ACE_OS::printf (option[ANSI]
942 ? "%s (const char *str)\n{\n"
943 : "%s (str)\n char *str;\n{\n",
944 option.function_name ());
946 // Use the switch in place of lookup table.
948 if (option[SWITCH])
949 output_switch ();
951 // Use the lookup table, in place of switch.
952 else
954 if (!option[GLOBAL])
956 if (option[LENTABLE])
957 output_keylength_table ();
958 output_keyword_table ();
962 // Logic to handle the Binary Search.
964 ACE_OS::printf ("int first = 0, last = 0, middle = 0;\n");
966 if (option[DUP] && total_duplicates > 0)
968 ACE_OS::printf ("%s*base = 0;\n",struct_tag);
971 ACE_OS::printf ("\nlast = %d;\n",total_keys - 1);
972 ACE_OS::printf ("while (last >= first)\n");
973 ACE_OS::printf ("\t{\n");
974 ACE_OS::printf ("\t middle = (last + first) / 2;\n");
975 ACE_OS::printf ("\t if (ACE_OS::strcmp (wordlist[middle].%s, str) == 0)\n break;\n", option.key_name());
976 ACE_OS::printf ("\t if (ACE_OS::strcmp (wordlist[middle].%s, str) < 0)\n first = middle + 1;\n", option.key_name());
977 ACE_OS::printf ("\t else last = middle - 1;\n");
978 ACE_OS::printf ("\t}\n");
979 ACE_OS::printf ("if (last < first)\n return 0;\n");
980 ACE_OS::printf ("else\n return (&wordlist[middle]);\n}\n");
982 if (additional_code)
984 for (;;)
986 int c = getchar ();
988 if (c == EOF)
989 break;
990 else
991 putchar (c);
995 ACE_OS::fflush(stdout);
997 return 0;
1000 // Generates C code for the linear search algorithm that returns
1001 // the proper encoding for each key word
1004 Key_List::output_linear_search_function ()
1006 ACE_OS::printf ("%s\n", include_src);
1008 // Get prototype for strncmp() and strcmp().
1009 if (!option[SKIPSTRINGH])
1010 ACE_OS::printf ("#include \"ace/OS_NS_string.h\"\n");
1012 // Output type declaration now, reference it later on....
1013 if (option[TYPE] && !option[NOTYPE])
1014 ACE_OS::printf ("%s;\n",
1015 array_type_);
1017 output_min_max ();
1019 if (option[STRCASECMP])
1020 output_strcasecmp ();
1022 // Class definition if -M is *not* enabled.
1023 if (option[CPLUSPLUS] && !option[SKIPCLASS])
1024 ACE_OS::printf ("class %s {\npublic:\n"
1025 " static %s%s%s (const char *str);\n};\n\n",
1026 option.class_name (),
1027 option[CONSTANT] ? "const " : "",
1028 return_type,
1029 option.function_name ());
1031 // Use the inline keyword to remove function overhead.
1032 if (option[INLINE])
1033 ACE_OS::printf ("inline\n");
1035 ACE_OS::printf ("%s%s\n",
1036 option[CONSTANT] ? "const " : "",
1037 return_type);
1038 if (option[CPLUSPLUS])
1039 ACE_OS::printf ("%s::", option.class_name ());
1041 ACE_OS::printf (option[ANSI]
1042 ? "%s (const char *str)\n{\n"
1043 : "%s (str)\n char *str;\n{\n",
1044 option.function_name ());
1046 // Use the switch in place of lookup table.
1048 if (option[SWITCH])
1049 output_switch ();
1050 // Use the lookup table, in place of switch.
1051 else
1053 if (!option[GLOBAL])
1055 if (option[LENTABLE])
1056 output_keylength_table ();
1057 output_keyword_table ();
1061 // Logic to handle the Linear Search.
1063 ACE_OS::printf ("for (int i=0; i<=%d; i++)",total_keys-1);
1064 ACE_OS::printf ("\t{\n");
1065 ACE_OS::printf ("\t if (ACE_OS::strcmp (wordlist[i].%s, str) == 0)\n", option.key_name());
1066 ACE_OS::printf ("\t return &wordlist[i];\n");
1067 ACE_OS::printf ("\t}\n");
1068 ACE_OS::printf ("return 0;\n}\n");
1070 if (additional_code)
1072 for (;;)
1074 int c = getchar ();
1076 if (c == EOF)
1077 break;
1078 else
1079 putchar (c);
1083 ACE_OS::fflush (stdout);
1085 return 0;
1087 // Generates C code for the hash function that returns the proper
1088 // encoding for each key word.
1090 void
1091 Key_List::output_hash_function ()
1093 const int max_column = 10;
1094 int count = max_hash_value;
1096 #if ACE_STANDARD_CHARACTER_SET_SIZE == ACE_EBCDIC_SIZE
1097 // Lookup table for converting ASCII to EBCDIC.
1098 static const int ascii_to_ebcdic[ACE_ASCII_SIZE] =
1100 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
1101 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
1102 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
1103 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
1105 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
1106 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
1107 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
1108 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
1110 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
1111 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
1112 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
1113 0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,
1115 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
1116 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
1117 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
1118 0xA7, 0xA8, 0xA9, 0xC0, 0x6A, 0xD0, 0xA1, 0x07};
1120 int ebcdic_to_ascii[ACE_EBCDIC_SIZE];
1121 int target;
1122 #endif /* ACE_STANDARD_CHARACTER_SET_SIZE == ACE_EBCDIC_SIZE */
1124 // Calculate maximum number of digits required for MAX_HASH_VALUE.
1126 for (Key_List::field_width = 2;
1127 (count /= 10) > 0;
1128 Key_List::field_width++)
1129 continue;
1131 if (option[INLINE])
1132 ACE_OS::printf ("inline\n");
1134 if (option[C])
1135 ACE_OS::printf ("static ");
1136 ACE_OS::printf ("unsigned int\n");
1137 if (option[CPLUSPLUS])
1138 ACE_OS::printf ("%s::", option.class_name ());
1140 ACE_OS::printf (option[ANSI]
1141 ? "%s (const char *str, unsigned int len)\n{\n"
1142 : "%s (str, len)\n char *str;\n unsigned int len;\n{\n",
1143 option.hash_name ());
1145 // Generate the asso_values table.
1146 ACE_OS::printf (" static %sunsigned %s asso_values[] =\n {",
1147 option[CONSTANT] ? "constexpr " : "",
1148 max_hash_value < ((int) UCHAR_MAX) ? "char" : (max_hash_value < ((int) USHRT_MAX) ? "short" : "int"));
1150 #if ACE_STANDARD_CHARACTER_SET_SIZE == ACE_EBCDIC_SIZE
1152 for (count = 0; count < ACE_ASCII_SIZE; ++count)
1154 if (!(count % max_column))
1155 ACE_OS::printf ("\n ");
1157 target = ascii_to_ebcdic[count];
1158 ACE_OS::printf ("%*d,",
1159 Key_List::field_width,
1160 Vectors::occurrences[target] ? Vectors::asso_values[target] : max_hash_value + 1);
1163 # else
1165 for (count = 0; count < ACE_ASCII_SIZE; ++count)
1167 if (!(count % max_column))
1168 ACE_OS::printf ("\n ");
1170 ACE_OS::printf ("%*d,",
1171 Key_List::field_width,
1172 Vectors::occurrences[count] ? Vectors::asso_values[count] : max_hash_value + 1);
1175 #endif /* ACE_STANDARD_CHARACTER_SET_SIZE == ACE_EBCDIC_SIZE */
1177 // Optimize special case of ``-k 1,$''
1178 if (option[DEFAULTCHARS])
1180 if (option[STRCASECMP])
1181 ACE_OS::printf ("\n };\n return %sasso_values[static_cast<int>(charmap[str[len - 1]]]) + asso_values[static_cast<int>(charmap[str[0]])];\n}\n\n",
1182 option[NOLENGTH] ? "" : "len + ");
1183 else
1184 ACE_OS::printf ("\n };\n return %sasso_values[static_cast<int>(str[len - 1])] + asso_values[static_cast<int>(str[0])];\n}\n\n",
1185 option[NOLENGTH] ? "" : "len + ");
1187 else
1189 int key_pos;
1191 option.reset ();
1193 // Get first (also highest) key position.
1194 key_pos = option.get ();
1196 // We can perform additional optimizations here.
1197 if (!option[ALLCHARS] && key_pos <= min_key_len)
1199 ACE_OS::printf ("\n };\n return %s", option[NOLENGTH] ? "" : "len + ");
1201 for (; key_pos != WORD_END; )
1203 ACE_OS::printf (option[STRCASECMP] ? "asso_values[static_cast<int>(charmap[str[%d]])]" : "asso_values[static_cast<int>(str[%d])]", key_pos - 1);
1204 if ((key_pos = option.get ()) != EOS)
1205 ACE_OS::printf (" + ");
1206 else
1207 break;
1210 ACE_OS::printf ("%s;\n}\n\n", key_pos == WORD_END
1211 ? (option[STRCASECMP] ? "asso_values[static_cast<int>(charmap[str[len - 1]])]" : "asso_values[static_cast<int>(str[len - 1])]")
1212 : "");
1215 // We've got to use the correct, but brute force, technique.
1216 else
1218 ACE_OS::printf ("\n };\n unsigned int hval = %s;\n\n switch (%s)\n {\n default:\n",
1219 option[NOLENGTH] ? "0" : "len", option[NOLENGTH] ? "len" : "hval");
1221 // User wants *all* characters considered in hash.
1222 if (option[ALLCHARS])
1224 int i;
1226 // Break these options up for speed (gee, is this misplaced efficiency or what?!
1227 if (option[STRCASECMP])
1229 for (i = max_key_len; i > 0; i--)
1230 ACE_OS::printf (" case %d:\n hval += asso_values[static_cast<int>(charmap[static_cast<int>(str[%d])])];\n", i, i - 1);
1232 else
1234 for (i = max_key_len; i > 0; i--)
1235 ACE_OS::printf (" case %d:\n hval += asso_values[static_cast<int>(str[%d])];\n", i, i - 1);
1237 ACE_OS::printf (" }\n return hval;\n}\n\n");
1239 else // do the hard part...
1241 count = key_pos + 1;
1245 while (--count > key_pos)
1246 ACE_OS::printf (" case %d:\n", count);
1248 ACE_OS::printf (option[STRCASECMP]
1249 ? " case %d:\n hval += asso_values[static_cast<int>(charmap[static_cast<int>(str[%d])])];\n // Fallthrough\n"
1250 : " case %d:\n hval += asso_values[static_cast<int>(str[%d])];\n // Fallthrough \n",
1251 key_pos, key_pos - 1);
1253 while ((key_pos = option.get ()) != EOS && key_pos != WORD_END);
1255 ACE_OS::printf (" }\n return hval%s;\n}\n\n",
1256 key_pos == WORD_END
1257 ? (option[STRCASECMP] ? " + asso_values[static_cast<int>(charmap[static_cast<int>(str[len - 1])])]" : " + asso_values[static_cast<int>(str[len - 1])]")
1258 : "");
1265 Key_List::count_duplicates (List_Node *link,
1266 const char *type)
1268 int count = 0;
1270 // Count the number of "static" duplicates for this hash value.
1271 for (List_Node *ptr = link;
1272 ptr != 0;
1273 ptr = ptr->link)
1275 count++;
1277 if (option[DEBUGGING])
1278 ACE_DEBUG ((LM_DEBUG,
1279 "%s linked keyword = %s, slot = %d, hash_value = %d\n",
1280 type,
1281 ptr->key,
1282 ptr->slot,
1283 ptr->hash_value));
1286 return count;
1289 void
1290 Key_List::update_lookup_array (int lookup_array[],
1291 int i1,
1292 int i2,
1293 Duplicate_Entry *dup_ptr,
1294 int value)
1296 lookup_array[i1] = -dup_ptr->slot;
1297 lookup_array[i2] = -dup_ptr->count;
1298 lookup_array[dup_ptr->hash_value] = value;
1301 // Generates the large, sparse table that maps hash values in the
1302 // smaller, contiguous range of the keyword table.
1305 Key_List::output_lookup_array ()
1307 if (total_duplicates > 0)
1309 const int DEFAULT_VALUE = -1;
1311 Duplicate_Entry *duplicates = 0;
1312 ACE_NEW_RETURN (duplicates,
1313 Duplicate_Entry[total_duplicates],
1314 -1);
1316 int *lookup_array = 0;
1317 ACE_NEW_RETURN (lookup_array,
1318 int[max_hash_value + 1],
1319 -1);
1321 Duplicate_Entry *dup_ptr = duplicates;
1322 int *lookup_ptr = lookup_array + max_hash_value + 1;
1324 // Initialize the lookup array to the DEFAULT_VALUE (-1).
1325 while (lookup_ptr > lookup_array)
1326 *--lookup_ptr = DEFAULT_VALUE;
1328 // Iterate through the keylist and handle the static and dynamic
1329 // duplicate entries.
1330 for (List_Node *temp = head; temp; temp = temp->next)
1332 int hash_value = temp->hash_value;
1333 // Store the keyword's slot location into the
1334 // <lookup_array> at the <hash_value>. If this is a
1335 // non-duplicate, then this value will point directly to the
1336 // keyword.
1337 lookup_array[hash_value] = temp->slot;
1339 if (option[DEBUGGING])
1340 ACE_DEBUG ((LM_DEBUG,
1341 "keyword = %s, slot = %d, hash_value = %d, lookup_array[hash_value] = %d\n",
1342 temp->key,
1343 temp->slot,
1344 temp->hash_value,
1345 lookup_array[temp->hash_value]));
1347 if (temp->link == 0 &&
1348 (temp->next == 0 || hash_value != temp->next->hash_value))
1349 // This isn't a duplicate. Note that we know this because
1350 // we sorted the keys by their hash value.
1351 continue;
1352 else
1354 // We'll handle the duplicates here.
1355 dup_ptr->hash_value = hash_value;
1356 dup_ptr->slot = temp->slot;
1357 dup_ptr->count = 1;
1359 // Count the number of "static" duplicates, i.e.,
1360 // keywords that had the same keysig when the keyfile
1361 // was first read.
1362 dup_ptr->count += this->count_duplicates (temp->link,
1363 "static");
1365 // Count the number of "dynamic" duplicates, i.e.,
1366 // keywords that ended up with the same hash value as a
1367 // result of the <asso_values> contents.
1368 for (;
1369 temp->next && hash_value == temp->next->hash_value;
1370 temp = temp->next)
1371 dup_ptr->count += this->count_duplicates (temp->next,
1372 "dynamic");
1373 dup_ptr++;
1377 // Compute the values in the lookup array.
1378 while (--dup_ptr >= duplicates)
1380 if (option[DEBUGGING])
1381 ACE_DEBUG ((LM_DEBUG,
1382 "dup_ptr[%d]: hash_value = %d, slot = %d, count = %d\n",
1383 dup_ptr - duplicates,
1384 dup_ptr->hash_value,
1385 dup_ptr->slot,
1386 dup_ptr->count));
1387 int i;
1389 // Look to the left first.
1390 for (i = dup_ptr->hash_value; i > 0; i--)
1391 if (lookup_array[i] == DEFAULT_VALUE && lookup_array[i - 1] == DEFAULT_VALUE)
1393 this->update_lookup_array (lookup_array,
1394 i - 1,
1396 dup_ptr,
1397 -(max_hash_value + (dup_ptr->hash_value - i + 1)));
1398 break;
1401 // If we didn't find it to the left look to the right
1402 // instead...
1403 if (i == 0)
1405 for (i = dup_ptr->hash_value; i < max_hash_value; i++)
1406 if (lookup_array[i] == DEFAULT_VALUE && lookup_array[i + 1] == DEFAULT_VALUE)
1408 this->update_lookup_array (lookup_array,
1410 i + 1,
1411 dup_ptr,
1412 max_hash_value + (i - dup_ptr->hash_value));
1413 break;
1416 // If this happens, we can't use the output array scheme...
1417 if (i >= max_hash_value)
1419 option = SWITCH;
1420 ACE_DEBUG ((LM_DEBUG,
1421 "GPERF: Automatically changing to -S1 switch option\n"));
1422 // Since we've already generated the keyword table
1423 // we need to use it!
1424 this->output_switch (1);
1426 delete [] duplicates;
1427 delete [] lookup_array;
1428 return 1; // 1 indicates that we've changed our mind...
1433 lookup_ptr = lookup_array + max_hash_value + 1;
1434 int max = INT_MIN;
1436 while (lookup_ptr > lookup_array)
1438 int val = abs (*--lookup_ptr);
1439 if (max < val)
1440 max = val;
1443 const char *indent = option[GLOBAL] ? "" : " ";
1445 ACE_OS::printf ("%sstatic %ssigned %s lookup[] =\n%s%s{\n%s", indent, option[CONSTANT] ? "constexpr " : "",
1446 max <= SCHAR_MAX ? "char" : (max <= SHRT_MAX ? "short" : "int"),
1447 indent, indent, option[DEBUGGING] ? "" : " ");
1449 int count = max;
1451 // Calculate maximum number of digits required for LOOKUP_ARRAY_SIZE.
1453 for (Key_List::field_width = 2; (count /= 10) > 0; Key_List::field_width++)
1454 continue;
1456 const int max_column = 15;
1457 int column = 0;
1459 for (lookup_ptr = lookup_array;
1460 lookup_ptr < lookup_array + max_hash_value + 1;
1461 lookup_ptr++)
1463 if (option[DEBUGGING])
1464 ACE_OS::printf (" %*d, /* slot = %d */\n",
1465 Key_List::field_width,
1466 *lookup_ptr,
1467 (int)(lookup_ptr - lookup_array));
1468 else
1469 ACE_OS::printf ("%*d, %s",
1470 Key_List::field_width,
1471 *lookup_ptr,
1472 ++column % (max_column - 1) ? "" : "\n ");
1474 ACE_OS::printf ("%s%s%s};\n\n", option[DEBUGGING] ? "" : "\n", indent, indent);
1476 delete [] duplicates;
1477 delete [] lookup_array;
1479 return 0;
1482 // Generates C code to perform the keyword lookup.
1484 void
1485 Key_List::output_lookup_function ()
1487 if (!option[OPTIMIZE])
1488 ACE_OS::printf (" if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)\n {\n");
1489 ACE_OS::printf (" unsigned int const key = %s (str, len);\n\n", option.hash_name ());
1490 if (!option[OPTIMIZE])
1491 ACE_OS::printf (" if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)\n");
1492 ACE_OS::printf (" {\n");
1494 if (option[DUP] && total_duplicates > 0)
1496 int pointer_and_type_enabled = option[POINTER] && option[TYPE];
1498 ACE_OS::printf (" int slot = lookup[key];\n\n"
1499 " if (slot >= 0 && slot < WORDLIST_SIZE)\n");
1500 if (option[OPTIMIZE])
1501 ACE_OS::printf (" return %swordlist[slot];\n", option[TYPE] && option[POINTER] ? "&" : "");
1502 else
1504 ACE_OS::printf (" {\n"
1505 " %schar *s = wordlist[slot]", option[CONSTANT] || pointer_and_type_enabled == 0 ? "const " : "");
1506 if (ACE_OS::strcmp (array_type_, Key_List::default_array_type) != 0)
1507 ACE_OS::printf (".%s", option.key_name ());
1509 ACE_OS::printf (";\n\n if (%s%s == *s && !ACE_OS::%s)\n return %s;\n }\n",
1510 option[LENTABLE] ? "len == lengthtable[key]\n && " : "",
1511 option[STRCASECMP] ? "charmap[*str]" : "*str",
1512 option[COMP] ? (option[STRCASECMP] ? "strncasecmp (str + 1, s + 1, len - 1)" : "strncmp (str + 1, s + 1, len - 1)")
1513 : (option[STRCASECMP] ? "strcasecmp (str + 1, s + 1)" : "strcmp (str + 1, s + 1)"),
1514 option[TYPE] && option[POINTER] ? "&wordlist[slot]" : "s");
1515 ACE_OS::printf (" else if (slot < 0 && slot >= -MAX_HASH_VALUE)\n"
1516 " return 0;\n");
1518 ACE_OS::printf (" else\n {\n"
1519 " unsigned int offset = key + slot + (slot > 0 ? -MAX_HASH_VALUE : MAX_HASH_VALUE);\n"
1520 " %s%s*base = &wordlist[-lookup[offset]];\n"
1521 " %s%s*ptr = base + -lookup[offset + 1];\n\n"
1522 " while (--ptr >= base)\n ",
1523 option[CONSTANT] || pointer_and_type_enabled == 0 ? "const " : "", struct_tag,
1524 option[CONSTANT] || pointer_and_type_enabled == 0 ? "const " : "", struct_tag);
1525 if (ACE_OS::strcmp (array_type_, Key_List::default_array_type) != 0)
1527 if (option[COMP])
1528 ACE_OS::printf ("if (%s == *ptr->%s && !ACE_OS::%s (str + 1, ptr->%s + 1, len - 1",
1529 option[STRCASECMP] ? "charmap[*str]" : "*str", option.key_name (),
1530 option[STRCASECMP] ? "strncasecmp" : "strncmp", option.key_name ());
1531 else
1532 ACE_OS::printf ("if (%s == *ptr->%s && !ACE_OS::%s (str + 1, ptr->%s + 1",
1533 option[STRCASECMP] ? "charmap[*str]" : "*str", option.key_name (),
1534 option[STRCASECMP] ? "strcasecmp" : "strcmp", option.key_name ());
1536 else
1537 ACE_OS::printf (option[STRCASECMP] ? "if (charmap[*str] == **ptr && !ACE_OS::%s" : "if (*str == **ptr && !ACE_OS::%s",
1538 option[COMP]
1539 ? (option[STRCASECMP] ? "strncasecmp (str + 1, *ptr + 1, len - 1" : "strncmp (str + 1, *ptr + 1, len - 1")
1540 : (option[STRCASECMP] ? "strcasecmp (str + 1, *ptr + 1" : "strcmp (str + 1, *ptr + 1"));
1541 ACE_OS::printf ("))\n return %sptr;"
1542 "\n }\n }\n %s\n}\n", ACE_OS::strcmp (array_type_,
1543 Key_List::default_array_type) == 0 ? "*" : "", option[OPTIMIZE] ? "" : "}\n return 0;");
1545 else
1547 if (option[OPTIMIZE])
1548 ACE_OS::printf (" return %swordlist[key]", option[TYPE] && option[POINTER] ? "&" : "");
1549 else
1551 int pointer_and_type_enabled = option[POINTER] && option[TYPE];
1553 ACE_OS::printf (" %schar *s = wordlist[key]", option[CONSTANT] || pointer_and_type_enabled == 0 ? "const " : "");
1555 if (ACE_OS::strcmp (array_type_, Key_List::default_array_type) != 0)
1556 ACE_OS::printf (".%s", option.key_name ());
1558 ACE_OS::printf (";\n\n if (%s%s == *s && !ACE_OS::%s)\n return %s",
1559 option[LENTABLE] ? "len == lengthtable[key]\n && " : "",
1560 option[STRCASECMP] ? "charmap[*str]" : "*str",
1561 option[COMP]
1562 ? (option[STRCASECMP] ? "strncasecmp (str + 1, s + 1, len - 1)" : "strncmp (str + 1, s + 1, len - 1)")
1563 : (option[STRCASECMP] ? "strcasecmp (str + 1, s + 1)" : "strcmp (str + 1, s + 1)"),
1564 option[TYPE] && option[POINTER] ? "&wordlist[key]" : "s");
1566 ACE_OS::printf (";\n }\n %s\n}\n", option[OPTIMIZE] ? "" : "}\n return 0;");
1570 // Output the table and the functions that map upper case into lower case!
1572 void
1573 Key_List::output_strcasecmp ()
1575 ACE_OS::printf ("%s",
1576 "/* This array is designed for mapping upper and lower case letter\n"
1577 " * together for a case independent comparison. The mappings are\n"
1578 " * based upon ascii character sequences.\n */"
1579 "static char charmap[] = {\n"
1580 " '\\000', '\\001', '\\002', '\\003', '\\004', '\\005', '\\006', '\\007',\n"
1581 " '\\010', '\\011', '\\012', '\\013', '\\014', '\\015', '\\016', '\\017',\n"
1582 " '\\020', '\\021', '\\022', '\\023', '\\024', '\\025', '\\026', '\\027',\n"
1583 " '\\030', '\\031', '\\032', '\\033', '\\034', '\\035', '\\036', '\\037',\n"
1584 " '\\040', '\\041', '\\042', '\\043', '\\044', '\\045', '\\046', '\\047',\n"
1585 " '\\050', '\\051', '\\052', '\\053', '\\054', '\\055', '\\056', '\\057',\n"
1586 " '\\060', '\\061', '\\062', '\\063', '\\064', '\\065', '\\066', '\\067',\n"
1587 " '\\070', '\\071', '\\072', '\\073', '\\074', '\\075', '\\076', '\\077',\n"
1588 " '\\100', '\\141', '\\142', '\\143', '\\144', '\\145', '\\146', '\\147',\n"
1589 " '\\150', '\\151', '\\152', '\\153', '\\154', '\\155', '\\156', '\\157',\n"
1590 " '\\160', '\\161', '\\162', '\\163', '\\164', '\\165', '\\166', '\\167',\n"
1591 " '\\170', '\\171', '\\172', '\\133', '\\134', '\\135', '\\136', '\\137',\n"
1592 " '\\140', '\\141', '\\142', '\\143', '\\144', '\\145', '\\146', '\\147',\n"
1593 " '\\150', '\\151', '\\152', '\\153', '\\154', '\\155', '\\156', '\\157',\n"
1594 " '\\160', '\\161', '\\162', '\\163', '\\164', '\\165', '\\166', '\\167',\n"
1595 " '\\170', '\\171', '\\172', '\\173', '\\174', '\\175', '\\176', '\\177',\n"
1596 " '\\200', '\\201', '\\202', '\\203', '\\204', '\\205', '\\206', '\\207',\n"
1597 " '\\210', '\\211', '\\212', '\\213', '\\214', '\\215', '\\216', '\\217',\n"
1598 " '\\220', '\\221', '\\222', '\\223', '\\224', '\\225', '\\226', '\\227',\n"
1599 " '\\230', '\\231', '\\232', '\\233', '\\234', '\\235', '\\236', '\\237',\n"
1600 " '\\240', '\\241', '\\242', '\\243', '\\244', '\\245', '\\246', '\\247',\n"
1601 " '\\250', '\\251', '\\252', '\\253', '\\254', '\\255', '\\256', '\\257',\n"
1602 " '\\260', '\\261', '\\262', '\\263', '\\264', '\\265', '\\266', '\\267',\n"
1603 " '\\270', '\\271', '\\272', '\\273', '\\274', '\\275', '\\276', '\\277',\n"
1604 " '\\300', '\\341', '\\342', '\\343', '\\344', '\\345', '\\346', '\\347',\n"
1605 " '\\350', '\\351', '\\352', '\\353', '\\354', '\\355', '\\356', '\\357',\n"
1606 " '\\360', '\\361', '\\362', '\\363', '\\364', '\\365', '\\366', '\\367',\n"
1607 " '\\370', '\\371', '\\372', '\\333', '\\334', '\\335', '\\336', '\\337',\n"
1608 " '\\340', '\\341', '\\342', '\\343', '\\344', '\\345', '\\346', '\\347',\n"
1609 " '\\350', '\\351', '\\352', '\\353', '\\354', '\\355', '\\356', '\\357',\n"
1610 " '\\360', '\\361', '\\362', '\\363', '\\364', '\\365', '\\366', '\\367',\n"
1611 " '\\370', '\\371', '\\372', '\\373', '\\374', '\\375', '\\376', '\\377',\n};\n\nstatic int\n");
1612 if (option[COMP])
1614 ACE_OS::printf ("%s", option[ANSI]
1615 ? "strncasecmp (char *s1, char *s2, int n)"
1616 : "strncasecmp (s1, s2, n)\n char *s1, *s2;\n int n;");
1617 ACE_OS::printf ("\n{\n char *cm = charmap;\n\n while (--n >= 0 && cm[*s1] == cm[*s2++])\n"
1618 " if (*s1++ == '\\0')\n return 0;\n"
1619 "\n return n < 0 ? 0 : cm[*s1] - cm[*--s2];\n}\n\n");
1621 else
1623 ACE_OS::printf ("%s", option[ANSI]
1624 ? "strcasecmp (char *s1, char *s2)"
1625 : "strcasecmp (s1, s2)\n char *s1, *s2;");
1626 ACE_OS::printf ("\n{\n char *cm = charmap;\n\n while (cm[*s1] == cm[*s2++])\n"
1627 " if (*s1++ == '\\0')\n return 0;\n"
1628 "\n return cm[*s1] - cm[*--s2];\n}\n\n");
1632 // Generates the hash function and the key word recognizer function
1633 // based upon the user's Options.
1636 Key_List::output ()
1638 if (option[BINARYSEARCH])
1639 // Generate code binary search.
1640 this->output_binary_search_function ();
1641 else if (option[LINEARSEARCH])
1642 // Generate code for linear search.
1643 this->output_linear_search_function ();
1644 else
1646 // Generate the usual GPERF things.
1647 ACE_OS::printf ("%s\n", include_src);
1649 // Get prototype for strncmp() and strcmp().
1650 if (!option[SKIPSTRINGH])
1651 ACE_OS::printf ("#include \"ace/OS_NS_string.h\"\n");
1653 // Output type declaration now, reference it later on....
1654 if (option[TYPE] && !option[NOTYPE])
1655 ACE_OS::printf ("%s;\n",
1656 array_type_);
1658 output_min_max ();
1660 if (option[STRCASECMP])
1661 output_strcasecmp ();
1663 // Class definition if -M is *not* enabled.
1664 if (option[CPLUSPLUS] && !option[SKIPCLASS])
1665 ACE_OS::printf ("class %s\n{\nprivate:\n"
1666 " static unsigned int %s (const char *str, unsigned int len);\npublic:\n"
1667 " static %s%s%s (const char *str, unsigned int len);\n};\n\n",
1668 option.class_name (),
1669 option.hash_name (),
1670 option[CONSTANT] ? "const " : "",
1671 return_type,
1672 option.function_name ());
1674 output_hash_function ();
1676 if (option[GLOBAL])
1678 if (option[SWITCH])
1680 if (option[LENTABLE] && option[DUP])
1682 output_keylength_table ();
1685 if (option[POINTER] && option[TYPE])
1687 output_keyword_table ();
1690 else
1692 if (option[LENTABLE])
1694 output_keylength_table ();
1697 output_keyword_table ();
1699 if (output_lookup_array () == -1)
1701 ACE_ERROR_RETURN ((LM_DEBUG,
1702 "%p\n",
1703 "output_lookup_array"),
1704 -1);
1709 // Use the inline keyword to remove function overhead.
1710 if (option[INLINE])
1712 ACE_OS::printf ("inline\n");
1715 int pointer_and_type_enabled = option[POINTER] && option[TYPE];
1717 ACE_OS::printf ("%s%s\n",
1718 option[CONSTANT] || pointer_and_type_enabled == 0 ? "const " : "",
1719 return_type);
1720 if (option[CPLUSPLUS])
1721 ACE_OS::printf ("%s::", option.class_name ());
1723 ACE_OS::printf (option[ANSI]
1724 ? "%s (const char *str, unsigned int len)\n{\n"
1725 : "%s (str, len)\n char *str;\n unsigned int len;\n{\n",
1726 option.function_name ());
1728 if (option[ENUM] && !option[GLOBAL])
1729 ACE_OS::printf (" enum\n {\n"
1730 " TOTAL_KEYWORDS = %d,\n"
1731 " MIN_WORD_LENGTH = %d,\n"
1732 " MAX_WORD_LENGTH = %d,\n"
1733 " MIN_HASH_VALUE = %d,\n"
1734 " MAX_HASH_VALUE = %d,\n"
1735 " HASH_VALUE_RANGE = %d,\n"
1736 " DUPLICATES = %d,\n"
1737 " WORDLIST_SIZE = %d\n };\n\n",
1738 total_keys, min_key_len, max_key_len, min_hash_value,
1739 max_hash_value, max_hash_value - min_hash_value + 1,
1740 total_duplicates ? total_duplicates + 1 : 0, total_keys + min_hash_value);
1741 // Use the switch in place of lookup table.
1742 if (option[SWITCH])
1743 output_switch ();
1744 // Use the lookup table, in place of switch.
1745 else
1747 if (!option[GLOBAL])
1749 if (option[LENTABLE])
1750 output_keylength_table ();
1751 output_keyword_table ();
1753 if (!option[GLOBAL])
1755 switch (output_lookup_array ())
1757 case -1:
1758 ACE_ERROR_RETURN ((LM_DEBUG,
1759 "%p\n",
1760 "output_lookup_array"),
1761 -1);
1762 /* NOTREACHED */
1763 case 0:
1764 output_lookup_function ();
1765 break;
1766 /* NOTREACHED */
1767 default:
1768 break;
1769 /* NOTREACHED */
1772 else
1773 output_lookup_function ();
1776 if (additional_code)
1778 for (;;)
1780 int c = getchar ();
1782 if (c == EOF)
1783 break;
1784 else
1785 putchar (c);
1788 ACE_OS::fflush (stdout);
1790 return 0;
1793 // Sorts the keys by hash value.
1795 void
1796 Key_List::sort ()
1798 // By default, we sort via hashing.
1799 hash_sort = 1;
1800 occurrence_sort = 0;
1802 this->head = merge_sort (this->head);
1805 // Sorts the keys by normal strcmp.
1806 void
1807 Key_List::string_sort ()
1809 // Flatten the equivalence class list to a linear list.
1811 List_Node *ptr;
1812 for(ptr=head;ptr;ptr=ptr->next)
1814 List_Node *curr;
1815 if(ptr->link)
1817 List_Node *last_node = 0;
1819 for(curr = ptr->link; curr; curr = curr->link)
1821 // Chnage the link to next pointer.
1822 curr->next = curr->link;
1824 // Save the pointer for the last node.
1825 if (curr->link == 0)
1826 last_node = curr;
1829 // Set the pointers, correctly.
1830 last_node->next = ptr->next;
1831 ptr->next = ptr->link;
1832 ptr = last_node;
1836 // Set all links to Null.
1838 for(ptr=head;ptr;ptr=ptr->next)
1840 ptr->link = 0;
1843 // Set the sorting options.
1845 key_sort = 1;
1846 hash_sort = 0;
1847 occurrence_sort = 0;
1849 // Sort.
1851 this->head = merge_sort (head);
1852 key_sort = 0;
1856 // Dumps the key list to stderr stream.
1858 void
1859 Key_List::dump ()
1861 ACE_DEBUG ((LM_DEBUG,
1862 "\nDumping key list information:\ntotal non-static linked keywords = %d"
1863 "\ntotal keywords = %d\ntotal duplicates = %d\nmaximum key length = %d\n",
1864 list_len,
1865 total_keys,
1866 total_duplicates ? total_duplicates + 1 : 0,
1867 max_key_len));
1869 u_int keysig_width = option.max_keysig_size () > ACE_OS::strlen ("keysig")
1870 ? option.max_keysig_size ()
1871 : static_cast<u_int> (ACE_OS::strlen ("keysig"));
1873 size_t key_length = this->max_key_length ();
1874 size_t keyword_width = key_length > ACE_OS::strlen ("keysig")
1875 ? key_length
1876 : ACE_OS::strlen ("keysig");
1878 ACE_DEBUG ((LM_DEBUG,
1879 "\nList contents are:\n(hash value, key length, slot, %*s, %*s, duplicates):\n",
1880 keysig_width,
1881 "keysig",
1882 keyword_width,
1883 "keyword"));
1885 for (List_Node *ptr = head; ptr; ptr = ptr->next)
1887 ACE_DEBUG ((LM_DEBUG,
1888 "%11d,%11d,%6d, %*s, %*s",
1889 ptr->hash_value,
1890 ptr->length,
1891 ptr->slot,
1892 keysig_width,
1893 ptr->keysig,
1894 keyword_width,
1895 ptr->key));
1897 List_Node *dup = ptr->link;
1898 if (dup)
1900 for (;
1901 dup != 0;
1902 dup = dup->link)
1903 ACE_DEBUG ((LM_DEBUG,
1904 " %s",
1905 dup->key));
1907 ACE_DEBUG ((LM_DEBUG,
1908 "\n"));
1910 ACE_DEBUG ((LM_DEBUG,
1911 "End dumping list.\n\n"));
1914 // Simple-minded constructor action here...
1916 Key_List::Key_List ()
1917 : head (0),
1918 total_duplicates (0),
1919 array_type_ (dup_string (Key_List::default_array_type)),
1920 return_type (dup_string (Key_List::default_return_type)),
1921 struct_tag (dup_string (Key_List::default_array_type)),
1922 max_key_len (INT_MIN),
1923 min_key_len (INT_MAX),
1924 key_sort (0),
1925 additional_code (0),
1926 total_keys (1)
1930 // Returns the length of entire key list.
1933 Key_List::keyword_list_length ()
1935 return list_len;
1938 // Returns length of longest key read.
1941 Key_List::max_key_length ()
1943 return max_key_len;