1 /* flags.c -- Flag support for Khepera
2  * Created: Sat Mar 23 10:11:52 1996 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{Flag Support}
26  *
27  * \intro These routines provide low-level support for run-time program
28  * flow control.  The mechanism used is similar to that used for debugging
29  * messages.  A set of global flags are maintained using "#define"
30  * statements.  These flags are assumed to be 32-bit integers, the top two
31  * bits of which are used to select one of four sets of debugging lags.
32  * Each set, therefore, has 30 bits of flag information.  For convenience,
33  * each flag can be given a unique name, so that flags can be set easily
34  * with command-line options.
35  * */
36 
37 #include "maaP.h"
38 
39 #define TEST(flags,var) (((flags)>>31)                                     \
40 			 ? (((flags)>>30)                                  \
41 			    ? ((var[3] & (flags)) << 2)                    \
42 			    : ((var[2] & (flags)) << 2))                   \
43 			 : (((flags)>>30)                                  \
44 			    ? ((var[1] & (flags)) << 2)                    \
45 			    : ((var[0] & (flags)) << 2)))
46 
47 static hsh_HashTable hash;
48 static flg_Type      setFlags[4];
49 static flg_Type      usedFlags[4];
50 
51 /* |_flg_exists| returns non-zero if |flag| has been associated with a name
52    (using the |flg_register| function). */
53 
_flg_exists(flg_Type flag)54 static int _flg_exists(flg_Type flag)
55 {
56 	return TEST(flag, usedFlags);
57 }
58 
59 /* |flg_name| returns a pointer to the name that was associated with the
60    |flag|. */
61 
flg_name(flg_Type flag)62 const char *flg_name(flg_Type flag)
63 {
64 	hsh_Position position;
65 	void         *key;
66 	void         *datum;
67 
68 	HSH_ITERATE(hash, position, key, datum) {
69 		if (flag == (flg_Type)datum) {
70 			HSH_ITERATE_END(hash);
71 			return key;
72 		}
73 	}
74 
75 	return "unknown flag";
76 }
77 
78 /* \doc |flg_register| is used to set up an asociated between a |flag| and
79    a |name|.  After this association is made, calls to |flg_set| can use
80    |name| to set the global flag.  */
81 
flg_register(flg_Type flag,const char * name)82 void flg_register(flg_Type flag, const char *name)
83 {
84 	flg_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 (_flg_exists(flag))
96 		err_fatal(__func__,
97 				  "The flag %lx has been used for \"%s\""
98 				  " and cannot be reused for \"%s\"",
99 				  flag,
100 				  flg_name(flag),
101 				  name);
102 
103 	hsh_insert(hash, name, (void *)flag);
104 }
105 
106 /* \doc |flg_set| sets the |name| flag.  If |name| is ``none,'' then all
107    flags are cleared.  */
108 
flg_set(const char * name)109 void flg_set(const char *name)
110 {
111 	flg_Type flag;
112 
113 	if (!name) err_internal(__func__, "name is NULL");
114 	if (!hash) err_fatal(__func__, "No flag names registered");
115 	if (!strcmp(name, "none")) {
116 		setFlags[0] = setFlags[1] = setFlags[2] = setFlags[3] = 0;
117 		return;
118 	}
119 	if (!strcmp(name, "all")) {
120 		setFlags[0] = setFlags[1] = setFlags[2] = setFlags[3] = ~0;
121 		return;
122 	}
123 
124 	if (!(flag = (flg_Type)hsh_retrieve(hash, name))) {
125 		flag = 0;
126 
127 		if (
128 			(*name != '-' && *name != '+') ||
129 			!(flag = (flg_Type) hsh_retrieve(hash, name+1)))
130 		{
131 			fprintf(stderr, "Valid flags are:\n");
132 			flg_list(stderr);
133 			err_fatal(__func__,
134 					  "\"%s\" is not a valid flag",
135 					  name);
136 		} else {
137 			if (flag){
138 				if (*name == '+') setFlags[ flag >> 30 ] |= flag;
139 				else              setFlags[ flag >> 30 ] &= ~flag; /* - */
140 			}
141 		}
142 	} else {
143 		setFlags[ flag >> 30 ] |= flag;
144 	}
145 }
146 
147 /* \doc This function tests the |flag|, returning non-zero if the
148    |flag| is set, and zero otherwise. */
149 
flg_test(flg_Type flag)150 int flg_test(flg_Type flag)
151 {
152 	return TEST(flag, setFlags);
153 }
154 
155 /* \doc |flg_destroy| destroys the memory associated with the flag support
156    routines.  This routine should \emph{never} be called by the programmer:
157    it is automatically called at program termination on systems that
158    support the |atexit| or |on_exit| calls. */
159 
flg_destroy(void)160 void flg_destroy(void)
161 {
162 	if (hash) hsh_destroy(hash);
163 	hash = NULL;
164 	setFlags[0] = setFlags[1] = setFlags[2] = setFlags[3] = 0;
165 	usedFlags[0] = usedFlags[1] = usedFlags[2] = usedFlags[3] = 0;
166 }
167 
168 
_flg_user(const void * key,const void * datum,void * arg)169 static int _flg_user(const void *key, const void *datum, void *arg)
170 {
171 	FILE     *stream = (FILE *)arg;
172 
173 	fprintf(stream, "  %s\n", (char*) __UNCONST(key));
174 	return 0;
175 }
176 
177 /* |flg_list| lists all of the valid flags to the specified |stream|. */
178 
flg_list(FILE * stream)179 void flg_list(FILE *stream)
180 {
181 	hsh_iterate_arg(hash, _flg_user, stream);
182 }
183