emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] Add a mechanism for passing unibyte strings from lisp to modules


From: Brennan Vincent
Subject: [PATCH] Add a mechanism for passing unibyte strings from lisp to modules.
Date: Fri, 21 Jun 2024 14:13:15 -0400

From: Brennan Vincent <brennan@umanwizard.com>

* src/data.c
(unibyte-string-p): New function.

* src/emacs-module.c
(module_copy_unibyte_string_contents): New function.

* src/module-env-30.h: Expose the above to modules.

* doc/lispref/internals.texi: Document the above.
---
 doc/lispref/internals.texi | 28 ++++++++++++++++++++++++++++
 src/data.c                 | 13 +++++++++++++
 src/emacs-module.c         | 37 +++++++++++++++++++++++++++++++++++++
 src/module-env-30.h        | 18 ++++++++++++++++++
 4 files changed, 96 insertions(+)

diff --git a/doc/lispref/internals.texi b/doc/lispref/internals.texi
index a5480a9bf8a..282ee5e1746 100644
--- a/doc/lispref/internals.texi
+++ b/doc/lispref/internals.texi
@@ -1725,6 +1725,34 @@ Module Values
 the text copying.
 @end deftypefn
 
+@deftypefn Function bool copy_unibyte_string_contents (emacs_env *@var{env}, 
emacs_value @var{arg}, char *@var{buf}, ptrdiff_t *@var{len})
+This function stores the raw bytes of a unibyte Lisp string specified
+by @var{arg} in the array of @code{char} pointed by @var{buf}, which
+should have enough space to hold at least @code{*@var{len}} bytes,
+including the terminating null byte.  The argument @var{len} must not
+be a @code{NULL} pointer, and, when the function is called, it should
+point to a value that specifies the size of @var{buf} in bytes.
+
+If the buffer size specified by @code{*@var{len}} is large enough to
+hold the string's bytes, the function stores in @code{*@var{len}} the
+actual number of bytes copied to @var{buf}, including the terminating
+null byte, and returns @code{true}.  If the buffer is too small, the
+function raises the @code{args-out-of-range} error condition, stores
+the required number of bytes in @code{*@var{len}}, and returns
+@code{false}.  @xref{Module Nonlocal}, for how to handle pending error
+conditions.
+
+The argument @var{buf} can be a @code{NULL} pointer, in which case the
+function stores in @code{*@var{len}} the number of bytes required for
+storing the contents of @var{arg}, and returns @code{true}.  This is
+how you can determine the size of @var{buf} needed to store a
+particular string: first call @code{copy_unibyte_string_contents} with
+@code{NULL} as @var{buf}, then allocate enough memory to hold the
+number of bytes stored by the function in @code{*@var{len}}, and call
+the function again with non-@code{NULL} @var{buf} to actually perform
+the text copying.
+@end deftypefn
+
 @deftypefn Function emacs_value vec_get (emacs_env *@var{env}, emacs_value 
@var{vector}, ptrdiff_t @var{index})
 This function returns the element of @var{vector} at @var{index}.  The
 @var{index} of the first vector element is zero.  The function raises
diff --git a/src/data.c b/src/data.c
index 3490d4985c9..7d8d5a46779 100644
--- a/src/data.c
+++ b/src/data.c
@@ -429,6 +429,17 @@ DEFUN ("multibyte-string-p", Fmultibyte_string_p, 
Smultibyte_string_p,
   return Qnil;
 }
 
+DEFUN("unibyte-string-p", Funibyte_string_p, Sunibyte_string_p,
+      1, 1, 0,
+      doc: /* Return t if OBJECT is a unibyte string.
+Return nil if OBJECT is either a multibyte string, or not a string.  */)
+  (Lisp_Object object)
+{
+  if (STRINGP (object) && !STRING_MULTIBYTE (object))
+    return Qt;
+  return Qnil;
+}
+
 DEFUN ("char-table-p", Fchar_table_p, Schar_table_p, 1, 1, 0,
        doc: /* Return t if OBJECT is a char-table.  */)
   (Lisp_Object object)
@@ -4023,6 +4034,7 @@ syms_of_data (void)
   DEFSYM (Qnatnump, "natnump");
   DEFSYM (Qwholenump, "wholenump");
   DEFSYM (Qstringp, "stringp");
+  DEFSYM (Qunibyte_string_p, "unibyte-string-p");
   DEFSYM (Qarrayp, "arrayp");
   DEFSYM (Qsequencep, "sequencep");
   DEFSYM (Qbufferp, "bufferp");
@@ -4219,6 +4231,7 @@ #define PUT_ERROR(sym, tail, msg)                 \
   defsubr (&Skeywordp);
   defsubr (&Sstringp);
   defsubr (&Smultibyte_string_p);
+  defsubr (&Sunibyte_string_p);
   defsubr (&Svectorp);
   defsubr (&Srecordp);
   defsubr (&Schar_table_p);
diff --git a/src/emacs-module.c b/src/emacs-module.c
index 08db39b0b0d..69192cd7fd2 100644
--- a/src/emacs-module.c
+++ b/src/emacs-module.c
@@ -769,6 +769,42 @@ module_make_float (emacs_env *env, double d)
   return value;
 }
 
+static bool
+module_copy_unibyte_string_contents (emacs_env *env, emacs_value value, char 
*buf,
+                                    ptrdiff_t *len)
+{
+  MODULE_FUNCTION_BEGIN (false);
+  Lisp_Object lisp_str = value_to_lisp (value);
+  CHECK_TYPE (STRINGP (lisp_str) && !STRING_MULTIBYTE (lisp_str),
+             Qunibyte_string_p, lisp_str);
+
+  ptrdiff_t raw_size = SBYTES (lisp_str);
+  ptrdiff_t required_buf_size = raw_size + 1;
+
+  if (buf == NULL)
+    {
+      *len = required_buf_size;
+      MODULE_INTERNAL_CLEANUP();
+      return true;
+    }
+
+  if (*len < required_buf_size)
+    {
+      ptrdiff_t actual = *len;
+      *len = required_buf_size;
+      args_out_of_range_3 (INT_TO_INTEGER (actual),
+                           INT_TO_INTEGER (required_buf_size),
+                           INT_TO_INTEGER (PTRDIFF_MAX));
+    }
+
+  *len = required_buf_size;
+  memcpy(buf, SDATA (lisp_str), required_buf_size);
+
+  MODULE_INTERNAL_CLEANUP();
+  return true;
+}
+
+
 static bool
 module_copy_string_contents (emacs_env *env, emacs_value value, char *buf,
                             ptrdiff_t *len)
@@ -1568,6 +1604,7 @@ initialize_environment (emacs_env *env, struct 
emacs_env_private *priv)
   env->extract_float = module_extract_float;
   env->make_float = module_make_float;
   env->copy_string_contents = module_copy_string_contents;
+  env->copy_unibyte_string_contents = module_copy_unibyte_string_contents;
   env->make_string = module_make_string;
   env->make_unibyte_string = module_make_unibyte_string;
   env->make_user_ptr = module_make_user_ptr;
diff --git a/src/module-env-30.h b/src/module-env-30.h
index e75210c7f8e..5837bfbf195 100644
--- a/src/module-env-30.h
+++ b/src/module-env-30.h
@@ -1,3 +1,21 @@
   /* Add module environment functions newly added in Emacs 30 here.
      Before Emacs 30 is released, remove this comment and start
      module-env-31.h on the master branch.  */
+
+  /* Copy the content of the Lisp string VALUE to BUFFER as an utf8
+     null-terminated string.
+
+     SIZE must point to the total size of the buffer.  If BUFFER is
+     NULL or if SIZE is not big enough, write the required buffer size
+     to SIZE and return true.
+
+     Note that SIZE must include the last null byte (e.g. "abc" needs
+     a buffer of size 4).
+
+     Return true if the string was successfully copied.  */
+
+  bool (*copy_unibyte_string_contents) (emacs_env *env,
+                                       emacs_value value,
+                                       char *buf,
+                                       ptrdiff_t *len)
+    EMACS_ATTRIBUTE_NONNULL(1, 4);
-- 
2.41.0





reply via email to

[Prev in Thread] Current Thread [Next in Thread]