1 /*
2  *  KCemu -- The emulator for the KC85 homecomputer series and much more.
3  *  Copyright (C) 1997-2010 Torsten Paul
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <fstream>
23 
24 #include "libdbg/dbg.h"
25 
p_map(const char * name,bool allow_subkeys)26 p_map::p_map(const char *name, bool allow_subkeys)
27 {
28   _name = strdup(name);
29   _allow_subkeys = allow_subkeys;
30 }
31 
~p_map(void)32 p_map::~p_map(void)
33 {
34   if (_name)
35     free(_name);
36 }
37 
38 const char *
get_name(void)39 p_map::get_name(void)
40 {
41   if (_name)
42     return _name;
43   return "<none>";
44 }
45 
46 void
set_allow_subkeys(bool allow_subkeys)47 p_map::set_allow_subkeys(bool allow_subkeys)
48 {
49   _allow_subkeys = allow_subkeys;
50 }
51 
52 bool
get_allow_subkeys(void)53 p_map::get_allow_subkeys(void)
54 {
55   return _allow_subkeys;
56 }
57 
p_tree(void)58 p_tree::p_tree(void)
59 {
60   _map = new p_map("", false);
61 }
62 
~p_tree(void)63 p_tree::~p_tree(void)
64 {
65   delete _map;
66 }
67 
68 void
add(const char * data,bool allow_subkeys)69 p_tree::add(const char *data, bool allow_subkeys)
70 {
71   p_map *m;
72   char *ptr, *tmp;
73   char d[1024];
74 
75   strncpy(d, data, 1024);
76   d[1023] = '\0';
77 
78   m = _map;
79   ptr = strtok(d, "/");
80   while (ptr != 0)
81     {
82       p_map::const_iterator m_it = m->find(ptr);
83       if (m_it == m->end())
84         {
85 	  tmp = strdup(ptr);
86           p_map *new_map = new p_map(tmp, false);
87           (*m)[tmp] = new_map;
88           m = new_map;
89         }
90       else
91         {
92           m = (*m_it).second;
93         }
94       ptr = strtok(0, "/");
95     }
96   if (allow_subkeys)
97     m->set_allow_subkeys(true);
98 }
99 
100 bool
check_path(const char * data)101 p_tree::check_path(const char *data)
102 {
103   p_map *m;
104   char *ptr;
105   char d[1024];
106 
107   strncpy(d, data, 1024);
108   d[1023] = '\0';
109 
110   m = _map;
111   ptr = strtok(d, "/");
112   while (ptr != 0)
113     {
114       if (m->get_allow_subkeys())
115         break;
116       p_map::const_iterator m_it = m->find(ptr);
117       if (m_it == m->end())
118         {
119           return false;
120         }
121       m = (*m_it).second;
122       ptr = strtok(0, "/");
123     }
124 
125   return true;
126 }
127 
128 void
clear()129 p_tree::clear()
130 {
131   clear(_map);
132 }
133 
134 void
clear(p_map * map)135 p_tree::clear(p_map *map)
136 {
137   for (p_map::iterator it = map->begin();it != map->end();it++)
138     clear((*it).second);
139 
140   map->clear();
141 
142   if (_map != map) // don't free top level object
143     delete map;
144 }
145 
146 void
dump(std::ostream & os,p_map * map,int level) const147 p_tree::dump(std::ostream& os, p_map *map, int level) const
148 {
149   for (int a = 0;a < level;a++)
150     os << "  ";
151   os << map->get_name();
152   if (map->get_allow_subkeys())
153     os << " <*>";
154   os << std::endl;
155 
156   for (p_map::iterator it = map->begin();it != map->end();it++)
157     dump(os, (*it).second, level + 1);
158 }
159 
operator <<(std::ostream & os,const p_tree & t)160 std::ostream& operator<< (std::ostream& os, const p_tree& t)
161 {
162   os << "p_tree:" << std::endl;
163   t.dump(os, t._map, 0);
164   return os;
165 }
166 
167 DBG_class *DBG_class::_singleton = 0;
168 
DBG_class(void)169 DBG_class::DBG_class(void)
170 {
171   _o = &std::cout;
172   load_config();
173 }
174 
~DBG_class(void)175 DBG_class::~DBG_class(void)
176 {
177   _tree.clear();
178 }
179 
180 DBG_class *
instance(void)181 DBG_class::instance(void)
182 {
183   if (_singleton == 0)
184     _singleton = new DBG_class();
185   return _singleton;
186 }
187 
188 void
clear(void)189 DBG_class::clear(void)
190 {
191   _tree.clear();
192 }
193 
194 void
load_config(void)195 DBG_class::load_config(void)
196 {
197   char *filename, *tmp;
198 
199   clear();
200 
201   tmp = getenv("HOME");
202   if (tmp)
203     {
204       filename = new char[strlen(tmp) + 8];
205       strcpy(filename, tmp);
206       strcat(filename, "/.debug");
207       load_file(filename);
208       delete[] filename;
209     }
210 }
211 
212 void
load_file(const char * filename)213 DBG_class::load_file(const char *filename)
214 {
215   std::ifstream is;
216   char line[4096];
217 
218   is.open(filename);
219   if (!is)
220     return;
221 
222   while (242)
223     {
224       is.getline(line, 4096);
225       if (is.eof())
226 	break;
227       if (line[0] != '#')
228         add_path(line, false);
229     }
230 
231   is.close();
232 }
233 
234 void
set_output_stream(std::ostream * os)235 DBG_class::set_output_stream(std::ostream *os)
236 {
237   _o = os;
238 }
239 
240 void
add_path(const char * path,bool allow_subkeys)241 DBG_class::add_path(const char *path, bool allow_subkeys)
242 {
243   _tree.add(path, allow_subkeys);
244 }
245 
246 void
form(const char * path,const char * format...)247 DBG_class::form(const char *path, const char *format ...)
248 {
249   char buf[8192];
250 
251   if (!_tree.check_path(path))
252     return;
253 
254   va_list ap;
255   va_start(ap, format);
256   vsnprintf(buf, 8192, format, ap);
257   *_o << buf;
258   _o->flush();
259   va_end(ap);
260 }
261 
262 void
print(const char * path,const char * msg)263 DBG_class::print(const char *path, const char *msg)
264 {
265   if (!_tree.check_path(path))
266     return;
267 
268   *_o << "DEBUG: " << path << " - " << msg;
269   _o->flush();
270 }
271 
272 void
println(const char * path,const char * msg)273 DBG_class::println(const char *path, const char *msg)
274 {
275   if (!_tree.check_path(path))
276     return;
277 
278   *_o << "DEBUG: " << path << " - " << msg << std::endl;
279   _o->flush();
280 }
281 
282 bool
check(const char * path)283 DBG_class::check(const char *path)
284 {
285   return _tree.check_path(path);
286 }
287 
operator <<(std::ostream & os,const DBG_class & dbg)288 std::ostream& operator<< (std::ostream& os, const DBG_class& dbg)
289 {
290   os << "DBG:" << std::endl;
291   os << dbg._tree;
292   return os;
293 }
294