root/1.8.3/tags/p6/src/atr_tab.c

Revision 1167, 10.9 KB (checked in by shawnw, 13 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 */
29typedef 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 */
35PTAB ptab_attrib;
36
37/** Attribute flags for setting */
38PRIV 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 */
64PRIV 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
96static ATTR *aname_find_exact(const char *name);
97void 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 */
103ATTR *
104aname_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 */
118void
119init_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 */
132int
133alias_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
150static ATTR *
151aname_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 */
173void
174do_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 */
251void
252do_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 */
282void
283do_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 */
330void
331do_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 */
364void
365do_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 */
375char *
376list_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 */
402void
403attr_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.