PageRenderTime 44ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/db_properties.c

https://gitlab.com/mudmoo/gammamoo
C | 730 lines | 552 code | 113 blank | 65 comment | 113 complexity | 96d49575cb9bb2939739f8dda72b5645 MD5 | raw file
  1. /******************************************************************************
  2. Copyright (c) 1995, 1996 Xerox Corporation. All rights reserved.
  3. Portions of this code were written by Stephen White, aka ghond.
  4. Use and copying of this software and preparation of derivative works based
  5. upon this software are permitted. Any distribution of this software or
  6. derivative works must comply with all applicable United States export
  7. control laws. This software is made available AS IS, and Xerox Corporation
  8. makes no warranty about the software, its performance or its conformity to
  9. any specification. Any person obtaining a copy of this software is requested
  10. to send their name and post office or electronic mail address to:
  11. Pavel Curtis
  12. Xerox PARC
  13. 3333 Coyote Hill Rd.
  14. Palo Alto, CA 94304
  15. Pavel@Xerox.Com
  16. *****************************************************************************/
  17. /*****************************************************************************
  18. * Routines for manipulating properties on DB objects
  19. *****************************************************************************/
  20. #include "config.h"
  21. #include "db.h"
  22. #include "db_private.h"
  23. #include "list.h"
  24. #include "storage.h"
  25. #include "utils.h"
  26. Propdef
  27. dbpriv_new_propdef(const char *name)
  28. {
  29. Propdef newprop;
  30. newprop.name = str_ref(name);
  31. newprop.hash = str_hash(name);
  32. return newprop;
  33. }
  34. int
  35. dbpriv_count_properties(Objid oid)
  36. {
  37. Object *o;
  38. int nprops = 0;
  39. for (o = dbpriv_find_object(oid); o; o = dbpriv_find_object(o->parent))
  40. nprops += o->propdefs.cur_length;
  41. return nprops;
  42. }
  43. static int
  44. property_defined_at_or_below(const char *pname, int phash, Objid oid)
  45. {
  46. /* Return true iff some descendant of OID defines a property named PNAME.
  47. */
  48. Objid c;
  49. Proplist *props = &dbpriv_find_object(oid)->propdefs;
  50. int length = props->cur_length;
  51. int i;
  52. for (i = 0; i < length; i++)
  53. if (props->l[i].hash == phash
  54. && !mystrcasecmp(props->l[i].name, pname))
  55. return 1;
  56. for (c = dbpriv_find_object(oid)->child;
  57. c != NOTHING;
  58. c = dbpriv_find_object(c)->sibling)
  59. if (property_defined_at_or_below(pname, phash, c))
  60. return 1;
  61. return 0;
  62. }
  63. static void
  64. insert_prop(Objid oid, int pos, Pval pval)
  65. {
  66. Pval *new_propval;
  67. Object *o;
  68. int i, nprops;
  69. nprops = dbpriv_count_properties(oid);
  70. new_propval = mymalloc(nprops * sizeof(Pval), M_PVAL);
  71. o = dbpriv_find_object(oid);
  72. for (i = 0; i < pos; i++)
  73. new_propval[i] = o->propval[i];
  74. new_propval[pos] = pval;
  75. new_propval[pos].var = var_ref(pval.var);
  76. if (new_propval[pos].perms & PF_CHOWN)
  77. new_propval[pos].owner = o->owner;
  78. for (i = pos + 1; i < nprops; i++)
  79. new_propval[i] = o->propval[i - 1];
  80. if (o->propval)
  81. myfree(o->propval, M_PVAL);
  82. o->propval = new_propval;
  83. }
  84. static void
  85. insert_prop_recursively(Objid root, int root_pos, Pval pv)
  86. {
  87. Objid c;
  88. insert_prop(root, root_pos, pv);
  89. pv.var.type = TYPE_CLEAR; /* do after initial insert_prop so only
  90. children will be TYPE_CLEAR */
  91. for (c = dbpriv_find_object(root)->child;
  92. c != NOTHING;
  93. c = dbpriv_find_object(c)->sibling) {
  94. int new_prop_count = dbpriv_find_object(c)->propdefs.cur_length;
  95. insert_prop_recursively(c, new_prop_count + root_pos, pv);
  96. }
  97. }
  98. static
  99. char
  100. is_reserved_property(const char *name)
  101. {
  102. #ifdef RESERVED_PROPERTIES
  103. static const char *reserved[] = {RESERVED_PROPERTIES};
  104. static int hashes[Arraysize(reserved)];
  105. static char hashes_init = 0;
  106. int i;
  107. int hash = str_hash(name);
  108. if (!hashes_init) {
  109. for (i = 0; i < Arraysize(reserved); ++i)
  110. hashes[i] = str_hash(reserved[i]);
  111. hashes_init = 1;
  112. }
  113. for (i = 0; i < Arraysize(reserved); ++i)
  114. if (hashes[i] == hash && !mystrcasecmp(name, reserved[i]))
  115. return 1;
  116. #endif
  117. return 0;
  118. }
  119. int
  120. db_add_propdef(Objid oid, const char *pname, Var value, Objid owner,
  121. unsigned flags)
  122. {
  123. Object *o;
  124. Pval pval;
  125. int i;
  126. db_prop_handle h;
  127. h = db_find_property(oid, pname, 0);
  128. if (h.ptr || property_defined_at_or_below(pname, str_hash(pname), oid))
  129. return 0;
  130. if (is_reserved_property(pname))
  131. return 0;
  132. o = dbpriv_find_object(oid);
  133. if (o->propdefs.cur_length == o->propdefs.max_length) {
  134. Propdef *old_props = o->propdefs.l;
  135. int new_size = (o->propdefs.max_length == 0
  136. ? 8 : 2 * o->propdefs.max_length);
  137. o->propdefs.l = mymalloc(new_size * sizeof(Propdef), M_PROPDEF);
  138. for (i = 0; i < o->propdefs.max_length; i++)
  139. o->propdefs.l[i] = old_props[i];
  140. o->propdefs.max_length = new_size;
  141. if (old_props)
  142. myfree(old_props, M_PROPDEF);
  143. }
  144. o->propdefs.l[o->propdefs.cur_length++] = dbpriv_new_propdef(pname);
  145. pval.var = value;
  146. pval.owner = owner;
  147. pval.perms = flags;
  148. insert_prop_recursively(oid, o->propdefs.cur_length - 1, pval);
  149. return 1;
  150. }
  151. int
  152. db_rename_propdef(Objid oid, const char *old, const char *new)
  153. {
  154. Proplist *props = &dbpriv_find_object(oid)->propdefs;
  155. int hash = str_hash(old);
  156. int count = props->cur_length;
  157. int i;
  158. db_prop_handle h;
  159. if (is_reserved_property(new))
  160. return 0;
  161. for (i = 0; i < count; i++) {
  162. Propdef p;
  163. p = props->l[i];
  164. if (p.hash == hash && !mystrcasecmp(p.name, old)) {
  165. if (mystrcasecmp(old, new) != 0) { /* Not changing just the case */
  166. h = db_find_property(oid, new, 0);
  167. if (h.ptr
  168. || property_defined_at_or_below(new, str_hash(new), oid))
  169. return 0;
  170. }
  171. free_str(props->l[i].name);
  172. props->l[i].name = str_ref(new);
  173. props->l[i].hash = str_hash(new);
  174. return 1;
  175. }
  176. }
  177. return 0;
  178. }
  179. static void
  180. remove_prop(Objid oid, int pos)
  181. {
  182. Pval *new_propval;
  183. Object *o;
  184. int i, nprops;
  185. o = dbpriv_find_object(oid);
  186. nprops = dbpriv_count_properties(oid);
  187. free_var(o->propval[pos].var); /* free deleted property */
  188. if (nprops) {
  189. new_propval = mymalloc(nprops * sizeof(Pval), M_PVAL);
  190. for (i = 0; i < pos; i++)
  191. new_propval[i] = o->propval[i];
  192. for (i = pos; i < nprops; i++)
  193. new_propval[i] = o->propval[i + 1];
  194. } else
  195. new_propval = 0;
  196. if (o->propval)
  197. myfree(o->propval, M_PVAL);
  198. o->propval = new_propval;
  199. }
  200. static void
  201. remove_prop_recursively(Objid root, int root_pos)
  202. {
  203. Objid c;
  204. remove_prop(root, root_pos);
  205. for (c = dbpriv_find_object(root)->child;
  206. c != NOTHING;
  207. c = dbpriv_find_object(c)->sibling) {
  208. int new_prop_count = dbpriv_find_object(c)->propdefs.cur_length;
  209. remove_prop_recursively(c, new_prop_count + root_pos);
  210. }
  211. }
  212. int
  213. db_delete_propdef(Objid oid, const char *pname)
  214. {
  215. Proplist *props = &dbpriv_find_object(oid)->propdefs;
  216. int hash = str_hash(pname);
  217. int count = props->cur_length;
  218. int max = props->max_length;
  219. int i, j;
  220. for (i = 0; i < count; i++) {
  221. Propdef p;
  222. p = props->l[i];
  223. if (p.hash == hash && !mystrcasecmp(p.name, pname)) {
  224. if (p.name)
  225. free_str(p.name);
  226. if (max > 8 && props->cur_length <= ((max * 3) / 8)) {
  227. int new_size = max / 2;
  228. Propdef *new_props;
  229. new_props = mymalloc(new_size * sizeof(Propdef), M_PROPDEF);
  230. for (j = 0; j < i; j++)
  231. new_props[j] = props->l[j];
  232. for (j = i + 1; j < count; j++)
  233. new_props[j - 1] = props->l[j];
  234. myfree(props->l, M_PROPDEF);
  235. props->l = new_props;
  236. props->max_length = new_size;
  237. } else
  238. for (j = i + 1; j < count; j++)
  239. props->l[j - 1] = props->l[j];
  240. props->cur_length--;
  241. remove_prop_recursively(oid, i);
  242. return 1;
  243. }
  244. }
  245. return 0;
  246. }
  247. int
  248. db_count_propdefs(Objid oid)
  249. {
  250. return dbpriv_find_object(oid)->propdefs.cur_length;
  251. }
  252. int
  253. db_for_all_propdefs(Objid oid, int (*func) (void *, const char *), void *data)
  254. {
  255. int i;
  256. Object *o = dbpriv_find_object(oid);
  257. int len = o->propdefs.cur_length;
  258. for (i = 0; i < len; i++)
  259. if (func(data, o->propdefs.l[i].name))
  260. return 1;
  261. return 0;
  262. }
  263. struct contents_data {
  264. Var r;
  265. int i;
  266. };
  267. static int
  268. add_to_list(void *data, Objid c)
  269. {
  270. struct contents_data *d = data;
  271. d->i++;
  272. d->r.v.list[d->i].type = TYPE_OBJ;
  273. d->r.v.list[d->i].v.obj = c;
  274. return 0;
  275. }
  276. static void
  277. get_bi_value(db_prop_handle h, Var * value)
  278. {
  279. Objid oid = *((Objid *) h.ptr);
  280. switch (h.built_in) {
  281. case BP_NAME:
  282. value->type = TYPE_STR;
  283. value->v.str = str_ref(db_object_name(oid));
  284. break;
  285. case BP_OWNER:
  286. value->type = TYPE_OBJ;
  287. value->v.obj = db_object_owner(oid);
  288. break;
  289. case BP_PROGRAMMER:
  290. value->type = TYPE_INT;
  291. value->v.num = db_object_has_flag(oid, FLAG_PROGRAMMER);
  292. break;
  293. case BP_WIZARD:
  294. value->type = TYPE_INT;
  295. value->v.num = db_object_has_flag(oid, FLAG_WIZARD);
  296. break;
  297. case BP_R:
  298. value->type = TYPE_INT;
  299. value->v.num = db_object_has_flag(oid, FLAG_READ);
  300. break;
  301. case BP_W:
  302. value->type = TYPE_INT;
  303. value->v.num = db_object_has_flag(oid, FLAG_WRITE);
  304. break;
  305. case BP_F:
  306. value->type = TYPE_INT;
  307. value->v.num = db_object_has_flag(oid, FLAG_FERTILE);
  308. break;
  309. case BP_LOCATION:
  310. value->type = TYPE_OBJ;
  311. value->v.obj = db_object_location(oid);
  312. break;
  313. case BP_CONTENTS:
  314. {
  315. struct contents_data d;
  316. d.r = new_list(db_count_contents(oid));
  317. d.i = 0;
  318. db_for_all_contents(oid, add_to_list, &d);
  319. *value = d.r;
  320. }
  321. break;
  322. default:
  323. panic("Unknown built-in property in GET_BI_VALUE!");
  324. }
  325. }
  326. db_prop_handle
  327. db_find_property(Objid oid, const char *name, Var * value)
  328. {
  329. static struct {
  330. const char *name;
  331. enum bi_prop prop;
  332. int hash;
  333. } ptable[] = {
  334. #define _ENTRY(P,p) { #p, BP_##P, 0 },
  335. BUILTIN_PROPERTIES(_ENTRY)
  336. #undef _ENTRY
  337. };
  338. static int ptable_init = 0;
  339. int i, n;
  340. db_prop_handle h;
  341. int hash = str_hash(name);
  342. Object *o;
  343. if (!ptable_init) {
  344. for (i = 0; i < Arraysize(ptable); i++)
  345. ptable[i].hash = str_hash(ptable[i].name);
  346. ptable_init = 1;
  347. }
  348. h.definer = NOTHING;
  349. for (i = 0; i < Arraysize(ptable); i++) {
  350. if (ptable[i].hash == hash && !mystrcasecmp(name, ptable[i].name)) {
  351. static Objid ret;
  352. ret = oid;
  353. h.built_in = ptable[i].prop;
  354. h.ptr = &ret;
  355. if (value)
  356. get_bi_value(h, value);
  357. return h;
  358. }
  359. }
  360. h.built_in = BP_NONE;
  361. n = 0;
  362. for (o = dbpriv_find_object(oid); o; o = dbpriv_find_object(o->parent)) {
  363. Proplist *props = &(o->propdefs);
  364. Propdef *defs = props->l;
  365. int length = props->cur_length;
  366. for (i = 0; i < length; i++, n++) {
  367. if (defs[i].hash == hash
  368. && !mystrcasecmp(defs[i].name, name)) {
  369. Pval *prop;
  370. h.definer = o->id;
  371. o = dbpriv_find_object(oid);
  372. prop = h.ptr = o->propval + n;
  373. if (value) {
  374. while (prop->var.type == TYPE_CLEAR) {
  375. n -= o->propdefs.cur_length;
  376. o = dbpriv_find_object(o->parent);
  377. prop = o->propval + n;
  378. }
  379. *value = prop->var;
  380. }
  381. return h;
  382. }
  383. }
  384. }
  385. h.ptr = 0;
  386. return h;
  387. }
  388. Var
  389. db_property_value(db_prop_handle h)
  390. {
  391. Var value;
  392. if (h.built_in)
  393. get_bi_value(h, &value);
  394. else {
  395. Pval *prop = h.ptr;
  396. value = prop->var;
  397. }
  398. return value;
  399. }
  400. void
  401. db_set_property_value(db_prop_handle h, Var value)
  402. {
  403. if (!h.built_in) {
  404. Pval *prop = h.ptr;
  405. free_var(prop->var);
  406. prop->var = value;
  407. } else {
  408. Objid oid = *((Objid *) h.ptr);
  409. db_object_flag flag;
  410. switch (h.built_in) {
  411. case BP_NAME:
  412. if (value.type != TYPE_STR)
  413. goto complain;
  414. db_set_object_name(oid, value.v.str);
  415. break;
  416. case BP_OWNER:
  417. if (value.type != TYPE_OBJ)
  418. goto complain;
  419. db_set_object_owner(oid, value.v.obj);
  420. break;
  421. case BP_PROGRAMMER:
  422. flag = FLAG_PROGRAMMER;
  423. goto finish_flag;
  424. case BP_WIZARD:
  425. flag = FLAG_WIZARD;
  426. goto finish_flag;
  427. case BP_R:
  428. flag = FLAG_READ;
  429. goto finish_flag;
  430. case BP_W:
  431. flag = FLAG_WRITE;
  432. goto finish_flag;
  433. case BP_F:
  434. flag = FLAG_FERTILE;
  435. finish_flag:
  436. if (is_true(value))
  437. db_set_object_flag(oid, flag);
  438. else
  439. db_clear_object_flag(oid, flag);
  440. free_var(value);
  441. break;
  442. case BP_LOCATION:
  443. case BP_CONTENTS:
  444. complain:
  445. panic("Inappropriate value in DB_SET_PROPERTY_VALUE!");
  446. break;
  447. default:
  448. panic("Unknown built-in property in DB_SET_PROPERTY_VALUE!");
  449. }
  450. }
  451. }
  452. Objid
  453. db_property_owner(db_prop_handle h)
  454. {
  455. if (h.built_in) {
  456. panic("Built-in property in DB_PROPERTY_OWNER!");
  457. return NOTHING;
  458. } else {
  459. Pval *prop = h.ptr;
  460. return prop->owner;
  461. }
  462. }
  463. void
  464. db_set_property_owner(db_prop_handle h, Objid oid)
  465. {
  466. if (h.built_in)
  467. panic("Built-in property in DB_SET_PROPERTY_OWNER!");
  468. else {
  469. Pval *prop = h.ptr;
  470. prop->owner = oid;
  471. }
  472. }
  473. unsigned
  474. db_property_flags(db_prop_handle h)
  475. {
  476. if (h.built_in) {
  477. panic("Built-in property in DB_PROPERTY_FLAGS!");
  478. return 0;
  479. } else {
  480. Pval *prop = h.ptr;
  481. return prop->perms;
  482. }
  483. }
  484. void
  485. db_set_property_flags(db_prop_handle h, unsigned flags)
  486. {
  487. if (h.built_in)
  488. panic("Built-in property in DB_SET_PROPERTY_FLAGS!");
  489. else {
  490. Pval *prop = h.ptr;
  491. prop->perms = flags;
  492. }
  493. }
  494. int
  495. db_property_allows(db_prop_handle h, Objid progr, db_prop_flag flag)
  496. {
  497. return ((db_property_flags(h) & flag)
  498. || progr == db_property_owner(h)
  499. || is_wizard(progr));
  500. }
  501. static void
  502. fix_props(Objid oid, int parent_local, int old, int new, int common)
  503. {
  504. Object *me = dbpriv_find_object(oid);
  505. Object *parent = dbpriv_find_object(me->parent);
  506. Pval *new_propval;
  507. int local = parent_local;
  508. int i;
  509. Objid c;
  510. local += me->propdefs.cur_length;
  511. for (i = local; i < local + old; i++)
  512. free_var(me->propval[i].var);
  513. if (local + new + common != 0) {
  514. new_propval = mymalloc((local + new + common) * sizeof(Pval), M_PVAL);
  515. for (i = 0; i < local; i++)
  516. new_propval[i] = me->propval[i];
  517. for (i = 0; i < new; i++) {
  518. Pval pv;
  519. pv = parent->propval[parent_local + i];
  520. new_propval[local + i] = pv;
  521. new_propval[local + i].var.type = TYPE_CLEAR;
  522. if (pv.perms & PF_CHOWN)
  523. new_propval[local + i].owner = me->owner;
  524. }
  525. for (i = 0; i < common; i++)
  526. new_propval[local + new + i] = me->propval[local + old + i];
  527. } else
  528. new_propval = 0;
  529. if (me->propval)
  530. myfree(me->propval, M_PVAL);
  531. me->propval = new_propval;
  532. for (c = me->child; c != NOTHING; c = dbpriv_find_object(c)->sibling)
  533. fix_props(c, local, old, new, common);
  534. }
  535. int
  536. dbpriv_check_properties_for_chparent(Objid oid, Objid new_parent)
  537. {
  538. Object *o;
  539. int i;
  540. for (o = dbpriv_find_object(new_parent);
  541. o;
  542. o = dbpriv_find_object(o->parent)) {
  543. Proplist *props = &o->propdefs;
  544. for (i = 0; i < props->cur_length; i++)
  545. if (property_defined_at_or_below(props->l[i].name,
  546. props->l[i].hash,
  547. oid))
  548. return 0;
  549. }
  550. return 1;
  551. }
  552. void
  553. dbpriv_fix_properties_after_chparent(Objid oid, Objid old_parent)
  554. {
  555. Objid o1, o2, common, new_parent;
  556. int common_props, old_props, new_props;
  557. /* Find the nearest common ancestor between old & new parent */
  558. new_parent = db_object_parent(oid);
  559. common = NOTHING;
  560. for (o1 = new_parent; o1 != NOTHING; o1 = db_object_parent(o1))
  561. for (o2 = old_parent; o2 != NOTHING; o2 = db_object_parent(o2))
  562. if (o1 == o2) {
  563. common = o1;
  564. goto endouter;
  565. }
  566. endouter:
  567. if (common != NOTHING)
  568. common_props = dbpriv_count_properties(common);
  569. else
  570. common_props = 0;
  571. old_props = dbpriv_count_properties(old_parent) - common_props;
  572. new_props = dbpriv_count_properties(new_parent) - common_props;
  573. fix_props(oid, 0, old_props, new_props, common_props);
  574. }
  575. char rcsid_db_properties[] = "$Id$";
  576. /*
  577. * $Log$
  578. * Revision 1.3 1998/12/14 13:17:38 nop
  579. * Merge UNSAFE_OPTS (ref fixups); fix Log tag placement to fit CVS whims
  580. *
  581. * Revision 1.2 1997/03/03 04:18:31 nop
  582. * GNU Indent normalization
  583. *
  584. * Revision 1.1.1.1 1997/03/03 03:44:59 nop
  585. * LambdaMOO 1.8.0p5
  586. *
  587. * Revision 2.6 1996/04/08 01:08:32 pavel
  588. * Fixed `db_rename_propdef()' to allow case-only changes. Release 1.8.0p3.
  589. *
  590. * Revision 2.5 1996/02/11 00:46:48 pavel
  591. * Enhanced db_find_property() to report the defining object of the found
  592. * property. Release 1.8.0beta2.
  593. *
  594. * Revision 2.4 1996/02/08 07:18:02 pavel
  595. * Renamed TYPE_NUM to TYPE_INT. Updated copyright notice for 1996.
  596. * Release 1.8.0beta1.
  597. *
  598. * Revision 2.3 1995/12/31 03:27:40 pavel
  599. * Removed a few more uses of `unsigned'. Reordered things in
  600. * db_delete_propdef() to fix an occasional memory smash.
  601. * Release 1.8.0alpha4.
  602. *
  603. * Revision 2.2 1995/12/28 00:41:34 pavel
  604. * Made *all* built-in property references return fresh value references.
  605. * Release 1.8.0alpha3.
  606. *
  607. * Revision 2.1 1995/12/11 07:52:27 pavel
  608. * Added support for renaming propdefs.
  609. *
  610. * Release 1.8.0alpha2.
  611. *
  612. * Revision 2.0 1995/11/30 04:21:13 pavel
  613. * New baseline version, corresponding to release 1.8.0alpha1.
  614. *
  615. * Revision 1.1 1995/11/30 04:21:02 pavel
  616. * Initial revision
  617. */