Browse Source

Add IoOut type to libpyfcgi

Yann Weber 4 years ago
parent
commit
8c69cd1b2f
2 changed files with 307 additions and 87 deletions
  1. 45
    19
      include/python_ioin.h
  2. 262
    68
      src/python_ioin.c

+ 45
- 19
include/python_ioin.h View File

@@ -41,20 +41,26 @@
41 41
 #include <limits.h>
42 42
 #include <stdlib.h>
43 43
 
44
+typedef int (*write_f)(const char*, size_t);
45
+
44 46
 #define IoIn__FromString(self, str) \
45
-(((IoIn*)self)->bin?PyBytes_FromString:PyUnicode_FromString)(str)
47
+(((PyIO_t*)self)->bin?PyBytes_FromString:PyUnicode_FromString)(str)
46 48
 
47
-#define IoIn__FromBuff(self) IoIn__FromString(self, ((IoIn*)self)->buff)
49
+#define IoIn__FromBuff(self) IoIn__FromString(self, ((PyIO_t*)self)->buff)
48 50
 
49 51
 extern PyMethodDef IoIn_methods[];
50 52
 extern PyMemberDef IoIn_members[];
51 53
 extern PyTypeObject IoInType;
52 54
 
55
+extern PyMethodDef IoOut_methods[];
56
+extern PyMemberDef IoOut_members[];
57
+extern PyTypeObject IoOutType;
58
+
53 59
 typedef struct
54 60
 {
55 61
 	PyObject_VAR_HEAD;
56 62
 	PyObject *closed;
57
-	FCGX_Stream **in_stream;
63
+	FCGX_Stream **io_stream;
58 64
 	char *buff;
59 65
 	/**@brief buffer size */
60 66
 	int buff_sz;
@@ -62,32 +68,52 @@ typedef struct
62 68
 	short bin;
63 69
 	/**@brief 1 if EOF encountered, else 0 */
64 70
 	short eof;
65
-} IoIn;
66 71
 
72
+	write_f write;
73
+} PyIO_t;
74
+
75
+int pyfcgi_io_init(PyObject *self);
67 76
 int pyfcgi_ioin_init(PyObject *self, PyObject *args, PyObject *kwds);
68
-void pyfcgi_ioin_del(IoIn *self);
77
+int pyfcgi_ioout_init(PyObject *self, PyObject *args, PyObject *kwds);
78
+
79
+void pyfcgi_io_del(PyIO_t *self);
80
+
81
+PyObject* pyfcgi_io_close(PyObject *self, PyObject **argv, Py_ssize_t argc);
82
+PyObject* pyfcgi_io_fileno(PyObject *self, PyObject **argv, Py_ssize_t argc);
83
+PyObject* pyfcgi_io_flush(PyObject *self, PyObject **argv, Py_ssize_t argc);
84
+
85
+PyObject* pyfcgi_io_truncate(PyObject *self, PyObject **argv, Py_ssize_t argc);
86
+PyObject* pyfcgi_io_seekable(PyObject *self, PyObject **argv, Py_ssize_t argc);
87
+#define pyfcgi_io_seekable pyfcgi_io_false
88
+#define pyfcgi_io_isatty pyfcgi_io_false
89
+
90
+PyObject* pyfcgi_io_SeekError(PyObject *self, PyObject **argv, Py_ssize_t argc);
91
+#define pyfcgi_io_seek pyfcgi_io_SeekError
92
+#define pyfcgi_io_tell pyfcgi_io_SeekError
93
+
94
+PyObject* pyfcgi_io_WriteError(PyObject *self, PyObject **argv, Py_ssize_t argc);
95
+PyObject* pyfcgi_io_ReadError(PyObject *self, PyObject **argv, Py_ssize_t argc);
69 96
 
70
-PyObject* pyfcgi_ioin_close(PyObject *self, PyObject **argv, Py_ssize_t argc);
71
-PyObject* pyfcgi_ioin_fileno(PyObject *self, PyObject **argv, Py_ssize_t argc);
72
-PyObject* pyfcgi_ioin_flush(PyObject *self, PyObject **argv, Py_ssize_t argc);
73
-PyObject* pyfcgi_ioin_isatty(PyObject *self, PyObject **argv, Py_ssize_t argc);
74
-PyObject* pyfcgi_ioin_readable(PyObject *self, PyObject **argv, Py_ssize_t argc);
97
+#define pyfcgi_ioin_readable pyfcgi_io_true
75 98
 PyObject* pyfcgi_ioin_readline(PyObject *self, PyObject **argv, Py_ssize_t argc);
76 99
 PyObject* pyfcgi_ioin_readlines(PyObject *self, PyObject **argv, Py_ssize_t argc);
77 100
 PyObject* pyfcgi_ioin_read(PyObject *self, PyObject **argv, Py_ssize_t argc);
78 101
 PyObject* pyfcgi_ioin_readall(PyObject *self, PyObject **argv, Py_ssize_t argc);
79 102
 PyObject* pyfcgi_ioin_readinto(PyObject *self, PyObject **argv, Py_ssize_t argc);
80 103
 
81
-PyObject* pyfcgi_ioin_WriteError(PyObject *self, PyObject **argv, Py_ssize_t argc);
82
-#define pyfcgi_ioin_writelines pyfcgi_ioin_WriteError
83
-#define pyfcgi_ioin_write pyfcgi_ioin_WriteError
104
+#define pyfcgi_ioin_writable pyfcgi_io_true
105
+#define pyfcgi_ioin_writelines pyfcgi_io_WriteError
106
+#define pyfcgi_ioin_write pyfcgi_io_WriteError
84 107
 
85
-PyObject* pyfcgi_ioin_SeekError(PyObject *self, PyObject **argv, Py_ssize_t argc);
86
-#define pyfcgi_ioin_seek pyfcgi_ioin_SeekError
87
-#define pyfcgi_ioin_tell pyfcgi_ioin_SeekError
108
+#define pyfcgi_ioout_readable pyfcgi_io_false
109
+#define pyfcgi_ioout_readline pyfcgi_io_ReadError
110
+#define pyfcgi_ioout_readlines pyfcgi_io_ReadError
111
+#define pyfcgi_ioout_read pyfcgi_io_ReadError
112
+#define pyfcgi_ioout_readall pyfcgi_io_ReadError
113
+#define pyfcgi_ioout_readinto pyfcgi_io_ReadError
88 114
 
89
-PyObject* pyfcgi_ioin_truncate(PyObject *self, PyObject **argv, Py_ssize_t argc);
90
-PyObject* pyfcgi_ioin_seekable(PyObject *self, PyObject **argv, Py_ssize_t argc);
91
-PyObject* pyfcgi_ioin_writable(PyObject *self, PyObject **argv, Py_ssize_t argc);
115
+#define pyfcgi_ioout_writable pyfcgi_io_true
116
+PyObject* pyfcgi_ioout_writelines(PyObject *self, PyObject **argv, Py_ssize_t argc);
117
+PyObject* pyfcgi_ioout_write(PyObject *self, PyObject **argv, Py_ssize_t argc);
92 118
 
93 119
 #endif

+ 262
- 68
src/python_ioin.c View File

@@ -3,7 +3,7 @@
3 3
  * @ingroup lib_ioin
4 4
  */
5 5
 
6
-/**@brief If given object in_stream is NULL set error indicator
6
+/**@brief If given object io_stream is NULL set error indicator
7 7
  * @return 0 if no error else -1 or -2
8 8
  */
9 9
 static int _check_nullin(PyObject *self);
@@ -14,24 +14,27 @@ static int _check_nullin(PyObject *self);
14 14
  * @param int nreq number of bytes required in buffer
15 15
  * @return 0 on error else buffer size
16 16
  */
17
-static int pyfcgi_ioin__reqbuf(PyObject *self, int nreq);
17
+static int pyfcgi_io__reqbuf(PyObject *self, int nreq);
18 18
 
19 19
 /**@brief Concat two bytes/unicode given IoIn configuration flag
20 20
  */
21 21
 static PyObject* IoIn__Concat(PyObject *self, PyObject *left, PyObject *right);
22 22
 
23
+PyObject* pyfcgi_io_true(PyObject *self, PyObject **argv, Py_ssize_t argc);
24
+PyObject* pyfcgi_io_false(PyObject *self, PyObject **argv, Py_ssize_t argc);
25
+
23 26
 PyMethodDef IoIn_methods[] = {
24
-	{"close", (PyCFunction)pyfcgi_ioin_close, METH_FASTCALL, NULL},
25
-	{"fileno", (PyCFunction)pyfcgi_ioin_fileno, METH_FASTCALL, NULL},
26
-	{"flush", (PyCFunction)pyfcgi_ioin_flush, METH_FASTCALL, NULL},
27
-	{"isatty", (PyCFunction)pyfcgi_ioin_isatty, METH_FASTCALL, NULL},
27
+	{"close", (PyCFunction)pyfcgi_io_close, METH_FASTCALL, NULL},
28
+	{"fileno", (PyCFunction)pyfcgi_io_fileno, METH_FASTCALL, NULL},
29
+	{"flush", (PyCFunction)pyfcgi_io_flush, METH_FASTCALL, NULL},
30
+	{"isatty", (PyCFunction)pyfcgi_io_isatty, METH_FASTCALL, NULL},
28 31
 	{"readable", (PyCFunction)pyfcgi_ioin_readable, METH_FASTCALL, NULL},
29 32
 	{"readline", (PyCFunction)pyfcgi_ioin_readline, METH_FASTCALL, NULL},
30 33
 	{"readlines", (PyCFunction)pyfcgi_ioin_readlines, METH_FASTCALL, NULL},
31
-	{"seek", (PyCFunction)pyfcgi_ioin_seek, METH_FASTCALL, NULL},
32
-	{"seekable", (PyCFunction)pyfcgi_ioin_seekable, METH_FASTCALL, NULL},
33
-	{"tell", (PyCFunction)pyfcgi_ioin_tell, METH_FASTCALL, NULL},
34
-	{"truncate", (PyCFunction)pyfcgi_ioin_truncate, METH_FASTCALL, NULL},
34
+	{"seek", (PyCFunction)pyfcgi_io_seek, METH_FASTCALL, NULL},
35
+	{"seekable", (PyCFunction)pyfcgi_io_seekable, METH_FASTCALL, NULL},
36
+	{"tell", (PyCFunction)pyfcgi_io_tell, METH_FASTCALL, NULL},
37
+	{"truncate", (PyCFunction)pyfcgi_io_truncate, METH_FASTCALL, NULL},
35 38
 	{"writable", (PyCFunction)pyfcgi_ioin_writable, METH_FASTCALL, NULL},
36 39
 	{"writelines", (PyCFunction)pyfcgi_ioin_writelines, METH_FASTCALL, NULL},
37 40
 	{"read", (PyCFunction)pyfcgi_ioin_read, METH_FASTCALL, NULL},
@@ -42,16 +45,16 @@ PyMethodDef IoIn_methods[] = {
42 45
 };
43 46
 
44 47
 PyMemberDef IoIn_members[] = {
45
-	{"closed", T_OBJECT, offsetof(IoIn, closed), READONLY, "True if the stream is closed"},
48
+	{"closed", T_OBJECT, offsetof(PyIO_t, closed), READONLY, "True if the stream is closed"},
46 49
 	{NULL}
47 50
 };
48 51
 
49 52
 PyTypeObject IoInType = {
50 53
 	PyVarObject_HEAD_INIT(NULL, 0)
51 54
 	"libpyfcgi.IoIn",                     /* tp_name */
52
-	sizeof(IoIn),                        /* tp_basicsize */
55
+	sizeof(PyIO_t),                        /* tp_basicsize */
53 56
 	0,                                               /* tp_itemsize */
54
-	(destructor)pyfcgi_ioin_del, /* tp_dealloc */
57
+	(destructor)pyfcgi_io_del, /* tp_dealloc */
55 58
 	0,                                               /* tp_print */
56 59
 	0,                                               /* tp_getattr */
57 60
 	0,                                               /* tp_setattr */
@@ -88,26 +91,108 @@ PyTypeObject IoInType = {
88 91
 	0,                            /* tp_new */
89 92
 };
90 93
 
94
+PyMethodDef IoOut_methods[] = {
95
+	{"close", (PyCFunction)pyfcgi_io_close, METH_FASTCALL, NULL},
96
+	{"fileno", (PyCFunction)pyfcgi_io_fileno, METH_FASTCALL, NULL},
97
+	{"flush", (PyCFunction)pyfcgi_io_flush, METH_FASTCALL, NULL},
98
+	{"isatty", (PyCFunction)pyfcgi_io_isatty, METH_FASTCALL, NULL},
99
+	{"readable", (PyCFunction)pyfcgi_ioout_readable, METH_FASTCALL, NULL},
100
+	{"readline", (PyCFunction)pyfcgi_ioout_readline, METH_FASTCALL, NULL},
101
+	{"readlines", (PyCFunction)pyfcgi_ioout_readlines, METH_FASTCALL, NULL},
102
+	{"seek", (PyCFunction)pyfcgi_io_seek, METH_FASTCALL, NULL},
103
+	{"seekable", (PyCFunction)pyfcgi_io_seekable, METH_FASTCALL, NULL},
104
+	{"tell", (PyCFunction)pyfcgi_io_tell, METH_FASTCALL, NULL},
105
+	{"truncate", (PyCFunction)pyfcgi_io_truncate, METH_FASTCALL, NULL},
106
+	{"writable", (PyCFunction)pyfcgi_ioout_writable, METH_FASTCALL, NULL},
107
+	{"writelines", (PyCFunction)pyfcgi_ioout_writelines, METH_FASTCALL, NULL},
108
+	{"read", (PyCFunction)pyfcgi_ioout_read, METH_FASTCALL, NULL},
109
+	{"readall", (PyCFunction)pyfcgi_ioout_readall, METH_FASTCALL, NULL},
110
+	{"readinto", (PyCFunction)pyfcgi_ioout_readinto, METH_FASTCALL, NULL},
111
+	{"write", (PyCFunction)pyfcgi_ioout_write, METH_FASTCALL, NULL},
112
+	{NULL} //Sentinel
113
+};
91 114
 
92
-int pyfcgi_ioin_init(PyObject *self, PyObject *args, PyObject *kwds)
115
+PyMemberDef IoOut_members[] = {
116
+	{"closed", T_OBJECT, offsetof(PyIO_t, closed), READONLY, "True if the stream is closed"},
117
+	{NULL}
118
+};
119
+
120
+PyTypeObject IoOutType = {
121
+	PyVarObject_HEAD_INIT(NULL, 0)
122
+	"libpyfcgi.IoOut",                     /* tp_name */
123
+	sizeof(PyIO_t),                        /* tp_basicsize */
124
+	0,                                               /* tp_itemsize */
125
+	(destructor)pyfcgi_io_del, /* tp_dealloc */
126
+	0,                                               /* tp_print */
127
+	0,                                               /* tp_getattr */
128
+	0,                                               /* tp_setattr */
129
+	0,                                               /* tp_reserved */
130
+	0,                                               /* tp_repr */
131
+	0,                                               /* tp_as_number */
132
+	0,                                               /* tp_as_sequence */
133
+	0,                              /* tp_as_mapping */
134
+	0,                                               /* tp_hash  */
135
+	0,                                               /* tp_call */
136
+	0,                                               /* tp_str */
137
+	0,                                               /* tp_getattro */
138
+	0,                                               /* tp_setattro */
139
+	0,                                               /* tp_as_buffer */
140
+	Py_TPFLAGS_DEFAULT |
141
+	Py_TPFLAGS_BASETYPE,   /* tp_flags */
142
+	"RawIo interface to FCGI input stream",                /* tp_doc */
143
+	0,                                               /* tp_traverse */
144
+	0,                                               /* tp_clear */
145
+	0,                                               /* tp_richcompare */
146
+	0,                                               /* tp_weaklistoffset */
147
+	0,                                               /* tp_iter */
148
+	0,                                               /* tp_iternext */
149
+	IoOut_methods,                        /* tp_methods */
150
+	IoOut_members,                        /* tp_members */
151
+	0,                                               /* tp_getset */
152
+	0,                                               /* tp_base */
153
+	0,                                               /* tp_dict */
154
+	0,                                               /* tp_descr_get */
155
+	0,                                               /* tp_descr_set */
156
+	0,                                               /* tp_dictoffset */
157
+	pyfcgi_ioout_init,          /* tp_init */
158
+	0,                                               /* tp_alloc */
159
+	0,                            /* tp_new */
160
+};
161
+
162
+
163
+
164
+int pyfcgi_io_init(PyObject *self)
93 165
 {
94
-	IoIn *ioin = (void*)self;
95
-	ioin->in_stream = NULL;
166
+	PyIO_t *ioin = (void*)self;
167
+	ioin->io_stream = NULL;
96 168
 	ioin->buff = NULL;
97 169
 	ioin->buff_sz = 0;
98 170
 	ioin->eof=0;
99 171
 	ioin->bin=1;
172
+	ioin->write = NULL;
173
+	return 0;
174
+}
175
+
176
+int pyfcgi_ioin_init(PyObject *self, PyObject *args, PyObject *kwds)
177
+{
178
+	pyfcgi_io_init(self);
100 179
 	return 0;
101 180
 }
102 181
 
103
-void pyfcgi_ioin_del(IoIn *self)
182
+int pyfcgi_ioout_init(PyObject *self, PyObject *args, PyObject *kwds)
104 183
 {
105
-	IoIn *ioin = self;
184
+	pyfcgi_io_init(self);
185
+	return 0;
186
+}
187
+
188
+void pyfcgi_io_del(PyIO_t *self)
189
+{
190
+	PyIO_t *ioin = self;
106 191
 	if(ioin->buff) { free(ioin->buff); }
107 192
 	Py_TYPE(self)->tp_free((PyObject*)self);
108 193
 }
109 194
 
110
-PyObject* pyfcgi_ioin_close(PyObject *self, PyObject **argv, Py_ssize_t argc)
195
+PyObject* pyfcgi_io_close(PyObject *self, PyObject **argv, Py_ssize_t argc)
111 196
 {
112 197
 	if(_check_nullin(self)) { Py_RETURN_NONE; }
113 198
 	if(argc)
@@ -117,22 +202,22 @@ PyObject* pyfcgi_ioin_close(PyObject *self, PyObject **argv, Py_ssize_t argc)
117 202
 			argc);
118 203
 		Py_RETURN_NONE;
119 204
 	}
120
-	if(FCGX_FClose(*((IoIn*)self)->in_stream) < 0)
205
+	if(FCGX_FClose(*((PyIO_t*)self)->io_stream) < 0)
121 206
 	{
122 207
 		PyErr_Format(PyExc_OSError,
123 208
 			"%A unable to close", self);
124 209
 	}
125
-	((IoIn*)self)->closed = Py_True;
210
+	((PyIO_t*)self)->closed = Py_True;
126 211
 	Py_RETURN_NONE;
127 212
 }
128 213
 
129
-PyObject* pyfcgi_ioin_fileno(PyObject *self, PyObject **argv, Py_ssize_t argc)
214
+PyObject* pyfcgi_io_fileno(PyObject *self, PyObject **argv, Py_ssize_t argc)
130 215
 {
131 216
 	PyErr_SetString(PyExc_OSError, "libpyfcgi.IoIn has no fileno");
132 217
 	Py_RETURN_NONE;
133 218
 }
134 219
 
135
-PyObject* pyfcgi_ioin_flush(PyObject *self, PyObject **argv, Py_ssize_t argc)
220
+PyObject* pyfcgi_io_flush(PyObject *self, PyObject **argv, Py_ssize_t argc)
136 221
 {
137 222
 	if(_check_nullin(self)) { Py_RETURN_NONE; }
138 223
 	if(argc)
@@ -142,7 +227,7 @@ PyObject* pyfcgi_ioin_flush(PyObject *self, PyObject **argv, Py_ssize_t argc)
142 227
 			argc);
143 228
 		Py_RETURN_NONE;
144 229
 	}
145
-	if(FCGX_FFlush(*((IoIn*)self)->in_stream) < 0)
230
+	if(FCGX_FFlush(*((PyIO_t*)self)->io_stream) < 0)
146 231
 	{
147 232
 		PyErr_Format(PyExc_OSError,
148 233
 			"%A unable to flush", self);
@@ -150,16 +235,6 @@ PyObject* pyfcgi_ioin_flush(PyObject *self, PyObject **argv, Py_ssize_t argc)
150 235
 	Py_RETURN_NONE;
151 236
 }
152 237
 
153
-PyObject* pyfcgi_ioin_isatty(PyObject *self, PyObject **argv, Py_ssize_t argc)
154
-{
155
-	return Py_False;
156
-}
157
-
158
-PyObject* pyfcgi_ioin_readable(PyObject *self, PyObject **argv, Py_ssize_t argc)
159
-{
160
-	return Py_True;
161
-}
162
-
163 238
 PyObject* pyfcgi_ioin_readline(PyObject *self, PyObject **argv, Py_ssize_t argc)
164 239
 {
165 240
 	int read_n;
@@ -176,7 +251,7 @@ PyObject* pyfcgi_ioin_readline(PyObject *self, PyObject **argv, Py_ssize_t argc)
176 251
 	}
177 252
 	if(!argc || !argv[0])
178 253
 	{
179
-		read_n = pyfcgi_ioin__reqbuf(self, 0);
254
+		read_n = pyfcgi_io__reqbuf(self, 0);
180 255
 	}
181 256
 	else
182 257
 	{
@@ -185,13 +260,13 @@ PyObject* pyfcgi_ioin_readline(PyObject *self, PyObject **argv, Py_ssize_t argc)
185 260
 		{
186 261
 			Py_RETURN_NONE;
187 262
 		}
188
-		read_n = pyfcgi_ioin__reqbuf(self, (arg>INT_MAX)?INT_MAX:arg);
263
+		read_n = pyfcgi_io__reqbuf(self, (arg>INT_MAX)?INT_MAX:arg);
189 264
 	}
190 265
 
191
-	ret = ((IoIn*)self)->buff;
192
-	if(!FCGX_GetLine(ret, read_n, *((IoIn*)self)->in_stream))
266
+	ret = ((PyIO_t*)self)->buff;
267
+	if(!FCGX_GetLine(ret, read_n, *((PyIO_t*)self)->io_stream))
193 268
 	{
194
-		((IoIn*)self)->eof = 1;
269
+		((PyIO_t*)self)->eof = 1;
195 270
 		ret = "";
196 271
 	}
197 272
 //dprintf(2, "readline : '%s'\n", ret);
@@ -236,17 +311,17 @@ PyObject* pyfcgi_ioin_readlines(PyObject *self, PyObject **argv, Py_ssize_t argc
236 311
 	}
237 312
 	Py_INCREF(res);
238 313
 
239
-	read_n = pyfcgi_ioin__reqbuf(self, 0);
240
-	buff = ((IoIn*)self)->buff;
314
+	read_n = pyfcgi_io__reqbuf(self, 0);
315
+	buff = ((PyIO_t*)self)->buff;
241 316
 	cur_str = NULL;
242 317
 
243 318
 	while((hint && left) || !hint)
244 319
 	{
245 320
 		toread = (hint&&((size_t)read_n > left))?(int)left:read_n;
246 321
 		if(!FCGX_GetLine(buff, toread,
247
-			*((IoIn*)self)->in_stream))
322
+			*((PyIO_t*)self)->io_stream))
248 323
 		{
249
-			((IoIn*)self)->eof = 1;
324
+			((PyIO_t*)self)->eof = 1;
250 325
 			break;
251 326
 		}
252 327
 		sz = strlen(buff);
@@ -311,7 +386,7 @@ PyObject* pyfcgi_ioin_read(PyObject *self, PyObject **argv, Py_ssize_t argc)
311 386
 		Py_RETURN_NONE;
312 387
 	}
313 388
 
314
-	if(((IoIn*)self)->eof)
389
+	if(((PyIO_t*)self)->eof)
315 390
 	{
316 391
 		return IoIn__FromString(self, "");
317 392
 	}
@@ -330,8 +405,8 @@ PyObject* pyfcgi_ioin_read(PyObject *self, PyObject **argv, Py_ssize_t argc)
330 405
 		}
331 406
 	}
332 407
 	left = max;
333
-	read_n = pyfcgi_ioin__reqbuf(self, 0);
334
-	buff = ((IoIn*)self)->buff;
408
+	read_n = pyfcgi_io__reqbuf(self, 0);
409
+	buff = ((PyIO_t*)self)->buff;
335 410
 	if(!(res = IoIn__FromString(self, "")))
336 411
 	{
337 412
 		Py_RETURN_NONE;
@@ -340,7 +415,7 @@ PyObject* pyfcgi_ioin_read(PyObject *self, PyObject **argv, Py_ssize_t argc)
340 415
 	while((max && left) || !max)
341 416
 	{
342 417
 		toread = (max&&((size_t)read_n > left))?(int)left:read_n;
343
-		sz = FCGX_GetStr(buff, toread, *((IoIn*)self)->in_stream);
418
+		sz = FCGX_GetStr(buff, toread, *((PyIO_t*)self)->io_stream);
344 419
 		if(sz)
345 420
 		{
346 421
 			if(sz == toread) { buff[sz] = '\0'; }
@@ -359,7 +434,7 @@ PyObject* pyfcgi_ioin_read(PyObject *self, PyObject **argv, Py_ssize_t argc)
359 434
 
360 435
 		if( sz < toread)
361 436
 		{
362
-			((IoIn*)self)->eof = 1;
437
+			((PyIO_t*)self)->eof = 1;
363 438
 			break;
364 439
 		}
365 440
 	}
@@ -408,14 +483,14 @@ PyObject* pyfcgi_ioin_readinto(PyObject *self, PyObject **argv, Py_ssize_t argc)
408 483
 	left = max = PyByteArray_Size(b);
409 484
 	buff = PyByteArray_AsString(b);
410 485
 	buff_ptr = buff;
411
-	read_n = pyfcgi_ioin__reqbuf(self, 0);
486
+	read_n = pyfcgi_io__reqbuf(self, 0);
412 487
 	while(left)
413 488
 	{
414 489
 		toread = left>read_n?read_n:left;
415 490
 		if((ret = FCGX_GetStr(buff_ptr, toread,
416
-			*((IoIn*)self)->in_stream)) < toread)
491
+			*((PyIO_t*)self)->io_stream)) < toread)
417 492
 		{
418
-			((IoIn*)self)->eof = 1;
493
+			((PyIO_t*)self)->eof = 1;
419 494
 			break;
420 495
 		}
421 496
 		buff_ptr += ret;
@@ -427,45 +502,164 @@ PyObject* pyfcgi_ioin_readinto(PyObject *self, PyObject **argv, Py_ssize_t argc)
427 502
 	return b;
428 503
 }	
429 504
 
430
-
431
-PyObject* pyfcgi_ioin_truncate(PyObject *self, PyObject **argv, Py_ssize_t argc)
505
+PyObject* pyfcgi_ioout_writelines(PyObject *self, PyObject **argv, Py_ssize_t argc)
432 506
 {
433
-	PyErr_SetString(PyExc_OSError, "libpyfcgi.IoIn cannot be truncated");
507
+	PyObject *lines, *iter, *line;
508
+	const char *bytes;
509
+	Py_ssize_t bytes_len, lineno;
510
+	if( ! *((PyIO_t*)self)->write)
511
+	{
512
+		PyErr_Format(PyExc_RuntimeError, "%A write function not set",
513
+			self);
514
+		Py_RETURN_NONE;
515
+	}
516
+	if(argc != 1)
517
+	{
518
+		PyErr_Format(PyExc_ValueError,
519
+			"libpyfcgi.IoOut.writelines() expected 1 argument but %zd given",
520
+			argc);
521
+		Py_RETURN_NONE;
522
+	}
523
+	lines = argv[0];
524
+	iter = PyObject_GetIter(lines);
525
+	if(!iter)
526
+	{
527
+		// should drop exception raised by GetIter ??
528
+		PyErr_Format(PyExc_ValueError,
529
+			"libpyfcgi.IoOut.writelines() first argument does not support iterator protocol : %A",
530
+			lines);
531
+		Py_RETURN_NONE;
532
+	}
533
+	lineno = 0;
534
+	Py_INCREF(iter);
535
+	while( (line = PyIter_Next(lines)) )
536
+	{
537
+		lineno++;
538
+		Py_INCREF(line);
539
+		if(PyUnicode_Check(line))
540
+		{
541
+			bytes = PyUnicode_AsUTF8AndSize(line, &bytes_len);
542
+			if(!bytes) { Py_RETURN_NONE; } //forward error
543
+		}
544
+		else if(PyBytes_Check(line))
545
+		{
546
+			if(PyBytes_AsStringAndSize(line, (char**)&bytes, &bytes_len) == -1)
547
+			{
548
+				Py_RETURN_NONE; //forward error
549
+			}
550
+		}
551
+		else
552
+		{
553
+			PyErr_Format(PyExc_TypeError,
554
+				"libpyfcgi.IoOut.writelines() expected argument to be\
555
+str or bytes but %A given on line %zd",
556
+				line, lineno);
557
+			Py_RETURN_NONE;
558
+		}
559
+		if( ((PyIO_t*)self)->write(bytes, bytes_len) == -1)
560
+		{
561
+			PyErr_Format(PyExc_EOFError,
562
+				"libpyfcgi.IoOut.writelines() EOF error when writing line %zd",
563
+				lineno);
564
+			Py_RETURN_NONE;
565
+		}
566
+		Py_DECREF(line);
567
+	}
568
+	Py_DECREF(iter);
434 569
 	Py_RETURN_NONE;
435 570
 }
436 571
 
437
-PyObject* pyfcgi_ioin_SeekError(PyObject *self, PyObject **argv, Py_ssize_t argc)
572
+PyObject* pyfcgi_ioout_write(PyObject *self, PyObject **argv, Py_ssize_t argc)
438 573
 {
439
-	PyErr_SetString(PyExc_OSError, "libpyfcgi.IoIn is not seekable");
574
+	PyObject *b;
575
+	const char *bytes;
576
+	Py_ssize_t bytes_len;
577
+	if( ! *((PyIO_t*)self)->write)
578
+	{
579
+		PyErr_Format(PyExc_RuntimeError, "%A write function not set",
580
+			self);
581
+		Py_RETURN_NONE;
582
+	}
583
+	if(argc != 1)
584
+	{
585
+		PyErr_Format(PyExc_ValueError,
586
+			"libpyfcgi.IoOut.writelines() expected 1 argument but %zd given",
587
+			argc);
588
+		Py_RETURN_NONE;
589
+	}
590
+	b = argv[0];
591
+	if(PyBytes_Check(b))
592
+	{
593
+		if(PyBytes_AsStringAndSize(b, (char**)&bytes, &bytes_len) == -1)
594
+		{
595
+			Py_RETURN_NONE; //forward error
596
+		}
597
+	}
598
+	else if(PyUnicode_Check(b))
599
+	{
600
+		bytes = PyUnicode_AsUTF8AndSize(b, &bytes_len);
601
+		if(!bytes) { Py_RETURN_NONE; } //forward error
602
+	}
603
+	else
604
+	{
605
+		PyErr_Format(PyExc_TypeError,
606
+			"libpyfcgi.IoOut.write() expected argument to be bytes\
607
+or str but %A given on line %zd",
608
+			b);
609
+		Py_RETURN_NONE;
610
+	}
611
+	if( ((PyIO_t*)self)->write(bytes, bytes_len) == -1)
612
+	{
613
+		PyErr_Format(PyExc_EOFError,
614
+			"libpyfcgi.IoOut.writelines() EOF error when calling write");
615
+		Py_RETURN_NONE;
616
+	}
440 617
 	Py_RETURN_NONE;
441 618
 }
442 619
 
443
-PyObject* pyfcgi_ioin_WriteError(PyObject *self, PyObject **argv, Py_ssize_t argc)
620
+PyObject* pyfcgi_io_false(PyObject *self, PyObject **argv, Py_ssize_t argc)
444 621
 {
445
-	PyErr_SetString(PyExc_OSError, "libpyfcgi.IoIn is not writable");
622
+	return Py_False;
623
+}
624
+
625
+PyObject* pyfcgi_io_true(PyObject *self, PyObject **argv, Py_ssize_t argc)
626
+{
627
+	return Py_True;
628
+}
629
+
630
+PyObject* pyfcgi_io_truncate(PyObject *self, PyObject **argv, Py_ssize_t argc)
631
+{
632
+	PyErr_SetString(PyExc_OSError, "libpyfcgi.Io cannot be truncated");
446 633
 	Py_RETURN_NONE;
447 634
 }
448 635
 
449
-PyObject* pyfcgi_ioin_seekable(PyObject *self, PyObject **argv, Py_ssize_t argc)
636
+PyObject* pyfcgi_io_SeekError(PyObject *self, PyObject **argv, Py_ssize_t argc)
450 637
 {
451
-	return Py_False;
638
+	PyErr_SetString(PyExc_OSError, "libpyfcgi.Io is not seekable");
639
+	Py_RETURN_NONE;
452 640
 }
453 641
 
454
-PyObject* pyfcgi_ioin_writable(PyObject *self, PyObject **argv, Py_ssize_t argc)
642
+PyObject* pyfcgi_io_WriteError(PyObject *self, PyObject **argv, Py_ssize_t argc)
455 643
 {
456
-	return Py_False;
644
+	PyErr_SetString(PyExc_OSError, "libpyfcgi.IoIn is not writable");
645
+	Py_RETURN_NONE;
457 646
 }
458 647
 
648
+PyObject* pyfcgi_io_ReadError(PyObject *self, PyObject **argv, Py_ssize_t argc)
649
+{
650
+	PyErr_SetString(PyExc_OSError, "libpyfcgi.IoOut is not readable");
651
+	Py_RETURN_NONE;
652
+}
459 653
 
460 654
 static int _check_nullin(PyObject *self)
461 655
 {
462
-	if(!((IoIn*)self)->in_stream)
656
+	if(!((PyIO_t*)self)->io_stream)
463 657
 	{
464 658
 		PyErr_SetString(PyExc_RuntimeError,
465 659
 			"pyfcgi.IoIn called in wrong context : FGCI input not set");
466 660
 		return -1;
467 661
 	}
468
-	else if(!(*(((IoIn*)self)->in_stream)))
662
+	else if(!(*(((PyIO_t*)self)->io_stream)))
469 663
 	{
470 664
 		PyErr_SetString(PyExc_RuntimeError,
471 665
 			"pyfcgi.IoIn called in wrong context : FGCI input is NULL");
@@ -474,13 +668,13 @@ static int _check_nullin(PyObject *self)
474 668
 	return 0;
475 669
 }
476 670
 
477
-static int pyfcgi_ioin__reqbuf(PyObject *self, int nreq)
671
+static int pyfcgi_io__reqbuf(PyObject *self, int nreq)
478 672
 {
479
-	IoIn *ioin;
673
+	PyIO_t *ioin;
480 674
 	void *tmp;
481 675
 	int err;
482 676
 
483
-	ioin = (IoIn*)self;
677
+	ioin = (PyIO_t*)self;
484 678
 
485 679
 	if(ioin->buff_sz > nreq && ioin->buff)
486 680
 	{
@@ -508,7 +702,7 @@ static int pyfcgi_ioin__reqbuf(PyObject *self, int nreq)
508 702
  */
509 703
 static PyObject* IoIn__Concat(PyObject *self, PyObject *left, PyObject *right)
510 704
 {
511
-	if(((IoIn*)self)->bin)
705
+	if(((PyIO_t*)self)->bin)
512 706
 	{
513 707
 		PyBytes_Concat(&left, right);
514 708
 		Py_DECREF(right);

Loading…
Cancel
Save