1 /*
2 Copyright (C) 2004, 2005, 2007, 2008, 2009, 2011 R. Bernstein
3 <rocky@gnu.org>
4 This file is part of GNU Make (remake variant).
5 
6 GNU Make is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Make is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Make; see the file COPYING.  If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.  */
20 /* Create filename to line number table used by breakpoints */
21 #include "../make.h"
22 #include <assert.h>
23 #include "../filedef.h"
24 #include "../file.h"
25 #include "../read.h"
26 #include "../rule.h"
27 #include "./file2line.h"
28 
29 unsigned long
file2lines_hash_1(const void * key)30 file2lines_hash_1 (const void *key)
31 {
32   return_ISTRING_HASH_1 (((const lineno_array_t *) key)->hname);
33 }
34 
35 unsigned long
file2lines_hash_2(const void * key)36 file2lines_hash_2 (const void *key)
37 {
38   return_ISTRING_HASH_2 (((const lineno_array_t *) key)->hname);
39 }
40 
41 static int
file2lines_hash_cmp(const void * x,const void * y)42 file2lines_hash_cmp (const void *x, const void *y)
43 {
44   return strcmp(((const lineno_array_t *) x)->hname,
45 		((const lineno_array_t *) y)->hname);
46 }
47 
48 lineno_array_t *
lookup_file2lines(const char * psz_filename)49 lookup_file2lines (const char *psz_filename)
50 {
51   assert (*psz_filename != '\0');
52   return hash_find_item (&file2lines, &psz_filename);
53 }
54 
55 /* FIXME return a status code when we fail. */
56 file_t *
target_for_file_and_line(const char * psz_filename,unsigned int lineno,f2l_entry_t * entry_type)57 target_for_file_and_line (const char *psz_filename, unsigned int lineno,
58                           /*out*/ f2l_entry_t *entry_type)
59 {
60   lineno_array_t **pp_linenos;
61   lineno_array_t lookup_linenos;
62   assert (*psz_filename != '\0');
63   lookup_linenos.hname = psz_filename;
64   if (0 == file2lines.ht_size) file2lines_init();
65   pp_linenos = (lineno_array_t **)
66     hash_find_slot(&file2lines, &lookup_linenos);
67 
68   if (NULL == *pp_linenos) return NULL;
69   if (lineno > (*pp_linenos)->size) return NULL;
70   *entry_type = (*pp_linenos)->type[lineno];
71   return (*pp_linenos)->array[lineno];
72 }
73 
74 void
enter_target_lineno(const char * psz_filename,unsigned int lineno,file_t * p_target)75 enter_target_lineno (const char *psz_filename, unsigned int lineno,
76 	      file_t *p_target)
77 {
78   lineno_array_t lookup_linenos;
79   lineno_array_t **pp_linenos;
80   file_t *p_file;
81 
82   lookup_linenos.hname = psz_filename;
83   pp_linenos = (lineno_array_t **)
84     hash_find_slot(&file2lines, &lookup_linenos);
85   p_file = lookup_file(psz_filename);
86 
87   if (p_file == NULL) {
88     printf("Could not find file %s\n", psz_filename);
89     return;
90   }
91   if (p_file->nlines == 0) {
92     printf("Warning: %s shows no lines\n", psz_filename);
93   }
94 
95   if (HASH_VACANT(*pp_linenos)) {
96     const unsigned int nlines = p_file->nlines+1;
97     void **new_array = calloc (sizeof(void *), nlines);
98     f2l_entry_t *new_type = calloc (sizeof(f2l_entry_t *), nlines);
99     lineno_array_t *p_new_linenos = calloc (sizeof(lineno_array_t), 1);
100     *pp_linenos = p_new_linenos;
101     (*pp_linenos)->hname = psz_filename;
102     (*pp_linenos)->type = new_type;
103     (*pp_linenos)->array = new_array;
104     (*pp_linenos)->size = nlines;
105   }
106   (*pp_linenos)->type[lineno]  = F2L_TARGET;
107   (*pp_linenos)->array[lineno] = p_target;
108 }
109 
110 
111 static void
file2line_init(const void * item)112 file2line_init (const void *item)
113 {
114   file_t *p_target = (file_t *) item;
115   const gmk_floc *p_floc = &p_target->floc;
116   if (p_floc && p_floc->filenm) {
117     enter_target_lineno(p_floc->filenm, p_floc->lineno, p_target);
118   }
119 }
120 
121 static void
enter_rule_lineno(rule_t * r)122 enter_rule_lineno (rule_t *r)
123 {
124   lineno_array_t lookup_linenos;
125   lineno_array_t **pp_linenos;
126   const char *psz_filename = r->floc.filenm;
127   const unsigned int lineno = r->floc.lineno;
128   file_t *p_file;
129 
130   if (!psz_filename) return;
131   lookup_linenos.hname = psz_filename;
132   pp_linenos = (lineno_array_t **)
133     hash_find_slot(&file2lines, &lookup_linenos);
134   p_file = lookup_file(psz_filename);
135 
136   if (p_file == NULL) {
137     printf("Could not find file %s\n", psz_filename);
138     return;
139   }
140   if (p_file->nlines == 0) {
141     printf("Warning: %s shows no lines\n", psz_filename);
142   }
143 
144   if (HASH_VACANT(*pp_linenos)) {
145     const unsigned int nlines = p_file->nlines+1;
146     void **new_array = calloc (sizeof(void *), nlines);
147     f2l_entry_t *new_type = calloc (sizeof(f2l_entry_t *), nlines);
148     lineno_array_t *p_new_linenos = calloc (sizeof(lineno_array_t), 1);
149     *pp_linenos = p_new_linenos;
150     (*pp_linenos)->hname = psz_filename;
151     (*pp_linenos)->type = new_type;
152     (*pp_linenos)->array = new_array;
153     (*pp_linenos)->size = nlines;
154   }
155   (*pp_linenos)->type[lineno]  = F2L_PATTERN;
156   (*pp_linenos)->array[lineno] = r;
157 }
158 
159 
160 /*!
161   Initializes hash table file2lines. file2lines is used in breakpoints
162   only. So we do this on demand.
163 */
file2lines_init(void)164 bool file2lines_init(void)
165 {
166   if (!read_makefiles) return false;
167   hash_init (&file2lines, files.ht_size, file2lines_hash_1, file2lines_hash_2,
168 	     file2lines_hash_cmp);
169   hash_map (&files, file2line_init);
170 
171   {
172     rule_t *r;
173     for (r = pattern_rules; r != 0; r = r->next) {
174       enter_rule_lineno(r);
175     }
176   }
177 
178   return true;
179 }
180 
file2lines_print_entry(const void * item)181 void file2lines_print_entry(const void *item)
182 {
183     const lineno_array_t *p_linenos = (lineno_array_t *) item;
184     unsigned int i;
185     file_t *p_target;
186     printf("%s:\n", p_linenos->hname);
187     for (i=0; i<p_linenos->size; i++)
188       {
189 	p_target = p_linenos->array[i];
190         if (p_target) {
191           if (p_linenos->type[i] == F2L_TARGET) {
192             printf("%8lu: %s\n",
193                    p_target->floc.lineno, p_target->name);
194           } else  {
195             rule_t *p_rule = (rule_t *) p_target;
196             printf("%8lu: %s (pattern)\n",
197                    p_rule->floc.lineno, p_rule->targets[0]);
198           }
199         }
200       }
201 }
202 
file2lines_dump(void)203 void file2lines_dump(void)
204 {
205   file2lines_init();
206   hash_map (&file2lines, file2lines_print_entry);
207 }
208 
209 /*
210  * Local variables:
211  * eval: (c-set-style "gnu")
212  * indent-tabs-mode: nil
213  * End:
214  */
215