+/*
+ All client code should use only the two macros
+
+ TO_EXTERNAL_FORMAT (source_type, source, sink_type, sink, coding_system)
+ TO_INTERNAL_FORMAT (source_type, source, sink_type, sink, coding_system)
+
+ Typical use is
+
+ TO_EXTERNAL_FORMAT (DATA, (ptr, len),
+ LISP_BUFFER, buffer,
+ Qfile_name);
+
+ The source or sink can be specified in one of these ways:
+
+ DATA, (ptr, len), // input data is a fixed buffer of size len
+ ALLOCA, (ptr, len), // output data is in a alloca()ed buffer of size len
+ MALLOC, (ptr, len), // output data is in a malloc()ed buffer of size len
+ C_STRING_ALLOCA, ptr, // equivalent to ALLOCA (ptr, len_ignored) on output.
+ C_STRING_MALLOC, ptr, // equivalent to MALLOC (ptr, len_ignored) on output.
+ C_STRING, ptr, // equivalent to DATA, (ptr, strlen (ptr) + 1) on input
+ LISP_STRING, string, // input or output is a Lisp_Object of type string
+ LISP_BUFFER, buffer, // output is written to (point) in lisp buffer
+ LISP_LSTREAM, lstream, // input or output is a Lisp_Object of type lstream
+ LISP_OPAQUE, object, // input or output is a Lisp_Object of type opaque
+
+ When specifying the sink, use lvalues, since the macro will assign to them,
+ except when the sink is an lstream or a lisp buffer.
+
+ The macros accept the kinds of sources and sinks appropriate for
+ internal and external data representation. See the type_checking_assert
+ macros below for the actual allowed types.
+
+ Since some sources and sinks use one argument (a Lisp_Object) to
+ specify them, while others take a (pointer, length) pair, we use
+ some C preprocessor trickery to allow pair arguments to be specified
+ by parenthesizing them, as in the examples above.
+
+ Anything prefixed by dfc_ (`data format conversion') is private.
+ They are only used to implement these macros.
+
+ Using C_STRING* is appropriate for using with external APIs that take
+ null-terminated strings. For internal data, we should try to be
+ '\0'-clean - i.e. allow arbitrary data to contain embedded '\0'.
+
+ Sometime in the future we might allow output to C_STRING_ALLOCA or
+ C_STRING_MALLOC _only_ with TO_EXTERNAL_FORMAT(), not
+ TO_INTERNAL_FORMAT(). */
+
+#define TO_EXTERNAL_FORMAT(source_type, source, sink_type, sink, coding_system) \
+do { \
+ dfc_conversion_type dfc_simplified_source_type; \
+ dfc_conversion_type dfc_simplified_sink_type; \
+ dfc_conversion_data dfc_source; \
+ dfc_conversion_data dfc_sink; \
+ \
+ type_checking_assert \
+ ((DFC_TYPE_##source_type == DFC_TYPE_DATA || \
+ DFC_TYPE_##source_type == DFC_TYPE_C_STRING || \
+ DFC_TYPE_##source_type == DFC_TYPE_LISP_STRING || \
+ DFC_TYPE_##source_type == DFC_TYPE_LISP_OPAQUE || \
+ DFC_TYPE_##source_type == DFC_TYPE_LISP_LSTREAM) \
+ && \
+ (DFC_TYPE_##sink_type == DFC_TYPE_ALLOCA || \
+ DFC_TYPE_##sink_type == DFC_TYPE_MALLOC || \
+ DFC_TYPE_##sink_type == DFC_TYPE_C_STRING_ALLOCA || \
+ DFC_TYPE_##sink_type == DFC_TYPE_C_STRING_MALLOC || \
+ DFC_TYPE_##sink_type == DFC_TYPE_LISP_LSTREAM || \
+ DFC_TYPE_##sink_type == DFC_TYPE_LISP_OPAQUE)); \
+ \
+ DFC_SOURCE_##source_type##_TO_ARGS (source); \
+ DFC_SINK_##sink_type##_TO_ARGS (sink); \
+ \
+ DFC_CONVERT_TO_EXTERNAL_FORMAT (dfc_simplified_source_type, &dfc_source, \
+ coding_system, \
+ dfc_simplified_sink_type, &dfc_sink); \
+ \
+ DFC_##sink_type##_USE_CONVERTED_DATA (sink); \
+} while (0)