summaryrefslogtreecommitdiff
path: root/src/lread.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lread.c')
-rw-r--r--src/lread.c369
1 files changed, 231 insertions, 138 deletions
diff --git a/src/lread.c b/src/lread.c
index b978e6ed09f..6005a7ce2d2 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -23,11 +23,11 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
#include "sysstdio.h"
+#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <errno.h>
-#include <limits.h> /* For CHAR_BIT. */
#include <math.h>
#include <stat-time.h>
#include "lisp.h"
@@ -36,13 +36,13 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include "character.h"
#include "buffer.h"
#include "charset.h"
-#include "coding.h"
#include <epaths.h>
#include "commands.h"
#include "keyboard.h"
#include "systime.h"
#include "termhooks.h"
#include "blockinput.h"
+#include <c-ctype.h>
#ifdef MSDOS
#include "msdos.h"
@@ -1039,7 +1039,7 @@ Return t if the file exists and loads successfully. */)
{
FILE *stream;
int fd;
- int fd_index;
+ int fd_index UNINIT;
ptrdiff_t count = SPECPDL_INDEX ();
Lisp_Object found, efound, hist_file_name;
/* True means we printed the ".el is newer" message. */
@@ -1155,12 +1155,7 @@ Return t if the file exists and loads successfully. */)
#endif
}
- if (fd < 0)
- {
- /* Pacify older GCC with --enable-gcc-warnings. */
- IF_LINT (fd_index = 0);
- }
- else
+ if (0 <= fd)
{
fd_index = SPECPDL_INDEX ();
record_unwind_protect_int (close_file_unwind, fd);
@@ -1209,7 +1204,11 @@ Return t if the file exists and loads successfully. */)
specbind (Qold_style_backquotes, Qnil);
record_unwind_protect (load_warn_old_style_backquotes, file);
- if (suffix_p (found, ".elc") || (fd >= 0 && (version = safe_to_load_version (fd)) > 0))
+ int is_elc;
+ if ((is_elc = suffix_p (found, ".elc")) != 0
+ /* version = 1 means the file is empty, in which case we can
+ treat it as not byte-compiled. */
+ || (fd >= 0 && (version = safe_to_load_version (fd)) > 1))
/* Load .elc files directly, but not when they are
remote and have no handler! */
{
@@ -1236,7 +1235,7 @@ Return t if the file exists and loads successfully. */)
/* openp already checked for newness, no point doing it again.
FIXME would be nice to get a message when openp
ignores suffix order due to load_prefer_newer. */
- if (!load_prefer_newer)
+ if (!load_prefer_newer && is_elc)
{
result = stat (SSDATA (efound), &s1);
if (result == 0)
@@ -1465,6 +1464,8 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes,
for (; CONSP (path); path = XCDR (path))
{
+ ptrdiff_t baselen, prefixlen;
+
filename = Fexpand_file_name (str, XCAR (path));
if (!complete_filename_p (filename))
/* If there are non-absolute elts in PATH (eg "."). */
@@ -1486,6 +1487,14 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes,
fn = SAFE_ALLOCA (fn_size);
}
+ /* Copy FILENAME's data to FN but remove starting /: if any. */
+ prefixlen = ((SCHARS (filename) > 2
+ && SREF (filename, 0) == '/'
+ && SREF (filename, 1) == ':')
+ ? 2 : 0);
+ baselen = SBYTES (filename) - prefixlen;
+ memcpy (fn, SDATA (filename) + prefixlen, baselen);
+
/* Loop over suffixes. */
for (tail = NILP (suffixes) ? list1 (empty_unibyte_string) : suffixes;
CONSP (tail); tail = XCDR (tail))
@@ -1494,16 +1503,10 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes,
ptrdiff_t fnlen, lsuffix = SBYTES (suffix);
Lisp_Object handler;
- /* Concatenate path element/specified name with the suffix.
- If the directory starts with /:, remove that. */
- int prefixlen = ((SCHARS (filename) > 2
- && SREF (filename, 0) == '/'
- && SREF (filename, 1) == ':')
- ? 2 : 0);
- fnlen = SBYTES (filename) - prefixlen;
- memcpy (fn, SDATA (filename) + prefixlen, fnlen);
- memcpy (fn + fnlen, SDATA (suffix), lsuffix + 1);
- fnlen += lsuffix;
+ /* Make complete filename by appending SUFFIX. */
+ memcpy (fn + baselen, SDATA (suffix), lsuffix + 1);
+ fnlen = baselen + lsuffix;
+
/* Check that the file exists and is not a directory. */
/* We used to only check for handlers on non-absolute file names:
if (absolute)
@@ -1582,8 +1585,7 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes,
}
else
{
- int oflags = O_RDONLY + (NILP (predicate) ? 0 : O_BINARY);
- fd = emacs_open (pfn, oflags, 0);
+ fd = emacs_open (pfn, O_RDONLY, 0);
if (fd < 0)
{
if (errno != ENOENT)
@@ -2142,18 +2144,57 @@ read0 (Lisp_Object readcharfun)
Fmake_string (make_number (1), make_number (c)));
}
-static ptrdiff_t read_buffer_size;
-static char *read_buffer;
-
-/* Grow the read buffer by at least MAX_MULTIBYTE_LENGTH bytes. */
+/* Grow a read buffer BUF that contains OFFSET useful bytes of data,
+ by at least MAX_MULTIBYTE_LENGTH bytes. Update *BUF_ADDR and
+ *BUF_SIZE accordingly; 0 <= OFFSET <= *BUF_SIZE. If *BUF_ADDR is
+ initially null, BUF is on the stack: copy its data to the new heap
+ buffer. Otherwise, BUF must equal *BUF_ADDR and can simply be
+ reallocated. Either way, remember the heap allocation (which is at
+ pdl slot COUNT) so that it can be freed when unwinding the stack.*/
+
+static char *
+grow_read_buffer (char *buf, ptrdiff_t offset,
+ char **buf_addr, ptrdiff_t *buf_size, ptrdiff_t count)
+{
+ char *p = xpalloc (*buf_addr, buf_size, MAX_MULTIBYTE_LENGTH, -1, 1);
+ if (!*buf_addr)
+ {
+ memcpy (p, buf, offset);
+ record_unwind_protect_ptr (xfree, p);
+ }
+ else
+ set_unwind_protect_ptr (count, xfree, p);
+ *buf_addr = p;
+ return p;
+}
-static void
-grow_read_buffer (void)
+/* Return the scalar value that has the Unicode character name NAME.
+ Raise 'invalid-read-syntax' if there is no such character. */
+static int
+character_name_to_code (char const *name, ptrdiff_t name_len)
{
- read_buffer = xpalloc (read_buffer, &read_buffer_size,
- MAX_MULTIBYTE_LENGTH, -1, 1);
+ /* For "U+XXXX", pass the leading '+' to string_to_number to reject
+ monstrosities like "U+-0000". */
+ Lisp_Object code
+ = (name[0] == 'U' && name[1] == '+'
+ ? string_to_number (name + 1, 16, false)
+ : call2 (Qchar_from_name, make_unibyte_string (name, name_len), Qt));
+
+ if (! RANGED_INTEGERP (0, code, MAX_UNICODE_CHAR)
+ || char_surrogate_p (XINT (code)))
+ {
+ AUTO_STRING (format, "\\N{%s}");
+ AUTO_STRING_WITH_LEN (namestr, name, name_len);
+ xsignal1 (Qinvalid_read_syntax, CALLN (Fformat, format, namestr));
+ }
+
+ return XINT (code);
}
+/* Bound on the length of a Unicode character name. As of
+ Unicode 9.0.0 the maximum is 83, so this should be safe. */
+enum { UNICODE_CHARACTER_NAME_LENGTH_BOUND = 200 };
+
/* Read a \-escape sequence, assuming we already read the `\'.
If the escape sequence forces unibyte, return eight-bit char. */
@@ -2361,6 +2402,54 @@ read_escape (Lisp_Object readcharfun, bool stringp)
return i;
}
+ case 'N':
+ /* Named character. */
+ {
+ c = READCHAR;
+ if (c != '{')
+ invalid_syntax ("Expected opening brace after \\N");
+ char name[UNICODE_CHARACTER_NAME_LENGTH_BOUND + 1];
+ bool whitespace = false;
+ ptrdiff_t length = 0;
+ while (true)
+ {
+ c = READCHAR;
+ if (c < 0)
+ end_of_file_error ();
+ if (c == '}')
+ break;
+ if (! (0 < c && c < 0x80))
+ {
+ AUTO_STRING (format,
+ "Invalid character U+%04X in character name");
+ xsignal1 (Qinvalid_read_syntax,
+ CALLN (Fformat, format, make_natnum (c)));
+ }
+ /* Treat multiple adjacent whitespace characters as a
+ single space character. This makes it easier to use
+ character names in e.g. multi-line strings. */
+ if (c_isspace (c))
+ {
+ if (whitespace)
+ continue;
+ c = ' ';
+ whitespace = true;
+ }
+ else
+ whitespace = false;
+ name[length++] = c;
+ if (length >= sizeof name)
+ invalid_syntax ("Character name too long");
+ }
+ if (length == 0)
+ invalid_syntax ("Empty character name");
+ name[length] = '\0';
+
+ /* character_name_to_code can invoke read1, recursively.
+ This is why read1's buffer is not static. */
+ return character_name_to_code (name, length);
+ }
+
default:
return c;
}
@@ -2397,7 +2486,7 @@ read_integer (Lisp_Object readcharfun, EMACS_INT radix)
{
/* Room for sign, leading 0, other digits, trailing null byte.
Also, room for invalid syntax diagnostic. */
- char buf[max (1 + 1 + sizeof (uintmax_t) * CHAR_BIT + 1,
+ char buf[max (1 + 1 + UINTMAX_WIDTH + 1,
sizeof "integer, radix " + INT_STRLEN_BOUND (EMACS_INT))];
int valid = -1; /* 1 if valid, 0 if not, -1 if incomplete. */
@@ -2447,7 +2536,7 @@ read_integer (Lisp_Object readcharfun, EMACS_INT radix)
*p = '\0';
}
- if (! valid)
+ if (valid != 1)
{
sprintf (buf, "integer, radix %"pI"d", radix);
invalid_syntax (buf);
@@ -2467,8 +2556,9 @@ static Lisp_Object
read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
{
int c;
- bool uninterned_symbol = 0;
+ bool uninterned_symbol = false;
bool multibyte;
+ char stackbuf[MAX_ALLOCA];
*pch = 0;
@@ -2799,7 +2889,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
/* #:foo is the uninterned symbol named foo. */
if (c == ':')
{
- uninterned_symbol = 1;
+ uninterned_symbol = true;
c = READCHAR;
if (!(c > 040
&& c != NO_BREAK_SPACE
@@ -2821,19 +2911,17 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
{
EMACS_INT n = 0;
Lisp_Object tem;
+ bool overflow = false;
/* Read a non-negative integer. */
while (c >= '0' && c <= '9')
{
- if (MOST_POSITIVE_FIXNUM / 10 < n
- || MOST_POSITIVE_FIXNUM < n * 10 + c - '0')
- n = MOST_POSITIVE_FIXNUM + 1;
- else
- n = n * 10 + c - '0';
+ overflow |= INT_MULTIPLY_WRAPV (n, 10, &n);
+ overflow |= INT_ADD_WRAPV (n, c - '0', &n);
c = READCHAR;
}
- if (n <= MOST_POSITIVE_FIXNUM)
+ if (!overflow && n <= MOST_POSITIVE_FIXNUM)
{
if (c == 'r' || c == 'R')
return read_integer (readcharfun, n);
@@ -3012,16 +3100,20 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
case '"':
{
+ ptrdiff_t count = SPECPDL_INDEX ();
+ char *read_buffer = stackbuf;
+ ptrdiff_t read_buffer_size = sizeof stackbuf;
+ char *heapbuf = NULL;
char *p = read_buffer;
char *end = read_buffer + read_buffer_size;
int ch;
/* True if we saw an escape sequence specifying
a multibyte character. */
- bool force_multibyte = 0;
+ bool force_multibyte = false;
/* True if we saw an escape sequence specifying
a single-byte character. */
- bool force_singlebyte = 0;
- bool cancel = 0;
+ bool force_singlebyte = false;
+ bool cancel = false;
ptrdiff_t nchars = 0;
while ((ch = READCHAR) >= 0
@@ -3030,7 +3122,9 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
if (end - p < MAX_MULTIBYTE_LENGTH)
{
ptrdiff_t offset = p - read_buffer;
- grow_read_buffer ();
+ read_buffer = grow_read_buffer (read_buffer, offset,
+ &heapbuf, &read_buffer_size,
+ count);
p = read_buffer + offset;
end = read_buffer + read_buffer_size;
}
@@ -3045,7 +3139,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
if (ch == -1)
{
if (p == read_buffer)
- cancel = 1;
+ cancel = true;
continue;
}
@@ -3053,9 +3147,9 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
ch = ch & ~CHAR_MODIFIER_MASK;
if (CHAR_BYTE8_P (ch))
- force_singlebyte = 1;
+ force_singlebyte = true;
else if (! ASCII_CHAR_P (ch))
- force_multibyte = 1;
+ force_multibyte = true;
else /* I.e. ASCII_CHAR_P (ch). */
{
/* Allow `\C- ' and `\C-?'. */
@@ -3081,7 +3175,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
string. */
modifiers &= ~CHAR_META;
ch = BYTE8_TO_CHAR (ch | 0x80);
- force_singlebyte = 1;
+ force_singlebyte = true;
}
}
@@ -3094,9 +3188,9 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
{
p += CHAR_STRING (ch, (unsigned char *) p);
if (CHAR_BYTE8_P (ch))
- force_singlebyte = 1;
+ force_singlebyte = true;
else if (! ASCII_CHAR_P (ch))
- force_multibyte = 1;
+ force_multibyte = true;
}
nchars++;
}
@@ -3108,7 +3202,7 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
return zero instead. This is for doc strings
that we are really going to find in etc/DOC.nn.nn. */
if (!NILP (Vpurify_flag) && NILP (Vdoc_file_name) && cancel)
- return make_number (0);
+ return unbind_to (count, make_number (0));
if (! force_multibyte && force_singlebyte)
{
@@ -3119,9 +3213,11 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
p = read_buffer + nchars;
}
- return make_specified_string (read_buffer, nchars, p - read_buffer,
- (force_multibyte
- || (p - read_buffer != nchars)));
+ Lisp_Object result
+ = make_specified_string (read_buffer, nchars, p - read_buffer,
+ (force_multibyte
+ || (p - read_buffer != nchars)));
+ return unbind_to (count, result);
}
case '.':
@@ -3149,81 +3245,74 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
read_symbol:
{
+ ptrdiff_t count = SPECPDL_INDEX ();
+ char *read_buffer = stackbuf;
+ ptrdiff_t read_buffer_size = sizeof stackbuf;
+ char *heapbuf = NULL;
char *p = read_buffer;
- bool quoted = 0;
+ char *end = read_buffer + read_buffer_size;
+ bool quoted = false;
EMACS_INT start_position = readchar_count - 1;
- {
- char *end = read_buffer + read_buffer_size;
-
- do
- {
- if (end - p < MAX_MULTIBYTE_LENGTH)
- {
- ptrdiff_t offset = p - read_buffer;
- grow_read_buffer ();
- p = read_buffer + offset;
- end = read_buffer + read_buffer_size;
- }
+ do
+ {
+ if (end - p < MAX_MULTIBYTE_LENGTH + 1)
+ {
+ ptrdiff_t offset = p - read_buffer;
+ read_buffer = grow_read_buffer (read_buffer, offset,
+ &heapbuf, &read_buffer_size,
+ count);
+ p = read_buffer + offset;
+ end = read_buffer + read_buffer_size;
+ }
- if (c == '\\')
- {
- c = READCHAR;
- if (c == -1)
- end_of_file_error ();
- quoted = 1;
- }
+ if (c == '\\')
+ {
+ c = READCHAR;
+ if (c == -1)
+ end_of_file_error ();
+ quoted = true;
+ }
- if (multibyte)
- p += CHAR_STRING (c, (unsigned char *) p);
- else
- *p++ = c;
- c = READCHAR;
- }
- while (c > 040
- && c != NO_BREAK_SPACE
- && (c >= 0200
- || strchr ("\"';()[]#`,", c) == NULL));
+ if (multibyte)
+ p += CHAR_STRING (c, (unsigned char *) p);
+ else
+ *p++ = c;
+ c = READCHAR;
+ }
+ while (c > 040
+ && c != NO_BREAK_SPACE
+ && (c >= 0200
+ || strchr ("\"';()[]#`,", c) == NULL));
- if (p == end)
- {
- ptrdiff_t offset = p - read_buffer;
- grow_read_buffer ();
- p = read_buffer + offset;
- end = read_buffer + read_buffer_size;
- }
- *p = 0;
- UNREAD (c);
- }
+ *p = 0;
+ UNREAD (c);
if (!quoted && !uninterned_symbol)
{
Lisp_Object result = string_to_number (read_buffer, 10, 0);
if (! NILP (result))
- return result;
+ return unbind_to (count, result);
}
- {
- Lisp_Object name, result;
- ptrdiff_t nbytes = p - read_buffer;
- ptrdiff_t nchars
- = (multibyte
- ? multibyte_chars_in_text ((unsigned char *) read_buffer,
- nbytes)
- : nbytes);
-
- name = ((uninterned_symbol && ! NILP (Vpurify_flag)
- ? make_pure_string : make_specified_string)
- (read_buffer, nchars, nbytes, multibyte));
- result = (uninterned_symbol ? Fmake_symbol (name)
- : Fintern (name, Qnil));
-
- if (EQ (Vread_with_symbol_positions, Qt)
- || EQ (Vread_with_symbol_positions, readcharfun))
- Vread_symbol_positions_list
- = Fcons (Fcons (result, make_number (start_position)),
- Vread_symbol_positions_list);
- return result;
- }
+
+ ptrdiff_t nbytes = p - read_buffer;
+ ptrdiff_t nchars
+ = (multibyte
+ ? multibyte_chars_in_text ((unsigned char *) read_buffer,
+ nbytes)
+ : nbytes);
+ Lisp_Object name = ((uninterned_symbol && ! NILP (Vpurify_flag)
+ ? make_pure_string : make_specified_string)
+ (read_buffer, nchars, nbytes, multibyte));
+ Lisp_Object result = (uninterned_symbol ? Fmake_symbol (name)
+ : Fintern (name, Qnil));
+
+ if (EQ (Vread_with_symbol_positions, Qt)
+ || EQ (Vread_with_symbol_positions, readcharfun))
+ Vread_symbol_positions_list
+ = Fcons (Fcons (result, make_number (start_position)),
+ Vread_symbol_positions_list);
+ return unbind_to (count, result);
}
}
}
@@ -3761,7 +3850,7 @@ intern_sym (Lisp_Object sym, Lisp_Object obarray, Lisp_Object index)
if (SREF (SYMBOL_NAME (sym), 0) == ':' && EQ (obarray, initial_obarray))
{
- XSYMBOL (sym)->constant = 1;
+ make_symbol_constant (sym);
XSYMBOL (sym)->redirect = SYMBOL_PLAINVAL;
SET_SYMBOL_VAL (XSYMBOL (sym), sym);
}
@@ -4027,17 +4116,12 @@ OBARRAY defaults to the value of `obarray'. */)
return Qnil;
}
-#define OBARRAY_SIZE 1511
+#define OBARRAY_SIZE 15121
void
init_obarray (void)
{
- Lisp_Object oblength;
- ptrdiff_t size = 100 + MAX_MULTIBYTE_LENGTH;
-
- XSETFASTINT (oblength, OBARRAY_SIZE);
-
- Vobarray = Fmake_vector (oblength, make_number (0));
+ Vobarray = Fmake_vector (make_number (OBARRAY_SIZE), make_number (0));
initial_obarray = Vobarray;
staticpro (&initial_obarray);
@@ -4048,21 +4132,18 @@ init_obarray (void)
DEFSYM (Qnil, "nil");
SET_SYMBOL_VAL (XSYMBOL (Qnil), Qnil);
- XSYMBOL (Qnil)->constant = 1;
+ make_symbol_constant (Qnil);
XSYMBOL (Qnil)->declared_special = true;
DEFSYM (Qt, "t");
SET_SYMBOL_VAL (XSYMBOL (Qt), Qt);
- XSYMBOL (Qt)->constant = 1;
+ make_symbol_constant (Qt);
XSYMBOL (Qt)->declared_special = true;
/* Qt is correct even if CANNOT_DUMP. loadup.el will set to nil at end. */
Vpurify_flag = Qt;
DEFSYM (Qvariable_documentation, "variable-documentation");
-
- read_buffer = xmalloc (size);
- read_buffer_size = size;
}
void
@@ -4190,7 +4271,9 @@ load_path_check (Lisp_Object lpath)
are running uninstalled.
Uses the following logic:
- If CANNOT_DUMP: Use PATH_LOADSEARCH.
+ If CANNOT_DUMP:
+ If Vinstallation_directory is not nil (ie, running uninstalled),
+ use PATH_DUMPLOADSEARCH (ie, build path). Else use PATH_LOADSEARCH.
The remainder is what happens when dumping works:
If purify-flag (ie dumping) just use PATH_DUMPLOADSEARCH.
Otherwise use PATH_LOADSEARCH.
@@ -4224,6 +4307,8 @@ load_path_default (void)
#endif
normal = PATH_LOADSEARCH;
+ if (!NILP (Vinstallation_directory)) normal = PATH_DUMPLOADSEARCH;
+
#ifdef HAVE_NS
lpath = decode_env_path (0, loadpath ? loadpath : normal, 0);
#else
@@ -4428,18 +4513,24 @@ void
dir_warning (char const *use, Lisp_Object dirname)
{
static char const format[] = "Warning: %s '%s': %s\n";
- int access_errno = errno;
- fprintf (stderr, format, use, SSDATA (ENCODE_SYSTEM (dirname)),
- strerror (access_errno));
+ char *diagnostic = emacs_strerror (errno);
+ fprintf (stderr, format, use, SSDATA (ENCODE_SYSTEM (dirname)), diagnostic);
/* Don't log the warning before we've initialized!! */
if (initialized)
{
- char const *diagnostic = emacs_strerror (access_errno);
+ ptrdiff_t diaglen = strlen (diagnostic);
+ AUTO_STRING_WITH_LEN (diag, diagnostic, diaglen);
+ if (! NILP (Vlocale_coding_system))
+ {
+ Lisp_Object s
+ = code_convert_string_norecord (diag, Vlocale_coding_system, false);
+ diagnostic = SSDATA (s);
+ diaglen = SBYTES (s);
+ }
USE_SAFE_ALLOCA;
char *buffer = SAFE_ALLOCA (sizeof format - 3 * (sizeof "%s" - 1)
- + strlen (use) + SBYTES (dirname)
- + strlen (diagnostic));
+ + strlen (use) + SBYTES (dirname) + diaglen);
ptrdiff_t message_len = esprintf (buffer, format, use, SSDATA (dirname),
diagnostic);
message_dolog (buffer, message_len, 0, STRING_MULTIBYTE (dirname));
@@ -4761,4 +4852,6 @@ that are loaded before your customizations are read! */);
DEFSYM (Qweakness, "weakness");
DEFSYM (Qrehash_size, "rehash-size");
DEFSYM (Qrehash_threshold, "rehash-threshold");
+
+ DEFSYM (Qchar_from_name, "char-from-name");
}