X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/b6bd159922608fa474026837771d63bf7eadcf97..a4b0cca119b01dc55bad802ef696c857fe014482:/src/cmds.c diff --git a/src/cmds.c b/src/cmds.c index 5a155ac77a..453a4b67e5 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. @@ -19,11 +19,11 @@ along with GNU Emacs. If not, see . */ #include -#include + #include "lisp.h" #include "commands.h" -#include "buffer.h" #include "character.h" +#include "buffer.h" #include "syntax.h" #include "window.h" #include "keyboard.h" @@ -47,61 +47,65 @@ 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 false. N defaults to 1. + Validate the new location. Return nil. */ +static Lisp_Object +move_point (Lisp_Object n, bool 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. +Interactively, N is the numeric prefix argument. Depending on the bidirectional context, the movement may be to the 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", doc: /* Move point N characters backward (forward if N is negative). On attempt to pass beginning or end of buffer, stop and signal error. +Interactively, N is the numeric prefix argument. Depending on the bidirectional context, the movement may be to the 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 +119,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 +191,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); @@ -275,7 +279,7 @@ After insertion, the value of `auto-fill-function' is called if the At the end, it runs `post-self-insert-hook'. */) (Lisp_Object n) { - int remove_boundary = 1; + bool remove_boundary = 1; CHECK_NATNUM (n); if (!EQ (Vthis_command, KVAR (current_kboard, Vlast_command))) @@ -294,16 +298,19 @@ At the end, it runs `post-self-insert-hook'. */) if (remove_boundary && CONSP (BVAR (current_buffer, undo_list)) - && NILP (XCAR (BVAR (current_buffer, undo_list)))) + && NILP (XCAR (BVAR (current_buffer, undo_list))) + /* Only remove auto-added boundaries, not boundaries + added be explicit calls to undo-boundary. */ + && EQ (BVAR (current_buffer, undo_list), last_undo_boundary)) /* Remove the undo_boundary that was just pushed. */ - BVAR (current_buffer, undo_list) = XCDR (BVAR (current_buffer, undo_list)); + bset_undo_list (current_buffer, XCDR (BVAR (current_buffer, undo_list))); /* Barf if the key that invoked this was not a character. */ if (!CHARACTERP (last_command_event)) 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 +340,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 +378,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; - - /* 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)))); + ptrdiff_t pos = PT; + ptrdiff_t pos_byte = PT_BYTE; + ptrdiff_t curcol = current_column (); - /* 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; } @@ -430,7 +440,7 @@ internal_self_insert (int c, EMACS_INT n) : UNIBYTE_TO_CHAR (XFASTINT (Fprevious_char ()))) == Sword)) { - int modiff = MODIFF; + EMACS_INT modiff = MODIFF; Lisp_Object sym; sym = call0 (Qexpand_abbrev); @@ -438,7 +448,8 @@ internal_self_insert (int c, EMACS_INT n) /* If we expanded an abbrev which has a hook, and the hook has a non-nil `no-self-insert' property, return right away--don't really self-insert. */ - if (SYMBOLP (sym) && ! NILP (sym) && ! NILP (XSYMBOL (sym)->function) + if (SYMBOLP (sym) && ! NILP (sym) + && ! NILP (XSYMBOL (sym)->function) && SYMBOLP (XSYMBOL (sym)->function)) { Lisp_Object prop;