mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-04-30 03:40:34 +02:00
commit
6dd9810902
10 changed files with 97 additions and 138 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -150,10 +150,14 @@ INSTALL
|
||||||
/lib/dirent.h
|
/lib/dirent.h
|
||||||
/lib/langinfo.h
|
/lib/langinfo.h
|
||||||
/lib/wctype.h
|
/lib/wctype.h
|
||||||
|
/lib/poll.h
|
||||||
|
/lib/sys/select.h
|
||||||
|
/lib/sys/times.h
|
||||||
/build-aux/ar-lib
|
/build-aux/ar-lib
|
||||||
/build-aux/test-driver
|
/build-aux/test-driver
|
||||||
*.trs
|
*.trs
|
||||||
/test-suite/standalone/test-smob-mark
|
/test-suite/standalone/test-smob-mark
|
||||||
/test-suite/standalone/test-scm-values
|
/test-suite/standalone/test-scm-values
|
||||||
/test-suite/standalone/test-scm-to-latin1-string
|
/test-suite/standalone/test-scm-to-latin1-string
|
||||||
|
/test-suite/standalone/test-scm-c-bind-keyword-arguments
|
||||||
/libguile/vm-operations.h
|
/libguile/vm-operations.h
|
||||||
|
|
|
@ -689,22 +689,18 @@ Vectors can literally be entered in source code, just like strings,
|
||||||
characters or some of the other data types. The read syntax for vectors
|
characters or some of the other data types. The read syntax for vectors
|
||||||
is as follows: A sharp sign (@code{#}), followed by an opening
|
is as follows: A sharp sign (@code{#}), followed by an opening
|
||||||
parentheses, all elements of the vector in their respective read syntax,
|
parentheses, all elements of the vector in their respective read syntax,
|
||||||
and finally a closing parentheses. The following are examples of the
|
and finally a closing parentheses. Like strings, vectors do not have to
|
||||||
read syntax for vectors; where the first vector only contains numbers
|
be quoted.
|
||||||
and the second three different object types: a string, a symbol and a
|
|
||||||
number in hexadecimal notation.
|
The following are examples of the read syntax for vectors; where the
|
||||||
|
first vector only contains numbers and the second three different object
|
||||||
|
types: a string, a symbol and a number in hexadecimal notation.
|
||||||
|
|
||||||
@lisp
|
@lisp
|
||||||
#(1 2 3)
|
#(1 2 3)
|
||||||
#("Hello" foo #xdeadbeef)
|
#("Hello" foo #xdeadbeef)
|
||||||
@end lisp
|
@end lisp
|
||||||
|
|
||||||
Like lists, vectors have to be quoted:
|
|
||||||
|
|
||||||
@lisp
|
|
||||||
'#(a b c) @result{} #(a b c)
|
|
||||||
@end lisp
|
|
||||||
|
|
||||||
@node Vector Creation
|
@node Vector Creation
|
||||||
@subsubsection Dynamic Vector Creation and Validation
|
@subsubsection Dynamic Vector Creation and Validation
|
||||||
|
|
||||||
|
@ -735,7 +731,7 @@ The inverse operation is @code{vector->list}:
|
||||||
Return a newly allocated list composed of the elements of @var{v}.
|
Return a newly allocated list composed of the elements of @var{v}.
|
||||||
|
|
||||||
@lisp
|
@lisp
|
||||||
(vector->list '#(dah dah didah)) @result{} (dah dah didah)
|
(vector->list #(dah dah didah)) @result{} (dah dah didah)
|
||||||
(list->vector '(dididit dah)) @result{} #(dididit dah)
|
(list->vector '(dididit dah)) @result{} #(dididit dah)
|
||||||
@end lisp
|
@end lisp
|
||||||
@end deffn
|
@end deffn
|
||||||
|
@ -796,8 +792,8 @@ Return the number of elements in @var{vec} as a @code{size_t}.
|
||||||
Return the contents of position @var{k} of @var{vec}.
|
Return the contents of position @var{k} of @var{vec}.
|
||||||
@var{k} must be a valid index of @var{vec}.
|
@var{k} must be a valid index of @var{vec}.
|
||||||
@lisp
|
@lisp
|
||||||
(vector-ref '#(1 1 2 3 5 8 13 21) 5) @result{} 8
|
(vector-ref #(1 1 2 3 5 8 13 21) 5) @result{} 8
|
||||||
(vector-ref '#(1 1 2 3 5 8 13 21)
|
(vector-ref #(1 1 2 3 5 8 13 21)
|
||||||
(let ((i (round (* 2 (acos -1)))))
|
(let ((i (round (* 2 (acos -1)))))
|
||||||
(if (inexact? i)
|
(if (inexact? i)
|
||||||
(inexact->exact i)
|
(inexact->exact i)
|
||||||
|
|
|
@ -31,7 +31,6 @@ datatypes described here.)
|
||||||
* Creating Smob Instances::
|
* Creating Smob Instances::
|
||||||
* Type checking::
|
* Type checking::
|
||||||
* Garbage Collecting Smobs::
|
* Garbage Collecting Smobs::
|
||||||
* Garbage Collecting Simple Smobs::
|
|
||||||
* Remembering During Operations::
|
* Remembering During Operations::
|
||||||
* Double Smobs::
|
* Double Smobs::
|
||||||
* The Complete Example::
|
* The Complete Example::
|
||||||
|
@ -40,31 +39,10 @@ datatypes described here.)
|
||||||
@node Describing a New Type
|
@node Describing a New Type
|
||||||
@subsection Describing a New Type
|
@subsection Describing a New Type
|
||||||
|
|
||||||
To define a new type, the programmer must write four functions to
|
To define a new type, the programmer must write two functions to
|
||||||
manage instances of the type:
|
manage instances of the type:
|
||||||
|
|
||||||
@table @code
|
@table @code
|
||||||
@item mark
|
|
||||||
Guile will apply this function to each instance of the new type it
|
|
||||||
encounters during garbage collection. This function is responsible for
|
|
||||||
telling the collector about any other @code{SCM} values that the object
|
|
||||||
has stored. The default smob mark function does nothing.
|
|
||||||
@xref{Garbage Collecting Smobs}, for more details.
|
|
||||||
|
|
||||||
@item free
|
|
||||||
Guile will apply this function to each instance of the new type that is
|
|
||||||
to be deallocated. The function should release all resources held by
|
|
||||||
the object. This is analogous to the Java finalization method-- it is
|
|
||||||
invoked at an unspecified time (when garbage collection occurs) after
|
|
||||||
the object is dead. The default free function frees the smob data (if
|
|
||||||
the size of the struct passed to @code{scm_make_smob_type} is non-zero)
|
|
||||||
using @code{scm_gc_free}. @xref{Garbage Collecting Smobs}, for more
|
|
||||||
details.
|
|
||||||
|
|
||||||
This function operates while the heap is in an inconsistent state and
|
|
||||||
must therefore be careful. @xref{Smobs}, for details about what this
|
|
||||||
function is allowed to do.
|
|
||||||
|
|
||||||
@item print
|
@item print
|
||||||
Guile will apply this function to each instance of the new type to print
|
Guile will apply this function to each instance of the new type to print
|
||||||
the value, as for @code{display} or @code{write}. The default print
|
the value, as for @code{display} or @code{write}. The default print
|
||||||
|
@ -81,6 +59,32 @@ never @code{equal?} unless they are @code{eq?}.
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
|
When the only resource associated with a smob is memory managed by the
|
||||||
|
garbage collector---i.e., memory allocated with the @code{scm_gc_malloc}
|
||||||
|
functions---this is sufficient. However, when a smob is associated with
|
||||||
|
other kinds of resources, it may be necessary to define one of the
|
||||||
|
following functions, or both:
|
||||||
|
|
||||||
|
@table @code
|
||||||
|
@item mark
|
||||||
|
Guile will apply this function to each instance of the new type it
|
||||||
|
encounters during garbage collection. This function is responsible for
|
||||||
|
telling the collector about any other @code{SCM} values that the object
|
||||||
|
has stored, and that are in memory regions not already scanned by the
|
||||||
|
garbage collector. @xref{Garbage Collecting Smobs}, for more details.
|
||||||
|
|
||||||
|
@item free
|
||||||
|
Guile will apply this function to each instance of the new type that is
|
||||||
|
to be deallocated. The function should release all resources held by
|
||||||
|
the object. This is analogous to the Java finalization method---it is
|
||||||
|
invoked at an unspecified time (when garbage collection occurs) after
|
||||||
|
the object is dead. @xref{Garbage Collecting Smobs}, for more details.
|
||||||
|
|
||||||
|
This function operates while the heap is in an inconsistent state and
|
||||||
|
must therefore be careful. @xref{Smobs}, for details about what this
|
||||||
|
function is allowed to do.
|
||||||
|
@end table
|
||||||
|
|
||||||
To actually register the new smob type, call @code{scm_make_smob_type}.
|
To actually register the new smob type, call @code{scm_make_smob_type}.
|
||||||
It returns a value of type @code{scm_t_bits} which identifies the new
|
It returns a value of type @code{scm_t_bits} which identifies the new
|
||||||
smob type.
|
smob type.
|
||||||
|
@ -164,35 +168,11 @@ word of a smob, you should use the macros @code{SCM_SMOB_OBJECT} and
|
||||||
@code{SCM_SET_SMOB_OBJECT} to access it.
|
@code{SCM_SET_SMOB_OBJECT} to access it.
|
||||||
|
|
||||||
Creating a smob instance can be tricky when it consists of multiple
|
Creating a smob instance can be tricky when it consists of multiple
|
||||||
steps that allocate resources and might fail. It is recommended that
|
steps that allocate resources. Most of the time, this is mainly about
|
||||||
you go about creating a smob in the following way:
|
allocating memory to hold associated data structures. Using memory
|
||||||
|
managed by the garbage collector simplifies things: the garbage
|
||||||
@itemize
|
collector will automatically scan those data structures for pointers,
|
||||||
@item
|
and reclaim them when they are no longer referenced.
|
||||||
Allocate the memory block for holding the data with
|
|
||||||
@code{scm_gc_malloc}.
|
|
||||||
@item
|
|
||||||
Initialize it to a valid state without calling any functions that might
|
|
||||||
cause a non-local exits. For example, initialize pointers to NULL.
|
|
||||||
Also, do not store @code{SCM} values in it that must be protected.
|
|
||||||
Initialize these fields with @code{SCM_BOOL_F}.
|
|
||||||
|
|
||||||
A valid state is one that can be safely acted upon by the @emph{mark}
|
|
||||||
and @emph{free} functions of your smob type.
|
|
||||||
@item
|
|
||||||
Create the smob using @code{scm_new_smob}, passing it the initialized
|
|
||||||
memory block. (This step will always succeed.)
|
|
||||||
@item
|
|
||||||
Complete the initialization of the memory block by, for example,
|
|
||||||
allocating additional resources and making it point to them.
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
This procedure ensures that the smob is in a valid state as soon as it
|
|
||||||
exists, that all resources that are allocated for the smob are
|
|
||||||
properly associated with it so that they can be properly freed, and
|
|
||||||
that no @code{SCM} values that need to be protected are stored in it
|
|
||||||
while the smob does not yet completely exist and thus can not protect
|
|
||||||
them.
|
|
||||||
|
|
||||||
Continuing the example from above, if the global variable
|
Continuing the example from above, if the global variable
|
||||||
@code{image_tag} contains a tag returned by @code{scm_make_smob_type},
|
@code{image_tag} contains a tag returned by @code{scm_make_smob_type},
|
||||||
|
@ -229,44 +209,19 @@ make_image (SCM name, SCM s_width, SCM s_height)
|
||||||
*/
|
*/
|
||||||
image->name = name;
|
image->name = name;
|
||||||
image->pixels =
|
image->pixels =
|
||||||
scm_gc_malloc (width * height, "image pixels");
|
scm_gc_malloc_pointerless (width * height, "image pixels");
|
||||||
|
|
||||||
return smob;
|
return smob;
|
||||||
@}
|
@}
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
Let us look at what might happen when @code{make_image} is called.
|
We use @code{scm_gc_malloc_pointerless} for the pixel buffer to tell the
|
||||||
|
garbage collector not to scan it for pointers. Calls to
|
||||||
|
@code{scm_gc_malloc}, @code{scm_new_smob}, and
|
||||||
|
@code{scm_gc_malloc_pointerless} raise an exception in out-of-memory
|
||||||
|
conditions; the garbage collector is able to reclaim previously
|
||||||
|
allocated memory if that happens.
|
||||||
|
|
||||||
The conversions of @var{s_width} and @var{s_height} to @code{int}s might
|
|
||||||
fail and signal an error, thus causing a non-local exit. This is not a
|
|
||||||
problem since no resources have been allocated yet that would have to be
|
|
||||||
freed.
|
|
||||||
|
|
||||||
The allocation of @var{image} in step 1 might fail, but this is likewise
|
|
||||||
no problem.
|
|
||||||
|
|
||||||
Step 2 can not exit non-locally. At the end of it, the @var{image}
|
|
||||||
struct is in a valid state for the @code{mark_image} and
|
|
||||||
@code{free_image} functions (see below).
|
|
||||||
|
|
||||||
Step 3 can not exit non-locally either. This is guaranteed by Guile.
|
|
||||||
After it, @var{smob} contains a valid smob that is properly initialized
|
|
||||||
and protected, and in turn can properly protect the Scheme values in its
|
|
||||||
@var{image} struct.
|
|
||||||
|
|
||||||
But before the smob is completely created, @code{scm_new_smob} might
|
|
||||||
cause the garbage collector to run. During this garbage collection, the
|
|
||||||
@code{SCM} values in the @var{image} struct would be invisible to Guile.
|
|
||||||
It only gets to know about them via the @code{mark_image} function, but
|
|
||||||
that function can not yet do its job since the smob has not been created
|
|
||||||
yet. Thus, it is important to not store @code{SCM} values in the
|
|
||||||
@var{image} struct until after the smob has been created.
|
|
||||||
|
|
||||||
Step 4, finally, might fail and cause a non-local exit. In that case,
|
|
||||||
the complete creation of the smob has not been successful, but it does
|
|
||||||
nevertheless exist in a valid state. It will eventually be freed by
|
|
||||||
the garbage collector, and all the resources that have been allocated
|
|
||||||
for it will be correctly freed by @code{free_image}.
|
|
||||||
|
|
||||||
@node Type checking
|
@node Type checking
|
||||||
@subsection Type checking
|
@subsection Type checking
|
||||||
|
@ -310,8 +265,17 @@ to @code{scm_remember_upto_here_1}.
|
||||||
@subsection Garbage Collecting Smobs
|
@subsection Garbage Collecting Smobs
|
||||||
|
|
||||||
Once a smob has been released to the tender mercies of the Scheme
|
Once a smob has been released to the tender mercies of the Scheme
|
||||||
system, it must be prepared to survive garbage collection. Guile calls
|
system, it must be prepared to survive garbage collection. In the
|
||||||
the @emph{mark} and @emph{free} functions of the smob to manage this.
|
example above, all the memory associated with the smob is managed by the
|
||||||
|
garbage collector because we used the @code{scm_gc_} allocation
|
||||||
|
functions. Thus, no special care must be taken: the garbage collector
|
||||||
|
automatically scans them and reclaims any unused memory.
|
||||||
|
|
||||||
|
However, when data associated with a smob is managed in some other
|
||||||
|
way---e.g., @code{malloc}'d memory or file descriptors---it is possible
|
||||||
|
to specify a @emph{free} function to release those resources when the
|
||||||
|
smob is reclaimed, and a @emph{mark} function to mark Scheme objects
|
||||||
|
otherwise invisible to the garbage collector.
|
||||||
|
|
||||||
As described in more detail elsewhere (@pxref{Conservative GC}), every
|
As described in more detail elsewhere (@pxref{Conservative GC}), every
|
||||||
object in the Scheme system has a @dfn{mark bit}, which the garbage
|
object in the Scheme system has a @dfn{mark bit}, which the garbage
|
||||||
|
@ -343,7 +307,9 @@ values will have become dangling references.
|
||||||
To mark an arbitrary Scheme object, the @emph{mark} function calls
|
To mark an arbitrary Scheme object, the @emph{mark} function calls
|
||||||
@code{scm_gc_mark}.
|
@code{scm_gc_mark}.
|
||||||
|
|
||||||
Thus, here is how we might write @code{mark_image}:
|
Thus, here is how we might write @code{mark_image}---again this is not
|
||||||
|
needed in our example since we used the @code{scm_gc_} allocation
|
||||||
|
routines, so this is just for the sake of illustration:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
@group
|
@group
|
||||||
|
@ -398,7 +364,8 @@ type of the @emph{free} function should be @code{size_t}, an unsigned
|
||||||
integral type; the @emph{free} function should always return zero.
|
integral type; the @emph{free} function should always return zero.
|
||||||
|
|
||||||
Here is how we might write the @code{free_image} function for the image
|
Here is how we might write the @code{free_image} function for the image
|
||||||
smob type:
|
smob type---again for the sake of illustration, since our example does
|
||||||
|
not need it thanks to the use of the @code{scm_gc_} allocation routines:
|
||||||
@example
|
@example
|
||||||
size_t
|
size_t
|
||||||
free_image (SCM image_smob)
|
free_image (SCM image_smob)
|
||||||
|
@ -426,37 +393,12 @@ during garbage collection; keep the @emph{mark} and @emph{free}
|
||||||
functions very simple. Since collections occur at unpredictable times,
|
functions very simple. Since collections occur at unpredictable times,
|
||||||
it is easy for any unusual activity to interfere with normal code.
|
it is easy for any unusual activity to interfere with normal code.
|
||||||
|
|
||||||
|
|
||||||
@node Garbage Collecting Simple Smobs
|
|
||||||
@subsection Garbage Collecting Simple Smobs
|
|
||||||
|
|
||||||
It is often useful to define very simple smob types --- smobs which have
|
|
||||||
no data to mark, other than the cell itself, or smobs whose immediate
|
|
||||||
data word is simply an ordinary Scheme object, to be marked recursively.
|
|
||||||
Guile provides some functions to handle these common cases; you can use
|
|
||||||
this function as your smob type's @emph{mark} function, if your smob's
|
|
||||||
structure is simple enough.
|
|
||||||
|
|
||||||
If the smob refers to no other Scheme objects, then no action is
|
|
||||||
necessary; the garbage collector has already marked the smob cell
|
|
||||||
itself. In that case, you can use zero as your mark function.
|
|
||||||
|
|
||||||
If the smob refers to exactly one other Scheme object via its first
|
|
||||||
immediate word, you can use @code{scm_markcdr} as its mark function.
|
|
||||||
Its definition is simply:
|
|
||||||
|
|
||||||
@smallexample
|
|
||||||
SCM
|
|
||||||
scm_markcdr (SCM obj)
|
|
||||||
@{
|
|
||||||
return SCM_SMOB_OBJECT (obj);
|
|
||||||
@}
|
|
||||||
@end smallexample
|
|
||||||
|
|
||||||
@node Remembering During Operations
|
@node Remembering During Operations
|
||||||
@subsection Remembering During Operations
|
@subsection Remembering During Operations
|
||||||
@cindex remembering
|
@cindex remembering
|
||||||
|
|
||||||
|
@c FIXME: Remove this section?
|
||||||
|
|
||||||
It's important that a smob is visible to the garbage collector
|
It's important that a smob is visible to the garbage collector
|
||||||
whenever its contents are being accessed. Otherwise it could be freed
|
whenever its contents are being accessed. Otherwise it could be freed
|
||||||
while code is still using it.
|
while code is still using it.
|
||||||
|
@ -516,6 +458,8 @@ while the collector runs.)
|
||||||
@node Double Smobs
|
@node Double Smobs
|
||||||
@subsection Double Smobs
|
@subsection Double Smobs
|
||||||
|
|
||||||
|
@c FIXME: Remove this section?
|
||||||
|
|
||||||
Smobs are called smob because they are small: they normally have only
|
Smobs are called smob because they are small: they normally have only
|
||||||
room for one @code{void*} or @code{SCM} value plus 16 bits. The
|
room for one @code{void*} or @code{SCM} value plus 16 bits. The
|
||||||
reason for this is that smobs are directly implemented by using the
|
reason for this is that smobs are directly implemented by using the
|
||||||
|
|
|
@ -677,8 +677,8 @@ Maps each seed value to next seed value.
|
||||||
@item seed
|
@item seed
|
||||||
The state value for the unfold.
|
The state value for the unfold.
|
||||||
|
|
||||||
@item tail-gen
|
@item tail
|
||||||
Creates the tail of the list; defaults to @code{(lambda (x) '())}.
|
The tail of the list; defaults to @code{'()}.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
|
@ -77,7 +77,7 @@
|
||||||
* 1) int foo (char arg) SCM_NORETURN;
|
* 1) int foo (char arg) SCM_NORETURN;
|
||||||
*/
|
*/
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#define SCM_NORETURN __attribute__ ((noreturn))
|
#define SCM_NORETURN __attribute__ ((__noreturn__))
|
||||||
#else
|
#else
|
||||||
#define SCM_NORETURN
|
#define SCM_NORETURN
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1535,7 +1535,9 @@ SCM_DEFINE (scm_nl_langinfo, "nl-langinfo", 1, 1, 0,
|
||||||
codeset = nl_langinfo (CODESET);
|
codeset = nl_langinfo (CODESET);
|
||||||
}
|
}
|
||||||
|
|
||||||
c_result = strdup (c_result);
|
if (c_result != NULL)
|
||||||
|
c_result = strdup (c_result);
|
||||||
|
|
||||||
unlock_locale_mutex ();
|
unlock_locale_mutex ();
|
||||||
|
|
||||||
if (c_result == NULL)
|
if (c_result == NULL)
|
||||||
|
|
|
@ -442,7 +442,7 @@ scm_handle_by_throw (void *handler_data SCM_UNUSED, SCM tag, SCM args)
|
||||||
}
|
}
|
||||||
|
|
||||||
SCM
|
SCM
|
||||||
scm_ithrow (SCM key, SCM args, int noreturn SCM_UNUSED)
|
scm_ithrow (SCM key, SCM args, int no_return SCM_UNUSED)
|
||||||
{
|
{
|
||||||
return scm_throw (key, args);
|
return scm_throw (key, args);
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,7 +79,7 @@ SCM_API int scm_exit_status (SCM args);
|
||||||
SCM_API SCM scm_catch_with_pre_unwind_handler (SCM tag, SCM thunk, SCM handler, SCM lazy_handler);
|
SCM_API SCM scm_catch_with_pre_unwind_handler (SCM tag, SCM thunk, SCM handler, SCM lazy_handler);
|
||||||
SCM_API SCM scm_catch (SCM tag, SCM thunk, SCM handler);
|
SCM_API SCM scm_catch (SCM tag, SCM thunk, SCM handler);
|
||||||
SCM_API SCM scm_with_throw_handler (SCM tag, SCM thunk, SCM handler);
|
SCM_API SCM scm_with_throw_handler (SCM tag, SCM thunk, SCM handler);
|
||||||
SCM_API SCM scm_ithrow (SCM key, SCM args, int noreturn);
|
SCM_API SCM scm_ithrow (SCM key, SCM args, int no_return);
|
||||||
|
|
||||||
SCM_API SCM scm_throw (SCM key, SCM args);
|
SCM_API SCM scm_throw (SCM key, SCM args);
|
||||||
SCM_INTERNAL void scm_init_throw (void);
|
SCM_INTERNAL void scm_init_throw (void);
|
||||||
|
|
|
@ -3053,7 +3053,14 @@
|
||||||
((read-file
|
((read-file
|
||||||
(lambda (fn dir k)
|
(lambda (fn dir k)
|
||||||
(let ((p (open-input-file
|
(let ((p (open-input-file
|
||||||
(if (absolute-file-name? fn) fn (in-vicinity dir fn)))))
|
(if (absolute-file-name? fn)
|
||||||
|
fn
|
||||||
|
(if dir
|
||||||
|
(in-vicinity dir fn)
|
||||||
|
(syntax-violation
|
||||||
|
'include
|
||||||
|
"relative file name only allowed when the include form is in a file"
|
||||||
|
x))))))
|
||||||
(let ((enc (file-encoding p)))
|
(let ((enc (file-encoding p)))
|
||||||
(set-port-encoding! p (let ((t enc)) (if t t "UTF-8")))
|
(set-port-encoding! p (let ((t enc)) (if t t "UTF-8")))
|
||||||
(let f ((x (read p)) (result '()))
|
(let f ((x (read p)) (result '()))
|
||||||
|
|
|
@ -3056,9 +3056,15 @@
|
||||||
(define read-file
|
(define read-file
|
||||||
(lambda (fn dir k)
|
(lambda (fn dir k)
|
||||||
(let* ((p (open-input-file
|
(let* ((p (open-input-file
|
||||||
(if (absolute-file-name? fn)
|
(cond ((absolute-file-name? fn)
|
||||||
fn
|
fn)
|
||||||
(in-vicinity dir fn))))
|
(dir
|
||||||
|
(in-vicinity dir fn))
|
||||||
|
(else
|
||||||
|
(syntax-violation
|
||||||
|
'include
|
||||||
|
"relative file name only allowed when the include form is in a file"
|
||||||
|
x)))))
|
||||||
(enc (file-encoding p)))
|
(enc (file-encoding p)))
|
||||||
|
|
||||||
;; Choose the input encoding deterministically.
|
;; Choose the input encoding deterministically.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue