diff options
| author | Michael Albinus | 2017-06-05 13:00:07 +0200 |
|---|---|---|
| committer | Michael Albinus | 2017-06-05 13:00:07 +0200 |
| commit | 9f496c591d457b511a42c0f63e0d2d923cda0247 (patch) | |
| tree | 86b550b9b3a8c1b5cb33bfdca82e470ab211bfac /src | |
| parent | 751d5920bed1a3af01fd5a31ce4eb7d8b6994151 (diff) | |
| parent | 13e9493ea36df04e2c6b69e9b316d40c072ee88b (diff) | |
| download | emacs-9f496c591d457b511a42c0f63e0d2d923cda0247.tar.gz emacs-9f496c591d457b511a42c0f63e0d2d923cda0247.zip | |
Merge branch 'master' of git.sv.gnu.org:/srv/git/emacs
Diffstat (limited to 'src')
| -rw-r--r-- | src/data.c | 10 | ||||
| -rw-r--r-- | src/dynlib.c | 34 | ||||
| -rw-r--r-- | src/dynlib.h | 16 | ||||
| -rw-r--r-- | src/editfns.c | 154 | ||||
| -rw-r--r-- | src/emacs-module.c | 162 | ||||
| -rw-r--r-- | src/emacs-module.h | 3 | ||||
| -rw-r--r-- | src/eval.c | 7 | ||||
| -rw-r--r-- | src/lisp.h | 16 | ||||
| -rw-r--r-- | src/print.c | 30 |
9 files changed, 226 insertions, 206 deletions
diff --git a/src/data.c b/src/data.c index 25859105ee0..e4e55290e62 100644 --- a/src/data.c +++ b/src/data.c | |||
| @@ -700,12 +700,10 @@ global value outside of any lexical scope. */) | |||
| 700 | return (EQ (valcontents, Qunbound) ? Qnil : Qt); | 700 | return (EQ (valcontents, Qunbound) ? Qnil : Qt); |
| 701 | } | 701 | } |
| 702 | 702 | ||
| 703 | /* FIXME: It has been previously suggested to make this function an | 703 | /* It has been previously suggested to make this function an alias for |
| 704 | alias for symbol-function, but upon discussion at Bug#23957, | 704 | symbol-function, but upon discussion at Bug#23957, there is a risk |
| 705 | there is a risk breaking backward compatibility, as some users of | 705 | breaking backward compatibility, as some users of fboundp may |
| 706 | fboundp may expect `t' in particular, rather than any true | 706 | expect `t' in particular, rather than any true value. */ |
| 707 | value. An alias is still welcome so long as the compatibility | ||
| 708 | issues are addressed. */ | ||
| 709 | DEFUN ("fboundp", Ffboundp, Sfboundp, 1, 1, 0, | 707 | DEFUN ("fboundp", Ffboundp, Sfboundp, 1, 1, 0, |
| 710 | doc: /* Return t if SYMBOL's function definition is not void. */) | 708 | doc: /* Return t if SYMBOL's function definition is not void. */) |
| 711 | (register Lisp_Object symbol) | 709 | (register Lisp_Object symbol) |
diff --git a/src/dynlib.c b/src/dynlib.c index 95619236d43..79e98b0f288 100644 --- a/src/dynlib.c +++ b/src/dynlib.c | |||
| @@ -28,6 +28,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 28 | 28 | ||
| 29 | #include "dynlib.h" | 29 | #include "dynlib.h" |
| 30 | 30 | ||
| 31 | #include <stddef.h> | ||
| 32 | |||
| 31 | #ifdef WINDOWSNT | 33 | #ifdef WINDOWSNT |
| 32 | 34 | ||
| 33 | /* MS-Windows systems. */ | 35 | /* MS-Windows systems. */ |
| @@ -120,7 +122,7 @@ dynlib_sym (dynlib_handle_ptr h, const char *sym) | |||
| 120 | return (void *)sym_addr; | 122 | return (void *)sym_addr; |
| 121 | } | 123 | } |
| 122 | 124 | ||
| 123 | bool | 125 | void |
| 124 | dynlib_addr (void *addr, const char **fname, const char **symname) | 126 | dynlib_addr (void *addr, const char **fname, const char **symname) |
| 125 | { | 127 | { |
| 126 | static char dll_filename[MAX_UTF8_PATH]; | 128 | static char dll_filename[MAX_UTF8_PATH]; |
| @@ -128,7 +130,6 @@ dynlib_addr (void *addr, const char **fname, const char **symname) | |||
| 128 | static GetModuleHandleExA_Proc s_pfn_Get_Module_HandleExA = NULL; | 130 | static GetModuleHandleExA_Proc s_pfn_Get_Module_HandleExA = NULL; |
| 129 | char *dll_fn = NULL; | 131 | char *dll_fn = NULL; |
| 130 | HMODULE hm_kernel32 = NULL; | 132 | HMODULE hm_kernel32 = NULL; |
| 131 | bool result = false; | ||
| 132 | HMODULE hm_dll = NULL; | 133 | HMODULE hm_dll = NULL; |
| 133 | wchar_t mfn_w[MAX_PATH]; | 134 | wchar_t mfn_w[MAX_PATH]; |
| 134 | char mfn_a[MAX_PATH]; | 135 | char mfn_a[MAX_PATH]; |
| @@ -206,23 +207,18 @@ dynlib_addr (void *addr, const char **fname, const char **symname) | |||
| 206 | dynlib_last_err = GetLastError (); | 207 | dynlib_last_err = GetLastError (); |
| 207 | } | 208 | } |
| 208 | if (dll_fn) | 209 | if (dll_fn) |
| 209 | { | 210 | dostounix_filename (dll_fn); |
| 210 | dostounix_filename (dll_fn); | ||
| 211 | /* We cannot easily produce the function name, since | ||
| 212 | typically all of the module functions will be unexported, | ||
| 213 | and probably even static, which means the symbols can be | ||
| 214 | obtained only if we link against libbfd (and the DLL can | ||
| 215 | be stripped anyway). So we just show the address and the | ||
| 216 | file name; they can use that with addr2line or GDB to | ||
| 217 | recover the symbolic name. */ | ||
| 218 | sprintf (addr_str, "at 0x%x", (DWORD_PTR)addr); | ||
| 219 | *symname = addr_str; | ||
| 220 | result = true; | ||
| 221 | } | ||
| 222 | } | 211 | } |
| 223 | 212 | ||
| 224 | *fname = dll_fn; | 213 | *fname = dll_fn; |
| 225 | return result; | 214 | |
| 215 | /* We cannot easily produce the function name, since typically all | ||
| 216 | of the module functions will be unexported, and probably even | ||
| 217 | static, which means the symbols can be obtained only if we link | ||
| 218 | against libbfd (and the DLL can be stripped anyway). So we just | ||
| 219 | show the address and the file name; they can use that with | ||
| 220 | addr2line or GDB to recover the symbolic name. */ | ||
| 221 | *symname = NULL; | ||
| 226 | } | 222 | } |
| 227 | 223 | ||
| 228 | const char * | 224 | const char * |
| @@ -283,19 +279,19 @@ dynlib_sym (dynlib_handle_ptr h, const char *sym) | |||
| 283 | return dlsym (h, sym); | 279 | return dlsym (h, sym); |
| 284 | } | 280 | } |
| 285 | 281 | ||
| 286 | bool | 282 | void |
| 287 | dynlib_addr (void *ptr, const char **path, const char **sym) | 283 | dynlib_addr (void *ptr, const char **path, const char **sym) |
| 288 | { | 284 | { |
| 285 | *path = NULL; | ||
| 286 | *sym = NULL; | ||
| 289 | #ifdef HAVE_DLADDR | 287 | #ifdef HAVE_DLADDR |
| 290 | Dl_info info; | 288 | Dl_info info; |
| 291 | if (dladdr (ptr, &info) && info.dli_fname && info.dli_sname) | 289 | if (dladdr (ptr, &info) && info.dli_fname && info.dli_sname) |
| 292 | { | 290 | { |
| 293 | *path = info.dli_fname; | 291 | *path = info.dli_fname; |
| 294 | *sym = info.dli_sname; | 292 | *sym = info.dli_sname; |
| 295 | return true; | ||
| 296 | } | 293 | } |
| 297 | #endif | 294 | #endif |
| 298 | return false; | ||
| 299 | } | 295 | } |
| 300 | 296 | ||
| 301 | const char * | 297 | const char * |
diff --git a/src/dynlib.h b/src/dynlib.h index 5ccec11bc79..1d53b8e5b2f 100644 --- a/src/dynlib.h +++ b/src/dynlib.h | |||
| @@ -24,11 +24,17 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 24 | 24 | ||
| 25 | typedef void *dynlib_handle_ptr; | 25 | typedef void *dynlib_handle_ptr; |
| 26 | dynlib_handle_ptr dynlib_open (const char *path); | 26 | dynlib_handle_ptr dynlib_open (const char *path); |
| 27 | void *dynlib_sym (dynlib_handle_ptr h, const char *sym); | ||
| 28 | typedef struct dynlib_function_ptr_nonce *(*dynlib_function_ptr) (void); | ||
| 29 | dynlib_function_ptr dynlib_func (dynlib_handle_ptr h, const char *sym); | ||
| 30 | bool dynlib_addr (void *ptr, const char **path, const char **sym); | ||
| 31 | const char *dynlib_error (void); | ||
| 32 | int dynlib_close (dynlib_handle_ptr h); | 27 | int dynlib_close (dynlib_handle_ptr h); |
| 28 | const char *dynlib_error (void); | ||
| 29 | |||
| 30 | ATTRIBUTE_MAY_ALIAS void *dynlib_sym (dynlib_handle_ptr h, const char *sym); | ||
| 31 | |||
| 32 | typedef struct dynlib_function_ptr_nonce *(ATTRIBUTE_MAY_ALIAS *dynlib_function_ptr) (void); | ||
| 33 | dynlib_function_ptr dynlib_func (dynlib_handle_ptr h, const char *sym); | ||
| 34 | |||
| 35 | /* Sets *FILE to the file name from which PTR was loaded, and *SYM to | ||
| 36 | its symbol name. If the file or symbol name could not be | ||
| 37 | determined, set the corresponding argument to NULL. */ | ||
| 38 | void dynlib_addr (void *ptr, const char **file, const char **sym); | ||
| 33 | 39 | ||
| 34 | #endif /* DYNLIB_H */ | 40 | #endif /* DYNLIB_H */ |
diff --git a/src/editfns.c b/src/editfns.c index 56aa8ce1a72..43b17f9f116 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -3891,8 +3891,8 @@ the next available argument, or the argument explicitly specified: | |||
| 3891 | The argument used for %d, %o, %x, %e, %f, %g or %c must be a number. | 3891 | The argument used for %d, %o, %x, %e, %f, %g or %c must be a number. |
| 3892 | Use %% to put a single % into the output. | 3892 | Use %% to put a single % into the output. |
| 3893 | 3893 | ||
| 3894 | A %-sequence may contain optional field number, flag, width, and | 3894 | A %-sequence other than %% may contain optional field number, flag, |
| 3895 | precision specifiers, as follows: | 3895 | width, and precision specifiers, as follows: |
| 3896 | 3896 | ||
| 3897 | %<field><flags><width><precision>character | 3897 | %<field><flags><width><precision>character |
| 3898 | 3898 | ||
| @@ -3901,10 +3901,9 @@ where field is [0-9]+ followed by a literal dollar "$", flags is | |||
| 3901 | followed by [0-9]+. | 3901 | followed by [0-9]+. |
| 3902 | 3902 | ||
| 3903 | If a %-sequence is numbered with a field with positive value N, the | 3903 | If a %-sequence is numbered with a field with positive value N, the |
| 3904 | Nth argument is substituted instead of the next one. A field number | 3904 | Nth argument is substituted instead of the next one. A format can |
| 3905 | should differ from the other field numbers in the same format. A | 3905 | contain either numbered or unnumbered %-sequences but not both, except |
| 3906 | format can contain either numbered or unnumbered %-sequences but not | 3906 | that %% can be mixed with numbered %-sequences. |
| 3907 | both, except that %% can be mixed with numbered %-sequences. | ||
| 3908 | 3907 | ||
| 3909 | The + flag character inserts a + before any positive number, while a | 3908 | The + flag character inserts a + before any positive number, while a |
| 3910 | space inserts a space before any positive number; these flags only | 3909 | space inserts a space before any positive number; these flags only |
| @@ -3980,49 +3979,40 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 3980 | bool arg_intervals = false; | 3979 | bool arg_intervals = false; |
| 3981 | USE_SAFE_ALLOCA; | 3980 | USE_SAFE_ALLOCA; |
| 3982 | 3981 | ||
| 3983 | /* Each element records, for one field, | 3982 | /* Information recorded for each format spec. */ |
| 3984 | the corresponding argument, | ||
| 3985 | the start and end bytepos in the output string, | ||
| 3986 | whether the argument has been converted to string (e.g., due to "%S"), | ||
| 3987 | and whether the argument is a string with intervals. */ | ||
| 3988 | struct info | 3983 | struct info |
| 3989 | { | 3984 | { |
| 3985 | /* The corresponding argument, converted to string if conversion | ||
| 3986 | was needed. */ | ||
| 3990 | Lisp_Object argument; | 3987 | Lisp_Object argument; |
| 3988 | |||
| 3989 | /* The start and end bytepos in the output string. */ | ||
| 3991 | ptrdiff_t start, end; | 3990 | ptrdiff_t start, end; |
| 3992 | bool_bf converted_to_string : 1; | 3991 | |
| 3992 | /* Whether the argument is a string with intervals. */ | ||
| 3993 | bool_bf intervals : 1; | 3993 | bool_bf intervals : 1; |
| 3994 | } *info; | 3994 | } *info; |
| 3995 | 3995 | ||
| 3996 | CHECK_STRING (args[0]); | 3996 | CHECK_STRING (args[0]); |
| 3997 | char *format_start = SSDATA (args[0]); | 3997 | char *format_start = SSDATA (args[0]); |
| 3998 | bool multibyte_format = STRING_MULTIBYTE (args[0]); | ||
| 3998 | ptrdiff_t formatlen = SBYTES (args[0]); | 3999 | ptrdiff_t formatlen = SBYTES (args[0]); |
| 3999 | 4000 | ||
| 4000 | /* The number of percent characters is a safe upper bound for the | 4001 | /* Upper bound on number of format specs. Each uses at least 2 chars. */ |
| 4001 | number of format fields. */ | 4002 | ptrdiff_t nspec_bound = SCHARS (args[0]) >> 1; |
| 4002 | ptrdiff_t num_percent = 0; | ||
| 4003 | for (ptrdiff_t i = 0; i < formatlen; ++i) | ||
| 4004 | if (format_start[i] == '%') | ||
| 4005 | ++num_percent; | ||
| 4006 | 4003 | ||
| 4007 | /* Allocate the info and discarded tables. */ | 4004 | /* Allocate the info and discarded tables. */ |
| 4008 | ptrdiff_t alloca_size; | 4005 | ptrdiff_t alloca_size; |
| 4009 | if (INT_MULTIPLY_WRAPV (num_percent, sizeof *info, &alloca_size) | 4006 | if (INT_MULTIPLY_WRAPV (nspec_bound, sizeof *info, &alloca_size) |
| 4010 | || INT_ADD_WRAPV (sizeof *info, alloca_size, &alloca_size) | ||
| 4011 | || INT_ADD_WRAPV (formatlen, alloca_size, &alloca_size) | 4007 | || INT_ADD_WRAPV (formatlen, alloca_size, &alloca_size) |
| 4012 | || SIZE_MAX < alloca_size) | 4008 | || SIZE_MAX < alloca_size) |
| 4013 | memory_full (SIZE_MAX); | 4009 | memory_full (SIZE_MAX); |
| 4014 | /* info[0] is unused. Unused elements have -1 for start. */ | ||
| 4015 | info = SAFE_ALLOCA (alloca_size); | 4010 | info = SAFE_ALLOCA (alloca_size); |
| 4016 | memset (info, 0, alloca_size); | ||
| 4017 | for (ptrdiff_t i = 0; i < num_percent + 1; i++) | ||
| 4018 | { | ||
| 4019 | info[i].argument = Qunbound; | ||
| 4020 | info[i].start = -1; | ||
| 4021 | } | ||
| 4022 | /* discarded[I] is 1 if byte I of the format | 4011 | /* discarded[I] is 1 if byte I of the format |
| 4023 | string was not copied into the output. | 4012 | string was not copied into the output. |
| 4024 | It is 2 if byte I was not the first byte of its character. */ | 4013 | It is 2 if byte I was not the first byte of its character. */ |
| 4025 | char *discarded = (char *) &info[num_percent + 1]; | 4014 | char *discarded = (char *) &info[nspec_bound]; |
| 4015 | memset (discarded, 0, formatlen); | ||
| 4026 | 4016 | ||
| 4027 | /* Try to determine whether the result should be multibyte. | 4017 | /* Try to determine whether the result should be multibyte. |
| 4028 | This is not always right; sometimes the result needs to be multibyte | 4018 | This is not always right; sometimes the result needs to be multibyte |
| @@ -4030,8 +4020,6 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4030 | or because a grave accent or apostrophe is requoted, | 4020 | or because a grave accent or apostrophe is requoted, |
| 4031 | and in that case, we won't know it here. */ | 4021 | and in that case, we won't know it here. */ |
| 4032 | 4022 | ||
| 4033 | /* True if the format is multibyte. */ | ||
| 4034 | bool multibyte_format = STRING_MULTIBYTE (args[0]); | ||
| 4035 | /* True if the output should be a multibyte string, | 4023 | /* True if the output should be a multibyte string, |
| 4036 | which is true if any of the inputs is one. */ | 4024 | which is true if any of the inputs is one. */ |
| 4037 | bool multibyte = multibyte_format; | 4025 | bool multibyte = multibyte_format; |
| @@ -4042,6 +4030,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4042 | int quoting_style = message ? text_quoting_style () : -1; | 4030 | int quoting_style = message ? text_quoting_style () : -1; |
| 4043 | 4031 | ||
| 4044 | ptrdiff_t ispec; | 4032 | ptrdiff_t ispec; |
| 4033 | ptrdiff_t nspec = 0; | ||
| 4045 | 4034 | ||
| 4046 | /* If we start out planning a unibyte result, | 4035 | /* If we start out planning a unibyte result, |
| 4047 | then discover it has to be multibyte, we jump back to retry. */ | 4036 | then discover it has to be multibyte, we jump back to retry. */ |
| @@ -4155,11 +4144,14 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4155 | if (! (n < nargs)) | 4144 | if (! (n < nargs)) |
| 4156 | error ("Not enough arguments for format string"); | 4145 | error ("Not enough arguments for format string"); |
| 4157 | 4146 | ||
| 4158 | eassert (ispec < num_percent); | 4147 | struct info *spec = &info[ispec++]; |
| 4159 | ++ispec; | 4148 | if (nspec < ispec) |
| 4160 | 4149 | { | |
| 4161 | if (EQ (info[ispec].argument, Qunbound)) | 4150 | spec->argument = args[n]; |
| 4162 | info[ispec].argument = args[n]; | 4151 | spec->intervals = false; |
| 4152 | nspec = ispec; | ||
| 4153 | } | ||
| 4154 | Lisp_Object arg = spec->argument; | ||
| 4163 | 4155 | ||
| 4164 | /* For 'S', prin1 the argument, and then treat like 's'. | 4156 | /* For 'S', prin1 the argument, and then treat like 's'. |
| 4165 | For 's', princ any argument that is not a string or | 4157 | For 's', princ any argument that is not a string or |
| @@ -4167,16 +4159,13 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4167 | happen after retrying. */ | 4159 | happen after retrying. */ |
| 4168 | if ((conversion == 'S' | 4160 | if ((conversion == 'S' |
| 4169 | || (conversion == 's' | 4161 | || (conversion == 's' |
| 4170 | && ! STRINGP (info[ispec].argument) | 4162 | && ! STRINGP (arg) && ! SYMBOLP (arg)))) |
| 4171 | && ! SYMBOLP (info[ispec].argument)))) | ||
| 4172 | { | 4163 | { |
| 4173 | if (! info[ispec].converted_to_string) | 4164 | if (EQ (arg, args[n])) |
| 4174 | { | 4165 | { |
| 4175 | Lisp_Object noescape = conversion == 'S' ? Qnil : Qt; | 4166 | Lisp_Object noescape = conversion == 'S' ? Qnil : Qt; |
| 4176 | info[ispec].argument = | 4167 | spec->argument = arg = Fprin1_to_string (arg, noescape); |
| 4177 | Fprin1_to_string (info[ispec].argument, noescape); | 4168 | if (STRING_MULTIBYTE (arg) && ! multibyte) |
| 4178 | info[ispec].converted_to_string = true; | ||
| 4179 | if (STRING_MULTIBYTE (info[ispec].argument) && ! multibyte) | ||
| 4180 | { | 4169 | { |
| 4181 | multibyte = true; | 4170 | multibyte = true; |
| 4182 | goto retry; | 4171 | goto retry; |
| @@ -4186,29 +4175,25 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4186 | } | 4175 | } |
| 4187 | else if (conversion == 'c') | 4176 | else if (conversion == 'c') |
| 4188 | { | 4177 | { |
| 4189 | if (INTEGERP (info[ispec].argument) | 4178 | if (INTEGERP (arg) && ! ASCII_CHAR_P (XINT (arg))) |
| 4190 | && ! ASCII_CHAR_P (XINT (info[ispec].argument))) | ||
| 4191 | { | 4179 | { |
| 4192 | if (!multibyte) | 4180 | if (!multibyte) |
| 4193 | { | 4181 | { |
| 4194 | multibyte = true; | 4182 | multibyte = true; |
| 4195 | goto retry; | 4183 | goto retry; |
| 4196 | } | 4184 | } |
| 4197 | info[ispec].argument = | 4185 | spec->argument = arg = Fchar_to_string (arg); |
| 4198 | Fchar_to_string (info[ispec].argument); | ||
| 4199 | info[ispec].converted_to_string = true; | ||
| 4200 | } | 4186 | } |
| 4201 | 4187 | ||
| 4202 | if (info[ispec].converted_to_string) | 4188 | if (!EQ (arg, args[n])) |
| 4203 | conversion = 's'; | 4189 | conversion = 's'; |
| 4204 | zero_flag = false; | 4190 | zero_flag = false; |
| 4205 | } | 4191 | } |
| 4206 | 4192 | ||
| 4207 | if (SYMBOLP (info[ispec].argument)) | 4193 | if (SYMBOLP (arg)) |
| 4208 | { | 4194 | { |
| 4209 | info[ispec].argument = | 4195 | spec->argument = arg = SYMBOL_NAME (arg); |
| 4210 | SYMBOL_NAME (info[ispec].argument); | 4196 | if (STRING_MULTIBYTE (arg) && ! multibyte) |
| 4211 | if (STRING_MULTIBYTE (info[ispec].argument) && ! multibyte) | ||
| 4212 | { | 4197 | { |
| 4213 | multibyte = true; | 4198 | multibyte = true; |
| 4214 | goto retry; | 4199 | goto retry; |
| @@ -4239,12 +4224,11 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4239 | else | 4224 | else |
| 4240 | { | 4225 | { |
| 4241 | ptrdiff_t nch, nby; | 4226 | ptrdiff_t nch, nby; |
| 4242 | width = lisp_string_width (info[ispec].argument, | 4227 | width = lisp_string_width (arg, prec, &nch, &nby); |
| 4243 | prec, &nch, &nby); | ||
| 4244 | if (prec < 0) | 4228 | if (prec < 0) |
| 4245 | { | 4229 | { |
| 4246 | nchars_string = SCHARS (info[ispec].argument); | 4230 | nchars_string = SCHARS (arg); |
| 4247 | nbytes = SBYTES (info[ispec].argument); | 4231 | nbytes = SBYTES (arg); |
| 4248 | } | 4232 | } |
| 4249 | else | 4233 | else |
| 4250 | { | 4234 | { |
| @@ -4254,11 +4238,8 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4254 | } | 4238 | } |
| 4255 | 4239 | ||
| 4256 | convbytes = nbytes; | 4240 | convbytes = nbytes; |
| 4257 | if (convbytes && multibyte && | 4241 | if (convbytes && multibyte && ! STRING_MULTIBYTE (arg)) |
| 4258 | ! STRING_MULTIBYTE (info[ispec].argument)) | 4242 | convbytes = count_size_as_multibyte (SDATA (arg), nbytes); |
| 4259 | convbytes = | ||
| 4260 | count_size_as_multibyte (SDATA (info[ispec].argument), | ||
| 4261 | nbytes); | ||
| 4262 | 4243 | ||
| 4263 | ptrdiff_t padding | 4244 | ptrdiff_t padding |
| 4264 | = width < field_width ? field_width - width : 0; | 4245 | = width < field_width ? field_width - width : 0; |
| @@ -4274,20 +4255,18 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4274 | p += padding; | 4255 | p += padding; |
| 4275 | nchars += padding; | 4256 | nchars += padding; |
| 4276 | } | 4257 | } |
| 4277 | info[ispec].start = nchars; | 4258 | spec->start = nchars; |
| 4278 | 4259 | ||
| 4279 | if (p > buf | 4260 | if (p > buf |
| 4280 | && multibyte | 4261 | && multibyte |
| 4281 | && !ASCII_CHAR_P (*((unsigned char *) p - 1)) | 4262 | && !ASCII_CHAR_P (*((unsigned char *) p - 1)) |
| 4282 | && STRING_MULTIBYTE (info[ispec].argument) | 4263 | && STRING_MULTIBYTE (arg) |
| 4283 | && !CHAR_HEAD_P (SREF (info[ispec].argument, 0))) | 4264 | && !CHAR_HEAD_P (SREF (arg, 0))) |
| 4284 | maybe_combine_byte = true; | 4265 | maybe_combine_byte = true; |
| 4285 | 4266 | ||
| 4286 | p += copy_text (SDATA (info[ispec].argument), | 4267 | p += copy_text (SDATA (arg), (unsigned char *) p, |
| 4287 | (unsigned char *) p, | ||
| 4288 | nbytes, | 4268 | nbytes, |
| 4289 | STRING_MULTIBYTE (info[ispec].argument), | 4269 | STRING_MULTIBYTE (arg), multibyte); |
| 4290 | multibyte); | ||
| 4291 | 4270 | ||
| 4292 | nchars += nchars_string; | 4271 | nchars += nchars_string; |
| 4293 | 4272 | ||
| @@ -4297,12 +4276,12 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4297 | p += padding; | 4276 | p += padding; |
| 4298 | nchars += padding; | 4277 | nchars += padding; |
| 4299 | } | 4278 | } |
| 4300 | info[ispec].end = nchars; | 4279 | spec->end = nchars; |
| 4301 | 4280 | ||
| 4302 | /* If this argument has text properties, record where | 4281 | /* If this argument has text properties, record where |
| 4303 | in the result string it appears. */ | 4282 | in the result string it appears. */ |
| 4304 | if (string_intervals (info[ispec].argument)) | 4283 | if (string_intervals (arg)) |
| 4305 | info[ispec].intervals = arg_intervals = true; | 4284 | spec->intervals = arg_intervals = true; |
| 4306 | 4285 | ||
| 4307 | continue; | 4286 | continue; |
| 4308 | } | 4287 | } |
| @@ -4313,8 +4292,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4313 | || conversion == 'X')) | 4292 | || conversion == 'X')) |
| 4314 | error ("Invalid format operation %%%c", | 4293 | error ("Invalid format operation %%%c", |
| 4315 | STRING_CHAR ((unsigned char *) format - 1)); | 4294 | STRING_CHAR ((unsigned char *) format - 1)); |
| 4316 | else if (! (INTEGERP (info[ispec].argument) | 4295 | else if (! (INTEGERP (arg) || (FLOATP (arg) && conversion != 'c'))) |
| 4317 | || (FLOATP (info[ispec].argument) && conversion != 'c'))) | ||
| 4318 | error ("Format specifier doesn't match argument type"); | 4296 | error ("Format specifier doesn't match argument type"); |
| 4319 | else | 4297 | else |
| 4320 | { | 4298 | { |
| @@ -4376,7 +4354,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4376 | if (INT_AS_LDBL) | 4354 | if (INT_AS_LDBL) |
| 4377 | { | 4355 | { |
| 4378 | *f = 'L'; | 4356 | *f = 'L'; |
| 4379 | f += INTEGERP (info[ispec].argument); | 4357 | f += INTEGERP (arg); |
| 4380 | } | 4358 | } |
| 4381 | } | 4359 | } |
| 4382 | else if (conversion != 'c') | 4360 | else if (conversion != 'c') |
| @@ -4408,22 +4386,22 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4408 | ptrdiff_t sprintf_bytes; | 4386 | ptrdiff_t sprintf_bytes; |
| 4409 | if (float_conversion) | 4387 | if (float_conversion) |
| 4410 | { | 4388 | { |
| 4411 | if (INT_AS_LDBL && INTEGERP (info[ispec].argument)) | 4389 | if (INT_AS_LDBL && INTEGERP (arg)) |
| 4412 | { | 4390 | { |
| 4413 | /* Although long double may have a rounding error if | 4391 | /* Although long double may have a rounding error if |
| 4414 | DIG_BITS_LBOUND * LDBL_MANT_DIG < FIXNUM_BITS - 1, | 4392 | DIG_BITS_LBOUND * LDBL_MANT_DIG < FIXNUM_BITS - 1, |
| 4415 | it is more accurate than plain 'double'. */ | 4393 | it is more accurate than plain 'double'. */ |
| 4416 | long double x = XINT (info[ispec].argument); | 4394 | long double x = XINT (arg); |
| 4417 | sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x); | 4395 | sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x); |
| 4418 | } | 4396 | } |
| 4419 | else | 4397 | else |
| 4420 | sprintf_bytes = sprintf (sprintf_buf, convspec, prec, | 4398 | sprintf_bytes = sprintf (sprintf_buf, convspec, prec, |
| 4421 | XFLOATINT (info[ispec].argument)); | 4399 | XFLOATINT (arg)); |
| 4422 | } | 4400 | } |
| 4423 | else if (conversion == 'c') | 4401 | else if (conversion == 'c') |
| 4424 | { | 4402 | { |
| 4425 | /* Don't use sprintf here, as it might mishandle prec. */ | 4403 | /* Don't use sprintf here, as it might mishandle prec. */ |
| 4426 | sprintf_buf[0] = XINT (info[ispec].argument); | 4404 | sprintf_buf[0] = XINT (arg); |
| 4427 | sprintf_bytes = prec != 0; | 4405 | sprintf_bytes = prec != 0; |
| 4428 | } | 4406 | } |
| 4429 | else if (conversion == 'd' || conversion == 'i') | 4407 | else if (conversion == 'd' || conversion == 'i') |
| @@ -4432,11 +4410,11 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4432 | instead so it also works for values outside | 4410 | instead so it also works for values outside |
| 4433 | the integer range. */ | 4411 | the integer range. */ |
| 4434 | printmax_t x; | 4412 | printmax_t x; |
| 4435 | if (INTEGERP (info[ispec].argument)) | 4413 | if (INTEGERP (arg)) |
| 4436 | x = XINT (info[ispec].argument); | 4414 | x = XINT (arg); |
| 4437 | else | 4415 | else |
| 4438 | { | 4416 | { |
| 4439 | double d = XFLOAT_DATA (info[ispec].argument); | 4417 | double d = XFLOAT_DATA (arg); |
| 4440 | if (d < 0) | 4418 | if (d < 0) |
| 4441 | { | 4419 | { |
| 4442 | x = TYPE_MINIMUM (printmax_t); | 4420 | x = TYPE_MINIMUM (printmax_t); |
| @@ -4456,11 +4434,11 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4456 | { | 4434 | { |
| 4457 | /* Don't sign-extend for octal or hex printing. */ | 4435 | /* Don't sign-extend for octal or hex printing. */ |
| 4458 | uprintmax_t x; | 4436 | uprintmax_t x; |
| 4459 | if (INTEGERP (info[ispec].argument)) | 4437 | if (INTEGERP (arg)) |
| 4460 | x = XUINT (info[ispec].argument); | 4438 | x = XUINT (arg); |
| 4461 | else | 4439 | else |
| 4462 | { | 4440 | { |
| 4463 | double d = XFLOAT_DATA (info[ispec].argument); | 4441 | double d = XFLOAT_DATA (arg); |
| 4464 | if (d < 0) | 4442 | if (d < 0) |
| 4465 | x = 0; | 4443 | x = 0; |
| 4466 | else | 4444 | else |
| @@ -4541,7 +4519,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4541 | exponent_bytes = src + sprintf_bytes - e; | 4519 | exponent_bytes = src + sprintf_bytes - e; |
| 4542 | } | 4520 | } |
| 4543 | 4521 | ||
| 4544 | info[ispec].start = nchars; | 4522 | spec->start = nchars; |
| 4545 | if (! minus_flag) | 4523 | if (! minus_flag) |
| 4546 | { | 4524 | { |
| 4547 | memset (p, ' ', padding); | 4525 | memset (p, ' ', padding); |
| @@ -4572,7 +4550,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4572 | p += padding; | 4550 | p += padding; |
| 4573 | nchars += padding; | 4551 | nchars += padding; |
| 4574 | } | 4552 | } |
| 4575 | info[ispec].end = nchars; | 4553 | spec->end = nchars; |
| 4576 | 4554 | ||
| 4577 | continue; | 4555 | continue; |
| 4578 | } | 4556 | } |
| @@ -4681,7 +4659,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4681 | if (CONSP (props)) | 4659 | if (CONSP (props)) |
| 4682 | { | 4660 | { |
| 4683 | ptrdiff_t bytepos = 0, position = 0, translated = 0; | 4661 | ptrdiff_t bytepos = 0, position = 0, translated = 0; |
| 4684 | ptrdiff_t fieldn = 1; | 4662 | ptrdiff_t fieldn = 0; |
| 4685 | 4663 | ||
| 4686 | /* Adjust the bounds of each text property | 4664 | /* Adjust the bounds of each text property |
| 4687 | to the proper start and end in the output string. */ | 4665 | to the proper start and end in the output string. */ |
| @@ -4747,7 +4725,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4747 | 4725 | ||
| 4748 | /* Add text properties from arguments. */ | 4726 | /* Add text properties from arguments. */ |
| 4749 | if (arg_intervals) | 4727 | if (arg_intervals) |
| 4750 | for (ptrdiff_t i = 1; i <= num_percent; i++) | 4728 | for (ptrdiff_t i = 0; i < nspec; i++) |
| 4751 | if (info[i].intervals) | 4729 | if (info[i].intervals) |
| 4752 | { | 4730 | { |
| 4753 | len = make_number (SCHARS (info[i].argument)); | 4731 | len = make_number (SCHARS (info[i].argument)); |
diff --git a/src/emacs-module.c b/src/emacs-module.c index 33c5fbd484b..71e04d869e9 100644 --- a/src/emacs-module.c +++ b/src/emacs-module.c | |||
| @@ -28,6 +28,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 28 | #include "lisp.h" | 28 | #include "lisp.h" |
| 29 | #include "dynlib.h" | 29 | #include "dynlib.h" |
| 30 | #include "coding.h" | 30 | #include "coding.h" |
| 31 | #include "keyboard.h" | ||
| 31 | #include "syssignal.h" | 32 | #include "syssignal.h" |
| 32 | 33 | ||
| 33 | #include <intprops.h> | 34 | #include <intprops.h> |
| @@ -36,12 +37,6 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 36 | 37 | ||
| 37 | /* Feature tests. */ | 38 | /* Feature tests. */ |
| 38 | 39 | ||
| 39 | #if __has_attribute (cleanup) | ||
| 40 | enum { module_has_cleanup = true }; | ||
| 41 | #else | ||
| 42 | enum { module_has_cleanup = false }; | ||
| 43 | #endif | ||
| 44 | |||
| 45 | #ifdef WINDOWSNT | 40 | #ifdef WINDOWSNT |
| 46 | #include <windows.h> | 41 | #include <windows.h> |
| 47 | #include "w32term.h" | 42 | #include "w32term.h" |
| @@ -88,8 +83,6 @@ struct emacs_env_private | |||
| 88 | environment. */ | 83 | environment. */ |
| 89 | struct emacs_runtime_private | 84 | struct emacs_runtime_private |
| 90 | { | 85 | { |
| 91 | /* FIXME: Ideally, we would just define "struct emacs_runtime_private" | ||
| 92 | as a synonym of "emacs_env", but I don't know how to do that in C. */ | ||
| 93 | emacs_env pub; | 86 | emacs_env pub; |
| 94 | }; | 87 | }; |
| 95 | 88 | ||
| @@ -102,8 +95,8 @@ static Lisp_Object value_to_lisp (emacs_value); | |||
| 102 | static emacs_value lisp_to_value (Lisp_Object); | 95 | static emacs_value lisp_to_value (Lisp_Object); |
| 103 | static enum emacs_funcall_exit module_non_local_exit_check (emacs_env *); | 96 | static enum emacs_funcall_exit module_non_local_exit_check (emacs_env *); |
| 104 | static void check_main_thread (void); | 97 | static void check_main_thread (void); |
| 105 | static void finalize_environment (struct emacs_env_private *); | 98 | static void initialize_environment (emacs_env *, struct emacs_env_private *); |
| 106 | static void initialize_environment (emacs_env *, struct emacs_env_private *priv); | 99 | static void finalize_environment (emacs_env *, struct emacs_env_private *); |
| 107 | static void module_handle_signal (emacs_env *, Lisp_Object); | 100 | static void module_handle_signal (emacs_env *, Lisp_Object); |
| 108 | static void module_handle_throw (emacs_env *, Lisp_Object); | 101 | static void module_handle_throw (emacs_env *, Lisp_Object); |
| 109 | static void module_non_local_exit_signal_1 (emacs_env *, Lisp_Object, Lisp_Object); | 102 | static void module_non_local_exit_signal_1 (emacs_env *, Lisp_Object, Lisp_Object); |
| @@ -169,7 +162,7 @@ static emacs_value const module_nil = 0; | |||
| 169 | module_out_of_memory (env); \ | 162 | module_out_of_memory (env); \ |
| 170 | return retval; \ | 163 | return retval; \ |
| 171 | } \ | 164 | } \ |
| 172 | verify (module_has_cleanup); \ | 165 | verify (__has_attribute (cleanup)); \ |
| 173 | struct handler *c __attribute__ ((cleanup (module_reset_handlerlist))) \ | 166 | struct handler *c __attribute__ ((cleanup (module_reset_handlerlist))) \ |
| 174 | = c0; \ | 167 | = c0; \ |
| 175 | if (sys_setjmp (c->jmp)) \ | 168 | if (sys_setjmp (c->jmp)) \ |
| @@ -213,14 +206,24 @@ static emacs_value const module_nil = 0; | |||
| 213 | instead of reporting the error back to Lisp, and also because | 206 | instead of reporting the error back to Lisp, and also because |
| 214 | 'eassert' is compiled to nothing in the release version. */ | 207 | 'eassert' is compiled to nothing in the release version. */ |
| 215 | 208 | ||
| 209 | /* Use MODULE_FUNCTION_BEGIN_NO_CATCH to implement steps 2 and 3 for | ||
| 210 | environment functions that are known to never exit non-locally. On | ||
| 211 | error it will return its argument, which can be a sentinel | ||
| 212 | value. */ | ||
| 213 | |||
| 214 | #define MODULE_FUNCTION_BEGIN_NO_CATCH(error_retval) \ | ||
| 215 | do { \ | ||
| 216 | check_main_thread (); \ | ||
| 217 | if (module_non_local_exit_check (env) != emacs_funcall_exit_return) \ | ||
| 218 | return error_retval; \ | ||
| 219 | } while (false) | ||
| 220 | |||
| 216 | /* Use MODULE_FUNCTION_BEGIN to implement steps 2 through 4 for most | 221 | /* Use MODULE_FUNCTION_BEGIN to implement steps 2 through 4 for most |
| 217 | environment functions. On error it will return its argument, which | 222 | environment functions. On error it will return its argument, which |
| 218 | should be a sentinel value. */ | 223 | can be a sentinel value. */ |
| 219 | 224 | ||
| 220 | #define MODULE_FUNCTION_BEGIN(error_retval) \ | 225 | #define MODULE_FUNCTION_BEGIN(error_retval) \ |
| 221 | check_main_thread (); \ | 226 | MODULE_FUNCTION_BEGIN_NO_CATCH (error_retval); \ |
| 222 | if (module_non_local_exit_check (env) != emacs_funcall_exit_return) \ | ||
| 223 | return error_retval; \ | ||
| 224 | MODULE_HANDLE_NONLOCAL_EXIT (error_retval) | 227 | MODULE_HANDLE_NONLOCAL_EXIT (error_retval) |
| 225 | 228 | ||
| 226 | static void | 229 | static void |
| @@ -342,7 +345,7 @@ module_non_local_exit_throw (emacs_env *env, emacs_value tag, emacs_value value) | |||
| 342 | value_to_lisp (value)); | 345 | value_to_lisp (value)); |
| 343 | } | 346 | } |
| 344 | 347 | ||
| 345 | /* A module function is a pseudovector of subtype type | 348 | /* A module function is a pseudovector of subtype |
| 346 | PVEC_MODULE_FUNCTION; see lisp.h for the definition. */ | 349 | PVEC_MODULE_FUNCTION; see lisp.h for the definition. */ |
| 347 | 350 | ||
| 348 | static emacs_value | 351 | static emacs_value |
| @@ -418,18 +421,14 @@ module_type_of (emacs_env *env, emacs_value value) | |||
| 418 | static bool | 421 | static bool |
| 419 | module_is_not_nil (emacs_env *env, emacs_value value) | 422 | module_is_not_nil (emacs_env *env, emacs_value value) |
| 420 | { | 423 | { |
| 421 | check_main_thread (); | 424 | MODULE_FUNCTION_BEGIN_NO_CATCH (false); |
| 422 | if (module_non_local_exit_check (env) != emacs_funcall_exit_return) | ||
| 423 | return false; | ||
| 424 | return ! NILP (value_to_lisp (value)); | 425 | return ! NILP (value_to_lisp (value)); |
| 425 | } | 426 | } |
| 426 | 427 | ||
| 427 | static bool | 428 | static bool |
| 428 | module_eq (emacs_env *env, emacs_value a, emacs_value b) | 429 | module_eq (emacs_env *env, emacs_value a, emacs_value b) |
| 429 | { | 430 | { |
| 430 | check_main_thread (); | 431 | MODULE_FUNCTION_BEGIN_NO_CATCH (false); |
| 431 | if (module_non_local_exit_check (env) != emacs_funcall_exit_return) | ||
| 432 | return false; | ||
| 433 | return EQ (value_to_lisp (a), value_to_lisp (b)); | 432 | return EQ (value_to_lisp (a), value_to_lisp (b)); |
| 434 | } | 433 | } |
| 435 | 434 | ||
| @@ -487,8 +486,6 @@ module_copy_string_contents (emacs_env *env, emacs_value value, char *buffer, | |||
| 487 | return true; | 486 | return true; |
| 488 | } | 487 | } |
| 489 | 488 | ||
| 490 | eassert (*length >= 0); | ||
| 491 | |||
| 492 | if (*length < required_buf_size) | 489 | if (*length < required_buf_size) |
| 493 | { | 490 | { |
| 494 | *length = required_buf_size; | 491 | *length = required_buf_size; |
| @@ -505,6 +502,8 @@ static emacs_value | |||
| 505 | module_make_string (emacs_env *env, const char *str, ptrdiff_t length) | 502 | module_make_string (emacs_env *env, const char *str, ptrdiff_t length) |
| 506 | { | 503 | { |
| 507 | MODULE_FUNCTION_BEGIN (module_nil); | 504 | MODULE_FUNCTION_BEGIN (module_nil); |
| 505 | if (! (0 <= length && length <= STRING_BYTES_BOUND)) | ||
| 506 | xsignal0 (Qoverflow_error); | ||
| 508 | AUTO_STRING_WITH_LEN (lstr, str, length); | 507 | AUTO_STRING_WITH_LEN (lstr, str, length); |
| 509 | return lisp_to_value (code_convert_string_norecord (lstr, Qutf_8, false)); | 508 | return lisp_to_value (code_convert_string_norecord (lstr, Qutf_8, false)); |
| 510 | } | 509 | } |
| @@ -593,6 +592,15 @@ module_vec_size (emacs_env *env, emacs_value vec) | |||
| 593 | return ASIZE (lvec); | 592 | return ASIZE (lvec); |
| 594 | } | 593 | } |
| 595 | 594 | ||
| 595 | /* This function should return true if and only if maybe_quit would do | ||
| 596 | anything. */ | ||
| 597 | static bool | ||
| 598 | module_should_quit (emacs_env *env) | ||
| 599 | { | ||
| 600 | MODULE_FUNCTION_BEGIN_NO_CATCH (false); | ||
| 601 | return (! NILP (Vquit_flag) && NILP (Vinhibit_quit)) || pending_signals; | ||
| 602 | } | ||
| 603 | |||
| 596 | 604 | ||
| 597 | /* Subroutines. */ | 605 | /* Subroutines. */ |
| 598 | 606 | ||
| @@ -607,15 +615,15 @@ DEFUN ("module-load", Fmodule_load, Smodule_load, 1, 1, 0, | |||
| 607 | CHECK_STRING (file); | 615 | CHECK_STRING (file); |
| 608 | handle = dynlib_open (SSDATA (file)); | 616 | handle = dynlib_open (SSDATA (file)); |
| 609 | if (!handle) | 617 | if (!handle) |
| 610 | error ("Cannot load file %s: %s", SDATA (file), dynlib_error ()); | 618 | xsignal2 (Qmodule_open_failed, file, build_string (dynlib_error ())); |
| 611 | 619 | ||
| 612 | gpl_sym = dynlib_sym (handle, "plugin_is_GPL_compatible"); | 620 | gpl_sym = dynlib_sym (handle, "plugin_is_GPL_compatible"); |
| 613 | if (!gpl_sym) | 621 | if (!gpl_sym) |
| 614 | error ("Module %s is not GPL compatible", SDATA (file)); | 622 | xsignal1 (Qmodule_not_gpl_compatible, file); |
| 615 | 623 | ||
| 616 | module_init = (emacs_init_function) dynlib_func (handle, "emacs_module_init"); | 624 | module_init = (emacs_init_function) dynlib_func (handle, "emacs_module_init"); |
| 617 | if (!module_init) | 625 | if (!module_init) |
| 618 | error ("Module %s does not have an init function.", SDATA (file)); | 626 | xsignal1 (Qmissing_module_init_function, file); |
| 619 | 627 | ||
| 620 | struct emacs_runtime_private rt; /* Includes the public emacs_env. */ | 628 | struct emacs_runtime_private rt; /* Includes the public emacs_env. */ |
| 621 | struct emacs_env_private priv; | 629 | struct emacs_env_private priv; |
| @@ -627,34 +635,33 @@ DEFUN ("module-load", Fmodule_load, Smodule_load, 1, 1, 0, | |||
| 627 | .get_environment = module_get_environment | 635 | .get_environment = module_get_environment |
| 628 | }; | 636 | }; |
| 629 | int r = module_init (&pub); | 637 | int r = module_init (&pub); |
| 630 | finalize_environment (&priv); | 638 | finalize_environment (&rt.pub, &priv); |
| 631 | 639 | ||
| 632 | if (r != 0) | 640 | if (r != 0) |
| 633 | { | 641 | { |
| 634 | if (FIXNUM_OVERFLOW_P (r)) | 642 | if (FIXNUM_OVERFLOW_P (r)) |
| 635 | xsignal0 (Qoverflow_error); | 643 | xsignal0 (Qoverflow_error); |
| 636 | xsignal2 (Qmodule_load_failed, file, make_number (r)); | 644 | xsignal2 (Qmodule_init_failed, file, make_number (r)); |
| 637 | } | 645 | } |
| 638 | 646 | ||
| 639 | return Qt; | 647 | return Qt; |
| 640 | } | 648 | } |
| 641 | 649 | ||
| 642 | Lisp_Object | 650 | Lisp_Object |
| 643 | funcall_module (const struct Lisp_Module_Function *const function, | 651 | funcall_module (Lisp_Object function, ptrdiff_t nargs, Lisp_Object *arglist) |
| 644 | ptrdiff_t nargs, Lisp_Object *arglist) | ||
| 645 | { | 652 | { |
| 646 | eassume (0 <= function->min_arity); | 653 | const struct Lisp_Module_Function *func = XMODULE_FUNCTION (function); |
| 647 | if (! (function->min_arity <= nargs | 654 | eassume (0 <= func->min_arity); |
| 648 | && (function->max_arity < 0 || nargs <= function->max_arity))) | 655 | if (! (func->min_arity <= nargs |
| 649 | xsignal2 (Qwrong_number_of_arguments, module_format_fun_env (function), | 656 | && (func->max_arity < 0 || nargs <= func->max_arity))) |
| 650 | make_number (nargs)); | 657 | xsignal2 (Qwrong_number_of_arguments, function, make_number (nargs)); |
| 651 | 658 | ||
| 652 | emacs_env pub; | 659 | emacs_env pub; |
| 653 | struct emacs_env_private priv; | 660 | struct emacs_env_private priv; |
| 654 | initialize_environment (&pub, &priv); | 661 | initialize_environment (&pub, &priv); |
| 655 | 662 | ||
| 656 | USE_SAFE_ALLOCA; | 663 | USE_SAFE_ALLOCA; |
| 657 | emacs_value *args; | 664 | ATTRIBUTE_MAY_ALIAS emacs_value *args; |
| 658 | if (plain_values) | 665 | if (plain_values) |
| 659 | args = (emacs_value *) arglist; | 666 | args = (emacs_value *) arglist; |
| 660 | else | 667 | else |
| @@ -664,28 +671,32 @@ funcall_module (const struct Lisp_Module_Function *const function, | |||
| 664 | args[i] = lisp_to_value (arglist[i]); | 671 | args[i] = lisp_to_value (arglist[i]); |
| 665 | } | 672 | } |
| 666 | 673 | ||
| 667 | emacs_value ret = function->subr (&pub, nargs, args, function->data); | 674 | emacs_value ret = func->subr (&pub, nargs, args, func->data); |
| 668 | SAFE_FREE (); | 675 | SAFE_FREE (); |
| 669 | 676 | ||
| 670 | eassert (&priv == pub.private_members); | 677 | eassert (&priv == pub.private_members); |
| 671 | 678 | ||
| 679 | /* Process the quit flag first, so that quitting doesn't get | ||
| 680 | overridden by other non-local exits. */ | ||
| 681 | maybe_quit (); | ||
| 682 | |||
| 672 | switch (priv.pending_non_local_exit) | 683 | switch (priv.pending_non_local_exit) |
| 673 | { | 684 | { |
| 674 | case emacs_funcall_exit_return: | 685 | case emacs_funcall_exit_return: |
| 675 | finalize_environment (&priv); | 686 | finalize_environment (&pub, &priv); |
| 676 | return value_to_lisp (ret); | 687 | return value_to_lisp (ret); |
| 677 | case emacs_funcall_exit_signal: | 688 | case emacs_funcall_exit_signal: |
| 678 | { | 689 | { |
| 679 | Lisp_Object symbol = priv.non_local_exit_symbol; | 690 | Lisp_Object symbol = priv.non_local_exit_symbol; |
| 680 | Lisp_Object data = priv.non_local_exit_data; | 691 | Lisp_Object data = priv.non_local_exit_data; |
| 681 | finalize_environment (&priv); | 692 | finalize_environment (&pub, &priv); |
| 682 | xsignal (symbol, data); | 693 | xsignal (symbol, data); |
| 683 | } | 694 | } |
| 684 | case emacs_funcall_exit_throw: | 695 | case emacs_funcall_exit_throw: |
| 685 | { | 696 | { |
| 686 | Lisp_Object tag = priv.non_local_exit_symbol; | 697 | Lisp_Object tag = priv.non_local_exit_symbol; |
| 687 | Lisp_Object value = priv.non_local_exit_data; | 698 | Lisp_Object value = priv.non_local_exit_data; |
| 688 | finalize_environment (&priv); | 699 | finalize_environment (&pub, &priv); |
| 689 | Fthrow (tag, value); | 700 | Fthrow (tag, value); |
| 690 | } | 701 | } |
| 691 | default: | 702 | default: |
| @@ -894,14 +905,17 @@ initialize_environment (emacs_env *env, struct emacs_env_private *priv) | |||
| 894 | env->vec_set = module_vec_set; | 905 | env->vec_set = module_vec_set; |
| 895 | env->vec_get = module_vec_get; | 906 | env->vec_get = module_vec_get; |
| 896 | env->vec_size = module_vec_size; | 907 | env->vec_size = module_vec_size; |
| 908 | env->should_quit = module_should_quit; | ||
| 897 | Vmodule_environments = Fcons (make_save_ptr (env), Vmodule_environments); | 909 | Vmodule_environments = Fcons (make_save_ptr (env), Vmodule_environments); |
| 898 | } | 910 | } |
| 899 | 911 | ||
| 900 | /* Must be called before the lifetime of the environment object | 912 | /* Must be called before the lifetime of the environment object |
| 901 | ends. */ | 913 | ends. */ |
| 902 | static void | 914 | static void |
| 903 | finalize_environment (struct emacs_env_private *env) | 915 | finalize_environment (emacs_env *env, struct emacs_env_private *priv) |
| 904 | { | 916 | { |
| 917 | eassert (env->private_members == priv); | ||
| 918 | eassert (XSAVE_POINTER (XCAR (Vmodule_environments), 0) == env); | ||
| 905 | Vmodule_environments = XCDR (Vmodule_environments); | 919 | Vmodule_environments = XCDR (Vmodule_environments); |
| 906 | } | 920 | } |
| 907 | 921 | ||
| @@ -937,35 +951,6 @@ module_handle_throw (emacs_env *env, Lisp_Object tag_val) | |||
| 937 | } | 951 | } |
| 938 | 952 | ||
| 939 | 953 | ||
| 940 | /* Function environments. */ | ||
| 941 | |||
| 942 | /* Return a string object that contains a user-friendly | ||
| 943 | representation of the function environment. */ | ||
| 944 | Lisp_Object | ||
| 945 | module_format_fun_env (const struct Lisp_Module_Function *env) | ||
| 946 | { | ||
| 947 | /* Try to print a function name if possible. */ | ||
| 948 | /* FIXME: Move this function into print.c, then use prin1-to-string | ||
| 949 | above. */ | ||
| 950 | const char *path, *sym; | ||
| 951 | static char const noaddr_format[] = "#<module function at %p>"; | ||
| 952 | char buffer[sizeof noaddr_format + INT_STRLEN_BOUND (intptr_t) + 256]; | ||
| 953 | char *buf = buffer; | ||
| 954 | ptrdiff_t bufsize = sizeof buffer; | ||
| 955 | ptrdiff_t size | ||
| 956 | = (dynlib_addr (env->subr, &path, &sym) | ||
| 957 | ? exprintf (&buf, &bufsize, buffer, -1, | ||
| 958 | "#<module function %s from %s>", sym, path) | ||
| 959 | : sprintf (buffer, noaddr_format, env->subr)); | ||
| 960 | AUTO_STRING_WITH_LEN (unibyte_result, buffer, size); | ||
| 961 | Lisp_Object result = code_convert_string_norecord (unibyte_result, | ||
| 962 | Qutf_8, false); | ||
| 963 | if (buf != buffer) | ||
| 964 | xfree (buf); | ||
| 965 | return result; | ||
| 966 | } | ||
| 967 | |||
| 968 | |||
| 969 | /* Segment initializer. */ | 954 | /* Segment initializer. */ |
| 970 | 955 | ||
| 971 | void | 956 | void |
| @@ -999,11 +984,34 @@ syms_of_module (void) | |||
| 999 | Fput (Qmodule_load_failed, Qerror_message, | 984 | Fput (Qmodule_load_failed, Qerror_message, |
| 1000 | build_pure_c_string ("Module load failed")); | 985 | build_pure_c_string ("Module load failed")); |
| 1001 | 986 | ||
| 1002 | DEFSYM (Qinvalid_module_call, "invalid-module-call"); | 987 | DEFSYM (Qmodule_open_failed, "module-open-failed"); |
| 1003 | Fput (Qinvalid_module_call, Qerror_conditions, | 988 | Fput (Qmodule_open_failed, Qerror_conditions, |
| 1004 | listn (CONSTYPE_PURE, 2, Qinvalid_module_call, Qerror)); | 989 | listn (CONSTYPE_PURE, 3, |
| 1005 | Fput (Qinvalid_module_call, Qerror_message, | 990 | Qmodule_open_failed, Qmodule_load_failed, Qerror)); |
| 1006 | build_pure_c_string ("Invalid module call")); | 991 | Fput (Qmodule_open_failed, Qerror_message, |
| 992 | build_pure_c_string ("Module could not be opened")); | ||
| 993 | |||
| 994 | DEFSYM (Qmodule_not_gpl_compatible, "module-not-gpl-compatible"); | ||
| 995 | Fput (Qmodule_not_gpl_compatible, Qerror_conditions, | ||
| 996 | listn (CONSTYPE_PURE, 3, | ||
| 997 | Qmodule_not_gpl_compatible, Qmodule_load_failed, Qerror)); | ||
| 998 | Fput (Qmodule_not_gpl_compatible, Qerror_message, | ||
| 999 | build_pure_c_string ("Module is not GPL compatible")); | ||
| 1000 | |||
| 1001 | DEFSYM (Qmissing_module_init_function, "missing-module-init-function"); | ||
| 1002 | Fput (Qmissing_module_init_function, Qerror_conditions, | ||
| 1003 | listn (CONSTYPE_PURE, 3, | ||
| 1004 | Qmissing_module_init_function, Qmodule_load_failed, Qerror)); | ||
| 1005 | Fput (Qmissing_module_init_function, Qerror_message, | ||
| 1006 | build_pure_c_string ("Module does not export an " | ||
| 1007 | "initialization function")); | ||
| 1008 | |||
| 1009 | DEFSYM (Qmodule_init_failed, "module-init-failed"); | ||
| 1010 | Fput (Qmodule_init_failed, Qerror_conditions, | ||
| 1011 | listn (CONSTYPE_PURE, 3, | ||
| 1012 | Qmodule_init_failed, Qmodule_load_failed, Qerror)); | ||
| 1013 | Fput (Qmodule_init_failed, Qerror_message, | ||
| 1014 | build_pure_c_string ("Module initialization failed")); | ||
| 1007 | 1015 | ||
| 1008 | DEFSYM (Qinvalid_arity, "invalid-arity"); | 1016 | DEFSYM (Qinvalid_arity, "invalid-arity"); |
| 1009 | Fput (Qinvalid_arity, Qerror_conditions, | 1017 | Fput (Qinvalid_arity, Qerror_conditions, |
diff --git a/src/emacs-module.h b/src/emacs-module.h index d9eeeabec3f..b8bf2ed2d5f 100644 --- a/src/emacs-module.h +++ b/src/emacs-module.h | |||
| @@ -185,6 +185,9 @@ struct emacs_env_25 | |||
| 185 | emacs_value val); | 185 | emacs_value val); |
| 186 | 186 | ||
| 187 | ptrdiff_t (*vec_size) (emacs_env *env, emacs_value vec); | 187 | ptrdiff_t (*vec_size) (emacs_env *env, emacs_value vec); |
| 188 | |||
| 189 | /* Returns whether a quit is pending. */ | ||
| 190 | bool (*should_quit) (emacs_env *env); | ||
| 188 | }; | 191 | }; |
| 189 | 192 | ||
| 190 | /* Every module should define a function as follows. */ | 193 | /* Every module should define a function as follows. */ |
diff --git a/src/eval.c b/src/eval.c index f472efad52e..ef961046bcf 100644 --- a/src/eval.c +++ b/src/eval.c | |||
| @@ -1474,7 +1474,10 @@ process_quit_flag (void) | |||
| 1474 | If quit-flag is set to `kill-emacs' the SIGINT handler has received | 1474 | If quit-flag is set to `kill-emacs' the SIGINT handler has received |
| 1475 | a request to exit Emacs when it is safe to do. | 1475 | a request to exit Emacs when it is safe to do. |
| 1476 | 1476 | ||
| 1477 | When not quitting, process any pending signals. */ | 1477 | When not quitting, process any pending signals. |
| 1478 | |||
| 1479 | If you change this function, also adapt module_should_quit in | ||
| 1480 | emacs-module.c. */ | ||
| 1478 | 1481 | ||
| 1479 | void | 1482 | void |
| 1480 | maybe_quit (void) | 1483 | maybe_quit (void) |
| @@ -2952,7 +2955,7 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs, | |||
| 2952 | } | 2955 | } |
| 2953 | #ifdef HAVE_MODULES | 2956 | #ifdef HAVE_MODULES |
| 2954 | else if (MODULE_FUNCTIONP (fun)) | 2957 | else if (MODULE_FUNCTIONP (fun)) |
| 2955 | return funcall_module (XMODULE_FUNCTION (fun), nargs, arg_vector); | 2958 | return funcall_module (fun, nargs, arg_vector); |
| 2956 | #endif | 2959 | #endif |
| 2957 | else | 2960 | else |
| 2958 | emacs_abort (); | 2961 | emacs_abort (); |
diff --git a/src/lisp.h b/src/lisp.h index 7b8f1e754d8..c35bd1f6df1 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -1346,7 +1346,9 @@ SSET (Lisp_Object string, ptrdiff_t index, unsigned char new) | |||
| 1346 | INLINE ptrdiff_t | 1346 | INLINE ptrdiff_t |
| 1347 | SCHARS (Lisp_Object string) | 1347 | SCHARS (Lisp_Object string) |
| 1348 | { | 1348 | { |
| 1349 | return XSTRING (string)->size; | 1349 | ptrdiff_t nchars = XSTRING (string)->size; |
| 1350 | eassume (0 <= nchars); | ||
| 1351 | return nchars; | ||
| 1350 | } | 1352 | } |
| 1351 | 1353 | ||
| 1352 | #ifdef GC_CHECK_STRING_BYTES | 1354 | #ifdef GC_CHECK_STRING_BYTES |
| @@ -1356,10 +1358,12 @@ INLINE ptrdiff_t | |||
| 1356 | STRING_BYTES (struct Lisp_String *s) | 1358 | STRING_BYTES (struct Lisp_String *s) |
| 1357 | { | 1359 | { |
| 1358 | #ifdef GC_CHECK_STRING_BYTES | 1360 | #ifdef GC_CHECK_STRING_BYTES |
| 1359 | return string_bytes (s); | 1361 | ptrdiff_t nbytes = string_bytes (s); |
| 1360 | #else | 1362 | #else |
| 1361 | return s->size_byte < 0 ? s->size : s->size_byte; | 1363 | ptrdiff_t nbytes = s->size_byte < 0 ? s->size : s->size_byte; |
| 1362 | #endif | 1364 | #endif |
| 1365 | eassume (0 <= nbytes); | ||
| 1366 | return nbytes; | ||
| 1363 | } | 1367 | } |
| 1364 | 1368 | ||
| 1365 | INLINE ptrdiff_t | 1369 | INLINE ptrdiff_t |
| @@ -1373,7 +1377,7 @@ STRING_SET_CHARS (Lisp_Object string, ptrdiff_t newsize) | |||
| 1373 | /* This function cannot change the size of data allocated for the | 1377 | /* This function cannot change the size of data allocated for the |
| 1374 | string when it was created. */ | 1378 | string when it was created. */ |
| 1375 | eassert (STRING_MULTIBYTE (string) | 1379 | eassert (STRING_MULTIBYTE (string) |
| 1376 | ? newsize <= SBYTES (string) | 1380 | ? 0 <= newsize && newsize <= SBYTES (string) |
| 1377 | : newsize == SCHARS (string)); | 1381 | : newsize == SCHARS (string)); |
| 1378 | XSTRING (string)->size = newsize; | 1382 | XSTRING (string)->size = newsize; |
| 1379 | } | 1383 | } |
| @@ -3952,10 +3956,8 @@ XMODULE_FUNCTION (Lisp_Object o) | |||
| 3952 | extern Lisp_Object make_user_ptr (void (*finalizer) (void *), void *p); | 3956 | extern Lisp_Object make_user_ptr (void (*finalizer) (void *), void *p); |
| 3953 | 3957 | ||
| 3954 | /* Defined in emacs-module.c. */ | 3958 | /* Defined in emacs-module.c. */ |
| 3955 | extern Lisp_Object funcall_module (const struct Lisp_Module_Function *, | 3959 | extern Lisp_Object funcall_module (Lisp_Object, ptrdiff_t, Lisp_Object *); |
| 3956 | ptrdiff_t, Lisp_Object *); | ||
| 3957 | extern Lisp_Object module_function_arity (const struct Lisp_Module_Function *); | 3960 | extern Lisp_Object module_function_arity (const struct Lisp_Module_Function *); |
| 3958 | extern Lisp_Object module_format_fun_env (const struct Lisp_Module_Function *); | ||
| 3959 | extern void syms_of_module (void); | 3961 | extern void syms_of_module (void); |
| 3960 | #endif | 3962 | #endif |
| 3961 | 3963 | ||
diff --git a/src/print.c b/src/print.c index 49408bbeb40..76ae10fe132 100644 --- a/src/print.c +++ b/src/print.c | |||
| @@ -33,6 +33,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 33 | #include "intervals.h" | 33 | #include "intervals.h" |
| 34 | #include "blockinput.h" | 34 | #include "blockinput.h" |
| 35 | #include "xwidget.h" | 35 | #include "xwidget.h" |
| 36 | #include "dynlib.h" | ||
| 36 | 37 | ||
| 37 | #include <c-ctype.h> | 38 | #include <c-ctype.h> |
| 38 | #include <float.h> | 39 | #include <float.h> |
| @@ -1699,8 +1700,33 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag, | |||
| 1699 | 1700 | ||
| 1700 | #ifdef HAVE_MODULES | 1701 | #ifdef HAVE_MODULES |
| 1701 | case PVEC_MODULE_FUNCTION: | 1702 | case PVEC_MODULE_FUNCTION: |
| 1702 | print_string (module_format_fun_env (XMODULE_FUNCTION (obj)), | 1703 | { |
| 1703 | printcharfun); | 1704 | print_c_string ("#<module function ", printcharfun); |
| 1705 | void *ptr = XMODULE_FUNCTION (obj)->subr; | ||
| 1706 | const char *file = NULL; | ||
| 1707 | const char *symbol = NULL; | ||
| 1708 | dynlib_addr (ptr, &file, &symbol); | ||
| 1709 | |||
| 1710 | if (symbol == NULL) | ||
| 1711 | { | ||
| 1712 | print_c_string ("at ", printcharfun); | ||
| 1713 | enum { pointer_bufsize = sizeof ptr * 16 / CHAR_BIT + 2 + 1 }; | ||
| 1714 | char buffer[pointer_bufsize]; | ||
| 1715 | int needed = snprintf (buffer, sizeof buffer, "%p", ptr); | ||
| 1716 | eassert (needed <= sizeof buffer); | ||
| 1717 | print_c_string (buffer, printcharfun); | ||
| 1718 | } | ||
| 1719 | else | ||
| 1720 | print_c_string (symbol, printcharfun); | ||
| 1721 | |||
| 1722 | if (file != NULL) | ||
| 1723 | { | ||
| 1724 | print_c_string (" from ", printcharfun); | ||
| 1725 | print_c_string (file, printcharfun); | ||
| 1726 | } | ||
| 1727 | |||
| 1728 | printchar ('>', printcharfun); | ||
| 1729 | } | ||
| 1704 | break; | 1730 | break; |
| 1705 | #endif | 1731 | #endif |
| 1706 | 1732 | ||