PennMUSH Community

root/1.8.3/trunk/src/atr_tab.c

Revision 1167, 10.9 kB (checked in by shawnw, 8 months ago)

Merge devel into trunk for p6 release

Line 
1 /**
2  * \file atr_tab.c
3  *
4  * \brief The table of standard attributes and code to manipulate it.
5  *
6  *
7  */
8
9 #include "config.h"
10
11 #include <string.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include "conf.h"
15 #include "externs.h"
16 #include "attrib.h"
17 #include "atr_tab.h"
18 #include "ptab.h"
19 #include "privtab.h"
20 #include "mymalloc.h"
21 #include "dbdefs.h"
22 #include "log.h"
23 #include "parse.h"
24 #include "confmagic.h"
25
26
27 /** An alias for an attribute.
28  */
29 typedef struct atr_alias {
30   const char *alias;            /**< The alias. */
31   const char *realname;         /**< The attribute's canonical name. */
32 } ATRALIAS;
33
34 /** Prefix table for standard attribute names */
35 PTAB ptab_attrib;
36
37 /** Attribute flags for setting */
38 PRIV attr_privs_set[] = {
39   {"no_command", '$', AF_NOPROG, AF_NOPROG},
40   {"no_inherit", 'i', AF_PRIVATE, AF_PRIVATE},
41   {"private", 'i', AF_PRIVATE, AF_PRIVATE},
42   {"no_clone", 'c', AF_NOCOPY, AF_NOCOPY},
43   {"wizard", 'w', AF_WIZARD, AF_WIZARD},
44   {"visual", 'v', AF_VISUAL, AF_VISUAL},
45   {"mortal_dark", 'm', AF_MDARK, AF_MDARK},
46   {"hidden", 'm', AF_MDARK, AF_MDARK},
47   {"regexp", 'R', AF_REGEXP, AF_REGEXP},
48   {"case", 'C', AF_CASE, AF_CASE},
49   {"locked", '+', AF_LOCKED, AF_LOCKED},
50   {"safe", 'S', AF_SAFE, AF_SAFE},
51   {"prefixmatch", '\0', AF_PREFIXMATCH, AF_PREFIXMATCH},
52   {"veiled", 'V', AF_VEILED, AF_VEILED},
53   {"debug", 'b', AF_DEBUG, AF_DEBUG},
54   {"public", 'p', AF_PUBLIC, AF_PUBLIC},
55   {"nearby", 'n', AF_NEARBY, AF_NEARBY},
56   {"noname", 'N', AF_NONAME, AF_NONAME},
57   {"nospace", 's', AF_NOSPACE, AF_NOSPACE},
58   {"amhear", 'M', AF_MHEAR, AF_MHEAR},
59   {"aahear", 'A', AF_AHEAR, AF_AHEAR},
60   {NULL, '\0', 0, 0}
61 };
62
63 /** Attribute flags for viewing */
64 PRIV attr_privs_view[] = {
65   {"no_command", '$', AF_NOPROG, AF_NOPROG},
66   {"no_inherit", 'i', AF_PRIVATE, AF_PRIVATE},
67   {"private", 'i', AF_PRIVATE, AF_PRIVATE},
68   {"no_clone", 'c', AF_NOCOPY, AF_NOCOPY},
69   {"wizard", 'w', AF_WIZARD, AF_WIZARD},
70   {"visual", 'v', AF_VISUAL, AF_VISUAL},
71   {"mortal_dark", 'm', AF_MDARK, AF_MDARK},
72   {"hidden", 'm', AF_MDARK, AF_MDARK},
73   {"regexp", 'R', AF_REGEXP, AF_REGEXP},
74   {"case", 'C', AF_CASE, AF_CASE},
75   {"locked", '+', AF_LOCKED, AF_LOCKED},
76   {"safe", 'S', AF_SAFE, AF_SAFE},
77   {"internal", '\0', AF_INTERNAL, AF_INTERNAL},
78   {"prefixmatch", '\0', AF_PREFIXMATCH, AF_PREFIXMATCH},
79   {"veiled", 'V', AF_VEILED, AF_VEILED},
80   {"debug", 'b', AF_DEBUG, AF_DEBUG},
81   {"public", 'p', AF_PUBLIC, AF_PUBLIC},
82   {"nearby", 'n', AF_NEARBY, AF_NEARBY},
83   {"noname", 'N', AF_NONAME, AF_NONAME},
84   {"nospace", 's', AF_NOSPACE, AF_NOSPACE},
85   {"amhear", 'M', AF_MHEAR, AF_MHEAR},
86   {"aahear", 'A', AF_AHEAR, AF_AHEAR},
87   {"", '`', AF_ROOT, AF_ROOT},
88   {NULL, '\0', 0, 0}
89 };
90
91
92 /*----------------------------------------------------------------------
93  * Prefix-table functions of various sorts
94  */
95
96 static ATTR *aname_find_exact(const char *name);
97 void init_aname_table(void);
98
99 /** Attribute table lookup by name or alias.
100  * given an attribute name, look it up in the complete attribute table
101  * (real names plus aliases), and return the appropriate real attribute.
102  */
103 ATTR *
104 aname_hash_lookup(const char *name)
105 {
106   ATTR *ap;
107   /* Exact matches always work */
108   if ((ap = (ATTR *) ptab_find_exact(&ptab_attrib, name)))
109     return ap;
110   /* Prefix matches work if the attribute is AF_PREFIXMATCH */
111   if ((ap = (ATTR *) ptab_find(&ptab_attrib, name)) && AF_Prefixmatch(ap))
112     return ap;
113   return NULL;
114 }
115
116 /** Build the basic attribute table.
117  */
118 void
119 init_aname_table(void)
120 {
121   ATTR *ap;
122
123   ptab_init(&ptab_attrib);
124   ptab_start_inserts(&ptab_attrib);
125   for (ap = attr; ap->name; ap++)
126     ptab_insert(&ptab_attrib, ap->name, ap);
127   ptab_end_inserts(&ptab_attrib);
128 }
129
130 /** Associate a new alias with an existing attribute.
131  */
132 int
133 alias_attribute(const char *atr, const char *alias)
134 {
135   ATTR *ap;
136
137   /* Make sure the alias doesn't exist already */
138   if (aname_find_exact(alias))
139     return 0;
140
141   /* Look up the original */
142   ap = aname_find_exact(atr);
143   if (!ap)
144     return 0;
145
146   ptab_insert_one(&ptab_attrib, strupper(alias), ap);
147   return 1;
148 }
149
150 static ATTR *
151 aname_find_exact(const char *name)
152 {
153   char atrname[BUFFER_LEN];
154   strcpy(atrname, name);
155   upcasestr(atrname);
156   return (ATTR *) ptab_find_exact(&ptab_attrib, atrname);
157 }
158
159
160 /** Add new standard attributes, or change permissions on them.
161  * \verbatim
162  * Given the name and permission string for an attribute, add it to
163  * the attribute table (or modify the permissions if it's already
164  * there). Permissions may be changed retroactively, which modifies
165  * permissions on any copies of that attribute set on objects in the
166  * database. This is the top-level code for @attribute/access.
167  * \endverbatim
168  * \param player the enactor.
169  * \param name the attribute name.
170  * \param perms a string of attribute permissions, space-separated.
171  * \param retroactive if true, apply the permissions retroactively.
172  */
173 void
174 do_attribute_access(dbref player, char *name, char *perms, int retroactive)
175 {
176   ATTR *ap, *ap2;
177   privbits flags = 0;
178   int i;
179   int insert = 0;
180
181   /* Parse name and perms */
182   if (!name || !*name) {
183     notify(player, T("Which attribute do you mean?"));
184     return;
185   }
186   if (strcasecmp(perms, "none")) {
187     flags = list_to_privs(attr_privs_set, perms, 0);
188     if (!flags) {
189       notify(player, T("I don't understand those permissions."));
190       return;
191     }
192   }
193   upcasestr(name);
194   /* Is this attribute already in the table? */
195   ap = (ATTR *) ptab_find_exact(&ptab_attrib, name);
196   if (ap) {
197     if (AF_Internal(ap)) {
198       /* Don't muck with internal attributes */
199       notify(player, T("That attribute's permissions can not be changed."));
200       return;
201     }
202   } else {
203     /* Create fresh if the name is ok */
204     if (!good_atr_name(name)) {
205       notify(player, T("Invalid attribute name."));
206       return;
207     }
208     insert = 1;
209     ap = (ATTR *) mush_malloc(sizeof(ATTR), "ATTR");
210     if (!ap) {
211       notify(player, "Critical memory failure - Alert God!");
212       do_log(LT_ERR, 0, 0, "do_attribute_access: unable to malloc ATTR");
213       return;
214     }
215     AL_NAME(ap) = strdup(name);
216     ap->data = NULL_CHUNK_REFERENCE;
217   }
218   AL_FLAGS(ap) = flags;
219   AL_CREATOR(ap) = player;
220
221   /* Only insert when it's not already in the table */
222   if (insert) {
223     ptab_insert_one(&ptab_attrib, name, ap);
224   }
225
226   /* Ok, now we need to see if there are any attributes of this name
227    * set on objects in the db. If so, and if we're retroactive, set
228    * perms/creator
229    */
230   if (retroactive) {
231     for (i = 0; i < db_top; i++) {
232       if ((ap2 = atr_get_noparent(i, name))) {
233         AL_FLAGS(ap2) = flags;
234         AL_CREATOR(ap2) = player;
235       }
236     }
237   }
238
239   notify_format(player, T("%s -- Attribute permissions now: %s"), name,
240                 privs_to_string(attr_privs_view, flags));
241 }
242
243
244 /** Delete an attribute from the attribute table.
245  * \verbatim
246  * Top-level function for @attrib/delete.
247  * \endverbatim
248  * \param player the enactor.
249  * \param name the name of the attribute to delete.
250  */
251 void
252 do_attribute_delete(dbref player, char *name)
253 {
254   ATTR *ap;
255
256   if (!name || !*name) {
257     notify(player, T("Which attribute do you mean?"));
258     return;
259   }
260
261   /* Is this attribute in the table? */
262   ap = (ATTR *) ptab_find_exact(&ptab_attrib, name);
263   if (!ap) {
264     notify(player, T("That attribute isn't in the attribute table"));
265     return;
266   }
267
268   /* Ok, take it out of the hash table */
269   ptab_delete(&ptab_attrib, name);
270   notify_format(player, T("Removed %s from attribute table."), name);
271   return;
272 }
273
274 /** Rename an attribute in the attribute table.
275  * \verbatim
276  * Top-level function for @attrib/rename.
277  * \endverbatim
278  * \param player the enactor.
279  * \param old the name of the attribute to rename.
280  * \param newname the new name (surprise!)
281  */
282 void
283 do_attribute_rename(dbref player, char *old, char *newname)
284 {
285   ATTR *ap;
286   if (!old || !*old || !newname || !*newname) {
287     notify(player, T("Which attributes do you mean?"));
288     return;
289   }
290   upcasestr(old);
291   upcasestr(newname);
292   /* Is the new name valid? */
293   if (!good_atr_name(newname)) {
294     notify(player, T("Invalid attribute name."));
295     return;
296   }
297   /* Is the new name already in use? */
298   ap = (ATTR *) ptab_find_exact(&ptab_attrib, newname);
299   if (ap) {
300     notify_format(player,
301                   T("The name %s is already used in the attribute table."),
302                   newname);
303     return;
304   }
305   /* Is the old name a real attribute? */
306   ap = (ATTR *) ptab_find_exact(&ptab_attrib, old);
307   if (!ap) {
308     notify(player, T("That attribute isn't in the attribute table"));
309     return;
310   }
311   /* Ok, take it out and put it back under the new name */
312   ptab_delete(&ptab_attrib, old);
313   /*  This causes a slight memory leak if you rename an attribute
314      added via /access. But that doesn't happen often. Will fix
315      someday.  */
316   AL_NAME(ap) = strdup(newname);
317   ptab_insert_one(&ptab_attrib, newname, ap);
318   notify_format(player,
319                 T("Renamed %s to %s in attribute table."), old, newname);
320   return;
321 }
322
323 /** Display information on an attribute from the table.
324  * \verbatim
325  * Top-level function for @attribute.
326  * \endverbatim
327  * \param player the enactor.
328  * \param name the name of the attribute.
329  */
330 void
331 do_attribute_info(dbref player, char *name)
332 {
333   ATTR *ap;
334   if (!name || !*name) {
335     notify(player, T("Which attribute do you mean?"));
336     return;
337   }
338
339   /* Is this attribute in the table? */
340
341   if (*name == '@')
342     name++;
343
344   ap = aname_hash_lookup(name);
345   if (!ap) {
346     notify(player, T("That attribute isn't in the attribute table"));
347     return;
348   }
349   notify_format(player, "Attribute: %s", AL_NAME(ap));
350   notify_format(player,
351                 "    Flags: %s", privs_to_string(attr_privs_view,
352                                                  AL_FLAGS(ap)));
353   notify_format(player, "  Creator: %s", unparse_dbref(AL_CREATOR(ap)));
354   return;
355 }
356
357 /** Display a list of standard attributes.
358  * \verbatim
359  * Top-level function for @list/attribs.
360  * \endverbatim
361  * \param player the enactor.
362  * \param lc if true, display the list in lowercase; otherwise uppercase.
363  */
364 void
365 do_list_attribs(dbref player, int lc)
366 {
367   char *b = list_attribs();
368   notify_format(player, T("Attribs: %s"), lc ? strlower(b) : b);
369 }
370
371 /** Return a list of standard attributes.
372  * This functions returns the list of standard attributes, separated by
373  * spaces, in a statically allocated buffer.
374  */
375 char *
376 list_attribs(void)
377 {
378   ATTR *ap;
379   const char *ptrs[BUFFER_LEN / 2];
380   static char buff[BUFFER_LEN];
381   char *bp;
382   int nptrs = 0, i;
383
384   ap = (ATTR *) ptab_firstentry(&ptab_attrib);
385   while (ap) {
386     ptrs[nptrs++] = AL_NAME(ap);
387     ap = (ATTR *) ptab_nextentry(&ptab_attrib);
388   }
389   bp = buff;
390   safe_str(ptrs[0], buff, &bp);
391   for (i = 1; i < nptrs; i++) {
392     safe_chr(' ', buff, &bp);
393     safe_str(ptrs[i], buff, &bp);
394   }
395   *bp = '\0';
396   return buff;
397 }
398
399 /** Attr things to be done after the config file is loaded but before
400  * objects are restarted.
401  */
402 void
403 attr_init_postconfig(void)
404 {
405   ATTR *a;
406   /* read_remote_desc affects AF_NEARBY flag on DESCRIBE attribute */
407   a = aname_hash_lookup("DESCRIBE");
408   if (READ_REMOTE_DESC)
409     a->flags &= ~AF_NEARBY;
410   else
411     a->flags |= AF_NEARBY;
412 }
Note: See TracBrowser for help on using the browser.