X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/821ff7208c4a8fb4b12a0ea8039006d2b2e57463..9d6b4d53469a9ffd67bd770fabc6fe254e35c21d:/src/cmds.c diff --git a/src/cmds.c b/src/cmds.c index c079ad7168..225c26b082 100644 --- a/src/cmds.c +++ b/src/cmds.c @@ -1,6 +1,6 @@ /* Simple built-in editing commands. -Copyright (C) 1985, 1993-1998, 2001-2011 Free Software Foundation, Inc. +Copyright (C) 1985, 1993-1998, 2001-2012 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -47,6 +47,41 @@ DEFUN ("forward-point", Fforward_point, Sforward_point, 1, 1, 0, return make_number (PT + XINT (n)); } +/* Add N to point; or subtract N if FORWARD is zero. N defaults to 1. + Validate the new location. Return nil. */ +static Lisp_Object +move_point (Lisp_Object n, int forward) +{ + /* This used to just set point to point + XINT (n), and then check + to see if it was within boundaries. But now that SET_PT can + potentially do a lot of stuff (calling entering and exiting + hooks, etcetera), that's not a good approach. So we validate the + proposed position, then set point. */ + + EMACS_INT new_point; + + if (NILP (n)) + XSETFASTINT (n, 1); + else + CHECK_NUMBER (n); + + new_point = PT + (forward ? XINT (n) : - XINT (n)); + + if (new_point < BEGV) + { + SET_PT (BEGV); + xsignal0 (Qbeginning_of_buffer); + } + if (new_point > ZV) + { + SET_PT (ZV); + xsignal0 (Qend_of_buffer); + } + + SET_PT (new_point); + return Qnil; +} + DEFUN ("forward-char", Fforward_char, Sforward_char, 0, 1, "^p", doc: /* Move point N characters forward (backward if N is negative). On reaching end or beginning of buffer, stop and signal error. @@ -56,34 +91,7 @@ right or to the left on the screen. This is in contrast with \\[right-char], which see. */) (Lisp_Object n) { - if (NILP (n)) - XSETFASTINT (n, 1); - else - CHECK_NUMBER (n); - - /* This used to just set point to point + XINT (n), and then check - to see if it was within boundaries. But now that SET_PT can - potentially do a lot of stuff (calling entering and exiting - hooks, etcetera), that's not a good approach. So we validate the - proposed position, then set point. */ - { - EMACS_INT new_point = PT + XINT (n); - - if (new_point < BEGV) - { - SET_PT (BEGV); - xsignal0 (Qbeginning_of_buffer); - } - if (new_point > ZV) - { - SET_PT (ZV); - xsignal0 (Qend_of_buffer); - } - - SET_PT (new_point); - } - - return Qnil; + return move_point (n, 1); } DEFUN ("backward-char", Fbackward_char, Sbackward_char, 0, 1, "^p", @@ -95,13 +103,7 @@ right or to the left on the screen. This is in contrast with \\[left-char], which see. */) (Lisp_Object n) { - if (NILP (n)) - XSETFASTINT (n, 1); - else - CHECK_NUMBER (n); - - XSETINT (n, - XINT (n)); - return Fforward_char (n); + return move_point (n, 0); } DEFUN ("forward-line", Fforward_line, Sforward_line, 0, 1, "^p", @@ -115,8 +117,8 @@ With positive N, a non-empty line at the end counts as one line successfully moved (for the return value). */) (Lisp_Object n) { - EMACS_INT opoint = PT, opoint_byte = PT_BYTE; - EMACS_INT pos, pos_byte; + ptrdiff_t opoint = PT, opoint_byte = PT_BYTE; + ptrdiff_t pos, pos_byte; EMACS_INT count, shortage; if (NILP (n)) @@ -187,7 +189,7 @@ not move. To ignore field boundaries bind `inhibit-field-text-motion' to t. */) (Lisp_Object n) { - EMACS_INT newpos; + ptrdiff_t newpos; if (NILP (n)) XSETFASTINT (n, 1); @@ -303,7 +305,7 @@ At the end, it runs `post-self-insert-hook'. */) bitch_at_user (); { int character = translate_char (Vtranslation_table_for_input, - (int) XINT (last_command_event)); + XINT (last_command_event)); int val = internal_self_insert (character, XFASTINT (n)); if (val == 2) nonundocount = 0; @@ -333,8 +335,8 @@ internal_self_insert (int c, EMACS_INT n) int len; /* Working buffer and pointer for multi-byte form of C. */ unsigned char str[MAX_MULTIBYTE_LENGTH]; - EMACS_INT chars_to_delete = 0; - EMACS_INT spaces_to_insert = 0; + ptrdiff_t chars_to_delete = 0; + ptrdiff_t spaces_to_insert = 0; overwrite = BVAR (current_buffer, overwrite_mode); if (!NILP (Vbefore_change_functions) || !NILP (Vafter_change_functions)) @@ -371,50 +373,53 @@ internal_self_insert (int c, EMACS_INT n) /* This is the character after point. */ int c2 = FETCH_CHAR (PT_BYTE); + int cwidth; + /* Overwriting in binary-mode always replaces C2 by C. Overwriting in textual-mode doesn't always do that. It inserts newlines in the usual way, and inserts any character at end of line or before a tab if it doesn't use the whole width of the tab. */ if (EQ (overwrite, Qoverwrite_mode_binary)) - chars_to_delete = n; - else if (c != '\n' && c2 != '\n') + chars_to_delete = min (n, PTRDIFF_MAX); + else if (c != '\n' && c2 != '\n' + && (cwidth = XFASTINT (Fchar_width (make_number (c)))) != 0) { - EMACS_INT pos = PT; - EMACS_INT pos_byte = PT_BYTE; + ptrdiff_t pos = PT; + ptrdiff_t pos_byte = PT_BYTE; + ptrdiff_t curcol = current_column (); - /* FIXME: Check for integer overflow when calculating - target_clm and actual_clm. */ - - /* Column the cursor should be placed at after this insertion. - The correct value should be calculated only when necessary. */ - EMACS_INT target_clm = (current_column () - + n * XINT (Fchar_width (make_number (c)))); - - /* The actual cursor position after the trial of moving - to column TARGET_CLM. It is greater than TARGET_CLM - if the TARGET_CLM is middle of multi-column - character. In that case, the new point is set after - that character. */ - EMACS_INT actual_clm - = XFASTINT (Fmove_to_column (make_number (target_clm), Qnil)); - - chars_to_delete = PT - pos; - - if (actual_clm > target_clm) + if (n <= (min (MOST_POSITIVE_FIXNUM, PTRDIFF_MAX) - curcol) / cwidth) { - /* We will delete too many columns. Let's fill columns - by spaces so that the remaining text won't move. */ - EMACS_INT actual = PT_BYTE; - DEC_POS (actual); - if (FETCH_CHAR (actual) == '\t') - /* Rather than add spaces, let's just keep the tab. */ - chars_to_delete--; - else - spaces_to_insert = actual_clm - target_clm; + /* Column the cursor should be placed at after this insertion. + The value should be calculated only when necessary. */ + ptrdiff_t target_clm = curcol + n * cwidth; + + /* The actual cursor position after the trial of moving + to column TARGET_CLM. It is greater than TARGET_CLM + if the TARGET_CLM is middle of multi-column + character. In that case, the new point is set after + that character. */ + ptrdiff_t actual_clm + = XFASTINT (Fmove_to_column (make_number (target_clm), Qnil)); + + chars_to_delete = PT - pos; + + if (actual_clm > target_clm) + { + /* We will delete too many columns. Let's fill columns + by spaces so that the remaining text won't move. */ + ptrdiff_t actual = PT_BYTE; + DEC_POS (actual); + if (FETCH_CHAR (actual) == '\t') + /* Rather than add spaces, let's just keep the tab. */ + chars_to_delete--; + else + spaces_to_insert = actual_clm - target_clm; + } + + SET_PT_BOTH (pos, pos_byte); } - - SET_PT_BOTH (pos, pos_byte); } hairy = 2; } @@ -472,7 +477,7 @@ internal_self_insert (int c, EMACS_INT n) { USE_SAFE_ALLOCA; char *strn, *p; - SAFE_ALLOCA (strn, char *, n * len); + SAFE_NALLOCA (strn, len, n); for (p = strn; n > 0; n--, p += len) memcpy (p, str, len); insert_and_inherit (strn, p - strn);