Skip to content

Commit 8e5b909

Browse files
committed
Introduce case_character function
Move single-character casing logic into a separate function so that it is collected in a single place. This will make future changes to the logic easier. This commit introduces no functionality changes. * src/casefiddle.c (struct casing_context, prepare_casing_context): New sturcture for saving casing context and function to initialise it. (case_character): New function which cases character base on provided context. (do_casify_integer, do_casify_multibyte_string, do_casify_unibyte_string, casify_object, casify_region): Convert to use casing_context and case_character.
1 parent ec2d002 commit 8e5b909

File tree

1 file changed

+76
-58
lines changed

1 file changed

+76
-58
lines changed

src/casefiddle.c

Lines changed: 76 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,55 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
3030
#include "keymap.h"
3131

3232
enum case_action {CASE_UP, CASE_DOWN, CASE_CAPITALIZE, CASE_CAPITALIZE_UP};
33+
34+
/* State for casing individual characters. */
35+
struct casing_context {
36+
/* User-requested action. */
37+
enum case_action flag;
38+
/* If true, function operates on a buffer as opposed to a string or character.
39+
When run on a buffer, syntax_prefix_flag_p is taken into account when
40+
determined inword flag. */
41+
bool inbuffer;
42+
/* Conceptually, this denotes whether we are inside of a word except
43+
that if flag is CASE_UP it’s always false and if flag is CASE_DOWN
44+
this is always true. */
45+
bool inword;
46+
};
47+
48+
/* Initialise CTX structure for casing characters. */
49+
static void
50+
prepare_casing_context (struct casing_context *ctx,
51+
enum case_action flag, bool inbuffer)
52+
{
53+
ctx->flag = flag;
54+
ctx->inbuffer = inbuffer;
55+
ctx->inword = flag == CASE_DOWN;
56+
57+
/* If the case table is flagged as modified, rescan it. */
58+
if (NILP (XCHAR_TABLE (BVAR (current_buffer, downcase_table))->extras[1]))
59+
Fset_case_table (BVAR (current_buffer, downcase_table));
60+
61+
if (inbuffer && (int) flag >= (int) CASE_CAPITALIZE)
62+
SETUP_BUFFER_SYNTAX_TABLE (); /* For syntax_prefix_flag_p. */
63+
}
64+
65+
/* Based on CTX, case character CH accordingly. Update CTX as necessary.
66+
Return cased character. */
67+
static int
68+
case_character (struct casing_context *ctx, int ch)
69+
{
70+
if (ctx->inword)
71+
ch = ctx->flag == CASE_CAPITALIZE_UP ? ch : downcase (ch);
72+
else
73+
ch = upcase(ch);
74+
if ((int) ctx->flag >= (int) CASE_CAPITALIZE)
75+
ctx->inword = SYNTAX (ch) == Sword &&
76+
(!ctx->inbuffer || ctx->inword || !syntax_prefix_flag_p (ch));
77+
return ch;
78+
}
3379

3480
static Lisp_Object
35-
do_casify_natnum (enum case_action flag, Lisp_Object obj)
81+
do_casify_natnum (struct casing_context *ctx, Lisp_Object obj)
3682
{
3783
int flagbits = (CHAR_ALT | CHAR_SUPER | CHAR_HYPER
3884
| CHAR_SHIFT | CHAR_CTL | CHAR_META);
@@ -55,7 +101,7 @@ do_casify_natnum (enum case_action flag, Lisp_Object obj)
55101
|| !NILP (BVAR (current_buffer, enable_multibyte_characters));
56102
if (! multibyte)
57103
MAKE_CHAR_MULTIBYTE (ch);
58-
cased = flag == CASE_DOWN ? downcase (ch) : upcase (ch);
104+
cased = case_character (ctx, ch);
59105
if (cased == ch)
60106
return obj;
61107

@@ -66,10 +112,9 @@ do_casify_natnum (enum case_action flag, Lisp_Object obj)
66112
}
67113

68114
static Lisp_Object
69-
do_casify_multibyte_string (enum case_action flag, Lisp_Object obj)
115+
do_casify_multibyte_string (struct casing_context *ctx, Lisp_Object obj)
70116
{
71117
ptrdiff_t i, i_byte, size = SCHARS (obj);
72-
bool inword = flag == CASE_DOWN;
73118
int len, ch, cased;
74119
USE_SAFE_ALLOCA;
75120
ptrdiff_t o_size;
@@ -83,14 +128,7 @@ do_casify_multibyte_string (enum case_action flag, Lisp_Object obj)
83128
if (o_size - MAX_MULTIBYTE_LENGTH < o - dst)
84129
string_overflow ();
85130
ch = STRING_CHAR_AND_LENGTH (SDATA (obj) + i_byte, len);
86-
if (inword && flag != CASE_CAPITALIZE_UP)
87-
cased = downcase (ch);
88-
else if (!inword || flag != CASE_CAPITALIZE_UP)
89-
cased = upcase (ch);
90-
else
91-
cased = ch;
92-
if ((int) flag >= (int) CASE_CAPITALIZE)
93-
inword = (SYNTAX (ch) == Sword);
131+
cased = case_character (ctx, ch);
94132
o += CHAR_STRING (cased, o);
95133
}
96134
eassert (o - dst <= o_size);
@@ -100,52 +138,43 @@ do_casify_multibyte_string (enum case_action flag, Lisp_Object obj)
100138
}
101139

102140
static Lisp_Object
103-
do_casify_unibyte_string (enum case_action flag, Lisp_Object obj)
141+
do_casify_unibyte_string (struct casing_context *ctx, Lisp_Object obj)
104142
{
105143
ptrdiff_t i, size = SCHARS (obj);
106-
bool inword = flag == CASE_DOWN;
107144
int ch, cased;
108145

109146
obj = Fcopy_sequence (obj);
110147
for (i = 0; i < size; i++)
111148
{
112149
ch = SREF (obj, i);
113150
MAKE_CHAR_MULTIBYTE (ch);
114-
cased = ch;
115-
if (inword && flag != CASE_CAPITALIZE_UP)
116-
ch = downcase (ch);
117-
else if (!uppercasep (ch)
118-
&& (!inword || flag != CASE_CAPITALIZE_UP))
119-
ch = upcase (cased);
120-
if ((int) flag >= (int) CASE_CAPITALIZE)
121-
inword = (SYNTAX (ch) == Sword);
151+
cased = case_character (ctx, ch);
122152
if (ch == cased)
123153
continue;
124-
MAKE_CHAR_UNIBYTE (ch);
154+
MAKE_CHAR_UNIBYTE (cased);
125155
/* If the char can't be converted to a valid byte, just don't change it */
126-
if (ch >= 0 && ch < 256)
127-
SSET (obj, i, ch);
156+
if (cased >= 0 && cased < 256)
157+
SSET (obj, i, cased);
128158
}
129159
return obj;
130160
}
131161

132162
static Lisp_Object
133163
casify_object (enum case_action flag, Lisp_Object obj)
134164
{
135-
/* If the case table is flagged as modified, rescan it. */
136-
if (NILP (XCHAR_TABLE (BVAR (current_buffer, downcase_table))->extras[1]))
137-
Fset_case_table (BVAR (current_buffer, downcase_table));
165+
struct casing_context ctx;
166+
prepare_casing_context (&ctx, flag, false);
138167

139168
if (NATNUMP (obj))
140-
return do_casify_natnum (flag, obj);
169+
return do_casify_natnum (&ctx, obj);
141170
else if (!STRINGP (obj))
142171
wrong_type_argument (Qchar_or_string_p, obj);
143172
else if (!SCHARS (obj))
144173
return obj;
145174
else if (STRING_MULTIBYTE (obj))
146-
return do_casify_multibyte_string (flag, obj);
175+
return do_casify_multibyte_string (&ctx, obj);
147176
else
148-
return do_casify_unibyte_string (flag, obj);
177+
return do_casify_unibyte_string (&ctx, obj);
149178
}
150179

151180
DEFUN ("upcase", Fupcase, Supcase, 1, 1, 0,
@@ -196,8 +225,6 @@ The argument object is not altered--the value is a copy. */)
196225
static void
197226
casify_region (enum case_action flag, Lisp_Object b, Lisp_Object e)
198227
{
199-
int c;
200-
bool inword = flag == CASE_DOWN;
201228
bool multibyte = !NILP (BVAR (current_buffer, enable_multibyte_characters));
202229
ptrdiff_t start, end;
203230
ptrdiff_t start_byte;
@@ -208,66 +235,57 @@ casify_region (enum case_action flag, Lisp_Object b, Lisp_Object e)
208235
ptrdiff_t opoint = PT;
209236
ptrdiff_t opoint_byte = PT_BYTE;
210237

238+
struct casing_context ctx;
239+
211240
if (EQ (b, e))
212241
/* Not modifying because nothing marked */
213242
return;
214243

215-
/* If the case table is flagged as modified, rescan it. */
216-
if (NILP (XCHAR_TABLE (BVAR (current_buffer, downcase_table))->extras[1]))
217-
Fset_case_table (BVAR (current_buffer, downcase_table));
218-
219244
validate_region (&b, &e);
220245
start = XFASTINT (b);
221246
end = XFASTINT (e);
222247
modify_text (start, end);
223248
record_change (start, end - start);
224249
start_byte = CHAR_TO_BYTE (start);
225250

226-
SETUP_BUFFER_SYNTAX_TABLE (); /* For syntax_prefix_flag_p. */
251+
prepare_casing_context (&ctx, flag, true);
227252

228253
while (start < end)
229254
{
230-
int c2, len;
255+
int ch, cased, len;
231256

232257
if (multibyte)
233258
{
234-
c = FETCH_MULTIBYTE_CHAR (start_byte);
235-
len = CHAR_BYTES (c);
259+
ch = FETCH_MULTIBYTE_CHAR (start_byte);
260+
len = CHAR_BYTES (ch);
236261
}
237262
else
238263
{
239-
c = FETCH_BYTE (start_byte);
240-
MAKE_CHAR_MULTIBYTE (c);
264+
ch = FETCH_BYTE (start_byte);
265+
MAKE_CHAR_MULTIBYTE (ch);
241266
len = 1;
242267
}
243-
c2 = c;
244-
if (inword && flag != CASE_CAPITALIZE_UP)
245-
c = downcase (c);
246-
else if (!inword || flag != CASE_CAPITALIZE_UP)
247-
c = upcase (c);
248-
if ((int) flag >= (int) CASE_CAPITALIZE)
249-
inword = ((SYNTAX (c) == Sword)
250-
&& (inword || !syntax_prefix_flag_p (c)));
251-
if (c != c2)
268+
cased = case_character (&ctx, ch);
269+
if (ch != cased)
252270
{
253271
last = start;
254272
if (first < 0)
255273
first = start;
256274

257275
if (! multibyte)
258276
{
259-
MAKE_CHAR_UNIBYTE (c);
260-
FETCH_BYTE (start_byte) = c;
277+
MAKE_CHAR_UNIBYTE (cased);
278+
FETCH_BYTE (start_byte) = cased;
261279
}
262-
else if (ASCII_CHAR_P (c2) && ASCII_CHAR_P (c))
263-
FETCH_BYTE (start_byte) = c;
280+
else if (ASCII_CHAR_P (cased) && ASCII_CHAR_P (ch))
281+
FETCH_BYTE (start_byte) = cased;
264282
else
265283
{
266-
int tolen = CHAR_BYTES (c);
284+
int tolen = CHAR_BYTES (cased);
267285
int j;
268286
unsigned char str[MAX_MULTIBYTE_LENGTH];
269287

270-
CHAR_STRING (c, str);
288+
CHAR_STRING (cased, str);
271289
if (len == tolen)
272290
{
273291
/* Length is unchanged. */

0 commit comments

Comments
 (0)