OSDN Git Service

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