Atrinik Server  4.0
attr_list.c
Go to the documentation of this file.
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21  * *
22  * The author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
50 #include <plugin_python.h>
51 #include <plugin.h>
52 #include <toolkit/packet.h>
53 #include <player.h>
54 
58 typedef enum attr_list_oper {
62  AL_OPER_APPEND, //< append()
69 
77 static Py_ssize_t attr_list_len(Atrinik_AttrList *al)
78 {
79  if (al->field == FIELDTYPE_CMD_PERMISSIONS) {
80  return *(int *) ((char *) al->ptr +
81  offsetof(player, num_cmd_permissions));
82  } else if (al->field == FIELDTYPE_FACTIONS) {
83  player_faction_t *factions = *(player_faction_t **) ((char *) al->ptr +
84  al->offset);
85  return HASH_CNT(hh, factions);
86  } else if (al->field == FIELDTYPE_PACKETS) {
87  packet_struct *head = *(packet_struct **) ((char *) al->ptr +
88  al->offset), *packet;
89  Py_ssize_t num = 0;
90  DL_FOREACH(head, packet) {
91  num++;
92  }
93 
94  return num;
95  }
96 
97  return 0;
98 }
99 
114  attr_list_oper_t oper, PyObject *key, PyObject **value)
115 {
116  char ***perms = ((char ***) ((char *) al->ptr + al->offset));
117  int *len = (int *) ((char *) al->ptr +
118  offsetof(player, num_cmd_permissions));
119  socket_struct *ns = (socket_struct *) ((char *) al->ptr +
120  offsetof(player, cs));
121 
122  if (oper == AL_OPER_CLEAR) {
123  if (*perms == NULL) {
124  return true;
125  }
126 
127  for (int i = 0; i < *len; i++) {
128  if ((*perms)[i] != NULL) {
129  efree((*perms)[i]);
130  }
131  }
132 
133  efree(*perms);
134  *perms = NULL;
135  *len = 0;
136 
137  ns->ext_title_flag = true;
138  return true;
139  } else if (oper == AL_OPER_ITEMS) {
140  HARD_ASSERT(value != NULL);
141  *value = PyList_New(*len);
142  for (int i = 0; i < *len; i++) {
143  PyList_SetItem(*value, i, Py_BuildValue("s", (*perms)[i]));
144  }
145 
146  return true;
147  } else if (oper == AL_OPER_CONTAINS) {
148  char *str = PyString_AsString(*value);
149  for (int i = 0; i < *len; i++) {
150  if ((*perms)[i] != NULL && strcmp((*perms)[i], str) == 0) {
151  return true;
152  }
153  }
154 
155  return false;
156  } else if (oper != AL_OPER_APPEND && oper != AL_OPER_GET &&
157  oper != AL_OPER_SET && oper != AL_OPER_ITER &&
158  oper != AL_OPER_REMOVE) {
159  PyErr_SetString(PyExc_NotImplementedError, "operation not implemented");
160  return false;
161  }
162 
163  HARD_ASSERT(value != NULL);
164 
165  PY_LONG_LONG idx;
166  if (oper == AL_OPER_APPEND) {
167  *perms = erealloc(*perms, sizeof(**perms) * (*len + 1));
168  idx = *len;
169  (*perms)[idx] = NULL;
170  (*len)++;
171  } else if (oper == AL_OPER_ITER) {
172  idx = al->iter.idx;
173  if (idx >= *len) {
174  return false;
175  }
176 
177  al->iter.idx++;
178  } else if (oper == AL_OPER_REMOVE) {
179  char *str = PyString_AsString(*value);
180  for (idx = 0; idx < *len; idx++) {
181  if ((*perms)[idx] != NULL && strcmp((*perms)[idx], str) == 0) {
182  break;
183  }
184  }
185 
186  if (idx >= *len) {
187  PyErr_SetString(PyExc_ValueError, "value not found");
188  return false;
189  }
190  } else {
191  HARD_ASSERT(key != NULL);
192  if (!PyLong_Check(key)) {
193  PyErr_SetString(PyExc_TypeError, "index must be an integer");
194  return false;
195  }
196 
197  idx = PyLong_AsLongLong(key);
198  if (idx < 0) {
199  idx += *len;
200  }
201 
202  if (idx >= *len) {
203  PyErr_SetString(PyExc_IndexError, "index out of range");
204  return false;
205  }
206  }
207 
208  void *ptr = &(*perms)[idx];
209  fields_struct field = {"xxx", FIELDTYPE_CSTR, 0, 0, 0, NULL};
210 
211  if (oper == AL_OPER_GET || oper == AL_OPER_ITER) {
212  *value = generic_field_getter(&field, ptr);
213  if (*value == NULL) {
214  return false;
215  }
216  } else {
217  PyObject *what = oper == AL_OPER_REMOVE ? Py_None : *value;
218  int ret = generic_field_setter(&field, ptr, what);
219  if (ret == -1) {
220  if (oper == AL_OPER_APPEND) {
221  (*len)--;
222  *perms = erealloc(*perms, sizeof(**perms) * (*len));
223  }
224 
225  return false;
226  }
227 
228  ns->ext_title_flag = true;
229  }
230 
231  return true;
232 }
233 
248  attr_list_oper_t oper, PyObject *key, PyObject **value)
249 {
250  HARD_ASSERT(al != NULL);
251 
252  if (oper == AL_OPER_CLEAR) {
254  (char *) al->ptr + al->offset), *faction, *tmp;
255  HASH_ITER(hh, factions, faction, tmp) {
256  hooks->player_faction_free(al->ptr, faction);
257  }
258 
259  return true;
260  } else if (oper == AL_OPER_ITEMS) {
261  *value = PyList_New(0);
263  (char *) al->ptr + al->offset), *faction, *tmp;
264  HASH_ITER(hh, factions, faction, tmp) {
265  PyObject *tuple = PyTuple_New(2);
266  PyTuple_SetItem(tuple, 0, Py_BuildValue("s", faction->name));
267  PyTuple_SetItem(tuple, 1, Py_BuildValue("f", faction->reputation));
268  PyList_Append(*value, tuple);
269  }
270 
271  return true;
272  } else if (oper != AL_OPER_CONTAINS && oper != AL_OPER_GET &&
273  oper != AL_OPER_SET && oper != AL_OPER_DELETE &&
274  oper != AL_OPER_ITER) {
275  PyErr_SetString(PyExc_NotImplementedError, "operation not implemented");
276  return false;
277  }
278 
279  if (oper == AL_OPER_CONTAINS) {
280  HARD_ASSERT(value != NULL);
281  key = *value;
282  }
283 
284  char *str = NULL;
285  if (oper != AL_OPER_ITER) {
286  HARD_ASSERT(key != NULL);
287  if (!PyString_Check(key)) {
288  PyErr_SetString(PyExc_TypeError, "key must be a string");
289  return false;
290  }
291 
292  str = PyString_AsString(key);
293  }
294 
295  if (oper == AL_OPER_CONTAINS) {
296  shstr *shared_str = hooks->find_string(str);
297  if (shared_str == NULL) {
298  return false;
299  }
300 
302  (char *) al->ptr + al->offset), *faction, *tmp;
303  HASH_ITER(hh, factions, faction, tmp) {
304  if (faction->name == shared_str) {
305  return true;
306  }
307  }
308 
309  return false;
310  }
311 
312  HARD_ASSERT(value != NULL);
313 
315  bool added_new = false;
316  if (oper == AL_OPER_ITER) {
317  player_faction_t *factions = *(player_faction_t **) ((char *) al->ptr +
318  al->offset), *tmp;
319  PY_LONG_LONG i = 0;
320  HASH_ITER(hh, factions, faction, tmp) {
321  if (i++ == al->iter.idx) {
322  break;
323  }
324  }
325 
326  if (faction == NULL) {
327  return false;
328  }
329 
330  al->iter.idx++;
331  } else {
332  shstr *shared_str;
333  if (oper == AL_OPER_SET) {
334  shared_str = hooks->add_string(str);
335  } else {
336  shared_str = hooks->find_string(str);
337  if (shared_str == NULL) {
338  PyErr_SetString(PyExc_KeyError, "invalid key");
339  return false;
340  }
341  }
342 
343  faction = hooks->player_faction_find(al->ptr, shared_str);
344  if (faction == NULL) {
345  if (oper != AL_OPER_SET) {
346  PyErr_SetString(PyExc_KeyError, "invalid key");
347  return false;
348  }
349 
350  faction = hooks->player_faction_create(al->ptr, shared_str);
351  added_new = true;
352  }
353 
354  if (oper == AL_OPER_SET) {
355  hooks->free_string_shared(shared_str);
356  } else if (oper == AL_OPER_DELETE) {
357  hooks->player_faction_free(al->ptr, faction);
358  return true;
359  }
360  }
361 
362  void *ptr = &(*(double **) ((char *) (void *) faction +
363  offsetof(player_faction_t, reputation)));
364  fields_struct field = {"xxx", FIELDTYPE_DOUBLE, 0, 0, 0, NULL};
365 
366  if (oper == AL_OPER_GET || oper == AL_OPER_ITER) {
367  *value = generic_field_getter(&field, ptr);
368  if (*value == NULL) {
369  return false;
370  }
371  } else {
372  int ret = generic_field_setter(&field, ptr, *value);
373  if (ret == -1) {
374  if (added_new) {
375  hooks->player_faction_free(al->ptr, faction);
376  }
377 
378  return false;
379  }
380  }
381 
382  return true;
383 }
384 
399  attr_list_oper_t oper, PyObject *key, PyObject **value)
400 {
401  HARD_ASSERT(al != NULL);
402 
403  if (oper == AL_OPER_SET || oper == AL_OPER_CONTAINS ||
404  oper == AL_OPER_APPEND) {
405  HARD_ASSERT(value != NULL);
406  if (!PyBytes_Check(*value)) {
407  PyErr_SetString(PyExc_TypeError, "value must be a bytes object");
408  return false;
409  }
410  }
411 
412  packet_struct **head = (packet_struct **) ((char *) al->ptr + al->offset);
413  if (oper == AL_OPER_CLEAR) {
414  packet_struct *packet, *tmp;
415  DL_FOREACH_SAFE(*head, packet, tmp) {
416  hooks->packet_free(packet);
417  }
418 
419  *head = NULL;
420  return true;
421  } else if (oper == AL_OPER_CONTAINS) {
422  char *str = PyBytes_AsString(*value);
423  size_t len = PyBytes_Size(*value);
424  packet_struct *packet;
425  DL_FOREACH(*head, packet) {
426  if (packet->len == len && memcmp(packet->data, str, len) == 0) {
427  return true;
428  }
429  }
430 
431  return false;
432  } else if (oper != AL_OPER_GET && oper != AL_OPER_SET &&
433  oper != AL_OPER_APPEND && oper != AL_OPER_ITER) {
434  PyErr_SetString(PyExc_NotImplementedError, "operation not implemented");
435  return false;
436  }
437 
438  packet_struct *elem = NULL;
439  if (oper == AL_OPER_ITER) {
440  elem = al->iter.ptr;
441  if (elem == NULL) {
442  elem = *head;
443  } else {
444  elem = elem->next;
445  }
446 
447  if (elem == NULL) {
448  return false;
449  }
450 
451  al->iter.ptr = elem;
452  } else if (oper != AL_OPER_APPEND) {
453  if (key == NULL) {
454  PyErr_SetString(PyExc_NotImplementedError,
455  "operation not implemented");
456  return false;
457  }
458 
459  if (!PyLong_Check(key)) {
460  PyErr_SetString(PyExc_TypeError, "index must be an integer");
461  return false;
462  }
463 
464  PY_LONG_LONG idx = PyLong_AsLongLong(key), i = 0;
465  if (idx < 0) {
466  DL_FOREACH_REVERSE(*head, elem) {
467  if (--i == idx) {
468  break;
469  }
470  }
471  } else {
472  DL_FOREACH(*head, elem) {
473  if (i++ == idx) {
474  break;
475  }
476  }
477  }
478  }
479 
480  if (oper != AL_OPER_APPEND && elem == NULL) {
481  PyErr_SetString(PyExc_IndexError, "index out of range");
482  return false;
483  }
484 
485  if (oper == AL_OPER_GET || oper == AL_OPER_ITER) {
486  *value = PyBytes_FromStringAndSize((const char *) elem->data,
487  elem->len);
488  return true;
489  }
490 
491  packet_struct *packet = hooks->packet_new(0, PyBytes_Size(*value), 0);
492  hooks->packet_append_data_len(packet, (uint8_t *) PyBytes_AsString(*value),
493  PyBytes_Size(*value));
494 
495  if (oper == AL_OPER_SET) {
496  DL_PREPEND_ELEM(*head, elem, packet);
497  DL_DELETE(*head, elem);
498  hooks->packet_free(elem);
499  } else {
500  DL_APPEND(*head, packet);
501  }
502 
503  return true;
504 }
505 
520  PyObject *key, PyObject **value)
521 {
522  switch (al->field) {
524  return attr_list_oper_cmd_permissions(al, oper, key, value);
525 
526  case FIELDTYPE_FACTIONS:
527  return attr_list_oper_factions(al, oper, key, value);
528 
529  case FIELDTYPE_PACKETS:
530  return attr_list_oper_packets(al, oper, key, value);
531 
532  default:
533  LOG(ERROR, "Unhandled field: %d", al->field);
534  return false;
535  }
536 }
537 
547 static PyObject *append(Atrinik_AttrList *al, PyObject *value)
548 {
549  if (!attr_list_oper(al, AL_OPER_APPEND, NULL, &value)) {
550  return NULL;
551  }
552 
553  Py_INCREF(Py_None);
554  return Py_None;
555 }
556 
566 static PyObject *attr_list_remove(Atrinik_AttrList *al, PyObject *value)
567 {
568  if (!attr_list_oper(al, AL_OPER_REMOVE, NULL, &value)) {
569  return NULL;
570  }
571 
572  Py_INCREF(Py_None);
573  return Py_None;
574 }
575 
583 static PyObject *attr_list_clear(Atrinik_AttrList *al)
584 {
585  if (!attr_list_oper(al, AL_OPER_CLEAR, NULL, NULL)) {
586  return NULL;
587  }
588 
589  Py_INCREF(Py_None);
590  return Py_None;
591 }
592 
600 static PyObject *attr_list_items(Atrinik_AttrList *al)
601 {
602  PyObject *value;
603  if (!attr_list_oper(al, AL_OPER_ITEMS, NULL, &value)) {
604  return NULL;
605  }
606 
607  return value;
608 }
609 
611 static PyMethodDef methods[] = {
612  {"append", (PyCFunction) append, METH_O, 0},
613  {"remove", (PyCFunction) attr_list_remove, METH_O, 0},
614  {"clear", (PyCFunction) attr_list_clear, METH_NOARGS, 0},
615  {"items", (PyCFunction) attr_list_items, METH_NOARGS, 0},
616  {NULL, NULL, 0, 0}
617 };
618 
626 static PyObject *iter(PyObject *seq)
627 {
628  Atrinik_AttrList *al, *orig_al = (Atrinik_AttrList *) seq;
629 
630  al = PyObject_NEW(Atrinik_AttrList, &Atrinik_AttrListType);
631  al->iter.ptr = NULL;
632  al->iter.idx = 0;
633  al->ptr = orig_al->ptr;
634  al->offset = orig_al->offset;
635  al->field = orig_al->field;
636 
637  return (PyObject *) al;
638 }
639 
647 static PyObject *iternext(Atrinik_AttrList *al)
648 {
649  PyObject *value = NULL;
650  attr_list_oper(al, AL_OPER_ITER, NULL, &value);
651  return value;
652 }
653 
661 static Py_ssize_t __len__(Atrinik_AttrList *al)
662 {
663  return attr_list_len(al);
664 }
665 
676 static PyObject *__getitem__(Atrinik_AttrList *al, PyObject *key)
677 {
678  PyObject *value = NULL;
679  attr_list_oper(al, AL_OPER_GET, key, &value);
680  return value;
681 }
682 
694 static int __setitem__(Atrinik_AttrList *al, PyObject *key, PyObject *value)
695 {
696  attr_list_oper_t oper = value != NULL ? AL_OPER_SET : AL_OPER_DELETE;
697  if (attr_list_oper(al, oper, key, &value)) {
698  return 0;
699  }
700 
701  return -1;
702 }
703 
713 static int __contains__(Atrinik_AttrList *al, PyObject *value)
714 {
715  return attr_list_oper(al, AL_OPER_CONTAINS, NULL, &value);
716 }
717 
719 static PySequenceMethods SequenceMethods = {
720  (lenfunc) __len__,
721  NULL, NULL, NULL, NULL, NULL, NULL,
722  (objobjproc) __contains__,
723  NULL, NULL
724 };
725 
730 static PyMappingMethods MappingMethods = {
731  (lenfunc) __len__,
732  (binaryfunc) __getitem__,
733  (objobjargproc) __setitem__,
734 };
735 
737 PyTypeObject Atrinik_AttrListType = {
738 #ifdef IS_PY3K
739  PyVarObject_HEAD_INIT(NULL, 0)
740 #else
741  PyObject_HEAD_INIT(NULL)
742  0,
743 #endif
744  "Atrinik.AttrList",
745  sizeof(Atrinik_AttrList),
746  0,
747  NULL,
748  NULL, NULL, NULL,
749  NULL,
750  NULL,
751  0,
752  &SequenceMethods,
753  &MappingMethods,
754  0, 0,
755  NULL,
756  0, 0, 0,
757  Py_TPFLAGS_DEFAULT,
758  "Atrinik attr lists",
759  NULL, NULL, NULL,
760  0,
761  (getiterfunc) iter,
762  (iternextfunc) iternext,
763  methods,
764  0,
765  NULL,
766  0, 0, 0, 0, 0, 0, 0,
767  NULL,
768  0, 0, 0, 0, 0, 0, 0, 0
769 #ifndef IS_PY_LEGACY
770  , 0
771 #endif
772 #ifdef Py_TPFLAGS_HAVE_FINALIZE
773  , NULL
774 #endif
775 };
776 
784 int Atrinik_AttrList_init(PyObject *module)
785 {
786  Atrinik_AttrListType.tp_new = PyType_GenericNew;
787 
788  if (PyType_Ready(&Atrinik_AttrListType) < 0) {
789  return 0;
790  }
791 
792  Py_INCREF(&Atrinik_AttrListType);
793  PyModule_AddObject(module, "AttrList", (PyObject *) &Atrinik_AttrListType);
794 
795  return 1;
796 }
797 
810 PyObject *wrap_attr_list(void *ptr, size_t offset, field_type field)
811 {
812  Atrinik_AttrList *wrapper = PyObject_NEW(Atrinik_AttrList,
813  &Atrinik_AttrListType);
814  if (wrapper != NULL) {
815  wrapper->ptr = ptr;
816  wrapper->offset = offset;
817  wrapper->field = field;
818  }
819 
820  return (PyObject *) wrapper;
821 }
getitem()
Definition: attr_list.c:60
static bool attr_list_oper_packets(Atrinik_AttrList *al, attr_list_oper_t oper, PyObject *key, PyObject **value)
Definition: attr_list.c:398
remove()
Definition: attr_list.c:61
static int __contains__(Atrinik_AttrList *al, PyObject *value)
Definition: attr_list.c:713
struct plugin_hooklist * hooks
Definition: plugin_arena.c:160
field_type field
static bool attr_list_oper_cmd_permissions(Atrinik_AttrList *al, attr_list_oper_t oper, PyObject *key, PyObject **value)
Definition: attr_list.c:113
enum attr_list_oper attr_list_oper_t
int generic_field_setter(fields_struct *field, void *ptr, PyObject *value)
items()
Definition: attr_list.c:65
static PyObject * append(Atrinik_AttrList *al, PyObject *value)
Definition: attr_list.c:547
static PyMethodDef methods[]
Definition: attr_list.c:611
static bool attr_list_oper_factions(Atrinik_AttrList *al, attr_list_oper_t oper, PyObject *key, PyObject **value)
Definition: attr_list.c:247
#define IS_PY_LEGACY
Definition: plugin_python.h:55
setitem()
Definition: attr_list.c:59
PyObject * wrap_attr_list(void *ptr, size_t offset, field_type field)
Definition: attr_list.c:810
clear()
Definition: attr_list.c:64
attr_list_oper
Definition: attr_list.c:58
PY_LONG_LONG idx
Index.
static PyObject * attr_list_remove(Atrinik_AttrList *al, PyObject *value)
Definition: attr_list.c:566
uint8_t ext_title_flag
Definition: newserver.h:161
static PyObject * attr_list_clear(Atrinik_AttrList *al)
Definition: attr_list.c:583
shstr * name
Name of the faction.
Definition: faction.c:93
static PyObject * attr_list_items(Atrinik_AttrList *al)
Definition: attr_list.c:600
PyObject_HEAD void * ptr
int Atrinik_AttrList_init(PyObject *module)
Definition: attr_list.c:784
static PyObject * iternext(Atrinik_AttrList *al)
Definition: attr_list.c:647
contains()
Definition: attr_list.c:63
field_type
uint64_t num
Number of successful updates.
Definition: metaserver.c:43
static PyObject * iter(PyObject *seq)
Definition: attr_list.c:626
static int __setitem__(Atrinik_AttrList *al, PyObject *key, PyObject *value)
Definition: attr_list.c:694
union Atrinik_AttrList::@9 iter
static Py_ssize_t attr_list_len(Atrinik_AttrList *al)
Definition: attr_list.c:77
PyObject * generic_field_getter(fields_struct *field, void *ptr)
static PySequenceMethods SequenceMethods
Definition: attr_list.c:719
PyTypeObject Atrinik_AttrListType
Definition: attr_list.c:737
iter()
Definition: attr_list.c:66
static faction_t factions
Definition: faction.c:132
static Py_ssize_t __len__(Atrinik_AttrList *al)
Definition: attr_list.c:661
static PyMappingMethods MappingMethods
Definition: attr_list.c:730
static PyObject * __getitem__(Atrinik_AttrList *al, PyObject *key)
Definition: attr_list.c:676