diff options
| author | Dmitry Antipov | 2014-06-25 14:36:51 +0400 |
|---|---|---|
| committer | Dmitry Antipov | 2014-06-25 14:36:51 +0400 |
| commit | 5697ca55cb79817a6704c344cc76d866ee2e1699 (patch) | |
| tree | 3d9cace5c0dd430485eb16697cb6c045553eb3ae | |
| parent | 9a214b9800b7c01d8a473a2564e8f57215990b24 (diff) | |
| download | emacs-5697ca55cb79817a6704c344cc76d866ee2e1699.tar.gz emacs-5697ca55cb79817a6704c344cc76d866ee2e1699.zip | |
Do not allow out-of-range character position in Fcompare_strings.
* src/fns.c (validate_subarray): Add prototype.
(Fcompare_substring): Use validate_subarray to check ranges.
Adjust comment to mention that the semantics was changed. Also see
http://lists.gnu.org/archive/html/emacs-devel/2014-06/msg00447.html.
* lisp/files.el (dir-locals-find-file, file-relative-name):
* lisp/info.el (Info-complete-menu-item):
* lisp/minibuffer.el (completion-table-subvert): Prefer string-prefix-p
to compare-strings to avoid out-of-range errors.
* lisp/subr.el (string-prefix-p): Adjust to match strict range
checking in compare-strings.
* test/automated/fns-tests.el (fns-tests-compare-string): New test.
| -rw-r--r-- | lisp/ChangeLog | 9 | ||||
| -rw-r--r-- | lisp/files.el | 17 | ||||
| -rw-r--r-- | lisp/info.el | 4 | ||||
| -rw-r--r-- | lisp/minibuffer.el | 6 | ||||
| -rw-r--r-- | lisp/subr.el | 10 | ||||
| -rw-r--r-- | src/ChangeLog | 8 | ||||
| -rw-r--r-- | src/fns.c | 65 | ||||
| -rw-r--r-- | test/ChangeLog | 4 | ||||
| -rw-r--r-- | test/automated/fns-tests.el | 31 |
9 files changed, 90 insertions, 64 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 80cdb66425c..c3951a08c0a 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,12 @@ | |||
| 1 | 2014-06-25 Dmitry Antipov <dmantipov@yandex.ru> | ||
| 2 | |||
| 3 | * files.el (dir-locals-find-file, file-relative-name): | ||
| 4 | * info.el (Info-complete-menu-item): | ||
| 5 | * minibuffer.el (completion-table-subvert): Prefer string-prefix-p | ||
| 6 | to compare-strings to avoid out-of-range errors. | ||
| 7 | * subr.el (string-prefix-p): Adjust to match strict range | ||
| 8 | checking in compare-strings. | ||
| 9 | |||
| 1 | 2014-06-24 Leonard Randall <leonard.a.randall@gmail.com> (tiny change) | 10 | 2014-06-24 Leonard Randall <leonard.a.randall@gmail.com> (tiny change) |
| 2 | 11 | ||
| 3 | * textmodes/reftex-parse.el (reftex-using-biblatex-p): Make search | 12 | * textmodes/reftex-parse.el (reftex-using-biblatex-p): Make search |
diff --git a/lisp/files.el b/lisp/files.el index 9017cc96703..65f2009c7ce 100644 --- a/lisp/files.el +++ b/lisp/files.el | |||
| @@ -3659,10 +3659,9 @@ of no valid cache entry." | |||
| 3659 | ;;; (setq locals-file nil)) | 3659 | ;;; (setq locals-file nil)) |
| 3660 | ;; Find the best cached value in `dir-locals-directory-cache'. | 3660 | ;; Find the best cached value in `dir-locals-directory-cache'. |
| 3661 | (dolist (elt dir-locals-directory-cache) | 3661 | (dolist (elt dir-locals-directory-cache) |
| 3662 | (when (and (eq t (compare-strings file nil (length (car elt)) | 3662 | (when (and (string-prefix-p (car elt) file |
| 3663 | (car elt) nil nil | 3663 | (memq system-type |
| 3664 | (memq system-type | 3664 | '(windows-nt cygwin ms-dos))) |
| 3665 | '(windows-nt cygwin ms-dos)))) | ||
| 3666 | (> (length (car elt)) (length (car dir-elt)))) | 3665 | (> (length (car elt)) (length (car dir-elt)))) |
| 3667 | (setq dir-elt elt))) | 3666 | (setq dir-elt elt))) |
| 3668 | (if (and dir-elt | 3667 | (if (and dir-elt |
| @@ -4507,18 +4506,14 @@ on a DOS/Windows machine, it returns FILENAME in expanded form." | |||
| 4507 | (let ((ancestor ".") | 4506 | (let ((ancestor ".") |
| 4508 | (filename-dir (file-name-as-directory filename))) | 4507 | (filename-dir (file-name-as-directory filename))) |
| 4509 | (while (not | 4508 | (while (not |
| 4510 | (or | 4509 | (or (string-prefix-p directory filename-dir fold-case) |
| 4511 | (eq t (compare-strings filename-dir nil (length directory) | 4510 | (string-prefix-p directory filename fold-case))) |
| 4512 | directory nil nil fold-case)) | ||
| 4513 | (eq t (compare-strings filename nil (length directory) | ||
| 4514 | directory nil nil fold-case)))) | ||
| 4515 | (setq directory (file-name-directory (substring directory 0 -1)) | 4511 | (setq directory (file-name-directory (substring directory 0 -1)) |
| 4516 | ancestor (if (equal ancestor ".") | 4512 | ancestor (if (equal ancestor ".") |
| 4517 | ".." | 4513 | ".." |
| 4518 | (concat "../" ancestor)))) | 4514 | (concat "../" ancestor)))) |
| 4519 | ;; Now ancestor is empty, or .., or ../.., etc. | 4515 | ;; Now ancestor is empty, or .., or ../.., etc. |
| 4520 | (if (eq t (compare-strings filename nil (length directory) | 4516 | (if (string-prefix-p directory filename fold-case) |
| 4521 | directory nil nil fold-case)) | ||
| 4522 | ;; We matched within FILENAME's directory part. | 4517 | ;; We matched within FILENAME's directory part. |
| 4523 | ;; Add the rest of FILENAME onto ANCESTOR. | 4518 | ;; Add the rest of FILENAME onto ANCESTOR. |
| 4524 | (let ((rest (substring filename (length directory)))) | 4519 | (let ((rest (substring filename (length directory)))) |
diff --git a/lisp/info.el b/lisp/info.el index 89ca8bdbe33..405d6a22449 100644 --- a/lisp/info.el +++ b/lisp/info.el | |||
| @@ -2691,9 +2691,7 @@ Because of ambiguities, this should be concatenated with something like | |||
| 2691 | (equal (nth 1 Info-complete-cache) Info-current-node) | 2691 | (equal (nth 1 Info-complete-cache) Info-current-node) |
| 2692 | (equal (nth 2 Info-complete-cache) Info-complete-next-re) | 2692 | (equal (nth 2 Info-complete-cache) Info-complete-next-re) |
| 2693 | (equal (nth 5 Info-complete-cache) Info-complete-nodes) | 2693 | (equal (nth 5 Info-complete-cache) Info-complete-nodes) |
| 2694 | (let ((prev (nth 3 Info-complete-cache))) | 2694 | (string-prefix-p (nth 3 Info-complete-cache) string) t) |
| 2695 | (eq t (compare-strings string 0 (length prev) | ||
| 2696 | prev 0 nil t)))) | ||
| 2697 | ;; We can reuse the previous list. | 2695 | ;; We can reuse the previous list. |
| 2698 | (setq completions (nth 4 Info-complete-cache)) | 2696 | (setq completions (nth 4 Info-complete-cache)) |
| 2699 | ;; The cache can't be used. | 2697 | ;; The cache can't be used. |
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index 7b252b4d46d..e7e08342b47 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el | |||
| @@ -244,8 +244,7 @@ The result is a completion table which completes strings of the | |||
| 244 | form (concat S1 S) in the same way as TABLE completes strings of | 244 | form (concat S1 S) in the same way as TABLE completes strings of |
| 245 | the form (concat S2 S)." | 245 | the form (concat S2 S)." |
| 246 | (lambda (string pred action) | 246 | (lambda (string pred action) |
| 247 | (let* ((str (if (eq t (compare-strings string 0 (length s1) s1 nil nil | 247 | (let* ((str (if (string-prefix-p s1 string completion-ignore-case) |
| 248 | completion-ignore-case)) | ||
| 249 | (concat s2 (substring string (length s1))))) | 248 | (concat s2 (substring string (length s1))))) |
| 250 | (res (if str (complete-with-action action table str pred)))) | 249 | (res (if str (complete-with-action action table str pred)))) |
| 251 | (when res | 250 | (when res |
| @@ -257,8 +256,7 @@ the form (concat S2 S)." | |||
| 257 | (+ beg (- (length s1) (length s2)))) | 256 | (+ beg (- (length s1) (length s2)))) |
| 258 | . ,(and (eq (car-safe res) 'boundaries) (cddr res))))) | 257 | . ,(and (eq (car-safe res) 'boundaries) (cddr res))))) |
| 259 | ((stringp res) | 258 | ((stringp res) |
| 260 | (if (eq t (compare-strings res 0 (length s2) s2 nil nil | 259 | (if (string-prefix-p s2 string completion-ignore-case) |
| 261 | completion-ignore-case)) | ||
| 262 | (concat s1 (substring res (length s2))))) | 260 | (concat s1 (substring res (length s2))))) |
| 263 | ((eq action t) | 261 | ((eq action t) |
| 264 | (let ((bounds (completion-boundaries str table pred ""))) | 262 | (let ((bounds (completion-boundaries str table pred ""))) |
diff --git a/lisp/subr.el b/lisp/subr.el index 524b7954b7e..09a085288a5 100644 --- a/lisp/subr.el +++ b/lisp/subr.el | |||
| @@ -3677,12 +3677,14 @@ and replace a sub-expression, e.g. | |||
| 3677 | (setq matches (cons (substring string start l) matches)) ; leftover | 3677 | (setq matches (cons (substring string start l) matches)) ; leftover |
| 3678 | (apply #'concat (nreverse matches))))) | 3678 | (apply #'concat (nreverse matches))))) |
| 3679 | 3679 | ||
| 3680 | (defun string-prefix-p (str1 str2 &optional ignore-case) | 3680 | (defun string-prefix-p (prefix string &optional ignore-case) |
| 3681 | "Return non-nil if STR1 is a prefix of STR2. | 3681 | "Return non-nil if PREFIX is a prefix of STRING. |
| 3682 | If IGNORE-CASE is non-nil, the comparison is done without paying attention | 3682 | If IGNORE-CASE is non-nil, the comparison is done without paying attention |
| 3683 | to case differences." | 3683 | to case differences." |
| 3684 | (eq t (compare-strings str1 nil nil | 3684 | (let ((prefix-length (length prefix))) |
| 3685 | str2 0 (length str1) ignore-case))) | 3685 | (if (> prefix-length (length string)) nil |
| 3686 | (eq t (compare-strings prefix 0 prefix-length string | ||
| 3687 | 0 prefix-length ignore-case))))) | ||
| 3686 | 3688 | ||
| 3687 | (defun string-suffix-p (suffix string &optional ignore-case) | 3689 | (defun string-suffix-p (suffix string &optional ignore-case) |
| 3688 | "Return non-nil if SUFFIX is a suffix of STRING. | 3690 | "Return non-nil if SUFFIX is a suffix of STRING. |
diff --git a/src/ChangeLog b/src/ChangeLog index 9f676a6518d..fc47fbc8978 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,11 @@ | |||
| 1 | 2014-06-25 Dmitry Antipov <dmantipov@yandex.ru> | ||
| 2 | |||
| 3 | Do not allow out-of-range character position in Fcompare_strings. | ||
| 4 | * fns.c (validate_subarray): Add prototype. | ||
| 5 | (Fcompare_substring): Use validate_subarray to check ranges. | ||
| 6 | Adjust comment to mention that the semantics was changed. Also see | ||
| 7 | http://lists.gnu.org/archive/html/emacs-devel/2014-06/msg00447.html. | ||
| 8 | |||
| 1 | 2014-06-24 Paul Eggert <eggert@cs.ucla.edu> | 9 | 2014-06-24 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 10 | ||
| 3 | Be more consistent about the 'Qfoo' naming convention. | 11 | Be more consistent about the 'Qfoo' naming convention. |
| @@ -50,7 +50,9 @@ static Lisp_Object Qcodeset, Qdays, Qmonths, Qpaper; | |||
| 50 | static Lisp_Object Qmd5, Qsha1, Qsha224, Qsha256, Qsha384, Qsha512; | 50 | static Lisp_Object Qmd5, Qsha1, Qsha224, Qsha256, Qsha384, Qsha512; |
| 51 | 51 | ||
| 52 | static bool internal_equal (Lisp_Object, Lisp_Object, int, bool, Lisp_Object); | 52 | static bool internal_equal (Lisp_Object, Lisp_Object, int, bool, Lisp_Object); |
| 53 | 53 | static void validate_subarray (Lisp_Object, Lisp_Object, Lisp_Object, | |
| 54 | ptrdiff_t, EMACS_INT *, EMACS_INT *); | ||
| 55 | |||
| 54 | DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0, | 56 | DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0, |
| 55 | doc: /* Return the argument unchanged. */) | 57 | doc: /* Return the argument unchanged. */) |
| 56 | (Lisp_Object arg) | 58 | (Lisp_Object arg) |
| @@ -232,6 +234,7 @@ string STR1, compare the part between START1 (inclusive) and END1 | |||
| 232 | \(exclusive). If START1 is nil, it defaults to 0, the beginning of | 234 | \(exclusive). If START1 is nil, it defaults to 0, the beginning of |
| 233 | the string; if END1 is nil, it defaults to the length of the string. | 235 | the string; if END1 is nil, it defaults to the length of the string. |
| 234 | Likewise, in string STR2, compare the part between START2 and END2. | 236 | Likewise, in string STR2, compare the part between START2 and END2. |
| 237 | Like in `substring', negative values are counted from the end. | ||
| 235 | 238 | ||
| 236 | The strings are compared by the numeric values of their characters. | 239 | The strings are compared by the numeric values of their characters. |
| 237 | For instance, STR1 is "less than" STR2 if its first differing | 240 | For instance, STR1 is "less than" STR2 if its first differing |
| @@ -244,43 +247,25 @@ If string STR1 is less, the value is a negative number N; | |||
| 244 | - 1 - N is the number of characters that match at the beginning. | 247 | - 1 - N is the number of characters that match at the beginning. |
| 245 | If string STR1 is greater, the value is a positive number N; | 248 | If string STR1 is greater, the value is a positive number N; |
| 246 | N - 1 is the number of characters that match at the beginning. */) | 249 | N - 1 is the number of characters that match at the beginning. */) |
| 247 | (Lisp_Object str1, Lisp_Object start1, Lisp_Object end1, Lisp_Object str2, Lisp_Object start2, Lisp_Object end2, Lisp_Object ignore_case) | 250 | (Lisp_Object str1, Lisp_Object start1, Lisp_Object end1, Lisp_Object str2, |
| 251 | Lisp_Object start2, Lisp_Object end2, Lisp_Object ignore_case) | ||
| 248 | { | 252 | { |
| 249 | register ptrdiff_t end1_char, end2_char; | 253 | EMACS_INT from1, to1, from2, to2; |
| 250 | register ptrdiff_t i1, i1_byte, i2, i2_byte; | 254 | ptrdiff_t i1, i1_byte, i2, i2_byte; |
| 251 | 255 | ||
| 252 | CHECK_STRING (str1); | 256 | CHECK_STRING (str1); |
| 253 | CHECK_STRING (str2); | 257 | CHECK_STRING (str2); |
| 254 | if (NILP (start1)) | 258 | |
| 255 | start1 = make_number (0); | 259 | validate_subarray (str1, start1, end1, SCHARS (str1), &from1, &to1); |
| 256 | if (NILP (start2)) | 260 | validate_subarray (str2, start2, end2, SCHARS (str2), &from2, &to2); |
| 257 | start2 = make_number (0); | 261 | |
| 258 | CHECK_NATNUM (start1); | 262 | i1 = from1; |
| 259 | CHECK_NATNUM (start2); | 263 | i2 = from2; |
| 260 | if (! NILP (end1)) | ||
| 261 | CHECK_NATNUM (end1); | ||
| 262 | if (! NILP (end2)) | ||
| 263 | CHECK_NATNUM (end2); | ||
| 264 | |||
| 265 | end1_char = SCHARS (str1); | ||
| 266 | if (! NILP (end1) && end1_char > XINT (end1)) | ||
| 267 | end1_char = XINT (end1); | ||
| 268 | if (end1_char < XINT (start1)) | ||
| 269 | args_out_of_range (str1, start1); | ||
| 270 | |||
| 271 | end2_char = SCHARS (str2); | ||
| 272 | if (! NILP (end2) && end2_char > XINT (end2)) | ||
| 273 | end2_char = XINT (end2); | ||
| 274 | if (end2_char < XINT (start2)) | ||
| 275 | args_out_of_range (str2, start2); | ||
| 276 | |||
| 277 | i1 = XINT (start1); | ||
| 278 | i2 = XINT (start2); | ||
| 279 | 264 | ||
| 280 | i1_byte = string_char_to_byte (str1, i1); | 265 | i1_byte = string_char_to_byte (str1, i1); |
| 281 | i2_byte = string_char_to_byte (str2, i2); | 266 | i2_byte = string_char_to_byte (str2, i2); |
| 282 | 267 | ||
| 283 | while (i1 < end1_char && i2 < end2_char) | 268 | while (i1 < to1 && i2 < to2) |
| 284 | { | 269 | { |
| 285 | /* When we find a mismatch, we must compare the | 270 | /* When we find a mismatch, we must compare the |
| 286 | characters, not just the bytes. */ | 271 | characters, not just the bytes. */ |
| @@ -307,12 +292,8 @@ If string STR1 is greater, the value is a positive number N; | |||
| 307 | 292 | ||
| 308 | if (! NILP (ignore_case)) | 293 | if (! NILP (ignore_case)) |
| 309 | { | 294 | { |
| 310 | Lisp_Object tem; | 295 | c1 = XINT (Fupcase (make_number (c1))); |
| 311 | 296 | c2 = XINT (Fupcase (make_number (c2))); | |
| 312 | tem = Fupcase (make_number (c1)); | ||
| 313 | c1 = XINT (tem); | ||
| 314 | tem = Fupcase (make_number (c2)); | ||
| 315 | c2 = XINT (tem); | ||
| 316 | } | 297 | } |
| 317 | 298 | ||
| 318 | if (c1 == c2) | 299 | if (c1 == c2) |
| @@ -322,15 +303,15 @@ If string STR1 is greater, the value is a positive number N; | |||
| 322 | past the character that we are comparing; | 303 | past the character that we are comparing; |
| 323 | hence we don't add or subtract 1 here. */ | 304 | hence we don't add or subtract 1 here. */ |
| 324 | if (c1 < c2) | 305 | if (c1 < c2) |
| 325 | return make_number (- i1 + XINT (start1)); | 306 | return make_number (- i1 + from1); |
| 326 | else | 307 | else |
| 327 | return make_number (i1 - XINT (start1)); | 308 | return make_number (i1 - from1); |
| 328 | } | 309 | } |
| 329 | 310 | ||
| 330 | if (i1 < end1_char) | 311 | if (i1 < to1) |
| 331 | return make_number (i1 - XINT (start1) + 1); | 312 | return make_number (i1 - from1 + 1); |
| 332 | if (i2 < end2_char) | 313 | if (i2 < to2) |
| 333 | return make_number (- i1 + XINT (start1) - 1); | 314 | return make_number (- i1 + from1 - 1); |
| 334 | 315 | ||
| 335 | return Qt; | 316 | return Qt; |
| 336 | } | 317 | } |
diff --git a/test/ChangeLog b/test/ChangeLog index 08492dd4c8f..3cb03b9f2f4 100644 --- a/test/ChangeLog +++ b/test/ChangeLog | |||
| @@ -1,3 +1,7 @@ | |||
| 1 | 2014-06-25 Dmitry Antipov <dmantipov@yandex.ru> | ||
| 2 | |||
| 3 | * automated/fns-tests.el (fns-tests-compare-string): New test. | ||
| 4 | |||
| 1 | 2014-06-24 Michael Albinus <michael.albinus@gmx.de> | 5 | 2014-06-24 Michael Albinus <michael.albinus@gmx.de> |
| 2 | 6 | ||
| 3 | * automated/tramp-tests.el (tramp-test26-process-file): Extend test | 7 | * automated/tramp-tests.el (tramp-test26-process-file): Extend test |
diff --git a/test/automated/fns-tests.el b/test/automated/fns-tests.el index 21a9e4536af..461995b602e 100644 --- a/test/automated/fns-tests.el +++ b/test/automated/fns-tests.el | |||
| @@ -69,3 +69,34 @@ | |||
| 69 | (nreverse A) | 69 | (nreverse A) |
| 70 | (should (equal [nil nil nil nil nil t t t t t] (vconcat A))) | 70 | (should (equal [nil nil nil nil nil t t t t t] (vconcat A))) |
| 71 | (should (equal [t t t t t nil nil nil nil nil] (vconcat (nreverse A)))))) | 71 | (should (equal [t t t t t nil nil nil nil nil] (vconcat (nreverse A)))))) |
| 72 | |||
| 73 | (ert-deftest fns-tests-compare-strings () | ||
| 74 | (should-error (compare-strings)) | ||
| 75 | (should-error (compare-strings "xyzzy" "xyzzy")) | ||
| 76 | (should-error (compare-strings "xyzzy" 0 10 "zyxxy" 0 5)) | ||
| 77 | (should-error (compare-strings "xyzzy" 0 5 "zyxxy" -1 2)) | ||
| 78 | (should-error (compare-strings "xyzzy" 'foo nil "zyxxy" 0 1)) | ||
| 79 | (should-error (compare-strings "xyzzy" 0 'foo "zyxxy" 2 3)) | ||
| 80 | (should-error (compare-strings "xyzzy" 0 2 "zyxxy" 'foo 3)) | ||
| 81 | (should-error (compare-strings "xyzzy" nil 3 "zyxxy" 4 'foo)) | ||
| 82 | (should (compare-strings "" nil nil "" nil nil)) | ||
| 83 | (should (compare-strings "" 0 0 "" 0 0)) | ||
| 84 | (should (compare-strings "test" nil nil "test" nil nil)) | ||
| 85 | (should (compare-strings "test" nil nil "test" nil nil t)) | ||
| 86 | (should (compare-strings "test" nil nil "test" nil nil nil)) | ||
| 87 | (should (compare-strings "Test" nil nil "test" nil nil t)) | ||
| 88 | (should (= (compare-strings "Test" nil nil "test" nil nil) -1)) | ||
| 89 | (should (= (compare-strings "Test" nil nil "test" nil nil) -1)) | ||
| 90 | (should (= (compare-strings "test" nil nil "Test" nil nil) 1)) | ||
| 91 | (should (= (compare-strings "foobaz" nil nil "barbaz" nil nil) 1)) | ||
| 92 | (should (= (compare-strings "barbaz" nil nil "foobar" nil nil) -1)) | ||
| 93 | (should (= (compare-strings "foobaz" nil nil "farbaz" nil nil) 2)) | ||
| 94 | (should (= (compare-strings "farbaz" nil nil "foobar" nil nil) -2)) | ||
| 95 | (should (compare-strings "abcxyz" 0 2 "abcprq" 0 2)) | ||
| 96 | (should (compare-strings "abcxyz" 0 -3 "abcprq" 0 -3)) | ||
| 97 | (should (= (compare-strings "abcxyz" 0 6 "abcprq" 0 6) 4)) | ||
| 98 | (should (= (compare-strings "abcprq" 0 6 "abcxyz" 0 6) -4)) | ||
| 99 | (should (compare-strings "xyzzy" -3 4 "azza" -3 3)) | ||
| 100 | (should (compare-strings "こんにちはコンニチハ" nil nil "こんにちはコンニチハ" nil nil)) | ||
| 101 | (should (= (compare-strings "んにちはコンニチハこ" nil nil "こんにちはコンニチハ" nil nil) 1)) | ||
| 102 | (should (= (compare-strings "こんにちはコンニチハ" nil nil "んにちはコンニチハこ" nil nil) -1))) | ||