aboutsummaryrefslogtreecommitdiffstats
path: root/src/casefiddle.c
diff options
context:
space:
mode:
authorStefan Monnier2008-03-24 19:42:12 +0000
committerStefan Monnier2008-03-24 19:42:12 +0000
commit438eba3c1edc5da3b8cbbc5d227264a0e5bd81e6 (patch)
treeffade7d393c3cf40826a26bc3287416b93bb88fa /src/casefiddle.c
parent89e2d47661a46e8bbfb2f3d39300860d48381c78 (diff)
downloademacs-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.c77
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
125DEFUN ("upcase", Fupcase, Supcase, 1, 1, 0, 148DEFUN ("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
332Lisp_Object 355static Lisp_Object
333operate_on_word (arg, newpoint) 356operate_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);