rdelim.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2006 Free Software Foundation, Inc.
  2. *
  3. * This library is free software; you can redistribute it and/or
  4. * modify it under the terms of the GNU Lesser General Public
  5. * License as published by the Free Software Foundation; either
  6. * version 2.1 of the License, or (at your option) any later version.
  7. *
  8. * This library 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 GNU
  11. * Lesser General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Lesser General Public
  14. * License along with this library; if not, write to the Free Software
  15. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  16. */
  17. #ifdef HAVE_CONFIG_H
  18. # include <config.h>
  19. #endif
  20. #include "libguile/_scm.h"
  21. #include <stdio.h>
  22. #ifdef HAVE_STRING_H
  23. #include <string.h>
  24. #endif
  25. #include "libguile/chars.h"
  26. #include "libguile/modules.h"
  27. #include "libguile/ports.h"
  28. #include "libguile/rdelim.h"
  29. #include "libguile/root.h"
  30. #include "libguile/strings.h"
  31. #include "libguile/strports.h"
  32. #include "libguile/validate.h"
  33. SCM_DEFINE (scm_read_delimited_x, "%read-delimited!", 3, 3, 0,
  34. (SCM delims, SCM str, SCM gobble, SCM port, SCM start, SCM end),
  35. "Read characters from @var{port} into @var{str} until one of the\n"
  36. "characters in the @var{delims} string is encountered. If\n"
  37. "@var{gobble} is true, discard the delimiter character;\n"
  38. "otherwise, leave it in the input stream for the next read. If\n"
  39. "@var{port} is not specified, use the value of\n"
  40. "@code{(current-input-port)}. If @var{start} or @var{end} are\n"
  41. "specified, store data only into the substring of @var{str}\n"
  42. "bounded by @var{start} and @var{end} (which default to the\n"
  43. "beginning and end of the string, respectively).\n"
  44. "\n"
  45. " Return a pair consisting of the delimiter that terminated the\n"
  46. "string and the number of characters read. If reading stopped\n"
  47. "at the end of file, the delimiter returned is the\n"
  48. "@var{eof-object}; if the string was filled without encountering\n"
  49. "a delimiter, this value is @code{#f}.")
  50. #define FUNC_NAME s_scm_read_delimited_x
  51. {
  52. size_t j;
  53. size_t cstart;
  54. size_t cend;
  55. int c;
  56. const char *cdelims;
  57. size_t num_delims;
  58. SCM_VALIDATE_STRING (1, delims);
  59. cdelims = scm_i_string_chars (delims);
  60. num_delims = scm_i_string_length (delims);
  61. SCM_VALIDATE_STRING (2, str);
  62. scm_i_get_substring_spec (scm_i_string_length (str),
  63. start, &cstart, end, &cend);
  64. if (SCM_UNBNDP (port))
  65. port = scm_current_input_port ();
  66. else
  67. SCM_VALIDATE_OPINPORT (4, port);
  68. for (j = cstart; j < cend; j++)
  69. {
  70. size_t k;
  71. c = scm_getc (port);
  72. for (k = 0; k < num_delims; k++)
  73. {
  74. if (cdelims[k] == c)
  75. {
  76. if (scm_is_false (gobble))
  77. scm_ungetc (c, port);
  78. return scm_cons (SCM_MAKE_CHAR (c),
  79. scm_from_size_t (j - cstart));
  80. }
  81. }
  82. if (c == EOF)
  83. return scm_cons (SCM_EOF_VAL,
  84. scm_from_size_t (j - cstart));
  85. scm_c_string_set_x (str, j, SCM_MAKE_CHAR (c));
  86. }
  87. return scm_cons (SCM_BOOL_F, scm_from_size_t (j - cstart));
  88. }
  89. #undef FUNC_NAME
  90. static unsigned char *
  91. scm_do_read_line (SCM port, size_t *len_p)
  92. {
  93. scm_t_port *pt = SCM_PTAB_ENTRY (port);
  94. unsigned char *end;
  95. /* I thought reading lines was simple. Mercy me. */
  96. /* The common case: the buffer contains a complete line.
  97. This needs to be fast. */
  98. if ((end = memchr (pt->read_pos, '\n', (pt->read_end - pt->read_pos)))
  99. != 0)
  100. {
  101. size_t buf_len = (end + 1) - pt->read_pos;
  102. /* Allocate a buffer of the perfect size. */
  103. unsigned char *buf = scm_malloc (buf_len + 1);
  104. memcpy (buf, pt->read_pos, buf_len);
  105. pt->read_pos += buf_len;
  106. buf[buf_len] = '\0';
  107. *len_p = buf_len;
  108. return buf;
  109. }
  110. /* The buffer contains no newlines. */
  111. {
  112. /* When live, len is always the number of characters in the
  113. current buffer that are part of the current line. */
  114. size_t len = (pt->read_end - pt->read_pos);
  115. size_t buf_size = (len < 50) ? 60 : len * 2;
  116. /* Invariant: buf always has buf_size + 1 characters allocated;
  117. the `+ 1' is for the final '\0'. */
  118. unsigned char *buf = scm_malloc (buf_size + 1);
  119. size_t buf_len = 0;
  120. for (;;)
  121. {
  122. if (buf_len + len > buf_size)
  123. {
  124. size_t new_size = (buf_len + len) * 2;
  125. buf = scm_realloc (buf, new_size + 1);
  126. buf_size = new_size;
  127. }
  128. /* Copy what we've got out of the port, into our buffer. */
  129. memcpy (buf + buf_len, pt->read_pos, len);
  130. buf_len += len;
  131. pt->read_pos += len;
  132. /* If we had seen a newline, we're done now. */
  133. if (end)
  134. break;
  135. /* Get more characters. */
  136. if (scm_fill_input (port) == EOF)
  137. {
  138. /* If we're missing a final newline in the file, return
  139. what we did get, sans newline. */
  140. if (buf_len > 0)
  141. break;
  142. free (buf);
  143. return 0;
  144. }
  145. /* Search the buffer for newlines. */
  146. if ((end = memchr (pt->read_pos, '\n',
  147. (len = (pt->read_end - pt->read_pos))))
  148. != 0)
  149. len = (end - pt->read_pos) + 1;
  150. }
  151. /* I wonder how expensive this realloc is. */
  152. buf = scm_realloc (buf, buf_len + 1);
  153. buf[buf_len] = '\0';
  154. *len_p = buf_len;
  155. return buf;
  156. }
  157. }
  158. /*
  159. * %read-line
  160. * truncates any terminating newline from its input, and returns
  161. * a cons of the string read and its terminating character. Doing
  162. * so makes it easy to implement the hairy `read-line' options
  163. * efficiently in Scheme.
  164. */
  165. SCM_DEFINE (scm_read_line, "%read-line", 0, 1, 0,
  166. (SCM port),
  167. "Read a newline-terminated line from @var{port}, allocating storage as\n"
  168. "necessary. The newline terminator (if any) is removed from the string,\n"
  169. "and a pair consisting of the line and its delimiter is returned. The\n"
  170. "delimiter may be either a newline or the @var{eof-object}; if\n"
  171. "@code{%read-line} is called at the end of file, it returns the pair\n"
  172. "@code{(#<eof> . #<eof>)}.")
  173. #define FUNC_NAME s_scm_read_line
  174. {
  175. scm_t_port *pt;
  176. char *s;
  177. size_t slen = 0;
  178. SCM line, term;
  179. if (SCM_UNBNDP (port))
  180. port = scm_current_input_port ();
  181. SCM_VALIDATE_OPINPORT (1,port);
  182. pt = SCM_PTAB_ENTRY (port);
  183. if (pt->rw_active == SCM_PORT_WRITE)
  184. scm_ptobs[SCM_PTOBNUM (port)].flush (port);
  185. s = (char *) scm_do_read_line (port, &slen);
  186. if (s == NULL)
  187. term = line = SCM_EOF_VAL;
  188. else
  189. {
  190. if (s[slen-1] == '\n')
  191. {
  192. term = SCM_MAKE_CHAR ('\n');
  193. s[slen-1] = '\0';
  194. line = scm_take_locale_stringn (s, slen-1);
  195. SCM_INCLINE (port);
  196. }
  197. else
  198. {
  199. /* Fix: we should check for eof on the port before assuming this. */
  200. term = SCM_EOF_VAL;
  201. line = scm_take_locale_stringn (s, slen);
  202. SCM_COL (port) += slen;
  203. }
  204. }
  205. if (pt->rw_random)
  206. pt->rw_active = SCM_PORT_READ;
  207. return scm_cons (line, term);
  208. }
  209. #undef FUNC_NAME
  210. SCM_DEFINE (scm_write_line, "write-line", 1, 1, 0,
  211. (SCM obj, SCM port),
  212. "Display @var{obj} and a newline character to @var{port}. If\n"
  213. "@var{port} is not specified, @code{(current-output-port)} is\n"
  214. "used. This function is equivalent to:\n"
  215. "@lisp\n"
  216. "(display obj [port])\n"
  217. "(newline [port])\n"
  218. "@end lisp")
  219. #define FUNC_NAME s_scm_write_line
  220. {
  221. scm_display (obj, port);
  222. return scm_newline (port);
  223. }
  224. #undef FUNC_NAME
  225. SCM
  226. scm_init_rdelim_builtins (void)
  227. {
  228. #include "libguile/rdelim.x"
  229. return SCM_UNSPECIFIED;
  230. }
  231. void
  232. scm_init_rdelim (void)
  233. {
  234. scm_c_define_gsubr ("%init-rdelim-builtins", 0, 0, 0,
  235. scm_init_rdelim_builtins);
  236. }
  237. /*
  238. Local Variables:
  239. c-file-style: "gnu"
  240. End:
  241. */