1/* Tree browser.
2   Copyright (C) 2002-2015 Free Software Foundation, Inc.
3   Contributed by Sebastian Pop <s.pop@laposte.net>
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3.  If not see
19<http://www.gnu.org/licenses/>.  */
20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24#include "hash-table.h"
25#include "hash-set.h"
26#include "machmode.h"
27#include "vec.h"
28#include "double-int.h"
29#include "input.h"
30#include "alias.h"
31#include "symtab.h"
32#include "options.h"
33#include "wide-int.h"
34#include "inchash.h"
35#include "tree.h"
36#include "tree-pretty-print.h"
37#include "print-tree.h"
38
39#define TB_OUT_FILE stdout
40#define TB_IN_FILE stdin
41#define TB_NIY fprintf (TB_OUT_FILE, "Sorry this command is not yet implemented.\n")
42#define TB_WF fprintf (TB_OUT_FILE, "Warning, this command failed.\n")
43
44/* Structures for handling Tree Browser's commands.  */
45#define DEFTBCODE(COMMAND, STRING, HELP)   COMMAND,
46enum TB_Comm_code {
47#include "tree-browser.def"
48  TB_UNUSED_COMMAND
49};
50#undef DEFTBCODE
51typedef enum TB_Comm_code TB_CODE;
52
53struct tb_command {
54  const char *help_msg;
55  const char *comm_text;
56  size_t comm_len;
57  TB_CODE comm_code;
58};
59
60#define DEFTBCODE(code, str, help) { help, str, sizeof (str) - 1, code },
61static const struct tb_command tb_commands[] =
62{
63#include "tree-browser.def"
64};
65#undef DEFTBCODE
66
67#define TB_COMMAND_LEN(N) (tb_commands[N].comm_len)
68#define TB_COMMAND_TEXT(N) (tb_commands[N].comm_text)
69#define TB_COMMAND_CODE(N) (tb_commands[N].comm_code)
70#define TB_COMMAND_HELP(N) (tb_commands[N].help_msg)
71
72
73/* Next structure is for parsing TREE_CODEs.  */
74struct tb_tree_code {
75  enum tree_code code;
76  const char *code_string;
77  size_t code_string_len;
78};
79
80#define DEFTREECODE(SYM, STRING, TYPE, NARGS) { SYM, STRING, sizeof (STRING) - 1 },
81#define END_OF_BASE_TREE_CODES \
82  { LAST_AND_UNUSED_TREE_CODE, "@dummy", sizeof ("@dummy") - 1 },
83static const struct tb_tree_code tb_tree_codes[] =
84{
85#include "all-tree.def"
86};
87#undef DEFTREECODE
88#undef END_OF_BASE_TREE_CODES
89
90#define TB_TREE_CODE(N) (tb_tree_codes[N].code)
91#define TB_TREE_CODE_TEXT(N) (tb_tree_codes[N].code_string)
92#define TB_TREE_CODE_LEN(N) (tb_tree_codes[N].code_string_len)
93
94
95/* Function declarations.  */
96
97static long TB_getline (char **, long *, FILE *);
98static TB_CODE TB_get_command (char *);
99static enum tree_code TB_get_tree_code (char *);
100static tree find_node_with_code (tree *, int *, void *);
101static tree store_child_info (tree *, int *, void *);
102static void TB_update_up (tree);
103static tree TB_current_chain_node (tree);
104static tree TB_prev_expr (tree);
105static tree TB_next_expr (tree);
106static tree TB_up_expr (tree);
107static tree TB_first_in_bind (tree);
108static tree TB_last_in_bind (tree);
109static tree TB_history_prev (void);
110
111/* FIXME: To be declared in a .h file.  */
112void browse_tree (tree);
113
114/* Hashtable helpers.  */
115struct tree_upper_hasher : pointer_hash<tree_node>
116{
117  static inline bool equal (const value_type &, const compare_type &);
118};
119
120inline bool
121tree_upper_hasher::equal (const value_type &parent, const compare_type &node)
122{
123  if (parent == NULL || node == NULL)
124    return 0;
125
126  if (EXPR_P (parent))
127    {
128      int n = TREE_OPERAND_LENGTH (parent);
129      int i;
130      for (i = 0; i < n; i++)
131	if (node == TREE_OPERAND (parent, i))
132	  return true;
133    }
134  return false;
135}
136
137/* Static variables.  */
138static hash_table<tree_upper_hasher> *TB_up_ht;
139static vec<tree, va_gc> *TB_history_stack;
140static int TB_verbose = 1;
141
142
143/* Entry point in the Tree Browser.  */
144
145void
146browse_tree (tree begin)
147{
148  tree head;
149  TB_CODE tbc = TB_UNUSED_COMMAND;
150  ssize_t rd;
151  char *input = NULL;
152  long input_size = 0;
153
154  fprintf (TB_OUT_FILE, "\nTree Browser\n");
155
156#define TB_SET_HEAD(N) do {                                           \
157  vec_safe_push (TB_history_stack, N);                                \
158  head = N;                                                           \
159  if (TB_verbose)                                                     \
160    if (head)                                                         \
161      {                                                               \
162	print_generic_expr (TB_OUT_FILE, head, 0);                    \
163	fprintf (TB_OUT_FILE, "\n");                                  \
164      }                                                               \
165} while (0)
166
167  TB_SET_HEAD (begin);
168
169  /* Store in a hashtable information about previous and upper statements.  */
170  {
171    TB_up_ht = new hash_table<tree_upper_hasher> (1023);
172    TB_update_up (head);
173  }
174
175  while (24)
176    {
177      fprintf (TB_OUT_FILE, "TB> ");
178      rd = TB_getline (&input, &input_size, TB_IN_FILE);
179
180      if (rd == -1)
181	/* EOF.  */
182	goto ret;
183
184      if (rd != 1)
185	/* Get a new command.  Otherwise the user just pressed enter, and thus
186	   she expects the last command to be reexecuted.  */
187	tbc = TB_get_command (input);
188
189      switch (tbc)
190	{
191	case TB_UPDATE_UP:
192	  TB_update_up (head);
193	  break;
194
195	case TB_MAX:
196	  if (head && (INTEGRAL_TYPE_P (head)
197		       || TREE_CODE (head) == REAL_TYPE
198		       || TREE_CODE (head) == FIXED_POINT_TYPE))
199	    TB_SET_HEAD (TYPE_MAX_VALUE (head));
200	  else
201	    TB_WF;
202	  break;
203
204	case TB_MIN:
205	  if (head && (INTEGRAL_TYPE_P (head)
206		       || TREE_CODE (head) == REAL_TYPE
207		       || TREE_CODE (head) == FIXED_POINT_TYPE))
208	    TB_SET_HEAD (TYPE_MIN_VALUE (head));
209	  else
210	    TB_WF;
211	  break;
212
213	case TB_ELT:
214	  if (head && TREE_CODE (head) == TREE_VEC)
215	    {
216	      /* This command takes another argument: the element number:
217		 for example "elt 1".  */
218	      TB_NIY;
219	    }
220	  else if (head && TREE_CODE (head) == VECTOR_CST)
221	    {
222	      /* This command takes another argument: the element number:
223                 for example "elt 1".  */
224              TB_NIY;
225	    }
226	  else
227	    TB_WF;
228	  break;
229
230	case TB_VALUE:
231	  if (head && TREE_CODE (head) == TREE_LIST)
232	    TB_SET_HEAD (TREE_VALUE (head));
233	  else
234	    TB_WF;
235	  break;
236
237	case TB_PURPOSE:
238	  if (head && TREE_CODE (head) == TREE_LIST)
239	    TB_SET_HEAD (TREE_PURPOSE (head));
240	  else
241	    TB_WF;
242	  break;
243
244	case TB_IMAG:
245	  if (head && TREE_CODE (head) == COMPLEX_CST)
246	    TB_SET_HEAD (TREE_IMAGPART (head));
247	  else
248	    TB_WF;
249	  break;
250
251	case TB_REAL:
252	  if (head && TREE_CODE (head) == COMPLEX_CST)
253	    TB_SET_HEAD (TREE_REALPART (head));
254	  else
255	    TB_WF;
256	  break;
257
258	case TB_BLOCK:
259	  if (head && TREE_CODE (head) == BIND_EXPR)
260	    TB_SET_HEAD (TREE_OPERAND (head, 2));
261	  else
262	    TB_WF;
263	  break;
264
265	case TB_SUBBLOCKS:
266	  if (head && TREE_CODE (head) == BLOCK)
267	    TB_SET_HEAD (BLOCK_SUBBLOCKS (head));
268	  else
269	    TB_WF;
270	  break;
271
272	case TB_SUPERCONTEXT:
273	  if (head && TREE_CODE (head) == BLOCK)
274	    TB_SET_HEAD (BLOCK_SUPERCONTEXT (head));
275	  else
276	    TB_WF;
277	  break;
278
279	case TB_VARS:
280	  if (head && TREE_CODE (head) == BLOCK)
281	    TB_SET_HEAD (BLOCK_VARS (head));
282	  else if (head && TREE_CODE (head) == BIND_EXPR)
283	    TB_SET_HEAD (TREE_OPERAND (head, 0));
284	  else
285	    TB_WF;
286	  break;
287
288	case TB_REFERENCE_TO_THIS:
289	  if (head && TYPE_P (head))
290	    TB_SET_HEAD (TYPE_REFERENCE_TO (head));
291	  else
292	    TB_WF;
293	  break;
294
295	case TB_POINTER_TO_THIS:
296	  if (head && TYPE_P (head))
297	    TB_SET_HEAD (TYPE_POINTER_TO (head));
298	  else
299	    TB_WF;
300	  break;
301
302	case TB_BASETYPE:
303	  if (head && TREE_CODE (head) == OFFSET_TYPE)
304	    TB_SET_HEAD (TYPE_OFFSET_BASETYPE (head));
305	  else
306	    TB_WF;
307	  break;
308
309	case TB_ARG_TYPES:
310	  if (head && (TREE_CODE (head) == FUNCTION_TYPE
311		       || TREE_CODE (head) == METHOD_TYPE))
312	    TB_SET_HEAD (TYPE_ARG_TYPES (head));
313	  else
314	    TB_WF;
315	  break;
316
317	case TB_METHOD_BASE_TYPE:
318	  if (head && (TREE_CODE (head) == FUNCTION_TYPE
319		       || TREE_CODE (head) == METHOD_TYPE)
320	      && TYPE_METHOD_BASETYPE (head))
321	    TB_SET_HEAD (TYPE_METHOD_BASETYPE (head));
322	  else
323	    TB_WF;
324	  break;
325
326	case TB_FIELDS:
327	  if (head && (TREE_CODE (head) == RECORD_TYPE
328		       || TREE_CODE (head) == UNION_TYPE
329		       || TREE_CODE (head) == QUAL_UNION_TYPE))
330	    TB_SET_HEAD (TYPE_FIELDS (head));
331	  else
332	    TB_WF;
333	  break;
334
335	case TB_DOMAIN:
336	  if (head && TREE_CODE (head) == ARRAY_TYPE)
337	    TB_SET_HEAD (TYPE_DOMAIN (head));
338	  else
339	    TB_WF;
340	  break;
341
342	case TB_VALUES:
343	  if (head && TREE_CODE (head) == ENUMERAL_TYPE)
344	    TB_SET_HEAD (TYPE_VALUES (head));
345	  else
346	    TB_WF;
347	  break;
348
349	case TB_ARG_TYPE:
350	  if (head && TREE_CODE (head) == PARM_DECL)
351	    TB_SET_HEAD (DECL_ARG_TYPE (head));
352	  else
353	    TB_WF;
354	  break;
355
356	case TB_INITIAL:
357	  if (head && DECL_P (head))
358	    TB_SET_HEAD (DECL_INITIAL (head));
359	  else
360	    TB_WF;
361	  break;
362
363	case TB_RESULT:
364	  if (head && DECL_P (head))
365	    TB_SET_HEAD (DECL_RESULT_FLD (head));
366	  else
367	    TB_WF;
368	  break;
369
370	case TB_ARGUMENTS:
371	  if (head && DECL_P (head))
372	    TB_SET_HEAD (DECL_ARGUMENTS (head));
373	  else
374	    TB_WF;
375	  break;
376
377	case TB_ABSTRACT_ORIGIN:
378	  if (head && DECL_P (head))
379	    TB_SET_HEAD (DECL_ABSTRACT_ORIGIN (head));
380	  else if (head && TREE_CODE (head) == BLOCK)
381	    TB_SET_HEAD (BLOCK_ABSTRACT_ORIGIN (head));
382	  else
383	    TB_WF;
384	  break;
385
386	case TB_ATTRIBUTES:
387	  if (head && DECL_P (head))
388	    TB_SET_HEAD (DECL_ATTRIBUTES (head));
389	  else if (head && TYPE_P (head))
390	    TB_SET_HEAD (TYPE_ATTRIBUTES (head));
391	  else
392	    TB_WF;
393	  break;
394
395	case TB_CONTEXT:
396	  if (head && DECL_P (head))
397	    TB_SET_HEAD (DECL_CONTEXT (head));
398	  else if (head && TYPE_P (head)
399		   && TYPE_CONTEXT (head))
400	    TB_SET_HEAD (TYPE_CONTEXT (head));
401	  else
402	    TB_WF;
403	  break;
404
405	case TB_OFFSET:
406	  if (head && TREE_CODE (head) == FIELD_DECL)
407	    TB_SET_HEAD (DECL_FIELD_OFFSET (head));
408	  else
409	    TB_WF;
410	  break;
411
412	case TB_BIT_OFFSET:
413	  if (head && TREE_CODE (head) == FIELD_DECL)
414	    TB_SET_HEAD (DECL_FIELD_BIT_OFFSET (head));
415	  else
416	    TB_WF;
417          break;
418
419	case TB_UNIT_SIZE:
420	  if (head && DECL_P (head))
421	    TB_SET_HEAD (DECL_SIZE_UNIT (head));
422	  else if (head && TYPE_P (head))
423	    TB_SET_HEAD (TYPE_SIZE_UNIT (head));
424	  else
425	    TB_WF;
426	  break;
427
428	case TB_SIZE:
429	  if (head && DECL_P (head))
430	    TB_SET_HEAD (DECL_SIZE (head));
431	  else if (head && TYPE_P (head))
432	    TB_SET_HEAD (TYPE_SIZE (head));
433	  else
434	    TB_WF;
435	  break;
436
437	case TB_TYPE:
438	  if (head && TREE_TYPE (head))
439	    TB_SET_HEAD (TREE_TYPE (head));
440	  else
441	    TB_WF;
442	  break;
443
444	case TB_DECL_SAVED_TREE:
445	  if (head && TREE_CODE (head) == FUNCTION_DECL
446	      && DECL_SAVED_TREE (head))
447	    TB_SET_HEAD (DECL_SAVED_TREE (head));
448	  else
449	    TB_WF;
450	  break;
451
452	case TB_BODY:
453	  if (head && TREE_CODE (head) == BIND_EXPR)
454	    TB_SET_HEAD (TREE_OPERAND (head, 1));
455	  else
456	    TB_WF;
457	  break;
458
459	case TB_CHILD_0:
460	  if (head && EXPR_P (head) && TREE_OPERAND (head, 0))
461	    TB_SET_HEAD (TREE_OPERAND (head, 0));
462	  else
463	    TB_WF;
464	  break;
465
466	case TB_CHILD_1:
467          if (head && EXPR_P (head) && TREE_OPERAND (head, 1))
468	    TB_SET_HEAD (TREE_OPERAND (head, 1));
469	  else
470	    TB_WF;
471          break;
472
473	case TB_CHILD_2:
474          if (head && EXPR_P (head) && TREE_OPERAND (head, 2))
475	    TB_SET_HEAD (TREE_OPERAND (head, 2));
476	  else
477	    TB_WF;
478	  break;
479
480	case TB_CHILD_3:
481	  if (head && EXPR_P (head) && TREE_OPERAND (head, 3))
482	    TB_SET_HEAD (TREE_OPERAND (head, 3));
483	  else
484	    TB_WF;
485          break;
486
487	case TB_PRINT:
488	  if (head)
489	    debug_tree (head);
490	  else
491	    TB_WF;
492	  break;
493
494	case TB_PRETTY_PRINT:
495	  if (head)
496	    {
497	      print_generic_stmt (TB_OUT_FILE, head, 0);
498	      fprintf (TB_OUT_FILE, "\n");
499	    }
500	  else
501	    TB_WF;
502	  break;
503
504	case TB_SEARCH_NAME:
505
506	  break;
507
508	case TB_SEARCH_CODE:
509	  {
510	    enum tree_code code;
511	    char *arg_text;
512
513	    arg_text = strchr (input, ' ');
514	    if (arg_text == NULL)
515	      {
516		fprintf (TB_OUT_FILE, "First argument is missing.  This isn't a valid search command.  \n");
517		break;
518	      }
519	    code = TB_get_tree_code (arg_text + 1);
520
521	    /* Search in the subtree a node with the given code.  */
522	    {
523	      tree res;
524
525	      res = walk_tree (&head, find_node_with_code, &code, NULL);
526	      if (res == NULL_TREE)
527		{
528		  fprintf (TB_OUT_FILE, "There's no node with this code (reachable via the walk_tree function from this node).\n");
529		}
530	      else
531		{
532		  fprintf (TB_OUT_FILE, "Achoo!  I got this node in the tree.\n");
533		  TB_SET_HEAD (res);
534		}
535	    }
536	    break;
537	  }
538
539#define TB_MOVE_HEAD(FCT) do {       \
540  if (head)                          \
541    {                                \
542      tree t;                        \
543      t = FCT (head);                \
544      if (t)                         \
545        TB_SET_HEAD (t);             \
546      else                           \
547	TB_WF;                       \
548    }                                \
549  else                               \
550    TB_WF;                           \
551} while (0)
552
553	case TB_FIRST:
554	  TB_MOVE_HEAD (TB_first_in_bind);
555          break;
556
557        case TB_LAST:
558          TB_MOVE_HEAD (TB_last_in_bind);
559          break;
560
561	case TB_UP:
562	  TB_MOVE_HEAD (TB_up_expr);
563	  break;
564
565	case TB_PREV:
566	  TB_MOVE_HEAD (TB_prev_expr);
567	  break;
568
569	case TB_NEXT:
570	  TB_MOVE_HEAD (TB_next_expr);
571	  break;
572
573	case TB_HPREV:
574	  /* This command is a little bit special, since it deals with history
575	     stack.  For this reason it should keep the "head = ..." statement
576	     and not use TB_MOVE_HEAD.  */
577	  if (head)
578	    {
579	      tree t;
580	      t = TB_history_prev ();
581	      if (t)
582		{
583		  head = t;
584		  if (TB_verbose)
585		    {
586		      print_generic_expr (TB_OUT_FILE, head, 0);
587		      fprintf (TB_OUT_FILE, "\n");
588		    }
589		}
590	      else
591		TB_WF;
592	    }
593	  else
594	    TB_WF;
595	  break;
596
597	case TB_CHAIN:
598	  /* Don't go further if it's the last node in this chain.  */
599	  if (head && TREE_CODE (head) == BLOCK)
600	    TB_SET_HEAD (BLOCK_CHAIN (head));
601	  else if (head && TREE_CHAIN (head))
602	    TB_SET_HEAD (TREE_CHAIN (head));
603	  else
604	    TB_WF;
605	  break;
606
607	case TB_FUN:
608	  /* Go up to the current function declaration.  */
609	  TB_SET_HEAD (current_function_decl);
610	  fprintf (TB_OUT_FILE, "Current function declaration.\n");
611	  break;
612
613	case TB_HELP:
614	  /* Display a help message.  */
615	  {
616	    int i;
617	    fprintf (TB_OUT_FILE, "Possible commands are:\n\n");
618	    for (i = 0; i < TB_UNUSED_COMMAND; i++)
619	      {
620		fprintf (TB_OUT_FILE, "%20s  -  %s\n", TB_COMMAND_TEXT (i), TB_COMMAND_HELP (i));
621	      }
622	  }
623	  break;
624
625	case TB_VERBOSE:
626	  if (TB_verbose == 0)
627	    {
628	      TB_verbose = 1;
629	      fprintf (TB_OUT_FILE, "Verbose on.\n");
630	    }
631	  else
632	    {
633	      TB_verbose = 0;
634	      fprintf (TB_OUT_FILE, "Verbose off.\n");
635	    }
636	  break;
637
638	case TB_EXIT:
639	case TB_QUIT:
640	  /* Just exit from this function.  */
641	  goto ret;
642
643	default:
644	  TB_NIY;
645	}
646    }
647
648 ret:;
649  delete TB_up_ht;
650  TB_up_ht = NULL;
651  return;
652}
653
654
655/* Search the first node in this BIND_EXPR.  */
656
657static tree
658TB_first_in_bind (tree node)
659{
660  tree t;
661
662  if (node == NULL_TREE)
663    return NULL_TREE;
664
665  while ((t = TB_prev_expr (node)))
666    node = t;
667
668  return node;
669}
670
671/* Search the last node in this BIND_EXPR.  */
672
673static tree
674TB_last_in_bind (tree node)
675{
676  tree t;
677
678  if (node == NULL_TREE)
679    return NULL_TREE;
680
681  while ((t = TB_next_expr (node)))
682    node = t;
683
684  return node;
685}
686
687/* Search the parent expression for this node.  */
688
689static tree
690TB_up_expr (tree node)
691{
692  tree res;
693  if (node == NULL_TREE)
694    return NULL_TREE;
695
696  res = TB_up_ht->find (node);
697  return res;
698}
699
700/* Search the previous expression in this BIND_EXPR.  */
701
702static tree
703TB_prev_expr (tree node)
704{
705  node = TB_current_chain_node (node);
706
707  if (node == NULL_TREE)
708    return NULL_TREE;
709
710  node = TB_up_expr (node);
711  if (node && TREE_CODE (node) == COMPOUND_EXPR)
712    return node;
713  else
714    return NULL_TREE;
715}
716
717/* Search the next expression in this BIND_EXPR.  */
718
719static tree
720TB_next_expr (tree node)
721{
722  node = TB_current_chain_node (node);
723
724  if (node == NULL_TREE)
725    return NULL_TREE;
726
727  node = TREE_OPERAND (node, 1);
728  return node;
729}
730
731static tree
732TB_current_chain_node (tree node)
733{
734  if (node == NULL_TREE)
735    return NULL_TREE;
736
737  if (TREE_CODE (node) == COMPOUND_EXPR)
738    return node;
739
740  node = TB_up_expr (node);
741  if (node)
742    {
743      if (TREE_CODE (node) == COMPOUND_EXPR)
744	return node;
745
746      node = TB_up_expr (node);
747      if (TREE_CODE (node) == COMPOUND_EXPR)
748	return node;
749    }
750
751  return NULL_TREE;
752}
753
754/* For each node store in its children nodes that the current node is their
755   parent.  This function is used by walk_tree.  */
756
757static tree
758store_child_info (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
759		  void *data ATTRIBUTE_UNUSED)
760{
761  tree node;
762  tree_node **slot;
763
764  node = *tp;
765
766  /* 'node' is the parent of 'TREE_OPERAND (node, *)'.  */
767  if (EXPR_P (node))
768    {
769      int n = TREE_OPERAND_LENGTH (node);
770      int i;
771      for (i = 0; i < n; i++)
772	{
773	  tree op = TREE_OPERAND (node, i);
774	  slot = TB_up_ht->find_slot (op, INSERT);
775	  *slot = node;
776	}
777    }
778
779  /* Never stop walk_tree.  */
780  return NULL_TREE;
781}
782
783/* Update information about upper expressions in the hash table.  */
784
785static void
786TB_update_up (tree node)
787{
788  while (node)
789    {
790      walk_tree (&node, store_child_info, NULL, NULL);
791
792      /* Walk function's body.  */
793      if (TREE_CODE (node) == FUNCTION_DECL)
794        if (DECL_SAVED_TREE (node))
795          walk_tree (&DECL_SAVED_TREE (node), store_child_info, NULL, NULL);
796
797      /* Walk rest of the chain.  */
798      node = TREE_CHAIN (node);
799    }
800  fprintf (TB_OUT_FILE, "Up/prev expressions updated.\n");
801}
802
803/* Parse the input string for determining the command the user asked for.  */
804
805static TB_CODE
806TB_get_command (char *input)
807{
808  unsigned int mn, size_tok;
809  int comp;
810  char *space;
811
812  space = strchr (input, ' ');
813  if (space != NULL)
814    size_tok = strlen (input) - strlen (space);
815  else
816    size_tok = strlen (input) - 1;
817
818  for (mn = 0; mn < TB_UNUSED_COMMAND; mn++)
819    {
820      if (size_tok != TB_COMMAND_LEN (mn))
821	continue;
822
823      comp = memcmp (input, TB_COMMAND_TEXT (mn), TB_COMMAND_LEN (mn));
824      if (comp == 0)
825	/* Here we just determined the command.  If this command takes
826	   an argument, then the argument is determined later.  */
827	return TB_COMMAND_CODE (mn);
828    }
829
830  /* Not a valid command.  */
831  return TB_UNUSED_COMMAND;
832}
833
834/* Parse the input string for determining the tree code.  */
835
836static enum tree_code
837TB_get_tree_code (char *input)
838{
839  unsigned int mn, size_tok;
840  int comp;
841  char *space;
842
843  space = strchr (input, ' ');
844  if (space != NULL)
845    size_tok = strlen (input) - strlen (space);
846  else
847    size_tok = strlen (input) - 1;
848
849  for (mn = 0; mn < LAST_AND_UNUSED_TREE_CODE; mn++)
850    {
851      if (size_tok != TB_TREE_CODE_LEN (mn))
852	continue;
853
854      comp = memcmp (input, TB_TREE_CODE_TEXT (mn), TB_TREE_CODE_LEN (mn));
855      if (comp == 0)
856	{
857	  fprintf (TB_OUT_FILE, "%s\n", TB_TREE_CODE_TEXT (mn));
858	  return TB_TREE_CODE (mn);
859	}
860    }
861
862  /* This isn't a valid code.  */
863  return LAST_AND_UNUSED_TREE_CODE;
864}
865
866/* Find a node with a given code.  This function is used as an argument to
867   walk_tree.  */
868
869static tree
870find_node_with_code (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
871		     void *data)
872{
873  enum tree_code *code;
874  code = (enum tree_code *) data;
875  if (*code == TREE_CODE (*tp))
876    return *tp;
877
878  return NULL_TREE;
879}
880
881/* Returns a pointer to the last visited node.  */
882
883static tree
884TB_history_prev (void)
885{
886  if (!vec_safe_is_empty (TB_history_stack))
887    {
888      tree last = TB_history_stack->last ();
889      TB_history_stack->pop ();
890      return last;
891    }
892  return NULL_TREE;
893}
894
895/* Read up to (and including) a '\n' from STREAM into *LINEPTR
896   (and null-terminate it). *LINEPTR is a pointer returned from malloc
897   (or NULL), pointing to *N characters of space.  It is realloc'd as
898   necessary.  Returns the number of characters read (not including the
899   null terminator), or -1 on error or EOF.
900   This function comes from sed (and is supposed to be a portable version
901   of getline).  */
902
903static long
904TB_getline (char **lineptr, long *n, FILE *stream)
905{
906  char *line, *p;
907  long size, copy;
908
909  if (lineptr == NULL || n == NULL)
910    {
911      errno = EINVAL;
912      return -1;
913    }
914
915  if (ferror (stream))
916    return -1;
917
918  /* Make sure we have a line buffer to start with.  */
919  if (*lineptr == NULL || *n < 2) /* !seen and no buf yet need 2 chars.  */
920    {
921#ifndef MAX_CANON
922#define MAX_CANON       256
923#endif
924      line = (char *) xrealloc (*lineptr, MAX_CANON);
925      if (line == NULL)
926        return -1;
927      *lineptr = line;
928      *n = MAX_CANON;
929    }
930
931  line = *lineptr;
932  size = *n;
933
934  copy = size;
935  p = line;
936
937  while (1)
938    {
939      long len;
940
941      while (--copy > 0)
942        {
943          register int c = getc (stream);
944          if (c == EOF)
945            goto lose;
946          else if ((*p++ = c) == '\n')
947            goto win;
948        }
949
950      /* Need to enlarge the line buffer.  */
951      len = p - line;
952      size *= 2;
953      line = (char *) xrealloc (line, size);
954      if (line == NULL)
955        goto lose;
956      *lineptr = line;
957      *n = size;
958      p = line + len;
959      copy = size - len;
960    }
961
962 lose:
963  if (p == *lineptr)
964    return -1;
965
966  /* Return a partial line since we got an error in the middle.  */
967 win:
968#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(MSDOS)
969  if (p - 2 >= *lineptr && p[-2] == '\r')
970    p[-2] = p[-1], --p;
971#endif
972  *p = '\0';
973  return p - *lineptr;
974}
975