strports.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. /* Copyright (C) 1995,1996,1998,1999,2000,2001,2005 Free Software Foundation, Inc.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2, or (at your option)
  6. * any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this software; see the file COPYING. If not, write to
  15. * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  16. * Boston, MA 02110-1301 USA
  17. *
  18. * As a special exception, the Free Software Foundation gives permission
  19. * for additional uses of the text contained in its release of GUILE.
  20. *
  21. * The exception is that, if you link the GUILE library with other files
  22. * to produce an executable, this does not by itself cause the
  23. * resulting executable to be covered by the GNU General Public License.
  24. * Your use of that executable is in no way restricted on account of
  25. * linking the GUILE library code into it.
  26. *
  27. * This exception does not however invalidate any other reasons why
  28. * the executable file might be covered by the GNU General Public License.
  29. *
  30. * This exception applies only to the code released by the
  31. * Free Software Foundation under the name GUILE. If you copy
  32. * code from other Free Software Foundation releases into a copy of
  33. * GUILE, as the General Public License permits, the exception does
  34. * not apply to the code that you add in this way. To avoid misleading
  35. * anyone as to the status of such modified files, you must delete
  36. * this exception notice from them.
  37. *
  38. * If you write modifications of your own for GUILE, it is your choice
  39. * whether to permit this exception to apply to your modifications.
  40. * If you do not wish that, delete this exception notice. */
  41. #include "libguile/_scm.h"
  42. #include <stdio.h>
  43. #ifdef HAVE_UNISTD_H
  44. #include <unistd.h>
  45. #endif
  46. #include "libguile/unif.h"
  47. #include "libguile/eval.h"
  48. #include "libguile/ports.h"
  49. #include "libguile/read.h"
  50. #include "libguile/root.h"
  51. #include "libguile/strings.h"
  52. #include "libguile/modules.h"
  53. #include "libguile/validate.h"
  54. #include "libguile/deprecation.h"
  55. #include "libguile/strports.h"
  56. #ifdef HAVE_STRING_H
  57. #include <string.h>
  58. #endif
  59. /* {Ports - string ports}
  60. *
  61. */
  62. /* NOTES:
  63. write_buf/write_end point to the ends of the allocated string.
  64. read_buf/read_end in principle point to the part of the string which
  65. has been written to, but this is only updated after a flush.
  66. read_pos and write_pos in principle should be equal, but this is only true
  67. when rw_active is SCM_PORT_NEITHER.
  68. */
  69. scm_t_bits scm_tc16_strport;
  70. static int
  71. stfill_buffer (SCM port)
  72. {
  73. scm_t_port *pt = SCM_PTAB_ENTRY (port);
  74. if (pt->read_pos >= pt->read_end)
  75. return EOF;
  76. else
  77. return scm_return_first_int (*pt->read_pos, port);
  78. }
  79. /* change the size of a port's string to new_size. this doesn't
  80. change read_buf_size. */
  81. static void
  82. st_resize_port (scm_t_port *pt, off_t new_size)
  83. {
  84. SCM old_stream = SCM_PACK (pt->stream);
  85. SCM new_stream = scm_allocate_string (new_size);
  86. unsigned long int old_size = SCM_STRING_LENGTH (old_stream);
  87. unsigned long int min_size = min (old_size, new_size);
  88. unsigned long int i;
  89. off_t index = pt->write_pos - pt->write_buf;
  90. pt->write_buf_size = new_size;
  91. for (i = 0; i != min_size; ++i)
  92. SCM_STRING_CHARS (new_stream) [i] = SCM_STRING_CHARS (old_stream) [i];
  93. /* reset buffer. */
  94. {
  95. pt->stream = SCM_UNPACK (new_stream);
  96. pt->read_buf = pt->write_buf = SCM_STRING_UCHARS (new_stream);
  97. pt->read_pos = pt->write_pos = pt->write_buf + index;
  98. pt->write_end = pt->write_buf + pt->write_buf_size;
  99. pt->read_end = pt->read_buf + pt->read_buf_size;
  100. }
  101. }
  102. /* amount by which write_buf is expanded. */
  103. #define SCM_WRITE_BLOCK 80
  104. /* ensure that write_pos < write_end by enlarging the buffer when
  105. necessary. update read_buf to account for written chars. */
  106. static void
  107. st_flush (SCM port)
  108. {
  109. scm_t_port *pt = SCM_PTAB_ENTRY (port);
  110. if (pt->write_pos == pt->write_end)
  111. {
  112. st_resize_port (pt, pt->write_buf_size * 3 / 2 + SCM_WRITE_BLOCK);
  113. }
  114. pt->read_pos = pt->write_pos;
  115. if (pt->read_pos > pt->read_end)
  116. {
  117. pt->read_end = (unsigned char *) pt->read_pos;
  118. pt->read_buf_size = pt->read_end - pt->read_buf;
  119. }
  120. pt->rw_active = SCM_PORT_NEITHER;
  121. }
  122. static void
  123. st_write (SCM port, const void *data, size_t size)
  124. {
  125. scm_t_port *pt = SCM_PTAB_ENTRY (port);
  126. const char *input = (char *) data;
  127. while (size > 0)
  128. {
  129. int space = pt->write_end - pt->write_pos;
  130. int write_len = (size > space) ? space : size;
  131. memcpy ((char *) pt->write_pos, input, write_len);
  132. pt->write_pos += write_len;
  133. size -= write_len;
  134. input += write_len;
  135. if (write_len == space)
  136. st_flush (port);
  137. }
  138. }
  139. static void
  140. st_end_input (SCM port, int offset)
  141. {
  142. scm_t_port *pt = SCM_PTAB_ENTRY (port);
  143. if (pt->read_pos - pt->read_buf < offset)
  144. scm_misc_error ("st_end_input", "negative position", SCM_EOL);
  145. pt->write_pos = (unsigned char *) (pt->read_pos = pt->read_pos - offset);
  146. pt->rw_active = SCM_PORT_NEITHER;
  147. }
  148. static off_t
  149. st_seek (SCM port, off_t offset, int whence)
  150. {
  151. scm_t_port *pt = SCM_PTAB_ENTRY (port);
  152. off_t target;
  153. if (pt->rw_active == SCM_PORT_READ && offset == 0 && whence == SEEK_CUR)
  154. /* special case to avoid disturbing the unread-char buffer. */
  155. {
  156. if (pt->read_buf == pt->putback_buf)
  157. {
  158. target = pt->saved_read_pos - pt->saved_read_buf
  159. - (pt->read_end - pt->read_pos);
  160. }
  161. else
  162. {
  163. target = pt->read_pos - pt->read_buf;
  164. }
  165. }
  166. else
  167. /* all other cases. */
  168. {
  169. if (pt->rw_active == SCM_PORT_WRITE)
  170. st_flush (port);
  171. if (pt->rw_active == SCM_PORT_READ)
  172. scm_end_input (port);
  173. switch (whence)
  174. {
  175. case SEEK_CUR:
  176. target = pt->read_pos - pt->read_buf + offset;
  177. break;
  178. case SEEK_END:
  179. target = pt->read_end - pt->read_buf + offset;
  180. break;
  181. default: /* SEEK_SET */
  182. target = offset;
  183. break;
  184. }
  185. if (target < 0)
  186. scm_misc_error ("st_seek", "negative offset", SCM_EOL);
  187. if (target >= pt->write_buf_size)
  188. {
  189. if (!(SCM_CELL_WORD_0 (port) & SCM_WRTNG))
  190. {
  191. if (target > pt->write_buf_size)
  192. {
  193. scm_misc_error ("st_seek",
  194. "seek past end of read-only strport",
  195. SCM_EOL);
  196. }
  197. }
  198. else
  199. {
  200. st_resize_port (pt, target + (target == pt->write_buf_size
  201. ? SCM_WRITE_BLOCK
  202. : 0));
  203. }
  204. }
  205. pt->read_pos = pt->write_pos = pt->read_buf + target;
  206. if (pt->read_pos > pt->read_end)
  207. {
  208. pt->read_end = (unsigned char *) pt->read_pos;
  209. pt->read_buf_size = pt->read_end - pt->read_buf;
  210. }
  211. }
  212. return target;
  213. }
  214. static void
  215. st_truncate (SCM port, off_t length)
  216. {
  217. scm_t_port *pt = SCM_PTAB_ENTRY (port);
  218. if (length > pt->write_buf_size)
  219. st_resize_port (pt, length);
  220. pt->read_buf_size = length;
  221. pt->read_end = pt->read_buf + length;
  222. if (pt->read_pos > pt->read_end)
  223. pt->read_pos = pt->read_end;
  224. if (pt->write_pos > pt->read_end)
  225. pt->write_pos = pt->read_end;
  226. }
  227. SCM
  228. scm_mkstrport (SCM pos, SCM str, long modes, const char *caller)
  229. {
  230. SCM z;
  231. scm_t_port *pt;
  232. size_t str_len;
  233. SCM_ASSERT (SCM_INUMP(pos) && SCM_INUM(pos) >= 0, pos, SCM_ARG1, caller);
  234. SCM_ASSERT (SCM_STRINGP (str), str, SCM_ARG1, caller);
  235. str_len = SCM_STRING_LENGTH (str);
  236. if (SCM_INUM (pos) > str_len)
  237. scm_out_of_range (caller, pos);
  238. if (!((modes & SCM_WRTNG) || (modes & SCM_RDNG)))
  239. scm_misc_error ("scm_mkstrport", "port must read or write", SCM_EOL);
  240. SCM_NEWCELL (z);
  241. SCM_DEFER_INTS;
  242. pt = scm_add_to_port_table (z);
  243. SCM_SET_CELL_TYPE (z, scm_tc16_strport | modes);
  244. SCM_SETPTAB_ENTRY (z, pt);
  245. SCM_SETSTREAM (z, SCM_UNPACK (str));
  246. pt->write_buf = pt->read_buf = SCM_STRING_UCHARS (str);
  247. pt->read_pos = pt->write_pos = pt->read_buf + SCM_INUM (pos);
  248. pt->write_buf_size = pt->read_buf_size = str_len;
  249. pt->write_end = pt->read_end = pt->read_buf + pt->read_buf_size;
  250. pt->rw_random = 1;
  251. SCM_ALLOW_INTS;
  252. /* ensure write_pos is writable. */
  253. if ((modes & SCM_WRTNG) && pt->write_pos == pt->write_end)
  254. st_flush (z);
  255. return z;
  256. }
  257. /* create a new string from a string port's buffer. */
  258. SCM scm_strport_to_string (SCM port)
  259. {
  260. scm_t_port *pt = SCM_PTAB_ENTRY (port);
  261. SCM str;
  262. if (pt->rw_active == SCM_PORT_WRITE)
  263. st_flush (port);
  264. str = scm_mem2string ((char *) pt->read_buf, pt->read_buf_size);
  265. scm_remember_upto_here_1 (port);
  266. return str;
  267. }
  268. SCM_DEFINE (scm_object_to_string, "object->string", 1, 1, 0,
  269. (SCM obj, SCM printer),
  270. "Return a Scheme string obtained by printing @var{obj}.\n"
  271. "Printing function can be specified by the optional second\n"
  272. "argument @var{printer} (default: @code{write}).")
  273. #define FUNC_NAME s_scm_object_to_string
  274. {
  275. SCM str, port;
  276. if (!SCM_UNBNDP (printer))
  277. SCM_VALIDATE_PROC (2, printer);
  278. str = scm_allocate_string (0);
  279. port = scm_mkstrport (SCM_INUM0, str, SCM_OPN | SCM_WRTNG, FUNC_NAME);
  280. if (SCM_UNBNDP (printer))
  281. scm_write (obj, port);
  282. else
  283. scm_call_2 (printer, obj, port);
  284. return scm_strport_to_string (port);
  285. }
  286. #undef FUNC_NAME
  287. #if (SCM_DEBUG_DEPRECATED == 0)
  288. SCM
  289. scm_strprint_obj (SCM obj)
  290. {
  291. return scm_object_to_string (obj, SCM_UNDEFINED);
  292. }
  293. #endif /* (SCM_DEBUG_DEPRECATED == 0) */
  294. SCM_DEFINE (scm_call_with_output_string, "call-with-output-string", 1, 0, 0,
  295. (SCM proc),
  296. "Calls the one-argument procedure @var{proc} with a newly created output\n"
  297. "port. When the function returns, the string composed of the characters\n"
  298. "written into the port is returned.")
  299. #define FUNC_NAME s_scm_call_with_output_string
  300. {
  301. SCM p;
  302. p = scm_mkstrport (SCM_INUM0,
  303. scm_make_string (SCM_INUM0, SCM_UNDEFINED),
  304. SCM_OPN | SCM_WRTNG,
  305. FUNC_NAME);
  306. scm_call_1 (proc, p);
  307. return scm_get_output_string (p);
  308. }
  309. #undef FUNC_NAME
  310. SCM_DEFINE (scm_call_with_input_string, "call-with-input-string", 2, 0, 0,
  311. (SCM string, SCM proc),
  312. "Calls the one-argument procedure @var{proc} with a newly\n"
  313. "created input port from which @var{string}'s contents may be\n"
  314. "read. The value yielded by the @var{proc} is returned.")
  315. #define FUNC_NAME s_scm_call_with_input_string
  316. {
  317. SCM p = scm_mkstrport(SCM_INUM0, string, SCM_OPN | SCM_RDNG, FUNC_NAME);
  318. return scm_call_1 (proc, p);
  319. }
  320. #undef FUNC_NAME
  321. SCM_DEFINE (scm_open_input_string, "open-input-string", 1, 0, 0,
  322. (SCM str),
  323. "Take a string and return an input port that delivers characters\n"
  324. "from the string. The port can be closed by\n"
  325. "@code{close-input-port}, though its storage will be reclaimed\n"
  326. "by the garbage collector if it becomes inaccessible.")
  327. #define FUNC_NAME s_scm_open_input_string
  328. {
  329. SCM p = scm_mkstrport(SCM_INUM0, str, SCM_OPN | SCM_RDNG, FUNC_NAME);
  330. return p;
  331. }
  332. #undef FUNC_NAME
  333. SCM_DEFINE (scm_open_output_string, "open-output-string", 0, 0, 0,
  334. (void),
  335. "Return an output port that will accumulate characters for\n"
  336. "retrieval by @code{get-output-string}. The port can be closed\n"
  337. "by the procedure @code{close-output-port}, though its storage\n"
  338. "will be reclaimed by the garbage collector if it becomes\n"
  339. "inaccessible.")
  340. #define FUNC_NAME s_scm_open_output_string
  341. {
  342. SCM p;
  343. p = scm_mkstrport (SCM_INUM0,
  344. scm_make_string (SCM_INUM0, SCM_UNDEFINED),
  345. SCM_OPN | SCM_WRTNG,
  346. FUNC_NAME);
  347. return p;
  348. }
  349. #undef FUNC_NAME
  350. SCM_DEFINE (scm_get_output_string, "get-output-string", 1, 0, 0,
  351. (SCM port),
  352. "Given an output port created by @code{open-output-string},\n"
  353. "return a string consisting of the characters that have been\n"
  354. "output to the port so far.")
  355. #define FUNC_NAME s_scm_get_output_string
  356. {
  357. SCM_VALIDATE_OPOUTSTRPORT (1, port);
  358. return scm_strport_to_string (port);
  359. }
  360. #undef FUNC_NAME
  361. /* Given a null-terminated string EXPR containing a Scheme expression
  362. read it, and return it as an SCM value. */
  363. SCM
  364. scm_c_read_string (const char *expr)
  365. {
  366. SCM port = scm_mkstrport (SCM_INUM0,
  367. scm_makfrom0str (expr),
  368. SCM_OPN | SCM_RDNG,
  369. "scm_c_read_string");
  370. SCM form;
  371. /* Read expressions from that port; ignore the values. */
  372. form = scm_read (port);
  373. scm_close_port (port);
  374. return form;
  375. }
  376. /* Given a null-terminated string EXPR containing Scheme program text,
  377. evaluate it, and return the result of the last expression evaluated. */
  378. SCM
  379. scm_c_eval_string (const char *expr)
  380. {
  381. return scm_eval_string (scm_makfrom0str (expr));
  382. }
  383. #if SCM_DEBUG_DEPRECATED == 0
  384. SCM
  385. scm_read_0str (char *expr)
  386. {
  387. scm_c_issue_deprecation_warning
  388. ("scm_read_0str is deprecated. Use scm_c_read_string instead.");
  389. return scm_c_read_string (expr);
  390. }
  391. SCM
  392. scm_eval_0str (const char *expr)
  393. {
  394. scm_c_issue_deprecation_warning
  395. ("scm_eval_0str is deprecated. Use scm_c_eval_string instead.");
  396. return scm_c_eval_string (expr);
  397. }
  398. #endif
  399. static SCM
  400. inner_eval_string (void *data)
  401. {
  402. SCM port = (SCM)data;
  403. SCM form;
  404. SCM ans = SCM_UNSPECIFIED;
  405. /* Read expressions from that port; ignore the values. */
  406. while (!SCM_EOF_OBJECT_P (form = scm_read (port)))
  407. ans = scm_primitive_eval_x (form);
  408. /* Don't close the port here; if we re-enter this function via a
  409. continuation, then the next time we enter it, we'll get an error.
  410. It's a string port anyway, so there's no advantage to closing it
  411. early. */
  412. return ans;
  413. }
  414. SCM_DEFINE (scm_eval_string, "eval-string", 1, 0, 0,
  415. (SCM string),
  416. "Evaluate @var{string} as the text representation of a Scheme\n"
  417. "form or forms, and return whatever value they produce.\n"
  418. "Evaluation takes place in the environment returned by the\n"
  419. "procedure @code{interaction-environment}.")
  420. #define FUNC_NAME s_scm_eval_string
  421. {
  422. SCM port = scm_mkstrport (SCM_INUM0, string, SCM_OPN | SCM_RDNG,
  423. "eval-string");
  424. return scm_c_call_with_current_module (scm_interaction_environment (),
  425. inner_eval_string, (void *)port);
  426. }
  427. #undef FUNC_NAME
  428. static scm_t_bits
  429. scm_make_stptob ()
  430. {
  431. scm_t_bits tc = scm_make_port_type ("string", stfill_buffer, st_write);
  432. scm_set_port_mark (tc, scm_markstream);
  433. scm_set_port_end_input (tc, st_end_input);
  434. scm_set_port_flush (tc, st_flush);
  435. scm_set_port_seek (tc, st_seek);
  436. scm_set_port_truncate (tc, st_truncate);
  437. return tc;
  438. }
  439. void
  440. scm_init_strports ()
  441. {
  442. scm_tc16_strport = scm_make_stptob ();
  443. #include "libguile/strports.x"
  444. }
  445. /*
  446. Local Variables:
  447. c-file-style: "gnu"
  448. End:
  449. */