1 /* debug.c -- Debugging support for Khepera
2  * Created: Fri Dec 23 10:53:10 1994 by faith@dict.org
3  * Copyright 1994-1997, 2002 Rickard E. Faith (faith@dict.org)
4  * Copyright 2002-2008 Aleksey Cheusov (vle@gmx.net)
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  * \section{Debugging Support}
26  *
27  * \intro These routines provide low-level support for run-time debugging
28  * messages.  A set of global flags are maintained using "#define"
29  * statements.  These flags are assumed to be 32-bit integers, the top two
30  * bits of which are used to select one of four sets of debugging lags.
31  * Each set, therefore, has 30 bits of flag information.  The last set
32  * (i.e., when the top two bits are both set) is reserved for internal use
33  * by the \khepera library.  For convenience, each flag can be given a
34  * unique name, so that flags can be set easily with command-line options.
35  *
36  */
37 
38 #include "maaP.h"
39 
40 #define TEST(flags,var) (((flags)>>31)                         \
41 			 ? (((flags)>>30)                                  \
42 			    ? ((var[3] & (flags)) << 2)                    \
43 			    : ((var[2] & (flags)) << 2))                   \
44 			 : (((flags)>>30)                                  \
45 			    ? ((var[1] & (flags)) << 2)                    \
46 			    : ((var[0] & (flags)) << 2)))
47 
48 static hsh_HashTable hash;
49 static dbg_Type      setFlags[4];
50 static dbg_Type      usedFlags[4];
51 
52 /* |_dbg_exists| returns non-zero if |flag| has been associated with a name
53    (using the |_dbg_register| function). */
54 
_dbg_exists(dbg_Type flag)55 static int _dbg_exists(dbg_Type flag)
56 {
57 	return TEST(flag, usedFlags);
58 }
59 
60 /* |_dbg_name| returns a pointer to the name that was associated with the
61    |flag|. */
62 
_dbg_name(dbg_Type flag)63 static const char *_dbg_name(dbg_Type flag)
64 {
65 	hsh_Position position;
66 	void         *key;
67 	void         *datum;
68 
69 	if (!hash) err_fatal(__func__, "No debugging names registered");
70 	HSH_ITERATE(hash, position, key, datum) {
71 		if (flag == (dbg_Type)datum) {
72 			HSH_ITERATE_END(hash);
73 			return key;
74 		}
75 	}
76 
77 	return "unknown flag";
78 }
79 
80 /* |_dbg_register| is documented in the |dbg_register| section. */
81 
_dbg_register(dbg_Type flag,const char * name)82 void _dbg_register(dbg_Type flag, const char *name)
83 {
84 	dbg_Type tmp;
85 
86 	for (tmp = flag & 0x3fffffff; tmp && !(tmp & 1); tmp >>= 1);
87 	if (!tmp || tmp >> 1)
88 		err_fatal(__func__,
89 				  "Malformed flag (%lx):"
90 				  " a single low-order bit must be set",
91 				  flag);
92 
93 	if (!hash) hash = hsh_create(NULL, NULL);
94 
95 	if (_dbg_exists(flag))
96 		err_fatal(__func__,
97 				  "The debug flag %lx has been used for \"%s\""
98 				  " and cannot be reused for \"%s\"",
99 				  flag,
100 				  _dbg_name(flag),
101 				  name);
102 
103 	hsh_insert(hash, name, (void *)flag);
104 }
105 
106 /* \doc |dbg_register| is used to set up an asociated between a |flag| and
107    a |name|.  After this association is made, calls to |dbg_set| can use
108    |name| to set the global debugging flag.  Both of the high bits cannot
109    be set simultaneously---these flags are reserved for internal use by the
110    \khepera library.\footnote{For internal \khepera library use,
111    |_dbg_register| can be used to register flags which have both high bits
112    set.} */
113 
dbg_register(dbg_Type flag,const char * name)114 void dbg_register(dbg_Type flag, const char *name)
115 {
116 				/* These values are reserved for Khepera */
117    if ((flag & 0xc0000000) == 0xc0000000)
118 	 err_fatal(__func__,
119 		    "Flag (%lx) may not have both high-order bits set",
120 		    flag);
121 
122    _dbg_register(flag, name);
123 }
124 
125 /* \doc |dbg_set| sets the |name| flag.  If |name| is ``none,'' then all
126    flags are cleared.  */
127 
dbg_set(const char * name)128 void dbg_set(const char *name)
129 {
130 	dbg_Type flag;
131 
132 	if (!name) err_internal(__func__, "name is NULL");
133 	if (!hash) err_fatal(__func__, "No debugging names registered");
134 	if (!strcmp(name, "none")) {
135 		setFlags[0] = setFlags[1] = setFlags[2] = setFlags[3] = 0;
136 		return;
137 	}
138 	if (!strcmp(name, "all")) {
139 		setFlags[0] = setFlags[1] = setFlags[2] = setFlags[3] = ~0;
140 		return;
141 	}
142 
143 	if (!(flag = (dbg_Type)hsh_retrieve(hash, name))) {
144 		if (!(flag = (dbg_Type)hsh_retrieve(hash, name+1))
145 			&& *name != '-'
146 			&& *name != '+') {
147 
148 			fprintf(stderr, "Valid debugging flags are:\n");
149 			dbg_list(stderr);
150 			err_fatal(__func__,
151 					  "\"%s\" is not a valid debugging flag",
152 					  name);
153 		} else {
154 			if (*name == '+') setFlags[ flag >> 30 ] |= flag;
155 			else              setFlags[ flag >> 30 ] &= ~flag; /* - */
156 		}
157 	} else {
158 		setFlags[ flag >> 30 ] |= flag;
159 	}
160 }
161 
162 /* \doc Used to set the flag using the predefined macro instead of the
163    string name. */
164 
dbg_set_flag(dbg_Type flag)165 void dbg_set_flag(dbg_Type flag)
166 {
167 	setFlags[ flag >> 30 ] |= flag;
168 }
169 
170 /* \doc Used to unset the flag using the predefined macro instead of the
171    string name. */
172 
dbg_unset_flag(dbg_Type flag)173 void dbg_unset_flag(dbg_Type flag)
174 {
175 	setFlags[ flag >> 30 ] &= ~flag;
176 }
177 
178 /* \doc This function tests the |flag|, returning non-zero if the
179    |flag| is set, and zero otherwise. */
180 
dbg_test(dbg_Type flag)181 int dbg_test(dbg_Type flag)
182 {
183 	return TEST(flag, setFlags);
184 }
185 
186 /* \doc |dbg_destroy| destroys the memory associated with the debugging
187    support routines.  This routine should \emph{never} be called by the
188    programmer: it is automatically called at program termination on systems
189    that support the |atexit| or |on_exit| calls. */
190 
dbg_destroy(void)191 void dbg_destroy(void)
192 {
193 	if (hash) hsh_destroy(hash);
194 	hash = NULL;
195 	setFlags[0] = setFlags[1] = setFlags[2] = setFlags[3] = 0;
196 	usedFlags[0] = usedFlags[1] = usedFlags[2] = usedFlags[3] = 0;
197 }
198 
199 
_dbg_user(const void * key,const void * datum,void * arg)200 static int _dbg_user(const void *key, const void *datum, void *arg)
201 {
202 	FILE     *stream = (FILE *)arg;
203 	dbg_Type flag    = (dbg_Type)datum;
204 
205 	if ((flag & 0xc0000000) != 0xc0000000)
206 		fprintf(stream, "  %s\n", (char*) __UNCONST(key));
207 	return 0;
208 }
209 
_dbg_builtin(const void * key,const void * datum,void * arg)210 static int _dbg_builtin(const void *key, const void *datum, void *arg)
211 {
212 	FILE     *stream = (FILE *)arg;
213 	dbg_Type flag    = (dbg_Type)datum;
214 
215 	if ((flag & 0xc0000000) == 0xc0000000)
216 		fprintf(stream, "  %s (builtin)\n", (char*) __UNCONST(key));
217 	return 0;
218 }
219 
220 /* |dbg_list| lists all of the valid user-level debugging flags to the
221    specified |stream|. */
222 
dbg_list(FILE * stream)223 void dbg_list(FILE *stream)
224 {
225 	hsh_iterate_arg(hash, _dbg_user, stream);
226 	hsh_iterate_arg(hash, _dbg_builtin, stream);
227 }
228