cStringIO.c revision 3dc35b0c66e2f0fc33346447041ad287bbf3d330
1/*
2
3  $Id$
4
5  A simple fast partial StringIO replacement.
6
7
8
9     Copyright
10
11       Copyright 1996 Digital Creations, L.C., 910 Princess Anne
12       Street, Suite 300, Fredericksburg, Virginia 22401 U.S.A. All
13       rights reserved.  Copyright in this software is owned by DCLC,
14       unless otherwise indicated. Permission to use, copy and
15       distribute this software is hereby granted, provided that the
16       above copyright notice appear in all copies and that both that
17       copyright notice and this permission notice appear. Note that
18       any product, process or technology described in this software
19       may be the subject of other Intellectual Property rights
20       reserved by Digital Creations, L.C. and are not licensed
21       hereunder.
22
23     Trademarks
24
25       Digital Creations & DCLC, are trademarks of Digital Creations, L.C..
26       All other trademarks are owned by their respective companies.
27
28     No Warranty
29
30       The software is provided "as is" without warranty of any kind,
31       either express or implied, including, but not limited to, the
32       implied warranties of merchantability, fitness for a particular
33       purpose, or non-infringement. This software could include
34       technical inaccuracies or typographical errors. Changes are
35       periodically made to the software; these changes will be
36       incorporated in new editions of the software. DCLC may make
37       improvements and/or changes in this software at any time
38       without notice.
39
40     Limitation Of Liability
41
42       In no event will DCLC be liable for direct, indirect, special,
43       incidental, economic, cover, or consequential damages arising
44       out of the use of or inability to use this software even if
45       advised of the possibility of such damages. Some states do not
46       allow the exclusion or limitation of implied warranties or
47       limitation of liability for incidental or consequential
48       damages, so the above limitation or exclusion may not apply to
49       you.
50
51    If you have questions regarding this software,
52    contact:
53
54      Jim Fulton, jim@digicool.com
55      Digital Creations L.C.
56
57      (540) 371-6909
58
59
60  $Log$
61  Revision 2.5  1997/04/11 19:56:06  guido
62  My own patch: support writable 'softspace' attribute.
63
64  Revision 2.4  1997/04/09 17:35:33  guido
65  Unknown changes by Jim Fulton.
66
67  Revision 1.16  1997/02/17 22:17:43  jim
68  *** empty log message ***
69
70  Revision 1.14  1997/01/24 19:56:24  chris
71  undid last change
72
73  Revision 1.13  1997/01/24 19:45:20  chris
74  extra byte in buffer no longer included in buf_size
75
76  Revision 1.12  1997/01/24 19:38:28  chris
77  *** empty log message ***
78
79  Revision 1.11  1997/01/23 20:45:01  jim
80  ANSIfied it.
81  Changed way C API was exported.
82
83  Revision 1.10  1997/01/02 15:19:55  chris
84  checked in to be sure repository is up to date.
85
86  Revision 1.9  1996/12/27 21:40:29  jim
87  Took out some lamosities in interface, like returning self from
88  write.
89
90  Revision 1.8  1996/12/23 15:52:49  jim
91  Added ifdef to check for CObject before using it.
92
93  Revision 1.7  1996/12/23 15:22:35  jim
94  Finished implementation, adding full compatibility with StringIO, and
95  then some.
96
97  We still need to take out some cStringIO oddities.
98
99  Revision 1.6  1996/10/15 18:42:07  jim
100  Added lots of casts to make warnings go away.
101
102  Revision 1.5  1996/10/11 21:03:42  jim
103  *** empty log message ***
104
105  Revision 1.4  1996/10/11 21:02:15  jim
106  *** empty log message ***
107
108  Revision 1.3  1996/10/07 20:51:38  chris
109  *** empty log message ***
110
111  Revision 1.2  1996/07/18 13:08:34  jfulton
112  *** empty log message ***
113
114  Revision 1.1  1996/07/15 17:06:33  jfulton
115  Initial version.
116
117
118*/
119static char cStringIO_module_documentation[] =
120"A simple fast partial StringIO replacement.\n"
121"\n"
122"This module provides a simple useful replacement for\n"
123"the StringIO module that is written in C.  It does not provide the\n"
124"full generality if StringIO, but it provides anough for most\n"
125"applications and is especially useful in conjuction with the\n"
126"pickle module.\n"
127"\n"
128"Usage:\n"
129"\n"
130"  from cStringIO import StringIO\n"
131"\n"
132"  an_output_stream=StringIO()\n"
133"  an_output_stream.write(some_stuff)\n"
134"  ...\n"
135"  value=an_output_stream.getvalue() # str(an_output_stream) works too!\n"
136"\n"
137"  an_input_stream=StringIO(a_string)\n"
138"  spam=an_input_stream.readline()\n"
139"  spam=an_input_stream.read(5)\n"
140"  an_input_stream.reset()           # OK, start over, note no seek yet\n"
141"  spam=an_input_stream.read()       # and read it all\n"
142"  \n"
143"If someone else wants to provide a more complete implementation,\n"
144"go for it. :-)  \n"
145;
146
147#include "Python.h"
148#include "import.h"
149#include "cStringIO.h"
150
151#define UNLESS(E) if(!(E))
152
153/* ----------------------------------------------------- */
154
155/* Declarations for objects of type StringO */
156
157typedef struct {
158  PyObject_HEAD
159  char *buf;
160  int pos, string_size, buf_size, closed, softspace;
161} Oobject;
162
163staticforward PyTypeObject Otype;
164
165/* ---------------------------------------------------------------- */
166
167/* Declarations for objects of type StringI */
168
169typedef struct {
170  PyObject_HEAD
171  char *buf;
172  int pos, string_size, closed;
173  PyObject *pbuf;
174} Iobject;
175
176staticforward PyTypeObject Itype;
177
178/* ---------------------------------------------------------------- */
179
180static char O_reset__doc__[] =
181"reset() -- Reset the file position to the beginning"
182;
183
184static PyObject *
185O_reset(Oobject *self, PyObject *args) {
186  self->pos = 0;
187
188  Py_INCREF(Py_None);
189  return Py_None;
190}
191
192
193static char O_tell__doc__[] =
194"tell() -- get the current position.";
195
196static PyObject *
197O_tell(Oobject *self, PyObject *args) {
198  return PyInt_FromLong(self->pos);
199}
200
201
202static char O_seek__doc__[] =
203"seek(position)       -- set the current position\n"
204"seek(position, mode) -- mode 0: absolute; 1: relative; 2: relative to EOF";
205
206static PyObject *
207O_seek(Oobject *self, PyObject *args) {
208  int position, mode = 0;
209
210  UNLESS(PyArg_ParseTuple(args, "i|i", &position, &mode))
211  {
212    return NULL;
213  }
214
215  if (mode == 2)
216  {
217    position += self->string_size;
218  }
219  else if (mode == 1)
220  {
221    position += self->pos;
222  }
223
224  self->pos = (position > self->string_size ? self->string_size :
225	       (position < 0 ? 0 : position));
226
227  Py_INCREF(Py_None);
228  return Py_None;
229}
230
231static char O_read__doc__[] =
232"read([s]) -- Read s characters, or the rest of the string"
233;
234
235static int
236O_cread(PyObject *self, char **output, int  n) {
237  int l;
238
239  l = ((Oobject*)self)->string_size - ((Oobject*)self)->pos;
240  if (n < 0 || n > l)
241  {
242    n = l;
243  }
244
245  *output=((Oobject*)self)->buf + ((Oobject*)self)->pos;
246  ((Oobject*)self)->pos += n;
247  return n;
248}
249
250static PyObject *
251O_read(Oobject *self, PyObject *args) {
252  int n = -1;
253  char *output;
254
255  UNLESS(PyArg_ParseTuple(args, "|i", &n)) return NULL;
256
257  n=O_cread((PyObject*)self,&output,n);
258
259  return PyString_FromStringAndSize(output, n);
260}
261
262
263static char O_readline__doc__[] =
264"readline() -- Read one line"
265;
266
267static int
268O_creadline(PyObject *self, char **output) {
269  char *n, *s;
270  int l;
271
272  for (n = ((Oobject*)self)->buf + ((Oobject*)self)->pos,
273	 s = ((Oobject*)self)->buf + ((Oobject*)self)->string_size;
274       n < s && *n != '\n'; n++);
275  if (n < s) n++;
276
277  *output=((Oobject*)self)->buf + ((Oobject*)self)->pos;
278  l = n - ((Oobject*)self)->buf - ((Oobject*)self)->pos;
279  ((Oobject*)self)->pos += l;
280  return l;
281}
282
283static PyObject *
284O_readline(Oobject *self, PyObject *args) {
285  int n;
286  char *output;
287
288  n=O_creadline((PyObject*)self,&output);
289  return PyString_FromStringAndSize(output, n);
290}
291
292static char O_write__doc__[] =
293"write(s) -- Write a string to the file"
294"\n\nNote (hack:) writing None resets the buffer"
295;
296
297
298static int
299O_cwrite(PyObject *self, char *c, int  l) {
300  int newl;
301
302  newl=((Oobject*)self)->pos+l;
303  if(newl >= ((Oobject*)self)->buf_size)
304    {
305      ((Oobject*)self)->buf_size*=2;
306      if(((Oobject*)self)->buf_size <= newl) ((Oobject*)self)->buf_size=newl+1;
307      UNLESS(((Oobject*)self)->buf=
308	     (char*)realloc(((Oobject*)self)->buf,
309			    (((Oobject*)self)->buf_size) *sizeof(char)))
310	{
311	  PyErr_SetString(PyExc_MemoryError,"out of memory");
312	  ((Oobject*)self)->buf_size=((Oobject*)self)->pos=0;
313	  return -1;
314	}
315    }
316
317  memcpy(((Oobject*)((Oobject*)self))->buf+((Oobject*)self)->pos,c,l);
318
319  ((Oobject*)self)->pos += l;
320
321  if (((Oobject*)self)->string_size < ((Oobject*)self)->pos)
322    {
323      ((Oobject*)self)->string_size = ((Oobject*)self)->pos;
324    }
325
326  return l;
327}
328
329static PyObject *
330O_write(Oobject *self, PyObject *args) {
331  PyObject *s;
332  char *c;
333  int l;
334
335  UNLESS(PyArg_Parse(args, "O", &s)) return NULL;
336  UNLESS(-1 != (l=PyString_Size(s))) return NULL;
337  UNLESS(c=PyString_AsString(s)) return NULL;
338  UNLESS(-1 != O_cwrite((PyObject*)self,c,l)) return NULL;
339
340  Py_INCREF(Py_None);
341  return Py_None;
342}
343
344static PyObject *
345O_getval(Oobject *self, PyObject *args) {
346  return PyString_FromStringAndSize(self->buf, self->pos);
347}
348
349static PyObject *
350O_cgetval(PyObject *self) {
351  return PyString_FromStringAndSize(((Oobject*)self)->buf,
352				    ((Oobject*)self)->pos);
353}
354
355static char O_truncate__doc__[] =
356"truncate(): truncate the file at the current position.";
357
358static PyObject *
359O_truncate(Oobject *self, PyObject *args) {
360  self->string_size = self->pos;
361  Py_INCREF(Py_None);
362  return Py_None;
363}
364
365static char O_isatty__doc__[] = "isatty(): always returns 0";
366
367static PyObject *
368O_isatty(Oobject *self, PyObject *args) {
369  return PyInt_FromLong(0);
370}
371
372static char O_close__doc__[] = "close(): explicitly release resources held.";
373
374static PyObject *
375O_close(Oobject *self, PyObject *args) {
376  free(self->buf);
377
378  self->pos = self->string_size = self->buf_size = 0;
379  self->closed = 1;
380
381  Py_INCREF(Py_None);
382  return Py_None;
383}
384
385static char O_flush__doc__[] = "flush(): does nothing.";
386
387static PyObject *
388O_flush(Oobject *self, PyObject *args) {
389  Py_INCREF(Py_None);
390  return Py_None;
391}
392
393
394static char O_writelines__doc__[] = "blah";
395static PyObject *
396O_writelines(Oobject *self, PyObject *args) {
397  PyObject *string_module = 0;
398  static PyObject *string_joinfields = 0;
399
400  UNLESS(PyArg_Parse(args, "O", args))
401  {
402    return NULL;
403  }
404
405  if (!string_joinfields)
406  {
407    UNLESS(string_module = PyImport_ImportModule("string"))
408    {
409      return NULL;
410    }
411
412    UNLESS(string_joinfields=
413        PyObject_GetAttrString(string_module, "joinfields"))
414    {
415      return NULL;
416    }
417
418    Py_DECREF(string_module);
419  }
420
421  if (PyObject_Length(args) == -1)
422  {
423    return NULL;
424  }
425
426  return O_write(self,
427      PyObject_CallFunction(string_joinfields, "Os", args, ""));
428}
429
430static struct PyMethodDef O_methods[] = {
431  {"write",	 (PyCFunction)O_write,        0,      O_write__doc__},
432  {"read",       (PyCFunction)O_read,         1,      O_read__doc__},
433  {"readline",   (PyCFunction)O_readline,     0,      O_readline__doc__},
434  {"reset",      (PyCFunction)O_reset,        0,      O_reset__doc__},
435  {"seek",       (PyCFunction)O_seek,         1,      O_seek__doc__},
436  {"tell",       (PyCFunction)O_tell,         0,      O_tell__doc__},
437  {"getvalue",   (PyCFunction)O_getval,       0,      "getvalue() -- Get the string value"},
438  {"truncate",   (PyCFunction)O_truncate,     0,      O_truncate__doc__},
439  {"isatty",     (PyCFunction)O_isatty,       0,      O_isatty__doc__},
440  {"close",      (PyCFunction)O_close,        0,      O_close__doc__},
441  {"flush",      (PyCFunction)O_flush,        0,      O_flush__doc__},
442  {"writelines", (PyCFunction)O_writelines,   0,      O_writelines__doc__},
443  {NULL,		NULL}		/* sentinel */
444};
445
446/* ---------- */
447
448
449static PyObject *
450newOobject(int  size) {
451  Oobject *self;
452
453  self = PyObject_NEW(Oobject, &Otype);
454  if (self == NULL)
455    return NULL;
456  self->pos=0;
457  self->closed = 0;
458  self->string_size = 0;
459  self->softspace = 0;
460
461  UNLESS(self->buf=malloc(size*sizeof(char)))
462    {
463      PyErr_SetString(PyExc_MemoryError,"out of memory");
464      self->buf_size = 0;
465      return NULL;
466    }
467
468  self->buf_size=size;
469  return (PyObject*)self;
470}
471
472
473static void
474O_dealloc(Oobject *self) {
475  free(self->buf);
476  PyMem_DEL(self);
477}
478
479static PyObject *
480O_getattr(Oobject *self, char *name) {
481  if (strcmp(name, "softspace") == 0) {
482	  return PyInt_FromLong(self->softspace);
483  }
484  return Py_FindMethod(O_methods, (PyObject *)self, name);
485}
486
487static int
488O_setattr(Oobject *self, char *name, PyObject *value) {
489	long x;
490	if (strcmp(name, "softspace") != 0) {
491		PyErr_SetString(PyExc_AttributeError, name);
492		return -1;
493	}
494	x = PyInt_AsLong(value);
495	if (x == -1 && PyErr_Occurred())
496		return -1;
497	self->softspace = x;
498	return 0;
499}
500
501static char Otype__doc__[] =
502"Simple type for output to strings."
503;
504
505static PyTypeObject Otype = {
506  PyObject_HEAD_INIT(NULL)
507  0,	       		/*ob_size*/
508  "StringO",     		/*tp_name*/
509  sizeof(Oobject),       	/*tp_basicsize*/
510  0,	       		/*tp_itemsize*/
511  /* methods */
512  (destructor)O_dealloc,	/*tp_dealloc*/
513  (printfunc)0,		/*tp_print*/
514  (getattrfunc)O_getattr,	/*tp_getattr*/
515  (setattrfunc)O_setattr,	/*tp_setattr*/
516  (cmpfunc)0,		/*tp_compare*/
517  (reprfunc)0,		/*tp_repr*/
518  0,			/*tp_as_number*/
519  0,			/*tp_as_sequence*/
520  0,			/*tp_as_mapping*/
521  (hashfunc)0,		/*tp_hash*/
522  (ternaryfunc)0,		/*tp_call*/
523  (reprfunc)0,		/*tp_str*/
524
525  /* Space for future expansion */
526  0L,0L,0L,0L,
527  Otype__doc__ 		/* Documentation string */
528};
529
530/* End of code for StringO objects */
531/* -------------------------------------------------------- */
532
533static PyObject *
534I_close(Iobject *self, PyObject *args) {
535  Py_DECREF(self->pbuf);
536
537  self->pos = self->string_size = 0;
538  self->closed = 1;
539
540  Py_INCREF(Py_None);
541  return Py_None;
542}
543
544static struct PyMethodDef I_methods[] = {
545  {"read",	(PyCFunction)O_read,         1,      O_read__doc__},
546  {"readline",	(PyCFunction)O_readline,	0,	O_readline__doc__},
547  {"reset",	(PyCFunction)O_reset,	0,	O_reset__doc__},
548  {"seek",      (PyCFunction)O_seek,         1,      O_seek__doc__},
549  {"tell",      (PyCFunction)O_tell,         0,      O_tell__doc__},
550  {"truncate",  (PyCFunction)O_truncate,     0,      O_truncate__doc__},
551  {"isatty",    (PyCFunction)O_isatty,       0,      O_isatty__doc__},
552  {"close",     (PyCFunction)I_close,        0,      O_close__doc__},
553  {"flush",     (PyCFunction)O_flush,        0,      O_flush__doc__},
554  {NULL,		NULL}		/* sentinel */
555};
556
557/* ---------- */
558
559
560static PyObject *
561newIobject(PyObject *s) {
562  Iobject *self;
563  char *buf;
564  int size;
565
566  UNLESS(buf=PyString_AsString(s)) return NULL;
567  UNLESS(-1 != (size=PyString_Size(s))) return NULL;
568  UNLESS(self = PyObject_NEW(Iobject, &Itype)) return NULL;
569  Py_INCREF(s);
570  self->buf=buf;
571  self->string_size=size;
572  self->pbuf=s;
573  self->pos=0;
574  self->closed = 0;
575
576  return (PyObject*)self;
577}
578
579
580static void
581I_dealloc(Iobject *self) {
582  Py_DECREF(self->pbuf);
583  PyMem_DEL(self);
584}
585
586static PyObject *
587I_getattr(Iobject *self, char *name) {
588  return Py_FindMethod(I_methods, (PyObject *)self, name);
589}
590
591static char Itype__doc__[] =
592"Simple type for treating strings as input file streams"
593;
594
595static PyTypeObject Itype = {
596  PyObject_HEAD_INIT(NULL)
597  0,		       	/*ob_size*/
598  "StringI",	       	/*tp_name*/
599  sizeof(Iobject),       	/*tp_basicsize*/
600  0,		       	/*tp_itemsize*/
601  /* methods */
602  (destructor)I_dealloc,	/*tp_dealloc*/
603  (printfunc)0,		/*tp_print*/
604  (getattrfunc)I_getattr,	/*tp_getattr*/
605  (setattrfunc)0,		/*tp_setattr*/
606  (cmpfunc)0,		/*tp_compare*/
607  (reprfunc)0,		/*tp_repr*/
608  0,			/*tp_as_number*/
609  0,			/*tp_as_sequence*/
610  0,			/*tp_as_mapping*/
611  (hashfunc)0,		/*tp_hash*/
612  (ternaryfunc)0,		/*tp_call*/
613  (reprfunc)0,		/*tp_str*/
614
615  /* Space for future expansion */
616  0L,0L,0L,0L,
617  Itype__doc__ 		/* Documentation string */
618};
619
620/* End of code for StringI objects */
621/* -------------------------------------------------------- */
622
623
624static char IO_StringIO__doc__[] =
625"StringIO([s]) -- Return a StringIO-like stream for reading or writing"
626;
627
628static PyObject *
629IO_StringIO(PyObject *self, PyObject *args) {
630  PyObject *s=0;
631
632  UNLESS(PyArg_ParseTuple(args, "|O", &s)) return NULL;
633  if(s) return newIobject(s);
634  return newOobject(128);
635}
636
637/* List of methods defined in the module */
638
639static struct PyMethodDef IO_methods[] = {
640  {"StringIO",	(PyCFunction)IO_StringIO,	1,	IO_StringIO__doc__},
641  {NULL,		NULL}		/* sentinel */
642};
643
644
645/* Initialization function for the module (*must* be called initcStringIO) */
646
647static struct PycStringIO_CAPI CAPI = {
648  O_cread,
649  O_creadline,
650  O_cwrite,
651  O_cgetval,
652  newOobject,
653  newIobject,
654  &Itype,
655  &Otype,
656};
657
658void
659initcStringIO() {
660  PyObject *m, *d;
661
662
663  /* Create the module and add the functions */
664  m = Py_InitModule4("cStringIO", IO_methods,
665		     cStringIO_module_documentation,
666		     (PyObject*)NULL,PYTHON_API_VERSION);
667
668  /* Add some symbolic constants to the module */
669  d = PyModule_GetDict(m);
670
671  /* Export C API */
672  Itype.ob_type=&PyType_Type;
673  Otype.ob_type=&PyType_Type;
674  PyDict_SetItemString(d,"cStringIO_CAPI", PyCObject_FromVoidPtr(&CAPI,NULL));
675
676  /* Export Types */
677  PyDict_SetItemString(d,"InputType",  (PyObject*)&Itype);
678  PyDict_SetItemString(d,"OutputType", (PyObject*)&Otype);
679
680  /* Check for errors */
681  if (PyErr_Occurred()) Py_FatalError("can't initialize module cStringIO");
682}
683
684