diff options
| author | Stefan Monnier | 2008-03-24 19:42:12 +0000 |
|---|---|---|
| committer | Stefan Monnier | 2008-03-24 19:42:12 +0000 |
| commit | 438eba3c1edc5da3b8cbbc5d227264a0e5bd81e6 (patch) | |
| tree | ffade7d393c3cf40826a26bc3287416b93bb88fa /src/casefiddle.c | |
| parent | 89e2d47661a46e8bbfb2f3d39300860d48381c78 (diff) | |
| download | emacs-438eba3c1edc5da3b8cbbc5d227264a0e5bd81e6.tar.gz emacs-438eba3c1edc5da3b8cbbc5d227264a0e5bd81e6.zip | |
(casify_object): Avoid pathological N^2 worst case if
every char is changed and has a different byte-length.
(Fupcase_word, Fdowncase_word, Fcapitalize_word, operate_on_word):
Fix int -> EMACS_INT.
Diffstat (limited to 'src/casefiddle.c')
| -rw-r--r-- | src/casefiddle.c | 77 |
1 files changed, 50 insertions, 27 deletions
diff --git a/src/casefiddle.c b/src/casefiddle.c index 650e046a266..316a56b639f 100644 --- a/src/casefiddle.c +++ b/src/casefiddle.c | |||
| @@ -75,23 +75,18 @@ casify_object (flag, obj) | |||
| 75 | return obj; | 75 | return obj; |
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | if (STRINGP (obj)) | 78 | if (!STRINGP (obj)) |
| 79 | wrong_type_argument (Qchar_or_string_p, obj); | ||
| 80 | else if (!STRING_MULTIBYTE (obj)) | ||
| 79 | { | 81 | { |
| 80 | int multibyte = STRING_MULTIBYTE (obj); | 82 | EMACS_INT i; |
| 81 | int i, i_byte, len; | 83 | EMACS_INT size = SCHARS (obj); |
| 82 | int size = SCHARS (obj); | ||
| 83 | 84 | ||
| 84 | obj = Fcopy_sequence (obj); | 85 | obj = Fcopy_sequence (obj); |
| 85 | for (i = i_byte = 0; i < size; i++, i_byte += len) | 86 | for (i = 0; i < size; i++) |
| 86 | { | 87 | { |
| 87 | if (multibyte) | 88 | c = SREF (obj, i); |
| 88 | c = STRING_CHAR_AND_LENGTH (SDATA (obj) + i_byte, 0, len); | ||
| 89 | else | ||
| 90 | { | ||
| 91 | c = SREF (obj, i_byte); | ||
| 92 | len = 1; | ||
| 93 | MAKE_CHAR_MULTIBYTE (c); | 89 | MAKE_CHAR_MULTIBYTE (c); |
| 94 | } | ||
| 95 | c1 = c; | 90 | c1 = c; |
| 96 | if (inword && flag != CASE_CAPITALIZE_UP) | 91 | if (inword && flag != CASE_CAPITALIZE_UP) |
| 97 | c = DOWNCASE (c); | 92 | c = DOWNCASE (c); |
| @@ -102,24 +97,52 @@ casify_object (flag, obj) | |||
| 102 | inword = (SYNTAX (c) == Sword); | 97 | inword = (SYNTAX (c) == Sword); |
| 103 | if (c != c1) | 98 | if (c != c1) |
| 104 | { | 99 | { |
| 105 | if (! multibyte) | ||
| 106 | { | ||
| 107 | MAKE_CHAR_UNIBYTE (c); | 100 | MAKE_CHAR_UNIBYTE (c); |
| 108 | SSET (obj, i_byte, c); | 101 | /* If the char can't be converted to a valid byte, just don't |
| 102 | change it. */ | ||
| 103 | if (c >= 0 && c < 256) | ||
| 104 | SSET (obj, i, c); | ||
| 105 | } | ||
| 106 | } | ||
| 107 | return obj; | ||
| 109 | } | 108 | } |
| 110 | else if (ASCII_CHAR_P (c1) && ASCII_CHAR_P (c)) | ||
| 111 | SSET (obj, i_byte, c); | ||
| 112 | else | 109 | else |
| 113 | { | 110 | { |
| 114 | Faset (obj, make_number (i), make_number (c)); | 111 | EMACS_INT i, i_byte, len; |
| 115 | i_byte += CHAR_BYTES (c) - len; | 112 | EMACS_INT size = SCHARS (obj); |
| 116 | } | 113 | USE_SAFE_ALLOCA; |
| 114 | unsigned char *dst, *o; | ||
| 115 | /* Over-allocate by 12%: this is a minor overhead, but should be | ||
| 116 | sufficient in 99.999% of the cases to avoid a reallocation. */ | ||
| 117 | EMACS_INT o_size = SBYTES (obj) + SBYTES (obj) / 8 + MAX_MULTIBYTE_LENGTH; | ||
| 118 | SAFE_ALLOCA (dst, void *, o_size); | ||
| 119 | o = dst; | ||
| 120 | |||
| 121 | for (i = i_byte = 0; i < size; i++, i_byte += len) | ||
| 122 | { | ||
| 123 | if ((o - dst) + MAX_MULTIBYTE_LENGTH > o_size) | ||
| 124 | { /* Not enough space for the next char: grow the destination. */ | ||
| 125 | unsigned char *old_dst = dst; | ||
| 126 | o_size += o_size; /* Probably overkill, but extremely rare. */ | ||
| 127 | SAFE_ALLOCA (dst, void *, o_size); | ||
| 128 | bcopy (old_dst, dst, o - old_dst); | ||
| 129 | o = dst + (o - old_dst); | ||
| 117 | } | 130 | } |
| 131 | c = STRING_CHAR_AND_LENGTH (SDATA (obj) + i_byte, 0, len); | ||
| 132 | if (inword && flag != CASE_CAPITALIZE_UP) | ||
| 133 | c = DOWNCASE (c); | ||
| 134 | else if (!UPPERCASEP (c) | ||
| 135 | && (!inword || flag != CASE_CAPITALIZE_UP)) | ||
| 136 | c = UPCASE1 (c); | ||
| 137 | if ((int) flag >= (int) CASE_CAPITALIZE) | ||
| 138 | inword = (SYNTAX (c) == Sword); | ||
| 139 | o += CHAR_STRING (c, o); | ||
| 118 | } | 140 | } |
| 141 | eassert (o - dst <= o_size); | ||
| 142 | obj = make_multibyte_string (dst, size, o - dst); | ||
| 143 | SAFE_FREE (); | ||
| 119 | return obj; | 144 | return obj; |
| 120 | } | 145 | } |
| 121 | |||
| 122 | wrong_type_argument (Qchar_or_string_p, obj); | ||
| 123 | } | 146 | } |
| 124 | 147 | ||
| 125 | DEFUN ("upcase", Fupcase, Supcase, 1, 1, 0, | 148 | DEFUN ("upcase", Fupcase, Supcase, 1, 1, 0, |
| @@ -329,10 +352,10 @@ character positions to operate on. */) | |||
| 329 | return Qnil; | 352 | return Qnil; |
| 330 | } | 353 | } |
| 331 | 354 | ||
| 332 | Lisp_Object | 355 | static Lisp_Object |
| 333 | operate_on_word (arg, newpoint) | 356 | operate_on_word (arg, newpoint) |
| 334 | Lisp_Object arg; | 357 | Lisp_Object arg; |
| 335 | int *newpoint; | 358 | EMACS_INT *newpoint; |
| 336 | { | 359 | { |
| 337 | Lisp_Object val; | 360 | Lisp_Object val; |
| 338 | int farend; | 361 | int farend; |
| @@ -358,7 +381,7 @@ See also `capitalize-word'. */) | |||
| 358 | Lisp_Object arg; | 381 | Lisp_Object arg; |
| 359 | { | 382 | { |
| 360 | Lisp_Object beg, end; | 383 | Lisp_Object beg, end; |
| 361 | int newpoint; | 384 | EMACS_INT newpoint; |
| 362 | XSETFASTINT (beg, PT); | 385 | XSETFASTINT (beg, PT); |
| 363 | end = operate_on_word (arg, &newpoint); | 386 | end = operate_on_word (arg, &newpoint); |
| 364 | casify_region (CASE_UP, beg, end); | 387 | casify_region (CASE_UP, beg, end); |
| @@ -373,7 +396,7 @@ With negative argument, convert previous words but do not move. */) | |||
| 373 | Lisp_Object arg; | 396 | Lisp_Object arg; |
| 374 | { | 397 | { |
| 375 | Lisp_Object beg, end; | 398 | Lisp_Object beg, end; |
| 376 | int newpoint; | 399 | EMACS_INT newpoint; |
| 377 | XSETFASTINT (beg, PT); | 400 | XSETFASTINT (beg, PT); |
| 378 | end = operate_on_word (arg, &newpoint); | 401 | end = operate_on_word (arg, &newpoint); |
| 379 | casify_region (CASE_DOWN, beg, end); | 402 | casify_region (CASE_DOWN, beg, end); |
| @@ -390,7 +413,7 @@ With negative argument, capitalize previous words but do not move. */) | |||
| 390 | Lisp_Object arg; | 413 | Lisp_Object arg; |
| 391 | { | 414 | { |
| 392 | Lisp_Object beg, end; | 415 | Lisp_Object beg, end; |
| 393 | int newpoint; | 416 | EMACS_INT newpoint; |
| 394 | XSETFASTINT (beg, PT); | 417 | XSETFASTINT (beg, PT); |
| 395 | end = operate_on_word (arg, &newpoint); | 418 | end = operate_on_word (arg, &newpoint); |
| 396 | casify_region (CASE_CAPITALIZE, beg, end); | 419 | casify_region (CASE_CAPITALIZE, beg, end); |