Added new optional credentials argument to SMTPHandler.__init__, and smtp.login(...
[python.git] / Objects / structseq.c
blob7ac2a1f61e31b22e7e1224a29a7d59ad91977417
1 /* Implementation helper: a struct that looks like a tuple. See timemodule
2 and posixmodule for example uses. */
4 #include "Python.h"
5 #include "structmember.h"
6 #include "structseq.h"
8 static char visible_length_key[] = "n_sequence_fields";
9 static char real_length_key[] = "n_fields";
10 static char unnamed_fields_key[] = "n_unnamed_fields";
12 /* Fields with this name have only a field index, not a field name.
13 They are only allowed for indices < n_visible_fields. */
14 char *PyStructSequence_UnnamedField = "unnamed field";
16 #define VISIBLE_SIZE(op) ((op)->ob_size)
17 #define VISIBLE_SIZE_TP(tp) PyInt_AsLong( \
18 PyDict_GetItemString((tp)->tp_dict, visible_length_key))
20 #define REAL_SIZE_TP(tp) PyInt_AsLong( \
21 PyDict_GetItemString((tp)->tp_dict, real_length_key))
22 #define REAL_SIZE(op) REAL_SIZE_TP((op)->ob_type)
24 #define UNNAMED_FIELDS_TP(tp) PyInt_AsLong( \
25 PyDict_GetItemString((tp)->tp_dict, unnamed_fields_key))
26 #define UNNAMED_FIELDS(op) UNNAMED_FIELDS_TP((op)->ob_type)
29 PyObject *
30 PyStructSequence_New(PyTypeObject *type)
32 PyStructSequence *obj;
34 obj = PyObject_New(PyStructSequence, type);
35 obj->ob_size = VISIBLE_SIZE_TP(type);
37 return (PyObject*) obj;
40 static void
41 structseq_dealloc(PyStructSequence *obj)
43 Py_ssize_t i, size;
45 size = REAL_SIZE(obj);
46 for (i = 0; i < size; ++i) {
47 Py_XDECREF(obj->ob_item[i]);
49 PyObject_Del(obj);
52 static Py_ssize_t
53 structseq_length(PyStructSequence *obj)
55 return VISIBLE_SIZE(obj);
58 static PyObject*
59 structseq_item(PyStructSequence *obj, Py_ssize_t i)
61 if (i < 0 || i >= VISIBLE_SIZE(obj)) {
62 PyErr_SetString(PyExc_IndexError, "tuple index out of range");
63 return NULL;
65 Py_INCREF(obj->ob_item[i]);
66 return obj->ob_item[i];
69 static PyObject*
70 structseq_slice(PyStructSequence *obj, Py_ssize_t low, Py_ssize_t high)
72 PyTupleObject *np;
73 Py_ssize_t i;
75 if (low < 0)
76 low = 0;
77 if (high > VISIBLE_SIZE(obj))
78 high = VISIBLE_SIZE(obj);
79 if (high < low)
80 high = low;
81 np = (PyTupleObject *)PyTuple_New(high-low);
82 if (np == NULL)
83 return NULL;
84 for(i = low; i < high; ++i) {
85 PyObject *v = obj->ob_item[i];
86 Py_INCREF(v);
87 PyTuple_SET_ITEM(np, i-low, v);
89 return (PyObject *) np;
92 static PyObject *
93 structseq_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
95 PyObject *arg = NULL;
96 PyObject *dict = NULL;
97 PyObject *ob;
98 PyStructSequence *res = NULL;
99 Py_ssize_t len, min_len, max_len, i, n_unnamed_fields;
100 static char *kwlist[] = {"sequence", "dict", 0};
102 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:structseq",
103 kwlist, &arg, &dict))
104 return NULL;
106 arg = PySequence_Fast(arg, "constructor requires a sequence");
108 if (!arg) {
109 return NULL;
112 if (dict && !PyDict_Check(dict)) {
113 PyErr_Format(PyExc_TypeError,
114 "%.500s() takes a dict as second arg, if any",
115 type->tp_name);
116 Py_DECREF(arg);
117 return NULL;
120 len = PySequence_Fast_GET_SIZE(arg);
121 min_len = VISIBLE_SIZE_TP(type);
122 max_len = REAL_SIZE_TP(type);
123 n_unnamed_fields = UNNAMED_FIELDS_TP(type);
125 if (min_len != max_len) {
126 if (len < min_len) {
127 PyErr_Format(PyExc_TypeError,
128 "%.500s() takes an at least %zd-sequence (%zd-sequence given)",
129 type->tp_name, min_len, len);
130 Py_DECREF(arg);
131 return NULL;
134 if (len > max_len) {
135 PyErr_Format(PyExc_TypeError,
136 "%.500s() takes an at most %zd-sequence (%zd-sequence given)",
137 type->tp_name, max_len, len);
138 Py_DECREF(arg);
139 return NULL;
142 else {
143 if (len != min_len) {
144 PyErr_Format(PyExc_TypeError,
145 "%.500s() takes a %zd-sequence (%zd-sequence given)",
146 type->tp_name, min_len, len);
147 Py_DECREF(arg);
148 return NULL;
152 res = (PyStructSequence*) PyStructSequence_New(type);
153 if (res == NULL) {
154 return NULL;
156 for (i = 0; i < len; ++i) {
157 PyObject *v = PySequence_Fast_GET_ITEM(arg, i);
158 Py_INCREF(v);
159 res->ob_item[i] = v;
161 for (; i < max_len; ++i) {
162 if (dict && (ob = PyDict_GetItemString(
163 dict, type->tp_members[i-n_unnamed_fields].name))) {
165 else {
166 ob = Py_None;
168 Py_INCREF(ob);
169 res->ob_item[i] = ob;
172 Py_DECREF(arg);
173 return (PyObject*) res;
176 static PyObject *
177 make_tuple(PyStructSequence *obj)
179 return structseq_slice(obj, 0, VISIBLE_SIZE(obj));
182 static PyObject *
183 structseq_repr(PyStructSequence *obj)
185 PyObject *tup, *str;
186 tup = make_tuple(obj);
187 str = PyObject_Repr(tup);
188 Py_DECREF(tup);
189 return str;
192 static PyObject *
193 structseq_concat(PyStructSequence *obj, PyObject *b)
195 PyObject *tup, *result;
196 tup = make_tuple(obj);
197 result = PySequence_Concat(tup, b);
198 Py_DECREF(tup);
199 return result;
202 static PyObject *
203 structseq_repeat(PyStructSequence *obj, Py_ssize_t n)
205 PyObject *tup, *result;
206 tup = make_tuple(obj);
207 result = PySequence_Repeat(tup, n);
208 Py_DECREF(tup);
209 return result;
212 static int
213 structseq_contains(PyStructSequence *obj, PyObject *o)
215 PyObject *tup;
216 int result;
217 tup = make_tuple(obj);
218 if (!tup)
219 return -1;
220 result = PySequence_Contains(tup, o);
221 Py_DECREF(tup);
222 return result;
225 static long
226 structseq_hash(PyObject *obj)
228 PyObject *tup;
229 long result;
230 tup = make_tuple((PyStructSequence*) obj);
231 if (!tup)
232 return -1;
233 result = PyObject_Hash(tup);
234 Py_DECREF(tup);
235 return result;
238 static PyObject *
239 structseq_richcompare(PyObject *obj, PyObject *o2, int op)
241 PyObject *tup, *result;
242 tup = make_tuple((PyStructSequence*) obj);
243 result = PyObject_RichCompare(tup, o2, op);
244 Py_DECREF(tup);
245 return result;
248 static PyObject *
249 structseq_reduce(PyStructSequence* self)
251 PyObject* tup;
252 PyObject* dict;
253 PyObject* result;
254 Py_ssize_t n_fields, n_visible_fields, n_unnamed_fields;
255 int i;
257 n_fields = REAL_SIZE(self);
258 n_visible_fields = VISIBLE_SIZE(self);
259 n_unnamed_fields = UNNAMED_FIELDS(self);
260 tup = PyTuple_New(n_visible_fields);
261 if (!tup) {
262 return NULL;
265 dict = PyDict_New();
266 if (!dict) {
267 Py_DECREF(tup);
268 return NULL;
271 for (i = 0; i < n_visible_fields; i++) {
272 Py_INCREF(self->ob_item[i]);
273 PyTuple_SET_ITEM(tup, i, self->ob_item[i]);
276 for (; i < n_fields; i++) {
277 char *n = self->ob_type->tp_members[i-n_unnamed_fields].name;
278 PyDict_SetItemString(dict, n,
279 self->ob_item[i]);
282 result = Py_BuildValue("(O(OO))", self->ob_type, tup, dict);
284 Py_DECREF(tup);
285 Py_DECREF(dict);
287 return result;
290 static PySequenceMethods structseq_as_sequence = {
291 (lenfunc)structseq_length,
292 (binaryfunc)structseq_concat, /* sq_concat */
293 (ssizeargfunc)structseq_repeat, /* sq_repeat */
294 (ssizeargfunc)structseq_item, /* sq_item */
295 (ssizessizeargfunc)structseq_slice, /* sq_slice */
296 0, /* sq_ass_item */
297 0, /* sq_ass_slice */
298 (objobjproc)structseq_contains, /* sq_contains */
301 static PyMethodDef structseq_methods[] = {
302 {"__reduce__", (PyCFunction)structseq_reduce,
303 METH_NOARGS, NULL},
304 {NULL, NULL}
307 static PyTypeObject _struct_sequence_template = {
308 PyObject_HEAD_INIT(&PyType_Type)
309 0, /* ob_size */
310 NULL, /* tp_name */
311 0, /* tp_basicsize */
312 0, /* tp_itemsize */
313 (destructor)structseq_dealloc, /* tp_dealloc */
314 0, /* tp_print */
315 0, /* tp_getattr */
316 0, /* tp_setattr */
317 0, /* tp_compare */
318 (reprfunc)structseq_repr, /* tp_repr */
319 0, /* tp_as_number */
320 &structseq_as_sequence, /* tp_as_sequence */
321 0, /* tp_as_mapping */
322 structseq_hash, /* tp_hash */
323 0, /* tp_call */
324 0, /* tp_str */
325 0, /* tp_getattro */
326 0, /* tp_setattro */
327 0, /* tp_as_buffer */
328 Py_TPFLAGS_DEFAULT, /* tp_flags */
329 NULL, /* tp_doc */
330 0, /* tp_traverse */
331 0, /* tp_clear */
332 structseq_richcompare, /* tp_richcompare */
333 0, /* tp_weaklistoffset */
334 0, /* tp_iter */
335 0, /* tp_iternext */
336 structseq_methods, /* tp_methods */
337 NULL, /* tp_members */
338 0, /* tp_getset */
339 0, /* tp_base */
340 0, /* tp_dict */
341 0, /* tp_descr_get */
342 0, /* tp_descr_set */
343 0, /* tp_dictoffset */
344 0, /* tp_init */
345 0, /* tp_alloc */
346 structseq_new, /* tp_new */
349 void
350 PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
352 PyObject *dict;
353 PyMemberDef* members;
354 int n_members, n_unnamed_members, i, k;
356 #ifdef Py_TRACE_REFS
357 /* if the type object was chained, unchain it first
358 before overwriting its storage */
359 if (type->_ob_next) {
360 _Py_ForgetReference((PyObject*)type);
362 #endif
364 n_unnamed_members = 0;
365 for (i = 0; desc->fields[i].name != NULL; ++i)
366 if (desc->fields[i].name == PyStructSequence_UnnamedField)
367 n_unnamed_members++;
368 n_members = i;
370 memcpy(type, &_struct_sequence_template, sizeof(PyTypeObject));
371 type->tp_name = desc->name;
372 type->tp_doc = desc->doc;
373 type->tp_basicsize = sizeof(PyStructSequence)+
374 sizeof(PyObject*)*(n_members-1);
375 type->tp_itemsize = 0;
377 members = PyMem_NEW(PyMemberDef, n_members-n_unnamed_members+1);
378 if (members == NULL)
379 return;
381 for (i = k = 0; i < n_members; ++i) {
382 if (desc->fields[i].name == PyStructSequence_UnnamedField)
383 continue;
384 members[k].name = desc->fields[i].name;
385 members[k].type = T_OBJECT;
386 members[k].offset = offsetof(PyStructSequence, ob_item)
387 + i * sizeof(PyObject*);
388 members[k].flags = READONLY;
389 members[k].doc = desc->fields[i].doc;
390 k++;
392 members[k].name = NULL;
394 type->tp_members = members;
396 if (PyType_Ready(type) < 0)
397 return;
398 Py_INCREF(type);
400 dict = type->tp_dict;
401 PyDict_SetItemString(dict, visible_length_key,
402 PyInt_FromLong((long) desc->n_in_sequence));
403 PyDict_SetItemString(dict, real_length_key,
404 PyInt_FromLong((long) n_members));
405 PyDict_SetItemString(dict, unnamed_fields_key,
406 PyInt_FromLong((long) n_unnamed_members));