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