OSDN Git Service

* gcc.dg/cpp/_Pragma4.c: Fix typo.
[pf3gnuchains/gcc-fork.git] / gcc / tree-dump.c
1 /* Tree-dumping functionality for intermediate representation.
2    Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc.
3    Written by Mark Mitchell <mark@codesourcery.com>
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING.  If not, write to the Free
19 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.  */
21
22 #include "config.h"
23 #include "system.h"
24 #include "tree.h"
25 #include "splay-tree.h"
26 #include "diagnostic.h"
27 #include "toplev.h"
28 #include "tree-dump.h"
29 #include "langhooks.h"
30
31 static unsigned int queue PARAMS ((dump_info_p, tree, int));
32 static void dump_index PARAMS ((dump_info_p, unsigned int));
33 static void dequeue_and_dump PARAMS ((dump_info_p));
34 static void dump_new_line PARAMS ((dump_info_p));
35 static void dump_maybe_newline PARAMS ((dump_info_p));
36 static void dump_string_field PARAMS ((dump_info_p, const char *, const char *));
37
38 /* Add T to the end of the queue of nodes to dump.  Returns the index
39    assigned to T.  */
40
41 static unsigned int
42 queue (di, t, flags)
43      dump_info_p di;
44      tree t;
45      int flags;
46 {
47   dump_queue_p dq;
48   dump_node_info_p dni;
49   unsigned int index;
50
51   /* Assign the next available index to T.  */
52   index = ++di->index;
53
54   /* Obtain a new queue node.  */
55   if (di->free_list)
56     {
57       dq = di->free_list;
58       di->free_list = dq->next;
59     }
60   else
61     dq = (dump_queue_p) xmalloc (sizeof (struct dump_queue));
62
63   /* Create a new entry in the splay-tree.  */
64   dni = (dump_node_info_p) xmalloc (sizeof (struct dump_node_info));
65   dni->index = index;
66   dni->binfo_p = ((flags & DUMP_BINFO) != 0);
67   dq->node = splay_tree_insert (di->nodes, (splay_tree_key) t,
68                                 (splay_tree_value) dni);
69
70   /* Add it to the end of the queue.  */
71   dq->next = 0;
72   if (!di->queue_end)
73     di->queue = dq;
74   else
75     di->queue_end->next = dq;
76   di->queue_end = dq;
77
78   /* Return the index.  */
79   return index;
80 }
81
82 static void
83 dump_index (di, index)
84      dump_info_p di;
85      unsigned int index;
86 {
87   fprintf (di->stream, "@%-6u ", index);
88   di->column += 8;
89 }
90
91 /* If T has not already been output, queue it for subsequent output.
92    FIELD is a string to print before printing the index.  Then, the
93    index of T is printed.  */
94
95 void
96 queue_and_dump_index (di, field, t, flags)
97      dump_info_p di;
98      const char *field;
99      tree t;
100      int flags;
101 {
102   unsigned int index;
103   splay_tree_node n;
104
105   /* If there's no node, just return.  This makes for fewer checks in
106      our callers.  */
107   if (!t)
108     return;
109
110   /* See if we've already queued or dumped this node.  */
111   n = splay_tree_lookup (di->nodes, (splay_tree_key) t);
112   if (n)
113     index = ((dump_node_info_p) n->value)->index;
114   else
115     /* If we haven't, add it to the queue.  */
116     index = queue (di, t, flags);
117
118   /* Print the index of the node.  */
119   dump_maybe_newline (di);
120   fprintf (di->stream, "%-4s: ", field);
121   di->column += 6;
122   dump_index (di, index);
123 }
124
125 /* Dump the type of T.  */
126
127 void
128 queue_and_dump_type (di, t)
129      dump_info_p di;
130      tree t;
131 {
132   queue_and_dump_index (di, "type", TREE_TYPE (t), DUMP_NONE);
133 }
134
135 /* Dump column control */
136 #define SOL_COLUMN 25           /* Start of line column.  */
137 #define EOL_COLUMN 55           /* End of line column.  */
138 #define COLUMN_ALIGNMENT 15     /* Alignment.  */
139
140 /* Insert a new line in the dump output, and indent to an appropriate
141    place to start printing more fields.  */
142
143 static void
144 dump_new_line (di)
145      dump_info_p di;
146 {
147   fprintf (di->stream, "\n%*s", SOL_COLUMN, "");
148   di->column = SOL_COLUMN;
149 }
150
151 /* If necessary, insert a new line.  */
152
153 static void
154 dump_maybe_newline (di)
155      dump_info_p di;
156 {
157   int extra;
158
159   /* See if we need a new line.  */
160   if (di->column > EOL_COLUMN)
161     dump_new_line (di);
162   /* See if we need any padding.  */
163   else if ((extra = (di->column - SOL_COLUMN) % COLUMN_ALIGNMENT) != 0)
164     {
165       fprintf (di->stream, "%*s", COLUMN_ALIGNMENT - extra, "");
166       di->column += COLUMN_ALIGNMENT - extra;
167     }
168 }
169
170 /* Dump pointer PTR using FIELD to identify it.  */
171
172 void
173 dump_pointer (di, field, ptr)
174      dump_info_p di;
175      const char *field;
176      void *ptr;
177 {
178   dump_maybe_newline (di);
179   fprintf (di->stream, "%-4s: %-8lx ", field, (long) ptr);
180   di->column += 15;
181 }
182
183 /* Dump integer I using FIELD to identify it.  */
184
185 void
186 dump_int (di, field, i)
187      dump_info_p di;
188      const char *field;
189      int i;
190 {
191   dump_maybe_newline (di);
192   fprintf (di->stream, "%-4s: %-7d ", field, i);
193   di->column += 14;
194 }
195
196 /* Dump the string S.  */
197
198 void
199 dump_string (di, string)
200      dump_info_p di;
201      const char *string;
202 {
203   dump_maybe_newline (di);
204   fprintf (di->stream, "%-13s ", string);
205   if (strlen (string) > 13)
206     di->column += strlen (string) + 1;
207   else
208     di->column += 14;
209 }
210
211 /* Dump the string field S.  */
212
213 static void
214 dump_string_field (di, field, string)
215      dump_info_p di;
216      const char *field;
217      const char *string;
218 {
219   dump_maybe_newline (di);
220   fprintf (di->stream, "%-4s: %-7s ", field, string);
221   if (strlen (string) > 7)
222     di->column += 6 + strlen (string) + 1;
223   else
224     di->column += 14;
225 }
226
227 /* Dump the next node in the queue.  */
228
229 static void
230 dequeue_and_dump (di)
231      dump_info_p di;
232 {
233   dump_queue_p dq;
234   splay_tree_node stn;
235   dump_node_info_p dni;
236   tree t;
237   unsigned int index;
238   enum tree_code code;
239   char code_class;
240   const char* code_name;
241
242   /* Get the next node from the queue.  */
243   dq = di->queue;
244   stn = dq->node;
245   t = (tree) stn->key;
246   dni = (dump_node_info_p) stn->value;
247   index = dni->index;
248
249   /* Remove the node from the queue, and put it on the free list.  */
250   di->queue = dq->next;
251   if (!di->queue)
252     di->queue_end = 0;
253   dq->next = di->free_list;
254   di->free_list = dq;
255
256   /* Print the node index.  */
257   dump_index (di, index);
258   /* And the type of node this is.  */
259   if (dni->binfo_p)
260     code_name = "binfo";
261   else
262     code_name = tree_code_name[(int) TREE_CODE (t)];
263   fprintf (di->stream, "%-16s ", code_name);
264   di->column = 25;
265
266   /* Figure out what kind of node this is.  */
267   code = TREE_CODE (t);
268   code_class = TREE_CODE_CLASS (code);
269
270   /* Although BINFOs are TREE_VECs, we dump them specially so as to be
271      more informative.  */
272   if (dni->binfo_p)
273     {
274       if (TREE_VIA_PUBLIC (t))
275         dump_string (di, "pub");
276       else if (TREE_VIA_PROTECTED (t))
277         dump_string (di, "prot");
278       else if (TREE_VIA_PRIVATE (t))
279         dump_string (di, "priv");
280       if (TREE_VIA_VIRTUAL (t))
281         dump_string (di, "virt");
282
283       dump_child ("type", BINFO_TYPE (t));
284       dump_child ("base", BINFO_BASETYPES (t));
285
286       goto done;
287     }
288
289   /* We can knock off a bunch of expression nodes in exactly the same
290      way.  */
291   if (IS_EXPR_CODE_CLASS (code_class))
292     {
293       /* If we're dumping children, dump them now.  */
294       queue_and_dump_type (di, t);
295
296       switch (code_class)
297         {
298         case '1':
299           dump_child ("op 0", TREE_OPERAND (t, 0));
300           break;
301
302         case '2':
303         case '<':
304           dump_child ("op 0", TREE_OPERAND (t, 0));
305           dump_child ("op 1", TREE_OPERAND (t, 1));
306           break;
307
308         case 'e':
309           /* These nodes are handled explicitly below.  */
310           break;
311
312         default:
313           abort ();
314         }
315     }
316   else if (DECL_P (t))
317     {
318       /* All declarations have names.  */
319       if (DECL_NAME (t))
320         dump_child ("name", DECL_NAME (t));
321       if (DECL_ASSEMBLER_NAME_SET_P (t)
322           && DECL_ASSEMBLER_NAME (t) != DECL_NAME (t))
323         dump_child ("mngl", DECL_ASSEMBLER_NAME (t));
324       /* And types.  */
325       queue_and_dump_type (di, t);
326       dump_child ("scpe", DECL_CONTEXT (t));
327       /* And a source position.  */
328       if (DECL_SOURCE_FILE (t))
329         {
330           const char *filename = strrchr (DECL_SOURCE_FILE (t), '/');
331           if (!filename)
332             filename = DECL_SOURCE_FILE (t);
333           else
334             /* Skip the slash.  */
335             ++filename;
336
337           dump_maybe_newline (di);
338           fprintf (di->stream, "srcp: %s:%-6d ", filename,
339                    DECL_SOURCE_LINE (t));
340           di->column += 6 + strlen (filename) + 8;
341         }
342       /* And any declaration can be compiler-generated.  */
343       if (DECL_ARTIFICIAL (t))
344         dump_string (di, "artificial");
345       if (TREE_CHAIN (t) && !dump_flag (di, TDF_SLIM, NULL))
346         dump_child ("chan", TREE_CHAIN (t));
347     }
348   else if (code_class == 't')
349     {
350       /* All types have qualifiers.  */
351       int quals = (*lang_hooks.tree_dump.type_quals) (t);
352
353       if (quals != TYPE_UNQUALIFIED)
354         {
355           fprintf (di->stream, "qual: %c%c%c     ",
356                    (quals & TYPE_QUAL_CONST) ? 'c' : ' ',
357                    (quals & TYPE_QUAL_VOLATILE) ? 'v' : ' ',
358                    (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' ');
359           di->column += 14;
360         }
361
362       /* All types have associated declarations.  */
363       dump_child ("name", TYPE_NAME (t));
364
365       /* All types have a main variant.  */
366       if (TYPE_MAIN_VARIANT (t) != t)
367         dump_child ("unql", TYPE_MAIN_VARIANT (t));
368
369       /* And sizes.  */
370       dump_child ("size", TYPE_SIZE (t));
371
372       /* All types have alignments.  */
373       dump_int (di, "algn", TYPE_ALIGN (t));
374     }
375   else if (code_class == 'c')
376     /* All constants can have types.  */
377     queue_and_dump_type (di, t);
378
379   /* Give the language-specific code a chance to print something.  If
380      it's completely taken care of things, don't bother printing
381      anything more ourselves.  */
382   if ((*lang_hooks.tree_dump.dump_tree) (di, t))
383     goto done;
384
385   /* Now handle the various kinds of nodes.  */
386   switch (code)
387     {
388       int i;
389
390     case IDENTIFIER_NODE:
391       dump_string_field (di, "strg", IDENTIFIER_POINTER (t));
392       dump_int (di, "lngt", IDENTIFIER_LENGTH (t));
393       break;
394
395     case TREE_LIST:
396       dump_child ("purp", TREE_PURPOSE (t));
397       dump_child ("valu", TREE_VALUE (t));
398       dump_child ("chan", TREE_CHAIN (t));
399       break;
400
401     case TREE_VEC:
402       dump_int (di, "lngt", TREE_VEC_LENGTH (t));
403       for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
404         {
405           char buffer[32];
406           sprintf (buffer, "%u", i);
407           dump_child (buffer, TREE_VEC_ELT (t, i));
408         }
409       break;
410
411     case INTEGER_TYPE:
412     case ENUMERAL_TYPE:
413       dump_int (di, "prec", TYPE_PRECISION (t));
414       if (TREE_UNSIGNED (t))
415         dump_string (di, "unsigned");
416       dump_child ("min", TYPE_MIN_VALUE (t));
417       dump_child ("max", TYPE_MAX_VALUE (t));
418
419       if (code == ENUMERAL_TYPE)
420         dump_child ("csts", TYPE_VALUES (t));
421       break;
422
423     case REAL_TYPE:
424       dump_int (di, "prec", TYPE_PRECISION (t));
425       break;
426
427     case POINTER_TYPE:
428       dump_child ("ptd", TREE_TYPE (t));
429       break;
430
431     case REFERENCE_TYPE:
432       dump_child ("refd", TREE_TYPE (t));
433       break;
434
435     case METHOD_TYPE:
436       dump_child ("clas", TYPE_METHOD_BASETYPE (t));
437       /* Fall through.  */
438
439     case FUNCTION_TYPE:
440       dump_child ("retn", TREE_TYPE (t));
441       dump_child ("prms", TYPE_ARG_TYPES (t));
442       break;
443
444     case ARRAY_TYPE:
445       dump_child ("elts", TREE_TYPE (t));
446       dump_child ("domn", TYPE_DOMAIN (t));
447       break;
448
449     case RECORD_TYPE:
450     case UNION_TYPE:
451       if (TREE_CODE (t) == RECORD_TYPE)
452         dump_string (di, "struct");
453       else
454         dump_string (di, "union");
455
456       dump_child ("flds", TYPE_FIELDS (t));
457       dump_child ("fncs", TYPE_METHODS (t));
458       queue_and_dump_index (di, "binf", TYPE_BINFO (t),
459                             DUMP_BINFO);
460       break;
461
462     case CONST_DECL:
463       dump_child ("cnst", DECL_INITIAL (t));
464       break;
465
466     case VAR_DECL:
467     case PARM_DECL:
468     case FIELD_DECL:
469     case RESULT_DECL:
470       if (TREE_CODE (t) == PARM_DECL)
471         dump_child ("argt", DECL_ARG_TYPE (t));
472       else
473         dump_child ("init", DECL_INITIAL (t));
474       dump_child ("size", DECL_SIZE (t));
475       dump_int (di, "algn", DECL_ALIGN (t));
476
477       if (TREE_CODE (t) == FIELD_DECL)
478         {
479           if (DECL_FIELD_OFFSET (t))
480             dump_child ("bpos", bit_position (t));
481         }
482       else if (TREE_CODE (t) == VAR_DECL
483                || TREE_CODE (t) == PARM_DECL)
484         {
485           dump_int (di, "used", TREE_USED (t));
486           if (DECL_REGISTER (t))
487             dump_string (di, "register");
488         }
489       break;
490
491     case FUNCTION_DECL:
492       dump_child ("args", DECL_ARGUMENTS (t));
493       if (DECL_EXTERNAL (t))
494         dump_string (di, "undefined");
495       if (TREE_PUBLIC (t))
496         dump_string (di, "extern");
497       else
498         dump_string (di, "static");
499       if (DECL_LANG_SPECIFIC (t) && !dump_flag (di, TDF_SLIM, t))
500         dump_child ("body", DECL_SAVED_TREE (t));
501       break;
502
503     case INTEGER_CST:
504       if (TREE_INT_CST_HIGH (t))
505         dump_int (di, "high", TREE_INT_CST_HIGH (t));
506       dump_int (di, "low", TREE_INT_CST_LOW (t));
507       break;
508
509     case STRING_CST:
510       fprintf (di->stream, "strg: %-7s ", TREE_STRING_POINTER (t));
511       dump_int (di, "lngt", TREE_STRING_LENGTH (t));
512       break;
513
514     case TRUTH_NOT_EXPR:
515     case ADDR_EXPR:
516     case INDIRECT_REF:
517     case CLEANUP_POINT_EXPR:
518     case SAVE_EXPR:
519       /* These nodes are unary, but do not have code class `1'.  */
520       dump_child ("op 0", TREE_OPERAND (t, 0));
521       break;
522
523     case TRUTH_ANDIF_EXPR:
524     case TRUTH_ORIF_EXPR:
525     case INIT_EXPR:
526     case MODIFY_EXPR:
527     case COMPONENT_REF:
528     case COMPOUND_EXPR:
529     case ARRAY_REF:
530     case PREDECREMENT_EXPR:
531     case PREINCREMENT_EXPR:
532     case POSTDECREMENT_EXPR:
533     case POSTINCREMENT_EXPR:
534       /* These nodes are binary, but do not have code class `2'.  */
535       dump_child ("op 0", TREE_OPERAND (t, 0));
536       dump_child ("op 1", TREE_OPERAND (t, 1));
537       break;
538
539     case COND_EXPR:
540       dump_child ("op 0", TREE_OPERAND (t, 0));
541       dump_child ("op 1", TREE_OPERAND (t, 1));
542       dump_child ("op 2", TREE_OPERAND (t, 2));
543       break;
544
545     case CALL_EXPR:
546       dump_child ("fn", TREE_OPERAND (t, 0));
547       dump_child ("args", TREE_OPERAND (t, 1));
548       break;
549
550     case CONSTRUCTOR:
551       dump_child ("elts", TREE_OPERAND (t, 1));
552       break;
553
554     case BIND_EXPR:
555       dump_child ("vars", TREE_OPERAND (t, 0));
556       dump_child ("body", TREE_OPERAND (t, 1));
557       break;
558
559     case LOOP_EXPR:
560       dump_child ("body", TREE_OPERAND (t, 0));
561       break;
562
563     case EXIT_EXPR:
564       dump_child ("cond", TREE_OPERAND (t, 0));
565       break;
566
567     case TARGET_EXPR:
568       dump_child ("decl", TREE_OPERAND (t, 0));
569       dump_child ("init", TREE_OPERAND (t, 1));
570       dump_child ("clnp", TREE_OPERAND (t, 2));
571       /* There really are two possible places the initializer can be.
572          After RTL expansion, the second operand is moved to the
573          position of the fourth operand, and the second operand
574          becomes NULL.  */
575       dump_child ("init", TREE_OPERAND (t, 3));
576       break;
577
578     case EXPR_WITH_FILE_LOCATION:
579       dump_child ("expr", EXPR_WFL_NODE (t));
580       break;
581
582     default:
583       /* There are no additional fields to print.  */
584       break;
585     }
586
587  done:
588   if (dump_flag (di, TDF_ADDRESS, NULL))
589     dump_pointer (di, "addr", (void *)t);
590
591   /* Terminate the line.  */
592   fprintf (di->stream, "\n");
593 }
594
595 /* Return non-zero if FLAG has been specified for the dump, and NODE
596    is not the root node of the dump.  */
597
598 int dump_flag (di, flag, node)
599      dump_info_p di;
600      int flag;
601      tree node;
602 {
603   return (di->flags & flag) && (node != di->node);
604 }
605
606 /* Dump T, and all its children, on STREAM.  */
607
608 void
609 dump_node (t, flags, stream)
610      tree t;
611      int flags;
612      FILE *stream;
613 {
614   struct dump_info di;
615   dump_queue_p dq;
616   dump_queue_p next_dq;
617
618   /* Initialize the dump-information structure.  */
619   di.stream = stream;
620   di.index = 0;
621   di.column = 0;
622   di.queue = 0;
623   di.queue_end = 0;
624   di.free_list = 0;
625   di.flags = flags;
626   di.node = t;
627   di.nodes = splay_tree_new (splay_tree_compare_pointers, 0,
628                              (splay_tree_delete_value_fn) &free);
629
630   /* Queue up the first node.  */
631   queue (&di, t, DUMP_NONE);
632
633   /* Until the queue is empty, keep dumping nodes.  */
634   while (di.queue)
635     dequeue_and_dump (&di);
636
637   /* Now, clean up.  */
638   for (dq = di.free_list; dq; dq = next_dq)
639     {
640       next_dq = dq->next;
641       free (dq);
642     }
643   splay_tree_delete (di.nodes);
644 }
645
646 /* Define a tree dump switch.  */
647 struct dump_file_info
648 {
649   const char *const suffix;     /* suffix to give output file.  */
650   const char *const swtch;      /* command line switch */
651   int flags;                    /* user flags */
652   int state;                    /* state of play */
653 };
654
655 /* Table of tree dump switches. This must be consistent with the
656    TREE_DUMP_INDEX enumeration in tree.h */
657 static struct dump_file_info dump_files[TDI_end] =
658 {
659   {".tu", "dump-translation-unit", 0, 0},
660   {".class", "dump-class-hierarchy", 0, 0},
661   {".original", "dump-tree-original", 0, 0},
662   {".optimized", "dump-tree-optimized", 0, 0},
663   {".inlined", "dump-tree-inlined", 0, 0},
664 };
665
666 /* Define a name->number mapping for a dump flag value.  */
667 struct dump_option_value_info
668 {
669   const char *const name;       /* the name of the value */
670   const int value;              /* the value of the name */
671 };
672
673 /* Table of dump options. This must be consistent with the TDF_* flags
674    in tree.h */
675 static const struct dump_option_value_info dump_options[] =
676 {
677   {"address", TDF_ADDRESS},
678   {"slim", TDF_SLIM},
679   {"all", ~0},
680   {NULL, 0}
681 };
682
683 /* Begin a tree dump for PHASE. Stores any user supplied flag in
684    *FLAG_PTR and returns a stream to write to. If the dump is not
685    enabled, returns NULL.
686    Multiple calls will reopen and append to the dump file.  */
687
688 FILE *
689 dump_begin (phase, flag_ptr)
690      enum tree_dump_index phase;
691      int *flag_ptr;
692 {
693   FILE *stream;
694   char *name;
695
696   if (!dump_files[phase].state)
697     return NULL;
698
699   name = concat (dump_base_name, dump_files[phase].suffix, NULL);
700   stream = fopen (name, dump_files[phase].state < 0 ? "w" : "a");
701   if (!stream)
702     error ("could not open dump file `%s'", name);
703   else
704     dump_files[phase].state = 1;
705   free (name);
706   if (flag_ptr)
707     *flag_ptr = dump_files[phase].flags;
708
709   return stream;
710 }
711
712 /* Returns non-zero if tree dump PHASE is enabled.  */
713
714 int
715 dump_enabled_p (phase)
716      enum tree_dump_index phase;
717 {
718   return dump_files[phase].state;
719 }
720
721 /* Returns the switch name of PHASE.  */
722
723 const char *
724 dump_flag_name (phase)
725      enum tree_dump_index phase;
726 {
727   return dump_files[phase].swtch;
728 }
729
730 /* Finish a tree dump for PHASE. STREAM is the stream created by
731    dump_begin.  */
732
733 void
734 dump_end (phase, stream)
735      enum tree_dump_index phase ATTRIBUTE_UNUSED;
736      FILE *stream;
737 {
738   fclose (stream);
739 }
740
741 /* Parse ARG as a dump switch. Return non-zero if it is, and store the
742    relevant details in the dump_files array.  */
743
744 int
745 dump_switch_p (arg)
746      const char *arg;
747 {
748   unsigned ix;
749   const char *option_value;
750
751   for (ix = 0; ix != TDI_end; ix++)
752     if ((option_value = skip_leading_substring (arg, dump_files[ix].swtch)))
753       {
754         const char *ptr = option_value;
755         int flags = 0;
756
757         while (*ptr)
758           {
759             const struct dump_option_value_info *option_ptr;
760             const char *end_ptr;
761             unsigned length;
762
763             while (*ptr == '-')
764               ptr++;
765             end_ptr = strchr (ptr, '-');
766             if (!end_ptr)
767               end_ptr = ptr + strlen (ptr);
768             length = end_ptr - ptr;
769
770             for (option_ptr = dump_options; option_ptr->name;
771                  option_ptr++)
772               if (strlen (option_ptr->name) == length
773                   && !memcmp (option_ptr->name, ptr, length))
774                 {
775                   flags |= option_ptr->value;
776                   goto found;
777                 }
778             warning ("ignoring unknown option `%.*s' in `-f%s'",
779                      length, ptr, dump_files[ix].swtch);
780           found:;
781             ptr = end_ptr;
782           }
783
784         dump_files[ix].state = -1;
785         dump_files[ix].flags = flags;
786
787         return 1;
788       }
789   return 0;
790 }