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