/* Lisp parsing and input streams.
-Copyright (C) 1985-1989, 1993-1995, 1997-2015 Free Software Foundation,
+Copyright (C) 1985-1989, 1993-1995, 1997-2016 Free Software Foundation,
Inc.
This file is part of GNU Emacs.
GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
#include "systime.h"
#include "termhooks.h"
#include "blockinput.h"
+#include <c-ctype.h>
#ifdef MSDOS
#include "msdos.h"
return c;
}
- if (CONSP (readcharfun))
+ if (CONSP (readcharfun) && STRINGP (XCAR (readcharfun)))
{
/* This is the case that read_vector is reading from a unibyte
string that contains a byte sequence previously skipped
read_from_string_index_byte
= string_char_to_byte (readcharfun, read_from_string_index);
}
- else if (CONSP (readcharfun))
+ else if (CONSP (readcharfun) && STRINGP (XCAR (readcharfun)))
{
unread_char = c;
}
}
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)
FINAL-STRING-INDEX is an integer giving the position of the next
remaining character in STRING. START and END optionally delimit
a substring of STRING from which to read; they default to 0 and
-(length STRING) respectively. Negative values are counted from
+\(length STRING) respectively. Negative values are counted from
the end of STRING. */)
(Lisp_Object string, Lisp_Object start, Lisp_Object end)
{
MAX_MULTIBYTE_LENGTH, -1, 1);
}
+/* 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)
+{
+ /* 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. */
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';
+ return character_name_to_code (name, length);
+ }
+
default:
return c;
}
Lisp_Object
check_obarray (Lisp_Object obarray)
{
- if (!VECTORP (obarray) || ASIZE (obarray) == 0)
+ /* We don't want to signal a wrong-type-argument error when we are
+ shutting down due to a fatal error, and we don't want to hit
+ assertions in VECTORP and ASIZE if the fatal error was during GC. */
+ if (!fatal_error_in_progress
+ && (!VECTORP (obarray) || ASIZE (obarray) == 0))
{
/* If Vobarray is now invalid, force it to be valid. */
if (EQ (Vobarray, obarray)) Vobarray = initial_obarray;
DEFSYM (Qweakness, "weakness");
DEFSYM (Qrehash_size, "rehash-size");
DEFSYM (Qrehash_threshold, "rehash-threshold");
+
+ DEFSYM (Qchar_from_name, "char-from-name");
}