Now on revision 111187. ------------------------------------------------------------ revno: 111187 committer: Eli Zaretskii branch nick: trunk timestamp: Tue 2012-12-11 09:49:06 +0200 message: Fix a typo in lisp/makefile.w32-in. See http://lists.gnu.org/archive/html/emacs-devel/2012-12/msg00288.html for the details. lisp/makefile.w32-in (compile4-SH): Fix a typo that caused term subdirectory be skipped. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2012-12-11 04:44:26 +0000 +++ lisp/ChangeLog 2012-12-11 07:49:06 +0000 @@ -1,3 +1,8 @@ +2012-12-11 Eli Zaretskii + + * makefile.w32-in (compile4-SH): Fix a typo that caused term + subdirectory be skipped. + 2012-12-11 Glenn Morris * net/rcirc.el (rcirc-urls, rcirc-condition-filter): Doc fixes. === modified file 'lisp/makefile.w32-in' --- lisp/makefile.w32-in 2012-12-09 21:32:12 +0000 +++ lisp/makefile.w32-in 2012-12-11 07:49:06 +0000 @@ -387,7 +387,7 @@ done compile4-SH: autoloads compile0-SH - for dir in $(WINS_BASIC4) $(WINS_CEDET) terms obsolete; do \ + for dir in $(WINS_BASIC4) $(WINS_CEDET) term obsolete; do \ for el in $$dir/*.el; do \ if test -f $$el; \ then \ ------------------------------------------------------------ revno: 111186 committer: Dmitry Antipov branch nick: trunk timestamp: Tue 2012-12-11 10:08:53 +0400 message: Consistently use marker_position and marker_byte_position. * fringe.c (Ffringe_bitmaps_at_pos): * indent.c (Fvertical_motion): * insdel.c (prepare_to_modify_buffer): * keyboard.c (make_lispy_position): * window.c (Fwindow_end, Fpos_visible_in_window_p, unshow_buffer) (window_scroll_pixel_based, displayed_window_lines) (Fset_window_configuration): * xdisp.c (message_dolog, with_echo_area_buffer_unwind_data) (mark_window_display_accurate_1, redisplay_window, decode_mode_spec): Replace direct access to marker fields with calls to marker_position and/or marker_byte_position. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2012-12-11 02:06:53 +0000 +++ src/ChangeLog 2012-12-11 06:08:53 +0000 @@ -1,3 +1,18 @@ +2012-12-11 Dmitry Antipov + + Consistently use marker_position and marker_byte_position. + * fringe.c (Ffringe_bitmaps_at_pos): + * indent.c (Fvertical_motion): + * insdel.c (prepare_to_modify_buffer): + * keyboard.c (make_lispy_position): + * window.c (Fwindow_end, Fpos_visible_in_window_p, unshow_buffer) + (window_scroll_pixel_based, displayed_window_lines) + (Fset_window_configuration): + * xdisp.c (message_dolog, with_echo_area_buffer_unwind_data) + (mark_window_display_accurate_1, redisplay_window, decode_mode_spec): + Replace direct access to marker fields with calls + to marker_position and/or marker_byte_position. + 2012-12-11 Juanma Barranquero * makefile.w32-in (SIG2STR_H): New macro. === modified file 'src/fringe.c' --- src/fringe.c 2012-11-02 10:34:26 +0000 +++ src/fringe.c 2012-12-11 06:08:53 +0000 @@ -1744,7 +1744,7 @@ else if (w == XWINDOW (selected_window)) textpos = PT; else - textpos = XMARKER (w->pointm)->charpos; + textpos = marker_position (w->pointm); row = MATRIX_FIRST_TEXT_ROW (w->current_matrix); row = row_containing_pos (w, textpos, row, NULL, 0); === modified file 'src/indent.c' --- src/indent.c 2012-12-10 02:00:42 +0000 +++ src/indent.c 2012-12-11 06:08:53 +0000 @@ -1991,8 +1991,8 @@ { /* Set the window's buffer temporarily to the current buffer. */ old_buffer = w->buffer; - old_charpos = XMARKER (w->pointm)->charpos; - old_bytepos = XMARKER (w->pointm)->bytepos; + old_charpos = marker_position (w->pointm); + old_bytepos = marker_byte_position (w->pointm); wset_buffer (w, Fcurrent_buffer ()); set_marker_both (w->pointm, w->buffer, BUF_PT (current_buffer), BUF_PT_BYTE (current_buffer)); === modified file 'src/insdel.c' --- src/insdel.c 2012-12-03 14:13:06 +0000 +++ src/insdel.c 2012-12-11 06:08:53 +0000 @@ -1854,7 +1854,7 @@ : (!NILP (Vselect_active_regions) && !NILP (Vtransient_mark_mode)))) { - ptrdiff_t b = XMARKER (BVAR (current_buffer, mark))->charpos; + ptrdiff_t b = marker_position (BVAR (current_buffer, mark)); ptrdiff_t e = PT; if (b < e) Vsaved_region_selection = make_buffer_string (b, e, 0); === modified file 'src/keyboard.c' --- src/keyboard.c 2012-12-10 20:46:20 +0000 +++ src/keyboard.c 2012-12-11 06:08:53 +0000 @@ -5138,7 +5138,7 @@ string_info = Fcons (string, make_number (charpos)); textpos = (w == XWINDOW (selected_window) && current_buffer == XBUFFER (w->buffer)) - ? PT : XMARKER (w->pointm)->charpos; + ? PT : marker_position (w->pointm); xret = wx; yret = wy; === modified file 'src/window.c' --- src/window.c 2012-12-10 17:34:47 +0000 +++ src/window.c 2012-12-11 06:08:53 +0000 @@ -1492,6 +1492,7 @@ && !noninteractive) { struct text_pos startp; + ptrdiff_t charpos = marker_position (w->start); struct it it; struct buffer *old_buffer = NULL; void *itdata = NULL; @@ -1509,9 +1510,9 @@ `-l' containing a call to `rmail' with subsequent other commands. At the end, W->start happened to be BEG, while rmail had already narrowed the buffer. */ - if (XMARKER (w->start)->charpos < BEGV) + if (charpos < BEGV) SET_TEXT_POS (startp, BEGV, BEGV_BYTE); - else if (XMARKER (w->start)->charpos > ZV) + else if (charpos > ZV) SET_TEXT_POS (startp, ZV, ZV_BYTE); else SET_TEXT_POS_FROM_MARKER (startp, w->start); @@ -1634,7 +1635,7 @@ else if (w == XWINDOW (selected_window)) posint = PT; else - posint = XMARKER (w->pointm)->charpos; + posint = marker_position (w->pointm); /* If position is above window start or outside buffer boundaries, or if window start is out of range, position is not visible. */ @@ -1980,7 +1981,7 @@ && EQ (buf, XWINDOW (BVAR (b, last_selected_window))->buffer))) temp_set_point_both (b, clip_to_bounds (BUF_BEGV (b), - XMARKER (w->pointm)->charpos, + marker_position (w->pointm), BUF_ZV (b)), clip_to_bounds (BUF_BEGV_BYTE (b), marker_byte_position (w->pointm), @@ -4616,7 +4617,7 @@ /* Set the window start, and set up the window for redisplay. */ set_marker_restricted (w->start, make_number (pos), w->buffer); - bytepos = XMARKER (w->start)->bytepos; + bytepos = marker_byte_position (w->start); w->start_at_line_beg = (pos == BEGV || FETCH_BYTE (bytepos - 1) == '\n'); w->update_mode_line = 1; w->last_modified = 0; @@ -5116,6 +5117,7 @@ { struct it it; struct text_pos start; + ptrdiff_t charpos = marker_position (w->start); int height = window_box_height (w); struct buffer *old_buffer; int bottom_y; @@ -5132,9 +5134,9 @@ /* In case W->start is out of the accessible range, do something reasonable. This happens in Info mode when Info-scroll-down calls (recenter -1) while W->start is 1. */ - if (XMARKER (w->start)->charpos < BEGV) + if (charpos < BEGV) SET_TEXT_POS (start, BEGV, BEGV_BYTE); - else if (XMARKER (w->start)->charpos > ZV) + else if (charpos > ZV) SET_TEXT_POS (start, ZV, ZV_BYTE); else SET_TEXT_POS_FROM_MARKER (start, w->start); @@ -5562,7 +5564,7 @@ && WINDOWP (selected_window) && EQ (XWINDOW (selected_window)->buffer, new_current_buffer) && !EQ (selected_window, data->current_window)) - old_point = XMARKER (XWINDOW (data->current_window)->pointm)->charpos; + old_point = marker_position (XWINDOW (data->current_window)->pointm); else old_point = PT; else @@ -5577,7 +5579,7 @@ if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer) /* If current_window = selected_window, its point is in BUF_PT. */ && !EQ (selected_window, data->current_window)) - old_point = XMARKER (XWINDOW (data->current_window)->pointm)->charpos; + old_point = marker_position (XWINDOW (data->current_window)->pointm); else old_point = BUF_PT (XBUFFER (new_current_buffer)); } === modified file 'src/xdisp.c' --- src/xdisp.c 2012-12-10 17:34:47 +0000 +++ src/xdisp.c 2012-12-11 06:08:53 +0000 @@ -9495,7 +9495,7 @@ del_range_both (BEG, BEG_BYTE, PT, PT_BYTE, 0); } } - BEGV = XMARKER (oldbegv)->charpos; + BEGV = marker_position (oldbegv); BEGV_BYTE = marker_byte_position (oldbegv); if (zv_at_end) @@ -9505,7 +9505,7 @@ } else { - ZV = XMARKER (oldzv)->charpos; + ZV = marker_position (oldzv); ZV_BYTE = marker_byte_position (oldzv); } @@ -9514,8 +9514,8 @@ else /* We can't do Fgoto_char (oldpoint) because it will run some Lisp code. */ - TEMP_SET_PT_BOTH (XMARKER (oldpoint)->charpos, - XMARKER (oldpoint)->bytepos); + TEMP_SET_PT_BOTH (marker_position (oldpoint), + marker_byte_position (oldpoint)); UNGCPRO; unchain_marker (XMARKER (oldpoint)); @@ -10087,8 +10087,8 @@ { XSETWINDOW (tmp, w); ASET (vector, i, tmp); ++i; ASET (vector, i, w->buffer); ++i; - ASET (vector, i, make_number (XMARKER (w->pointm)->charpos)); ++i; - ASET (vector, i, make_number (XMARKER (w->pointm)->bytepos)); ++i; + ASET (vector, i, make_number (marker_position (w->pointm))); ++i; + ASET (vector, i, make_number (marker_byte_position (w->pointm))); ++i; } else { @@ -13801,7 +13801,7 @@ if (w == XWINDOW (selected_window)) w->last_point = BUF_PT (b); else - w->last_point = XMARKER (w->pointm)->charpos; + w->last_point = marker_position (w->pointm); } } @@ -15562,7 +15562,7 @@ window, set up appropriate value. */ if (!EQ (window, selected_window)) { - ptrdiff_t new_pt = XMARKER (w->pointm)->charpos; + ptrdiff_t new_pt = marker_position (w->pointm); ptrdiff_t new_pt_byte = marker_byte_position (w->pointm); if (new_pt < BEGV) { @@ -21526,7 +21526,7 @@ if (mode_line_target == MODE_LINE_TITLE) return ""; - startpos = XMARKER (w->start)->charpos; + startpos = marker_position (w->start); startpos_byte = marker_byte_position (w->start); height = WINDOW_TOTAL_LINES (w); ------------------------------------------------------------ revno: 111185 committer: Glenn Morris branch nick: trunk timestamp: Mon 2012-12-10 20:44:26 -0800 message: * lisp/net/rcirc.el (rcirc-urls, rcirc-condition-filter): Doc fixes. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2012-12-11 04:42:49 +0000 +++ lisp/ChangeLog 2012-12-11 04:44:26 +0000 @@ -1,5 +1,7 @@ 2012-12-11 Glenn Morris + * net/rcirc.el (rcirc-urls, rcirc-condition-filter): Doc fixes. + * progmodes/f90.el (f90-line-continued, f90-indent-region): Treat preprocessor lines embedded in continuations like comments. (f90-indent-line): Special-case preprocessor lines. (Bug#13138) === modified file 'lisp/net/rcirc.el' --- lisp/net/rcirc.el 2012-12-05 16:45:37 +0000 +++ lisp/net/rcirc.el 2012-12-11 04:44:26 +0000 @@ -406,8 +406,7 @@ "The channel or user associated with this buffer.") (defvar rcirc-urls nil - "List of URLs seen in the current buffer and the position in -the buffer where the URL starts.") + "List of URLs seen in the current buffer and their start positions.") (put 'rcirc-urls 'permanent-local t) (defvar rcirc-timeout-seconds 600 @@ -2393,9 +2392,11 @@ "\\)") "Regexp matching URLs. Set to nil to disable URL features in rcirc.") +;; cf cl-remove-if-not (defun rcirc-condition-filter (condp lst) - "Given a condition and a list, returns the list with elements -that do not satisfy the condition removed." + "Remove all items not satisfying condition CONDP in list LST. +CONDP is a function that takes a list element as argument and returns +non-nil if that element should be included. Returns a new list." (delq nil (mapcar (lambda (x) (and (funcall condp x) x)) lst))) (defun rcirc-browse-url (&optional arg) ------------------------------------------------------------ revno: 111184 fixes bug: http://debbugs.gnu.org/13138 committer: Glenn Morris branch nick: trunk timestamp: Mon 2012-12-10 20:42:49 -0800 message: Fix for indentation of f90 preproc lines embedded in continuations * lisp/progmodes/f90.el (f90-line-continued, f90-indent-region): Treat preprocessor lines embedded in continuations like comments. (f90-indent-line): Special-case preprocessor lines. * test/automated/f90.el (f90-test-bug13138): New test. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2012-12-11 02:29:21 +0000 +++ lisp/ChangeLog 2012-12-11 04:42:49 +0000 @@ -1,3 +1,9 @@ +2012-12-11 Glenn Morris + + * progmodes/f90.el (f90-line-continued, f90-indent-region): + Treat preprocessor lines embedded in continuations like comments. + (f90-indent-line): Special-case preprocessor lines. (Bug#13138) + 2012-12-11 Jay Belanger * calc/calc.el (calc-standard-date-formats): Add more date === modified file 'lisp/progmodes/f90.el' --- lisp/progmodes/f90.el 2012-09-17 05:41:04 +0000 +++ lisp/progmodes/f90.el 2012-12-11 04:42:49 +0000 @@ -1178,11 +1178,11 @@ (defsubst f90-line-continued () "Return t if the current line is a continued one. -This includes comment lines embedded in continued lines, but -not the last line of a continued statement." +This includes comment or preprocessor lines embedded in continued lines, +but not the last line of a continued statement." (save-excursion (beginning-of-line) - (while (and (looking-at "[ \t]*\\(!\\|$\\)") (zerop (forward-line -1)))) + (while (and (looking-at "[ \t]*\\([!#]\\|$\\)") (zerop (forward-line -1)))) (end-of-line) (while (f90-in-comment) (search-backward "!" (line-beginning-position)) @@ -1832,11 +1832,15 @@ (f90-indent-line-no) (setq no-line-number t) (skip-chars-forward " \t")) - (if (looking-at "!") - (setq indent (f90-comment-indent)) - (and f90-smart-end (looking-at "end") - (f90-match-end)) - (setq indent (f90-calculate-indent))) + ;; FIXME This means f90-calculate-indent gives different answers + ;; for comments and preprocessor lines to this function. + ;; Better to make f90-calculate-indent return the correct answer? + (cond ((looking-at "!") (setq indent (f90-comment-indent))) + ((looking-at "#") (setq indent 0)) + (t + (and f90-smart-end (looking-at "end") + (f90-match-end)) + (setq indent (f90-calculate-indent)))) (or (= indent (current-column)) (f90-indent-to indent no-line-number)) ;; If initial point was within line's indentation, @@ -1973,12 +1977,13 @@ (f90-indent-to ind-curr)) (while (and (f90-line-continued) (zerop (forward-line 1)) (< (point) end-region-mark)) - (if (looking-at "[ \t]*!") - (f90-indent-to (f90-comment-indent)) - (or (= (current-indentation) - (+ ind-curr f90-continuation-indent)) - (f90-indent-to - (+ ind-curr f90-continuation-indent) 'no-line-no))))) + (cond ((looking-at "[ \t]*#") (f90-indent-to 0)) + ((looking-at "[ \t]*!") (f90-indent-to (f90-comment-indent))) + (t + (or (= (current-indentation) + (+ ind-curr f90-continuation-indent)) + (f90-indent-to + (+ ind-curr f90-continuation-indent) 'no-line-no)))))) ;; Restore point, etc. (setq f90-cache-position nil) (goto-char save-point) === modified file 'test/ChangeLog' --- test/ChangeLog 2012-12-10 11:17:21 +0000 +++ test/ChangeLog 2012-12-11 04:42:49 +0000 @@ -1,3 +1,7 @@ +2012-12-11 Glenn Morris + + * automated/f90.el (f90-test-bug13138): New test. + 2012-12-10 Rüdiger Sonderfeld * automated/inotify-test.el: New test. === modified file 'test/automated/f90.el' --- test/automated/f90.el 2012-01-05 09:46:05 +0000 +++ test/automated/f90.el 2012-12-11 04:42:49 +0000 @@ -154,5 +154,23 @@ (f90-indent-line) (should (= 0 (current-indentation))))) +(ert-deftest f90-test-bug13138 () + "Test for http://debbugs.gnu.org/13138 ." + (with-temp-buffer + (f90-mode) + (insert "program prog + integer :: i = & +#ifdef foo + & 1 +#else + & 2 +#endif + + write(*,*) i +end program prog") + (goto-char (point-min)) + (forward-line 2) + (f90-indent-subprogram) + (should (= 0 (current-indentation))))) ;;; f90.el ends here ------------------------------------------------------------ revno: 111183 committer: Jay Belanger branch nick: trunk timestamp: Mon 2012-12-10 20:37:36 -0600 message: * lisp/calc/calc-forms.el (calc-date-notation): Fix typo. diff: === modified file 'lisp/calc/calc-forms.el' --- lisp/calc/calc-forms.el 2012-12-11 02:29:21 +0000 +++ lisp/calc/calc-forms.el 2012-12-11 02:37:36 +0000 @@ -82,7 +82,7 @@ (calc-wrapper (if (string-match-p "\\`\\s-*\\'" fmt) (setq fmt "1")) - (if (string-match "\\` \\(*[0-9]\\|10\\|11\\) *\\'" fmt) + (if (string-match "\\` *\\([0-9]\\|10\\|11\\) *\\'" fmt) (setq fmt (nth (string-to-number fmt) calc-standard-date-formats))) (or (string-match "[a-zA-Z]" fmt) (error "Bad date format specifier")) ------------------------------------------------------------ revno: 111182 committer: Jay Belanger branch nick: trunk timestamp: Mon 2012-12-10 20:29:21 -0600 message: * lisp/calc/calc.el (calc-standard-date-formats): Add more date formats. * lisp/calc/calc-forms.el (math-parse-iso-date): New function. (math-parse-date): Use `math-parse-iso-date' when appropriate. (math-parse-iso-date-validate): Add extra error checking. (calc-date-notation): Add ability to access new date formats. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2012-12-10 21:26:13 +0000 +++ lisp/ChangeLog 2012-12-11 02:29:21 +0000 @@ -1,3 +1,12 @@ +2012-12-11 Jay Belanger + + * calc/calc.el (calc-standard-date-formats): Add more date + formats. + * calc/calc-forms.el (math-parse-iso-date): New function. + (math-parse-date): Use `math-parse-iso-date' when appropriate. + (math-parse-iso-date-validate): Add extra error checking. + (calc-date-notation): Add ability to access new date formats. + 2012-12-10 Stefan Monnier * hi-lock.el (hi-lock--regexps-at-point): Fix boundary case for === modified file 'lisp/calc/calc-forms.el' --- lisp/calc/calc-forms.el 2012-12-03 04:46:49 +0000 +++ lisp/calc/calc-forms.el 2012-12-11 02:29:21 +0000 @@ -82,13 +82,13 @@ (calc-wrapper (if (string-match-p "\\`\\s-*\\'" fmt) (setq fmt "1")) - (if (string-match "\\` *[0-9] *\\'" fmt) + (if (string-match "\\` \\(*[0-9]\\|10\\|11\\) *\\'" fmt) (setq fmt (nth (string-to-number fmt) calc-standard-date-formats))) (or (string-match "[a-zA-Z]" fmt) (error "Bad date format specifier")) (and arg (>= (setq arg (prefix-numeric-value arg)) 0) - (<= arg 9) + (<= arg 11) (setq calc-standard-date-formats (copy-sequence calc-standard-date-formats)) (setcar (nthcdr arg calc-standard-date-formats) fmt)) @@ -918,6 +918,8 @@ (catch 'syntax (or (math-parse-standard-date math-pd-str t) (math-parse-standard-date math-pd-str nil) + (and (or (memq 'IYYY calc-date-format) (memq 'Iww calc-date-format)) + (math-parse-iso-date math-pd-str)) (and (string-match "\\`[^-+/0-9a-zA-Z]*\\([-+]?[0-9]+\\.?[0-9]*\\([eE][-+]?[0-9]+\\)?\\)[^-+/0-9a-zA-Z]*\\'" math-pd-str) (list 'date (math-read-number (math-match-substring math-pd-str 1)))) (let ((case-fold-search t) @@ -1085,6 +1087,8 @@ (defun math-parse-iso-date-validate (isoyear isoweek isoweekday hour minute second) (if (or (< isoweek 1) (> isoweek 53)) (throw 'syntax "Week value is out of range")) + (if (or (< isoweekday 1) (> isoweekday 7)) + (throw 'syntax "Weekday value is out of range")) (and hour (progn (if (or (< hour 0) (> hour 23)) @@ -1290,6 +1294,31 @@ (setq day (math-add day (1- yearday)))) day)))))) +(defun math-parse-iso-date (math-pd-str) + "Parse MATH-PD-STR as an ISO week date, or return nil." + (let ((case-fold-search t) + (isoyear nil) (isoweek nil) (isoweekday nil) + (hour nil) (minute nil) (second nil)) + ;; Extract the time, if any. + (if (string-match "T[^0-9]*\\([0-9][0-9]\\)[^0-9]*\\([0-9][0-9]\\)?[^0-9]*\\([0-9][0-9]\\(\\.[0-9]+\\)?\\)?" math-pd-str) + (progn + (setq hour (string-to-number (math-match-substring math-pd-str 1)) + minute (math-match-substring math-pd-str 2) + second (math-match-substring math-pd-str 3) + math-pd-str (substring math-pd-str 0 (match-beginning 0))) + (if (equal minute "") + (setq minute 0) + (setq minute (string-to-number minute))) + (if (equal second "") + (setq second 0) + (setq second (math-read-number second))))) + ;; Next, the year, week and weekday + (if (string-match "\\(-?[0-9]*\\)[^0-9]*W\\([0-9][0-9]\\)[^0-9]*\\([0-9]\\)[^0-9]*\\'" math-pd-str) + (progn + (setq isoyear (string-to-number (math-match-substring math-pd-str 1)) + isoweek (string-to-number (math-match-substring math-pd-str 2)) + isoweekday (string-to-number (math-match-substring math-pd-str 3))) + (math-parse-iso-date-validate isoyear isoweek isoweekday hour minute second))))) (defun calcFunc-now (&optional zone) (let ((date (let ((calc-date-format nil)) === modified file 'lisp/calc/calc.el' --- lisp/calc/calc.el 2012-11-22 08:09:03 +0000 +++ lisp/calc/calc.el 2012-12-11 02:29:21 +0000 @@ -787,7 +787,9 @@ "M-D-Y< H:mm:SSpp>" "D-M-Y< h:mm:SS>" "j<, h:mm:SS>" - "YYddd< hh:mm:ss>")) + "YYddd< hh:mm:ss>" + "ZYYY-MM-DD Www< hh:mm>" + "IYYY-Iww-w< Thh:mm:ss>")) (defcalcmodevar calc-autorange-units nil "If non-nil, automatically set unit prefixes to keep units in a reasonable range.") ------------------------------------------------------------ revno: 111181 committer: Juanma Barranquero branch nick: trunk timestamp: Tue 2012-12-11 03:06:53 +0100 message: (lib-src,src,lib)/makefile.w32-in: Update dependencies. diff: === modified file 'ChangeLog' --- ChangeLog 2012-12-10 20:55:02 +0000 +++ ChangeLog 2012-12-11 02:06:53 +0000 @@ -1,3 +1,8 @@ +2012-12-11 Juanma Barranquero + + * lib/makefile.w32-in (SIG2STR_H): New macro. + ($(BLD)/sig2str.$(O)): Update dependencies. + 2012-12-10 Paul Eggert * configure.ac (HAVE_INOTIFY): Speed up configure-time test. === modified file 'lib-src/ChangeLog' --- lib-src/ChangeLog 2012-12-10 13:25:17 +0000 +++ lib-src/ChangeLog 2012-12-11 02:06:53 +0000 @@ -1,3 +1,7 @@ +2012-12-11 Juanma Barranquero + + * makefile.w32-in (SYSWAIT_H): Update dependencies. + 2012-12-10 Eli Zaretskii * makefile.w32-in (obj): Add w32notify.o. Add missing X and Unix === modified file 'lib-src/makefile.w32-in' --- lib-src/makefile.w32-in 2012-12-10 13:25:17 +0000 +++ lib-src/makefile.w32-in 2012-12-11 02:06:53 +0000 @@ -378,6 +378,7 @@ $(NT_INC)/sys/time.h \ $(GNU_LIB)/timespec.h SYSWAIT_H = $(SRC)/syswait.h \ + $(NT_INC)/stdbool.h \ $(NT_INC)/sys/wait.h $(BLD)/ctags.$(O) : \ === modified file 'lib/makefile.w32-in' --- lib/makefile.w32-in 2012-12-08 09:57:43 +0000 +++ lib/makefile.w32-in 2012-12-11 02:06:53 +0000 @@ -103,6 +103,8 @@ $(NT_INC)/stdint.h SHA512_H = $(GNU_LIB)/sha512.h \ $(U64_H) +SIG2STR_H = $(GNU_LIB)/sig2str.h \ + $(GNU_LIB)/intprops.h STAT_TIME_H = $(GNU_LIB)/stat-time.h \ $(NT_INC)/sys/stat.h @@ -243,8 +245,7 @@ $(BLD)/sig2str.$(O) : \ $(GNU_LIB)/sig2str.c \ $(CONFIG_H) \ - $(GNU_LIB)/sig2str.h \ - $(GNU_LIB)/intprops.h + $(SIG2STR_H) # The following dependencies are for supporting parallel builds, where === modified file 'src/ChangeLog' --- src/ChangeLog 2012-12-10 20:46:20 +0000 +++ src/ChangeLog 2012-12-11 02:06:53 +0000 @@ -1,3 +1,9 @@ +2012-12-11 Juanma Barranquero + + * makefile.w32-in (SIG2STR_H): New macro. + (SYSWAIT_H, $(BLD)/emacs.$(O), $(BLD)/process.$(O)) + ($(BLD)/w32notify.$(O)): Update dependencies. + 2012-12-10 Daniel Colascione * w32term.c, keyboard.c: Fix build break in cygw32 by omitting === modified file 'src/makefile.w32-in' --- src/makefile.w32-in 2012-12-10 12:08:02 +0000 +++ src/makefile.w32-in 2012-12-11 02:06:53 +0000 @@ -462,6 +462,8 @@ $(NT_INC)/stdint.h SHA512_H = $(GNU_LIB)/sha512.h \ $(U64_H) +SIG2STR_H = $(GNU_LIB)/sig2str.h \ + $(GNU_LIB)/intprops.h SOCKET_H = $(NT_INC)/sys/socket.h \ $(SRC)/w32.h STAT_TIME_H = $(GNU_LIB)/stat-time.h \ @@ -472,6 +474,7 @@ $(NT_INC)/sys/ioctl.h \ $(NT_INC)/unistd.h SYSWAIT_H = $(SRC)/syswait.h \ + $(NT_INC)/stdbool.h \ $(NT_INC)/sys/wait.h TERMHOOKS_H = $(SRC)/termhooks.h \ $(SYSTIME_H) @@ -800,6 +803,7 @@ $(SRC)/keymap.h \ $(SRC)/unexec.h \ $(SRC)/w32.h \ + $(SRC)/w32common.h \ $(SRC)/w32heap.h \ $(SRC)/w32select.h \ $(NT_INC)/sys/file.h \ @@ -1288,11 +1292,13 @@ $(CHARACTER_H) \ $(CODING_H) \ $(CONFIG_H) \ + $(C_CTYPE_H) \ $(DISPEXTERN_H) \ $(FRAME_H) \ $(KEYBOARD_H) \ $(LISP_H) \ $(PROCESS_H) \ + $(SIG2STR_H) \ $(SOCKET_H) \ $(SYSSIGNAL_H) \ $(SYSTIME_H) \ @@ -1696,6 +1702,7 @@ $(BLD)/w32notify.$(O) : \ $(SRC)/w32notify.c \ + $(SRC)/w32.h \ $(SRC)/w32common.h \ $(CODING_H) \ $(CONFIG_H) \ ------------------------------------------------------------ revno: 111180 committer: Juanma Barranquero branch nick: trunk timestamp: Tue 2012-12-11 02:35:28 +0100 message: nt/config.nt: Sync with autogen/config.in. (HAVE_DECL_UNSETENV, HAVE_SIG2STR, VOID_UNSETENV): New macros. (ULIMIT_BREAK_VALUE): Remove. diff: === modified file 'nt/ChangeLog' --- nt/ChangeLog 2012-12-10 17:52:35 +0000 +++ nt/ChangeLog 2012-12-11 01:35:28 +0000 @@ -1,3 +1,9 @@ +2012-12-11 Juanma Barranquero + + * config.nt: Sync with autogen/config.in. + (HAVE_DECL_UNSETENV, HAVE_SIG2STR, VOID_UNSETENV): New macros. + (ULIMIT_BREAK_VALUE): Remove. + 2012-12-10 Daniel Colascione * emacs.rc: Use forward slashes in relative paths in order to === modified file 'nt/config.nt' --- nt/config.nt 2012-12-08 11:32:10 +0000 +++ nt/config.nt 2012-12-11 01:35:28 +0000 @@ -325,6 +325,10 @@ */ #define HAVE_DECL_TZNAME 1 +/* Define to 1 if you have the declaration of `unsetenv', and to 0 if you + don't. */ +#undef HAVE_DECL_UNSETENV + /* Define to 1 if you have the declaration of `__fpending', and to 0 if you don't. */ #undef HAVE_DECL___FPENDING @@ -790,6 +794,9 @@ /* Define to 1 if you have the `shutdown' function. */ #define HAVE_SHUTDOWN 1 +/* Define to 1 if you have the `sig2str' function. */ +#undef HAVE_SIG2STR + /* Define to 1 if 'sig_atomic_t' is a signed integer type. */ #undef HAVE_SIGNED_SIG_ATOMIC_T @@ -990,12 +997,12 @@ /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 +/* Define to 1 if you have the `unsetenv' function. */ +#define HAVE_UNSETENV 1 + /* Define to 1 if the system has the type 'unsigned long long int'. */ #undef HAVE_UNSIGNED_LONG_LONG_INT -/* Define to 1 if you have the `unsetenv' function. */ -#define HAVE_UNSETENV 1 - /* Define to 1 if you have the header file. */ #undef HAVE_UTIL_H @@ -1338,9 +1345,6 @@ timespec. */ #undef TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC -/* Undocumented. */ -#undef ULIMIT_BREAK_VALUE - /* Define to 1 for Encore UMAX. */ #undef UMAX @@ -1397,6 +1401,9 @@ /* Version number of package */ #define VERSION "24.3.50" +/* Define to 1 if unsetenv returns void instead of int. */ +#undef VOID_UNSETENV + /* Define to l, ll, u, ul, ull, etc., as suitable for constants of type 'wchar_t'. */ #undef WCHAR_T_SUFFIX ------------------------------------------------------------ revno: 111179 committer: Paul Eggert branch nick: trunk timestamp: Mon 2012-12-10 16:13:44 -0800 message: * internals.texi (C Integer Types): New section. This follows up and records an email in . diff: === modified file 'doc/lispref/ChangeLog' --- doc/lispref/ChangeLog 2012-12-10 02:00:42 +0000 +++ doc/lispref/ChangeLog 2012-12-11 00:13:44 +0000 @@ -1,3 +1,9 @@ +2012-12-11 Paul Eggert + + * internals.texi (C Integer Types): New section. + This follows up and records an email in + . + 2012-12-10 Stefan Monnier * control.texi (Pattern maching case statement): New node. === modified file 'doc/lispref/internals.texi' --- doc/lispref/internals.texi 2012-12-07 02:37:20 +0000 +++ doc/lispref/internals.texi 2012-12-11 00:13:44 +0000 @@ -16,6 +16,7 @@ * Memory Usage:: Info about total size of Lisp objects made so far. * Writing Emacs Primitives:: Writing C code for Emacs. * Object Internals:: Data formats of buffers, windows, processes. +* C Integer Types:: How C integer types are used inside Emacs. @end menu @node Building Emacs @@ -1531,4 +1532,91 @@ @end table +@node C Integer Types +@section C Integer Types +@cindex integer types (C programming language) + +Here are some guidelines for use of integer types in the Emacs C +source code. These guidelines sometimes give competing advice; common +sense is advised. + +@itemize @bullet +@item +Avoid arbitrary limits. For example, avoid @code{int len = strlen +(s);} unless the length of @code{s} is required for other reasons to +fit in @code{int} range. + +@item +Do not assume that signed integer arithmetic wraps around on overflow. +This is no longer true of Emacs porting targets: signed integer +overflow has undefined behavior in practice, and can dump core or +even cause earlier or later code to behave ``illogically''. Unsigned +overflow does wrap around reliably, modulo a power of two. + +@item +Prefer signed types to unsigned, as code gets confusing when signed +and unsigned types are combined. Many other guidelines assume that +types are signed; in the rarer cases where unsigned types are needed, +similar advice may apply to the unsigned counterparts (e.g., +@code{size_t} instead of @code{ptrdiff_t}, or @code{uintptr_t} instead +of @code{intptr_t}). + +@item +Prefer @code{int} for Emacs character codes, in the range 0 ..@: 0x3FFFFF. + +@item +Prefer @code{ptrdiff_t} for sizes, i.e., for integers bounded by the +maximum size of any individual C object or by the maximum number of +elements in any C array. This is part of Emacs's general preference +for signed types. Using @code{ptrdiff_t} limits objects to +@code{PTRDIFF_MAX} bytes, but larger objects would cause trouble +anyway since they would break pointer subtraction, so this does not +impose an arbitrary limit. + +@item +Prefer @code{intptr_t} for internal representations of pointers, or +for integers bounded only by the number of objects that can exist at +any given time or by the total number of bytes that can be allocated. +Currently Emacs sometimes uses other types when @code{intptr_t} would +be better; fixing this is lower priority, as the code works as-is on +Emacs's current porting targets. + +@item +Prefer the Emacs-defined type @code{EMACS_INT} for representing values +converted to or from Emacs Lisp fixnums, as fixnum arithmetic is based +on @code{EMACS_INT}. + +@item +When representing a system value (such as a file size or a count of +seconds since the Epoch), prefer the corresponding system type (e.g., +@code{off_t}, @code{time_t}). Do not assume that a system type is +signed, unless this assumption is known to be safe. For example, +although @code{off_t} is always signed, @code{time_t} need not be. + +@item +Prefer the Emacs-defined type @code{printmax_t} for representing +values that might be any signed integer value that can be printed, +using a @code{printf}-family function. + +@item +Prefer @code{intmax_t} for representing values that might be any +signed integer value. + +@item +In bitfields, prefer @code{unsigned int} or @code{signed int} to +@code{int}, as @code{int} is less portable: it might be signed, and +might not be. Single-bit bit fields are invariably @code{unsigned +int} so that their values are 0 and 1. + +@item +In C, Emacs commonly uses @code{bool}, 1, and 0 for boolean values. +Using @code{bool} for booleans can make programs easier to read and a +bit faster than using @code{int}. Although it is also OK to use +@code{int}, this older style is gradually being phased out. When +using @code{bool}, respect the limitations of the replacement +implementation of @code{bool}, as documented in the source file +@file{lib/stdbool.in.h}, so that Emacs remains portable to pre-C99 +platforms. +@end itemize + @c FIXME Mention src/globals.h somewhere in this file? ------------------------------------------------------------ revno: 111178 committer: Stefan Monnier branch nick: trunk timestamp: Mon 2012-12-10 16:26:13 -0500 message: * lisp/hi-lock.el (hi-lock--regexps-at-point): Fix boundary case for font-lock as well as when there's no text-property. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2012-12-10 18:33:59 +0000 +++ lisp/ChangeLog 2012-12-10 21:26:13 +0000 @@ -1,3 +1,8 @@ +2012-12-10 Stefan Monnier + + * hi-lock.el (hi-lock--regexps-at-point): Fix boundary case for + font-lock as well as when there's no text-property. + 2012-12-10 Jambunathan K * hi-lock.el: Refine the choice of default face. === modified file 'lisp/hi-lock.el' --- lisp/hi-lock.el 2012-12-10 18:33:59 +0000 +++ lisp/hi-lock.el 2012-12-10 21:26:13 +0000 @@ -474,19 +474,33 @@ (let ((regexp (get-char-property (point) 'hi-lock-overlay-regexp))) (when regexp (push regexp regexps))) ;; With font-locking on, check if the cursor is on a highlighted text. - (and (memq (face-at-point) - (mapcar #'hi-lock-keyword->face hi-lock-interactive-patterns)) - (let* ((hi-text - (buffer-substring-no-properties - (previous-single-property-change (point) 'face) - (next-single-property-change (point) 'face)))) - ;; Compute hi-lock patterns that match the - ;; highlighted text at point. Use this later in - ;; during completing-read. - (dolist (hi-lock-pattern hi-lock-interactive-patterns) - (let ((regexp (car hi-lock-pattern))) - (if (string-match regexp hi-text) - (push regexp regexps)))))) + (let ((face-after (get-text-property (point) 'face)) + (face-before + (unless (bobp) (get-text-property (1- (point)) 'face))) + (faces (mapcar #'hi-lock-keyword->face + hi-lock-interactive-patterns))) + (unless (memq face-before faces) (setq face-before nil)) + (unless (memq face-after faces) (setq face-after nil)) + (when (and face-before face-after (not (eq face-before face-after))) + (setq face-before nil)) + (when (or face-after face-before) + (let* ((hi-text + (buffer-substring-no-properties + (if face-before + (or (previous-single-property-change (point) 'face) + (point-min)) + (point)) + (if face-after + (or (next-single-property-change (point) 'face) + (point-max)) + (point))))) + ;; Compute hi-lock patterns that match the + ;; highlighted text at point. Use this later in + ;; during completing-read. + (dolist (hi-lock-pattern hi-lock-interactive-patterns) + (let ((regexp (car hi-lock-pattern))) + (if (string-match regexp hi-text) + (push regexp regexps))))))) regexps)) (defvar-local hi-lock--unused-faces nil ------------------------------------------------------------ revno: 111177 [merge] committer: dancol@dancol.org branch nick: realtrunk timestamp: Mon 2012-12-10 12:55:02 -0800 message: Merge from private trunk Daniel Colascione 2012-12-10 Add emacs.res to .bzrignore Daniel Colascione 2012-12-10 Fix cygw32 build break diff: === modified file '.bzrignore' --- .bzrignore 2012-11-14 04:55:41 +0000 +++ .bzrignore 2012-12-10 20:47:57 +0000 @@ -153,6 +153,7 @@ src/prefix-args* src/stamp-oldxmenu src/stamp-h.in +src/emacs.res src/temacs test/indent/*.new +* === modified file 'ChangeLog' --- ChangeLog 2012-12-10 20:27:33 +0000 +++ ChangeLog 2012-12-10 20:55:02 +0000 @@ -6,6 +6,8 @@ 2012-12-10 Daniel Colascione + * .bzrignore: add src/emacs.res. + * configure.ac (W32_RES, W32_RES_LINK, WINDRES): Teach the cygw32 build how to compile Windows resource files; use these variables to tell src/Makefile.in how and whether to compile resources. === modified file 'src/ChangeLog' --- src/ChangeLog 2012-12-10 17:52:35 +0000 +++ src/ChangeLog 2012-12-10 20:46:20 +0000 @@ -1,5 +1,8 @@ 2012-12-10 Daniel Colascione + * w32term.c, keyboard.c: Fix build break in cygw32 by omitting + Windows file notification functionality unless WINDOWSNT. + * w32gui.h (hprevinst, lpCmdLine, nCmdShow): Remove unused declarations. === modified file 'src/keyboard.c' --- src/keyboard.c 2012-12-10 12:08:02 +0000 +++ src/keyboard.c 2012-12-10 20:46:20 +0000 @@ -3909,6 +3909,8 @@ make_number (event->modifiers))); kbd_fetch_ptr = event + 1; } +#endif +#ifdef WINDOWSNT else if (event->kind == FILE_NOTIFY_EVENT) { /* Make an event (file-notify (DESCRIPTOR ACTION FILE) CALLBACK). */ @@ -11361,6 +11363,9 @@ #ifdef HAVE_NTGUI DEFSYM (Qlanguage_change, "language-change"); +#endif + +#ifdef WINDOWSNT DEFSYM (Qfile_w32notify, "file-w32notify"); #endif === modified file 'src/w32term.c' --- src/w32term.c 2012-12-10 12:08:02 +0000 +++ src/w32term.c 2012-12-10 20:46:20 +0000 @@ -3244,6 +3244,7 @@ return retval; } +#ifdef WINDOWSNT /* Put file notifications into the Emacs input event queue. This function runs when the WM_EMACS_FILENOTIFY message arrives from a watcher thread. */ @@ -3320,6 +3321,7 @@ /* We've stuffed all the events ourselves, so w32_read_socket shouldn't. */ event->kind = NO_EVENT; } +#endif /* Function to report a mouse movement to the mainstream Emacs code. @@ -4954,11 +4956,13 @@ check_visibility = 1; break; +#ifdef WINDOWSNT case WM_EMACS_FILENOTIFY: f = x_window_to_frame (dpyinfo, msg.msg.hwnd); if (f) queue_notifications (&inev, &msg, f, &count); break; +#endif default: /* Check for messages registered at runtime. */ ------------------------------------------------------------ revno: 111176 committer: Paul Eggert branch nick: trunk timestamp: Mon 2012-12-10 12:27:33 -0800 message: * configure.ac (HAVE_INOTIFY): Speed up configure-time test. There's no need to test for any of three inotify functions, since we use all three. Check for just the first one. diff: === modified file 'ChangeLog' --- ChangeLog 2012-12-10 17:52:35 +0000 +++ ChangeLog 2012-12-10 20:27:33 +0000 @@ -1,3 +1,9 @@ +2012-12-10 Paul Eggert + + * configure.ac (HAVE_INOTIFY): Speed up configure-time test. + There's no need to test for any of three inotify functions, + since we use all three. Check for just the first one. + 2012-12-10 Daniel Colascione * configure.ac (W32_RES, W32_RES_LINK, WINDRES): Teach the cygw32 === modified file 'configure.ac' --- configure.ac 2012-12-10 17:52:35 +0000 +++ configure.ac 2012-12-10 20:27:33 +0000 @@ -2187,15 +2187,14 @@ AC_SUBST(LIBGNUTLS_CFLAGS) dnl inotify is only available on GNU/Linux. -HAVE_INOTIFY=no if test "${with_inotify}" = "yes"; then AC_CHECK_HEADERS(sys/inotify.h) if test "$ac_cv_header_sys_inotify_h" = yes ; then - AC_CHECK_FUNCS(inotify_init1 inotify_add_watch inotify_rm_watch, HAVE_INOTIFY=yes) + AC_CHECK_FUNC(inotify_init1) fi fi -if test "${HAVE_INOTIFY}" = "yes"; then - AC_DEFINE(HAVE_INOTIFY, [1], [Define to 1 to use inotify]) +if test "$ac_cv_func_inotify_init1" = yes; then + AC_DEFINE(HAVE_INOTIFY, 1, [Define to 1 to use inotify.]) fi dnl Do not put whitespace before the #include statements below. ------------------------------------------------------------ revno: 111175 fixes bug: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=11095 author: Jambunathan K committer: Stefan Monnier branch nick: trunk timestamp: Mon 2012-12-10 13:33:59 -0500 message: * lisp/hi-lock.el: Refine the choice of default face. (hi-lock-keyword->face): New function. Use it wherever we used cadadadr instead. (hi-lock--regexps-at-point): Ignore faces that can't come from hi-lock. (hi-lock--last-face): Remove var. (hi-lock--unused-faces): New var to replace it. (hi-lock-read-face-name): Use/maintain it. (hi-lock-unface-buffer): Maintain it. Fix error for the C-u case. (hi-lock-set-pattern): Ignore new rule if it has the same regexp even if it has another face. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2012-12-10 13:25:17 +0000 +++ lisp/ChangeLog 2012-12-10 18:33:59 +0000 @@ -1,3 +1,16 @@ +2012-12-10 Jambunathan K + + * hi-lock.el: Refine the choice of default face. + (hi-lock-keyword->face): New function. Use it wherever we used + cadadadr instead. + (hi-lock--regexps-at-point): Ignore faces that can't come from hi-lock. + (hi-lock--last-face): Remove var. + (hi-lock--unused-faces): New var to replace it. + (hi-lock-read-face-name): Use/maintain it. + (hi-lock-unface-buffer): Maintain it. Fix error for the C-u case. + (hi-lock-set-pattern): Ignore new rule if it has the same regexp even + if it has another face. + 2012-12-10 Eli Zaretskii * subr.el (w32notify-handle-event): New function. @@ -13,8 +26,7 @@ 2012-12-10 Eli Zaretskii - * textmodes/texinfo.el (texinfo-enable-quote-envs): Add - "smallexample". + * textmodes/texinfo.el (texinfo-enable-quote-envs): Add "smallexample". 2012-12-10 Le Wang === modified file 'lisp/hi-lock.el' --- lisp/hi-lock.el 2012-12-07 16:48:42 +0000 +++ lisp/hi-lock.el 2012-12-10 18:33:59 +0000 @@ -462,6 +462,9 @@ (unless hi-lock-mode (hi-lock-mode 1)) (hi-lock-set-pattern regexp face)) +(defun hi-lock-keyword->face (keyword) + (cadr (cadr (cadr keyword)))) ; Keyword looks like (REGEXP (0 'FACE) ...). + (declare-function x-popup-menu "menu.c" (position menu)) (defun hi-lock--regexps-at-point () @@ -470,23 +473,25 @@ ;; choice of regexp. (let ((regexp (get-char-property (point) 'hi-lock-overlay-regexp))) (when regexp (push regexp regexps))) - ;; With font-locking on, check if the cursor is on an highlighted text. - ;; Checking for hi-lock face is a good heuristic. FIXME: use "hi-lock-". - (and (string-match "\\`hi-" (face-name (face-at-point))) - (let* ((hi-text - (buffer-substring-no-properties - (previous-single-property-change (point) 'face) - (next-single-property-change (point) 'face)))) - ;; Compute hi-lock patterns that match the - ;; highlighted text at point. Use this later in - ;; during completing-read. - (dolist (hi-lock-pattern hi-lock-interactive-patterns) - (let ((regexp (car hi-lock-pattern))) - (if (string-match regexp hi-text) - (push regexp regexps)))))) + ;; With font-locking on, check if the cursor is on a highlighted text. + (and (memq (face-at-point) + (mapcar #'hi-lock-keyword->face hi-lock-interactive-patterns)) + (let* ((hi-text + (buffer-substring-no-properties + (previous-single-property-change (point) 'face) + (next-single-property-change (point) 'face)))) + ;; Compute hi-lock patterns that match the + ;; highlighted text at point. Use this later in + ;; during completing-read. + (dolist (hi-lock-pattern hi-lock-interactive-patterns) + (let ((regexp (car hi-lock-pattern))) + (if (string-match regexp hi-text) + (push regexp regexps)))))) regexps)) -(defvar-local hi-lock--last-face nil) +(defvar-local hi-lock--unused-faces nil + "List of faces that is not used and is available for highlighting new text. +Face names from this list come from `hi-lock-face-defaults'.") ;;;###autoload (defalias 'unhighlight-regexp 'hi-lock-unface-buffer) @@ -514,7 +519,7 @@ (list (car pattern) (format "%s (%s)" (car pattern) - (cadr (cadr (cadr pattern)))) + (hi-lock-keyword->face pattern)) (cons nil nil) (car pattern))) hi-lock-interactive-patterns)))) @@ -541,16 +546,14 @@ (dolist (keyword (if (eq regexp t) hi-lock-interactive-patterns (list (assoc regexp hi-lock-interactive-patterns)))) (when keyword - (let ((face (cadr (cadr (cadr keyword))))) + (let ((face (hi-lock-keyword->face keyword))) ;; Make `face' the next one to use by default. - (setq hi-lock--last-face - (cadr (member (symbol-name face) - (reverse hi-lock-face-defaults))))) + (add-to-list 'hi-lock--unused-faces (face-name face))) (font-lock-remove-keywords nil (list keyword)) (setq hi-lock-interactive-patterns (delq keyword hi-lock-interactive-patterns)) (remove-overlays - nil nil 'hi-lock-overlay-regexp (hi-lock--hashcons regexp)) + nil nil 'hi-lock-overlay-regexp (hi-lock--hashcons (car keyword))) (when font-lock-fontified (font-lock-fontify-buffer))))) ;;;###autoload @@ -608,27 +611,35 @@ "Return face for interactive highlighting. When `hi-lock-auto-select-face' is non-nil, just return the next face. Otherwise, read face name from minibuffer with completion and history." - (let ((default (or (cadr (member hi-lock--last-face hi-lock-face-defaults)) - (car hi-lock-face-defaults)))) - (setq hi-lock--last-face + (unless hi-lock-interactive-patterns + (setq hi-lock--unused-faces hi-lock-face-defaults)) + (let* ((last-used-face + (when hi-lock-interactive-patterns + (face-name (hi-lock-keyword->face + (car hi-lock-interactive-patterns))))) + (defaults (append hi-lock--unused-faces + (cdr (member last-used-face hi-lock-face-defaults)) + hi-lock-face-defaults)) + face) (if (and hi-lock-auto-select-face (not current-prefix-arg)) - default - (completing-read - (format "Highlight using face (default %s): " default) - obarray 'facep t nil 'face-name-history - (append (member default hi-lock-face-defaults) - hi-lock-face-defaults)))) - (unless (member hi-lock--last-face hi-lock-face-defaults) - (setq hi-lock-face-defaults - (append hi-lock-face-defaults (list hi-lock--last-face)))) - (intern hi-lock--last-face))) + (setq face (or (pop hi-lock--unused-faces) (car defaults))) + (setq face (completing-read + (format "Highlight using face (default %s): " + (car defaults)) + obarray 'facep t nil 'face-name-history defaults)) + ;; Update list of un-used faces. + (setq hi-lock--unused-faces (remove face hi-lock--unused-faces)) + ;; Grow the list of defaults. + (add-to-list 'hi-lock-face-defaults face t)) + (intern face))) (defun hi-lock-set-pattern (regexp face) "Highlight REGEXP with face FACE." ;; Hashcons the regexp, so it can be passed to remove-overlays later. (setq regexp (hi-lock--hashcons regexp)) (let ((pattern (list regexp (list 0 (list 'quote face) t)))) - (unless (member pattern hi-lock-interactive-patterns) + ;; Refuse to highlight a text that is already highlighted. + (unless (assoc regexp hi-lock-interactive-patterns) (push pattern hi-lock-interactive-patterns) (if font-lock-mode (progn ------------------------------------------------------------ revno: 111174 [merge] committer: Daniel Colascione branch nick: trunk timestamp: Mon 2012-12-10 09:52:35 -0800 message: Move fix for cygw32 icon issue from emacs-24 branch to trunk as Stefan Monnier requests diff: === modified file 'ChangeLog' --- ChangeLog 2012-12-10 11:17:21 +0000 +++ ChangeLog 2012-12-10 17:52:35 +0000 @@ -1,3 +1,9 @@ +2012-12-10 Daniel Colascione + + * configure.ac (W32_RES, W32_RES_LINK, WINDRES): Teach the cygw32 + build how to compile Windows resource files; use these variables + to tell src/Makefile.in how and whether to compile resources. + 2012-12-10 Rüdiger Sonderfeld * configure.ac (inotify): New option. === modified file 'configure.ac' --- configure.ac 2012-12-10 11:17:21 +0000 +++ configure.ac 2012-12-10 17:52:35 +0000 @@ -1606,6 +1606,8 @@ HAVE_W32=no W32_OBJ= W32_LIBS= +W32_RES= +W32_RES_LINK= if test "${with_w32}" != no; then if test "${opsys}" != "cygwin"; then AC_MSG_ERROR([Using w32 with an autotools build is only supported for Cygwin.]) @@ -1614,13 +1616,21 @@ [AC_MSG_ERROR([`--with-w32' was specified, but windows.h cannot be found.])]) AC_DEFINE(HAVE_NTGUI, 1, [Define to use native MS Windows GUI.]) + AC_CHECK_TOOL(WINDRES, [windres], + [AC_MSG_ERROR([No resource compiler found.])]) W32_OBJ="w32fns.o w32menu.o w32reg.o w32font.o w32term.o" W32_OBJ="$W32_OBJ w32xfns.o w32select.o w32uniscribe.o" W32_LIBS="$W32_LIBS -lkernel32 -luser32 -lgdi32 -lole32 -lcomdlg32" W32_LIBS="$W32_LIBS -lusp10 -lcomctl32 -lwinspool" + W32_RES="emacs.res" + # Tell the linker that emacs.res is an object (which we compile from + # the rc file), not a linker script. + W32_RES_LINK="-Wl,-bpe-i386 -Wl,emacs.res" fi AC_SUBST(W32_OBJ) AC_SUBST(W32_LIBS) +AC_SUBST(W32_RES) +AC_SUBST(W32_RES_LINK) if test "${HAVE_W32}" = "yes"; then window_system=w32 === modified file 'nt/ChangeLog' --- nt/ChangeLog 2012-12-09 22:10:18 +0000 +++ nt/ChangeLog 2012-12-10 17:52:35 +0000 @@ -1,3 +1,9 @@ +2012-12-10 Daniel Colascione + + * emacs.rc: Use forward slashes in relative paths in order to + avoid complaints from Cygwin. (Forward slashes work perfectly + well in the NT build.) + 2012-12-09 Eli Zaretskii * inc/unistd.h (unsetenv): Provide a prototype. === modified file 'nt/emacs.rc' --- nt/emacs.rc 2012-11-27 03:10:32 +0000 +++ nt/emacs.rc 2012-12-10 17:52:35 +0000 @@ -1,5 +1,5 @@ -Emacs ICON icons\emacs.ico -32649 CURSOR icons\hand.cur +Emacs ICON icons/emacs.ico +32649 CURSOR icons/hand.cur #ifdef WIN64 1 24 "emacs-x64.manifest" #else === modified file 'src/ChangeLog' --- src/ChangeLog 2012-12-10 17:34:47 +0000 +++ src/ChangeLog 2012-12-10 17:52:35 +0000 @@ -1,3 +1,24 @@ +2012-12-10 Daniel Colascione + + * w32gui.h (hprevinst, lpCmdLine, nCmdShow): Remove unused + declarations. + + * w32fns.c (cache_system_info): Initialize the global hinst + variable here so various initialization calls DTRT. + + * unexw32.c (hprevinst, lpCmdLine, nCmdShow): Remove unused + variables. + (hinst): Remove unneeded extern declaration. + (_start): Remove initialization of above variables; remove + initialization of hinst, as cache_system_info now does that. + + * emacs.c (main): Call cache_system_info early in startup; we + previously weren't calling it in Cygwin builds. + + * Makefile.in (ntsource, WINDRES, W32_RES, W#@_RES_LINK): Teach + the autoconf build system how to compile a Windows resource file + and link it to Emacs. + 2012-12-10 Dmitry Antipov Per-buffer window counters. === modified file 'src/Makefile.in' --- src/Makefile.in 2012-12-10 12:08:02 +0000 +++ src/Makefile.in 2012-12-10 17:52:35 +0000 @@ -28,9 +28,11 @@ # Here are the things that we expect ../configure to edit. # We use $(srcdir) explicitly in dependencies so as not to depend on VPATH. srcdir = @srcdir@ +ntsource = $(srcdir)/../nt abs_builddir = @abs_builddir@ VPATH = $(srcdir) CC = @CC@ +WINDRES = @WINDRES@ CFLAGS = @CFLAGS@ CPPFLAGS = @CPPFLAGS@ LDFLAGS = @LDFLAGS@ @@ -267,6 +269,13 @@ ## --lwinspool if HAVE_W32, else empty. W32_LIBS=@W32_LIBS@ +## emacs.res if HAVE_W32 +W32_RES=@W32_RES@ +## If HAVE_W32, compiler arguments for including +## the resource file in the binary. +## XXX -Wl,-b -Wl,pe-i386 -Wl,emacs.res +W32_RES_LINK=@W32_RES_LINK@ + ## Empty if !HAVE_X_WINDOWS ## xfont.o ftfont.o xftfont.o ftxfont.o if HAVE_XFT ## xfont.o ftfont.o ftxfont.o if HAVE_FREETYPE @@ -329,7 +338,6 @@ @$(MKDEPDIR) $(CC) -c $(CPPFLAGS) $(ALL_OBJC_CFLAGS) $< - ## lastfile must follow all files whose initialized data areas should ## be dumped as pure by dump-emacs. base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \ @@ -463,9 +471,11 @@ $(lib)/libgnu.a: $(config_h) cd $(lib) && $(MAKE) libgnu.a -temacs$(EXEEXT): $(START_FILES) stamp-oldxmenu $(obj) $(otherobj) $(lib)/libgnu.a +temacs$(EXEEXT): $(START_FILES) stamp-oldxmenu $(obj) $(otherobj) \ + $(lib)/libgnu.a $(W32_RES) $(CC) $(LD_FIRSTFLAG) $(ALL_CFLAGS) $(TEMACS_LDFLAGS) $(TEMACS_LDFLAGS2) \ - -o temacs $(START_FILES) $(obj) $(otherobj) $(lib)/libgnu.a $(LIBES) + -o temacs $(START_FILES) $(obj) $(otherobj) $(lib)/libgnu.a $(LIBES) \ + $(W32_RES_LINK) test "$(CANNOT_DUMP)" = "yes" || \ test "X$(PAXCTL)" = X || $(PAXCTL) -r temacs$(EXEEXT) @@ -506,11 +516,14 @@ doc.o: buildobj.h +emacs.res: $(ntsource)/emacs.rc \ + $(ntsource)/icons/emacs.ico \ + $(ntsource)/emacs-x86.manifest + $(WINDRES) -O COFF -o $@ $(ntsource)/emacs.rc ns-app: emacs$(EXEEXT) cd ../nextstep && $(MAKE) $(MFLAGS) all - .PHONY: mostlyclean clean bootstrap-clean distclean maintainer-clean .PHONY: versionclean extraclean frc === modified file 'src/emacs.c' --- src/emacs.c 2012-12-10 12:08:02 +0000 +++ src/emacs.c 2012-12-10 17:52:35 +0000 @@ -41,6 +41,7 @@ #if defined WINDOWSNT || defined HAVE_NTGUI #include "w32select.h" #include "w32font.h" +#include "w32common.h" #endif #if defined HAVE_NTGUI && defined CYGWIN @@ -733,6 +734,13 @@ } #endif +#if defined WINDOWSNT || defined HAVE_NTGUI + /* Set global variables used to detect Windows version. Do this as + early as possible. (unexw32.c calls this function as well, but + the additional call here is harmless.) */ + cache_system_info (); +#endif + #ifdef RUN_TIME_REMAP if (initialized) run_time_remap (argv[0]); === modified file 'src/unexw32.c' --- src/unexw32.c 2012-10-17 19:02:44 +0000 +++ src/unexw32.c 2012-12-10 07:11:21 +0000 @@ -85,13 +85,6 @@ PIMAGE_SECTION_HEADER heap_section; -#ifdef HAVE_NTGUI -extern HINSTANCE hinst; -HINSTANCE hprevinst = NULL; -LPSTR lpCmdLine = ""; -int nCmdShow = 0; -#endif /* HAVE_NTGUI */ - /* Startup code for running on NT. When we are running as the dumped version, we need to bootstrap our heap and .bss section into our address space before we can actually hand off control to the startup @@ -121,15 +114,6 @@ /* Prevent Emacs from being locked up (eg. in batch mode) when accessing devices that aren't mounted (eg. removable media drives). */ SetErrorMode (SEM_FAILCRITICALERRORS); - - /* Invoke the NT CRT startup routine now that our housecleaning - is finished. */ -#ifdef HAVE_NTGUI - /* determine WinMain args like crt0.c does */ - hinst = GetModuleHandle (NULL); - lpCmdLine = GetCommandLine (); - nCmdShow = SW_SHOWDEFAULT; -#endif mainCRTStartup (); } === modified file 'src/w32fns.c' --- src/w32fns.c 2012-12-10 12:08:02 +0000 +++ src/w32fns.c 2012-12-10 17:52:35 +0000 @@ -1821,7 +1821,6 @@ static BOOL w32_init_class (HINSTANCE hinst) { - if (w32_unicode_gui) { WNDCLASSW uwc; @@ -7027,6 +7026,9 @@ DWORD data; } version; + /* Cache the module handle of Emacs itself. */ + hinst = GetModuleHandle (NULL); + /* Cache the version of the operating system. */ version.data = GetVersion (); w32_major_version = version.info.major; === modified file 'src/w32gui.h' --- src/w32gui.h 2012-09-20 01:02:21 +0000 +++ src/w32gui.h 2012-12-10 07:11:21 +0000 @@ -79,9 +79,6 @@ #define FACE_DEFAULT (~0) extern HINSTANCE hinst; -extern HINSTANCE hprevinst; -extern LPSTR lpCmdLine; -extern int nCmdShow; /* Bit Gravity */ ------------------------------------------------------------ revno: 111173 committer: Dmitry Antipov branch nick: trunk timestamp: Mon 2012-12-10 21:34:47 +0400 message: Per-buffer window counters. * buffer.h (struct buffer): New member window_count. (buffer_window_count): New function. * buffer.c (Fget_buffer_create, Fmake_indirect_buffer): Initialize window_count. (Fkill_buffer): Verify window_count for the buffer being killed. (modify_overlay): Do not force redisplay if buffer is not shown in any window. (init_buffer_once): Initialize window_count for buffer_defaults and buffer_local_symbols. * window.h (buffer_shared): Remove declaration. (wset_buffer): Convert from inline ... * window.c (wset_buffer): ... to an ordinary function. (adjust_window_count): New function. (make_parent_window): Use it. * xdisp.c (buffer_shared): Remove. (redisplay_internal, redisplay_window): Adjust users. (buffer_shared_and_changed): Use per-buffer window counter. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2012-12-10 13:25:17 +0000 +++ src/ChangeLog 2012-12-10 17:34:47 +0000 @@ -1,3 +1,24 @@ +2012-12-10 Dmitry Antipov + + Per-buffer window counters. + * buffer.h (struct buffer): New member window_count. + (buffer_window_count): New function. + * buffer.c (Fget_buffer_create, Fmake_indirect_buffer): + Initialize window_count. + (Fkill_buffer): Verify window_count for the buffer being killed. + (modify_overlay): Do not force redisplay if buffer is not shown + in any window. + (init_buffer_once): Initialize window_count for buffer_defaults + and buffer_local_symbols. + * window.h (buffer_shared): Remove declaration. + (wset_buffer): Convert from inline ... + * window.c (wset_buffer): ... to an ordinary function. + (adjust_window_count): New function. + (make_parent_window): Use it. + * xdisp.c (buffer_shared): Remove. + (redisplay_internal, redisplay_window): Adjust users. + (buffer_shared_and_changed): Use per-buffer window counter. + 2012-12-10 Eli Zaretskii Support for filesystem notifications on MS-Windows. === modified file 'src/buffer.c' --- src/buffer.c 2012-12-07 07:16:32 +0000 +++ src/buffer.c 2012-12-10 17:34:47 +0000 @@ -547,6 +547,8 @@ b->base_buffer = NULL; /* No one shares the text with us now. */ b->indirections = 0; + /* No one shows us now. */ + b->window_count = 0; BUF_GAP_SIZE (b) = 20; block_input (); @@ -794,6 +796,8 @@ b->indirections = -1; /* Notify base buffer that we share the text now. */ b->base_buffer->indirections++; + /* Always -1 for an indirect buffer. */ + b->window_count = -1; b->pt = b->base_buffer->pt; b->begv = b->base_buffer->begv; @@ -1929,10 +1933,16 @@ eassert (b->indirections == -1); b->base_buffer->indirections--; eassert (b->base_buffer->indirections >= 0); + /* Make sure that we wasn't confused. */ + eassert (b->window_count == -1); } else - /* No one shares our buffer text, can free it. */ - free_buffer_text (b); + { + /* Make sure that no one shows us. */ + eassert (b->window_count == 0); + /* No one shares our buffer text, can free it. */ + free_buffer_text (b); + } if (b->newline_cache) { @@ -3880,17 +3890,17 @@ BUF_COMPUTE_UNCHANGED (buf, start, end); - /* If this is a buffer not in the selected window, - we must do other windows. */ - if (buf != XBUFFER (XWINDOW (selected_window)->buffer)) - windows_or_buffers_changed = 1; - /* If multiple windows show this buffer, we must do other windows. */ - else if (buffer_shared > 1) - windows_or_buffers_changed = 1; - /* If we modify an overlay at the end of the buffer, we cannot - be sure that window end is still valid. */ - else if (end >= ZV && start <= ZV) - windows_or_buffers_changed = 1; + /* If BUF is visible, consider updating the display if ... */ + if (buffer_window_count (buf) > 0) + { + /* ... it's visible in other window than selected, */ + if (buf != XBUFFER (XWINDOW (selected_window)->buffer)) + windows_or_buffers_changed = 1; + /* ... or if we modify an overlay at the end of the buffer + and so we cannot be sure that window end is still valid. */ + else if (end >= ZV && start <= ZV) + windows_or_buffers_changed = 1; + } ++BUF_OVERLAY_MODIFF (buf); } @@ -5125,6 +5135,9 @@ /* No one will share the text with these buffers, but let's play it safe. */ buffer_defaults.indirections = 0; buffer_local_symbols.indirections = 0; + /* Likewise no one will display them. */ + buffer_defaults.window_count = 0; + buffer_local_symbols.window_count = 0; set_buffer_intervals (&buffer_defaults, NULL); set_buffer_intervals (&buffer_local_symbols, NULL); /* This is not strictly necessary, but let's make them initialized. */ === modified file 'src/buffer.h' --- src/buffer.h 2012-12-07 07:16:32 +0000 +++ src/buffer.h 2012-12-10 17:34:47 +0000 @@ -770,11 +770,15 @@ In an ordinary buffer, it is 0. */ struct buffer *base_buffer; - /* In an indirect buffer, this is -1. In an ordinary buffer, + /* In an indirect buffer, this is -1. In an ordinary buffer, it's the number of indirect buffers that share our text; zero means that we're the only owner of this text. */ int indirections; + /* Number of windows showing this buffer. Always -1 for + an indirect buffer since it counts as its base buffer. */ + int window_count; + /* A non-zero value in slot IDX means that per-buffer variable with index IDX has a local value in this buffer. The index IDX for a buffer-local variable is stored in that variable's slot @@ -1173,7 +1177,18 @@ + pos + BUF_BEG_ADDR (buf) - BEG_BYTE); return STRING_CHAR (p); } - + +/* Return number of windows showing B. */ + +BUFFER_INLINE int +buffer_window_count (struct buffer *b) +{ + if (b->base_buffer) + b = b->base_buffer; + eassert (b->window_count >= 0); + return b->window_count; +} + /* Overlays */ /* Return the marker that stands for where OV starts in the buffer. */ === modified file 'src/window.c' --- src/window.c 2012-12-07 08:13:49 +0000 +++ src/window.c 2012-12-10 17:34:47 +0000 @@ -270,6 +270,35 @@ return w; } +/* Called when W's buffer slot is changed. ARG -1 means that W is about to + cease its buffer, and 1 means that W is about to set up the new one. */ + +static void +adjust_window_count (struct window *w, int arg) +{ + eassert (eabs (arg) == 1); + if (BUFFERP (w->buffer)) + { + struct buffer *b = XBUFFER (w->buffer); + + if (b->base_buffer) + b = b->base_buffer; + b->window_count += arg; + eassert (b->window_count >= 0); + } +} + +/* Set W's buffer slot to VAL and recompute number + of windows showing VAL if it is a buffer. */ + +void +wset_buffer (struct window *w, Lisp_Object val) +{ + adjust_window_count (w, -1); + w->buffer = val; + adjust_window_count (w, 1); +} + /* Build a frequently used 4-integer (X Y W H) list. */ static Lisp_Object @@ -3391,6 +3420,8 @@ memcpy ((char *) p + sizeof (struct vectorlike_header), (char *) o + sizeof (struct vectorlike_header), word_size * VECSIZE (struct window)); + /* P's buffer slot may change from nil to a buffer. */ + adjust_window_count (p, 1); XSETWINDOW (parent, p); p->sequence_number = ++sequence_number; === modified file 'src/window.h' --- src/window.h 2012-11-02 10:34:26 +0000 +++ src/window.h 2012-12-10 17:34:47 +0000 @@ -351,11 +351,6 @@ /* Most code should use these functions to set Lisp fields in struct window. */ WINDOW_INLINE void -wset_buffer (struct window *w, Lisp_Object val) -{ - w->buffer = val; -} -WINDOW_INLINE void wset_frame (struct window *w, Lisp_Object val) { w->frame = val; @@ -947,11 +942,6 @@ extern int cursor_type_changed; -/* Number of windows displaying the selected buffer. Normally this is - 1, but it can be more. */ - -extern int buffer_shared; - /* If *ROWS or *COLS are too small a size for FRAME, set them to the minimum allowable size. */ @@ -997,6 +987,8 @@ extern void temp_output_buffer_show (Lisp_Object); extern void replace_buffer_in_windows (Lisp_Object); extern void replace_buffer_in_windows_safely (Lisp_Object); +/* This looks like a setter, but it is a bit special. */ +extern void wset_buffer (struct window *, Lisp_Object); extern void init_window_once (void); extern void init_window (void); extern void syms_of_window (void); === modified file 'src/xdisp.c' --- src/xdisp.c 2012-12-04 15:15:30 +0000 +++ src/xdisp.c 2012-12-10 17:34:47 +0000 @@ -515,11 +515,6 @@ static int overlay_arrow_seen; -/* Number of windows showing the buffer of the selected - window (or another buffer with the same base buffer). */ - -int buffer_shared; - /* Vector containing glyphs for an ellipsis `...'. */ static Lisp_Object default_invis_vector[3]; @@ -10894,9 +10889,8 @@ static int buffer_shared_and_changed (void) { - /* The variable buffer_shared is set in redisplay_window and - indicates that we redisplay a buffer in different windows. */ - return (buffer_shared > 1 && UNCHANGED_MODIFIED < MODIFF); + return (buffer_window_count (current_buffer) > 1 + && UNCHANGED_MODIFIED < MODIFF); } /* Nonzero if W doesn't reflect the actual state of current buffer due @@ -13470,10 +13464,6 @@ FOR_EACH_FRAME (tail, frame) XFRAME (frame)->updated_p = 0; - /* Recompute # windows showing selected buffer. This will be - incremented each time such a window is displayed. */ - buffer_shared = 0; - FOR_EACH_FRAME (tail, frame) { struct frame *f = XFRAME (frame); @@ -15568,21 +15558,6 @@ if (mode_line_update_needed (w)) update_mode_line = 1; - /* Count number of windows showing the selected buffer. An indirect - buffer counts as its base buffer. */ - if (!just_this_one_p) - { - struct buffer *current_base, *window_base; - current_base = current_buffer; - window_base = XBUFFER (XWINDOW (selected_window)->buffer); - if (current_base->base_buffer) - current_base = current_base->base_buffer; - if (window_base->base_buffer) - window_base = window_base->base_buffer; - if (current_base == window_base) - buffer_shared++; - } - /* Point refers normally to the selected window. For any other window, set up appropriate value. */ if (!EQ (window, selected_window)) ------------------------------------------------------------ revno: 111172 [merge] committer: Eli Zaretskii branch nick: trunk timestamp: Mon 2012-12-10 16:12:19 +0200 message: Support for filesystem notifications on MS-Windows. src/w32proc.c (sys_select): If drain_message_queue returns non-zero, and this is a TTY frame, signal the caller that keyboard input is available. src/w32xfns.c (drain_message_queue): Now returns an int: an indication whether any WM_EMACS_FILENOTIFY messages were found in the queue. src/w32inevt.c (handle_file_notifications): New function. (w32_console_read_socket): Call it to process file notifications. src/w32console.c (initialize_w32_display): Record the main thread ID in dwMainThreadId. src/deps.mk (inotify.o): New dependency list. src/Makefile.in (SOME_MACHINE_OBJECTS): Add w32notify.o. src/w32term.h (WM_EMACS_FILENOTIFY): New custom message. (WM_EMACS_END): Bump value by 1. (notification_buffer_in_use, file_notifications) (notifications_size, notifications_desc): Declare. (w32_get_watch_object, lispy_file_action, globals_of_w32notify): Add prototypes. src/w32term.c (lispy_file_action, queue_notifications): New functions. (syms_of_w32term) : New symbols. (w32_read_socket): Handle the WM_EMACS_FILENOTIFY message. src/w32notify.c: New file, implements file event notifications for MS-Windows. src/w32fns.c (w32_wnd_proc): Handle the WM_EMACS_FILENOTIFY message by posting it to the w32_read_socket queue. src/termhooks.h (enum event_kind) [HAVE_NTGUI]: Support FILE_NOTIFY_EVENT. src/makefile.w32-in (OBJ2): Add $(BLD)/w32notify.$(O). (GLOBAL_SOURCES): Add w32notify.c ($(BLD)/w32notify.$(O)): New set of dependencies. src/lisp.h (syms_of_w32notify) [WINDOWSNT]: Add prototype. src/keyboard.c (kbd_buffer_get_event) [WINDOWSNT]: Handle FILE_NOTIFY_EVENT. (syms_of_keyboard) [HAVE_NTGUI] : New symbol. (keys_of_keyboard) [WINDOWSNT]: Bind file-notify to w32notify-handle-event by default. src/emacs.c (main) [WINDOWSNT]: Call globals_of_w32notify and syms_of_w32notify. lisp/subr.el (w32notify-handle-event): New function. (inotify-handle-event): Doc fix. lib-src/makefile.w32-in (obj): Add w32notify.o. Add missing X and Unix sources. diff: === modified file 'etc/NEWS' --- etc/NEWS 2012-12-10 11:17:21 +0000 +++ etc/NEWS 2012-12-10 12:38:49 +0000 @@ -136,7 +136,8 @@ ** Support for filesystem notifications. Emacs now supports notifications of filesystem changes, such as creation, modification, and deletion of files. This requires the -'inotify' API on GNU/Linux systems. +'inotify' API on GNU/Linux systems. On MS-Windows systems, this is +supported for Windows XP and newer versions. ** Face changes === modified file 'lib-src/ChangeLog' --- lib-src/ChangeLog 2012-12-02 01:47:56 +0000 +++ lib-src/ChangeLog 2012-12-10 13:25:17 +0000 @@ -1,3 +1,8 @@ +2012-12-10 Eli Zaretskii + + * makefile.w32-in (obj): Add w32notify.o. Add missing X and Unix + sources. + 2012-12-02 Kevin Ryde * etags.c (Lisp_functions): Skip (defvar foo) declarations unless === modified file 'lib-src/makefile.w32-in' --- lib-src/makefile.w32-in 2012-11-17 23:16:24 +0000 +++ lib-src/makefile.w32-in 2012-12-10 13:25:17 +0000 @@ -123,10 +123,13 @@ # obj = dosfns.o msdos.o \ xterm.o xfns.o xmenu.o xselect.o xrdb.o xsmfns.o fringe.o image.o \ - fontset.o menu.o \ - w32.o w32console.o w32fns.o w32heap.o w32inevt.o cygw32.o \ + fontset.o menu.o dbusbind.o cygw32.o \ + nsterm.o nsfns.o nsmenu.o nsselect.o nsimage.o nsfont.o \ + w32.o w32console.o w32fns.o w32heap.o w32inevt.o w32notify.o \ w32menu.o w32proc.o w32reg.o w32select.o w32term.o w32xfns.o \ - font.o w32font.o w32uniscribe.o \ + w16select.o widget.o xfont.o ftfont.o xftfont.o ftxfont.o gtkutil.o \ + xsettings.o xgselect.o termcap.o \ + font.o w32font.o w32uniscribe.o w32notify.o \ dispnew.o frame.o scroll.o xdisp.o window.o bidi.o \ charset.o coding.o category.o ccl.o character.o chartab.o \ cm.o term.o terminal.o xfaces.o \ === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2012-12-10 11:17:21 +0000 +++ lisp/ChangeLog 2012-12-10 13:25:17 +0000 @@ -1,3 +1,8 @@ +2012-12-10 Eli Zaretskii + + * subr.el (w32notify-handle-event): New function. + (inotify-handle-event): Doc fix. + 2012-12-10 Rüdiger Sonderfeld * subr.el (inotify-event-p, inotify-handle-event): New functions. === modified file 'lisp/subr.el' --- lisp/subr.el 2012-12-10 11:17:21 +0000 +++ lisp/subr.el 2012-12-10 12:08:02 +0000 @@ -4333,15 +4333,25 @@ ;;;###autoload (defun inotify-handle-event (event) - "Handle file system monitoring event. -If EVENT is a filewatch event then the callback is called. If EVENT is -not a filewatch event then a `filewatch-error' is signaled." + "Handle inotify file system monitoring event. +If EVENT is an inotify filewatch event, call its callback. +Otherwise, signal a `filewatch-error'." (interactive "e") (unless (inotify-event-p event) (signal 'filewatch-error (cons "Not a valid inotify event" event))) - (funcall (nth 2 event) (nth 1 event))) +(defun w32notify-handle-event (event) + "Handle MS-Windows file system monitoring event. +If EVENT is an MS-Windows filewatch event, call its callback. +Otherwise, signal a `filewatch-error'." + (interactive "e") + (if (and (eq (car event) 'file-w32notify) + (= (length event) 3)) + (funcall (nth 2 event) (nth 1 event)) + (signal 'filewatch-error + (cons "Not a valid MS-Windows file-notify event" event)))) + ;;;; Comparing version strings. === modified file 'src/ChangeLog' --- src/ChangeLog 2012-12-10 11:17:21 +0000 +++ src/ChangeLog 2012-12-10 13:25:17 +0000 @@ -1,5 +1,63 @@ +2012-12-10 Eli Zaretskii + + Support for filesystem notifications on MS-Windows. + * w32proc.c (sys_select): If drain_message_queue returns non-zero, + and this is a TTY frame, signal the caller that keyboard input is + available. + + * w32xfns.c (drain_message_queue): Now returns an int: an + indication whether any WM_EMACS_FILENOTIFY messages were found in + the queue. + + * w32inevt.c (handle_file_notifications): New function. + (w32_console_read_socket): Call it to process file notifications. + + * w32console.c (initialize_w32_display): Record the main thread ID + in dwMainThreadId. + + * deps.mk (inotify.o): New dependency list. + + * Makefile.in (SOME_MACHINE_OBJECTS): Add w32notify.o. + + * w32term.h (WM_EMACS_FILENOTIFY): New custom message. + (WM_EMACS_END): Bump value by 1. + (notification_buffer_in_use, file_notifications) + (notifications_size, notifications_desc): Declare. + (w32_get_watch_object, lispy_file_action, globals_of_w32notify): + Add prototypes. + + * w32term.c (lispy_file_action, queue_notifications): New functions. + (syms_of_w32term) + : New symbols. + (w32_read_socket): Handle the WM_EMACS_FILENOTIFY message. + + * w32notify.c: New file, implements file event notifications for + MS-Windows. + + * w32fns.c (w32_wnd_proc): Handle the WM_EMACS_FILENOTIFY message + by posting it to the w32_read_socket queue. + + * termhooks.h (enum event_kind) [HAVE_NTGUI]: Support + FILE_NOTIFY_EVENT. + + * makefile.w32-in (OBJ2): Add $(BLD)/w32notify.$(O). + (GLOBAL_SOURCES): Add w32notify.c + ($(BLD)/w32notify.$(O)): New set of dependencies. + + * lisp.h (syms_of_w32notify) [WINDOWSNT]: Add prototype. + + * keyboard.c (kbd_buffer_get_event) [WINDOWSNT]: Handle + FILE_NOTIFY_EVENT. + (syms_of_keyboard) [HAVE_NTGUI] : New symbol. + (keys_of_keyboard) [WINDOWSNT]: Bind file-notify to + w32notify-handle-event by default. + + * emacs.c (main) [WINDOWSNT]: Call globals_of_w32notify and + syms_of_w32notify. + 2012-12-10 Rüdiger Sonderfeld + Support for filesystem notifications on GNU/Linux via inotify. * termhooks.h (enum event_kind) [HAVE_INOTIFY]: Add FILE_NOTIFY_EVENT. === modified file 'src/Makefile.in' --- src/Makefile.in 2012-12-10 11:17:21 +0000 +++ src/Makefile.in 2012-12-10 12:08:02 +0000 @@ -358,7 +358,7 @@ xterm.o xfns.o xmenu.o xselect.o xrdb.o xsmfns.o fringe.o image.o \ fontset.o dbusbind.o cygw32.o \ nsterm.o nsfns.o nsmenu.o nsselect.o nsimage.o nsfont.o \ - w32.o w32console.o w32fns.o w32heap.o w32inevt.o \ + w32.o w32console.o w32fns.o w32heap.o w32inevt.o w32notify.o \ w32menu.o w32proc.o w32reg.o w32select.o w32term.o w32xfns.o \ w16select.o widget.o xfont.o ftfont.o xftfont.o ftxfont.o gtkutil.o \ xsettings.o xgselect.o termcap.o === modified file 'src/deps.mk' --- src/deps.mk 2012-01-05 09:46:05 +0000 +++ src/deps.mk 2012-12-10 13:25:17 +0000 @@ -128,6 +128,7 @@ indent.o: indent.c frame.h window.h indent.h buffer.h lisp.h $(config_h) \ termchar.h termopts.h disptab.h region-cache.h character.h category.h \ keyboard.h systime.h coding.h $(INTERVALS_H) globals.h +inotify.o: inotify.c lisp.h coding.h process.h keyboard.h frame.h termhooks.h insdel.o: insdel.c window.h buffer.h $(INTERVALS_H) blockinput.h character.h \ atimer.h systime.h region-cache.h lisp.h globals.h $(config_h) keyboard.o: keyboard.c termchar.h termhooks.h termopts.h buffer.h character.h \ === modified file 'src/emacs.c' --- src/emacs.c 2012-12-10 11:17:21 +0000 +++ src/emacs.c 2012-12-10 12:08:02 +0000 @@ -1287,6 +1287,7 @@ #ifdef WINDOWSNT globals_of_w32 (); + globals_of_w32notify (); /* Initialize environment from registry settings. */ init_environment (argv); init_ntproc (dumping); /* must precede init_editfns. */ @@ -1452,6 +1453,7 @@ #ifdef WINDOWSNT syms_of_ntterm (); + syms_of_w32notify (); #endif /* WINDOWSNT */ syms_of_profiler (); === modified file 'src/keyboard.c' --- src/keyboard.c 2012-12-10 11:17:21 +0000 +++ src/keyboard.c 2012-12-10 12:08:02 +0000 @@ -313,6 +313,9 @@ Lisp_Object Qmouse_click; #ifdef HAVE_NTGUI Lisp_Object Qlanguage_change; +#ifdef WINDOWSNT +Lisp_Object Qfile_w32notify; +#endif #endif static Lisp_Object Qdrag_n_drop; static Lisp_Object Qsave_session; @@ -3906,6 +3909,16 @@ make_number (event->modifiers))); kbd_fetch_ptr = event + 1; } + else if (event->kind == FILE_NOTIFY_EVENT) + { + /* Make an event (file-notify (DESCRIPTOR ACTION FILE) CALLBACK). */ + obj = Fcons (Qfile_w32notify, + list2 (list3 (make_number (event->code), + XCAR (event->arg), + XCDR (event->arg)), + event->frame_or_window)); + kbd_fetch_ptr = event + 1; + } #endif else if (event->kind == SAVE_SESSION_EVENT) { @@ -11348,6 +11361,7 @@ #ifdef HAVE_NTGUI DEFSYM (Qlanguage_change, "language-change"); + DEFSYM (Qfile_w32notify, "file-w32notify"); #endif #ifdef HAVE_DBUS @@ -12126,6 +12140,8 @@ #if defined (WINDOWSNT) initial_define_lispy_key (Vspecial_event_map, "language-change", "ignore"); + initial_define_lispy_key (Vspecial_event_map, "file-w32notify", + "w32notify-handle-event"); #endif } === modified file 'src/lisp.h' --- src/lisp.h 2012-12-10 11:17:21 +0000 +++ src/lisp.h 2012-12-10 12:08:02 +0000 @@ -3516,6 +3516,11 @@ extern Lisp_Object Qfont_param; #endif +#ifdef WINDOWSNT +/* Defined on w32notify.c. */ +extern void syms_of_w32notify (void); +#endif + /* Defined in inotify.c */ #ifdef HAVE_INOTIFY extern void syms_of_inotify (void); === modified file 'src/makefile.w32-in' --- src/makefile.w32-in 2012-11-23 08:47:34 +0000 +++ src/makefile.w32-in 2012-12-10 12:08:02 +0000 @@ -134,6 +134,7 @@ $(BLD)/w32menu.$(O) \ $(BLD)/w32reg.$(O) \ $(BLD)/w32font.$(O) \ + $(BLD)/w32notify.$(O) \ $(BLD)/w32uniscribe.$(O) LIBS = $(TLIB0) \ @@ -209,7 +210,7 @@ fontset.c menu.c dbusbind.c \ w32.c w32console.c w32fns.c w32heap.c w32inevt.c cygw32.c \ w32menu.c w32proc.c w32reg.c w32select.c w32term.c w32xfns.c \ - font.c w32font.c w32uniscribe.c \ + font.c w32font.c w32uniscribe.c w32notify.c \ dispnew.c frame.c scroll.c xdisp.c window.c bidi.c \ charset.c coding.c category.c ccl.c character.c chartab.c \ cm.c term.c terminal.c xfaces.c \ @@ -1693,6 +1694,17 @@ $(W32FONT_H) \ $(W32TERM_H) +$(BLD)/w32notify.$(O) : \ + $(SRC)/w32notify.c \ + $(SRC)/w32common.h \ + $(CODING_H) \ + $(CONFIG_H) \ + $(FRAME_H) \ + $(KEYBOARD_H) \ + $(LISP_H) \ + $(TERMHOOKS_H) \ + $(W32TERM_H) + # Each object file depends on stamp_BLD, because in parallel builds we must # make sure $(BLD) exists before starting compilations. # === modified file 'src/termhooks.h' --- src/termhooks.h 2012-12-10 11:17:21 +0000 +++ src/termhooks.h 2012-12-10 13:25:17 +0000 @@ -211,7 +211,7 @@ , NS_NONKEY_EVENT #endif -#ifdef HAVE_INOTIFY +#if defined (HAVE_INOTIFY) || defined (HAVE_NTGUI) /* File or directory was changed. */ , FILE_NOTIFY_EVENT #endif === modified file 'src/w32console.c' --- src/w32console.c 2012-10-08 12:53:18 +0000 +++ src/w32console.c 2012-10-12 09:47:00 +0000 @@ -746,6 +746,9 @@ else w32_console_unicode_input = 0; + /* This is needed by w32notify.c:send_notifications. */ + dwMainThreadId = GetCurrentThreadId (); + /* Setup w32_display_info structure for this frame. */ w32_initialize_display_info (build_string ("Console")); === modified file 'src/w32fns.c' --- src/w32fns.c 2012-12-10 02:00:42 +0000 +++ src/w32fns.c 2012-12-10 12:08:02 +0000 @@ -3957,6 +3957,9 @@ return retval; } + case WM_EMACS_FILENOTIFY: + my_post_msg (&wmsg, hwnd, msg, wParam, lParam); + return 1; default: /* Check for messages registered at runtime. */ === modified file 'src/w32inevt.c' --- src/w32inevt.c 2012-10-12 14:14:35 +0000 +++ src/w32inevt.c 2012-10-18 18:00:00 +0000 @@ -576,6 +576,74 @@ 0, 0, 0); } +static int +handle_file_notifications (struct input_event *hold_quit) +{ + BYTE *p = file_notifications; + FILE_NOTIFY_INFORMATION *fni = (PFILE_NOTIFY_INFORMATION)p; + const DWORD min_size + = offsetof (FILE_NOTIFY_INFORMATION, FileName) + sizeof(wchar_t); + struct input_event inev; + int nevents = 0; + + /* We cannot process notification before Emacs is fully initialized, + since we need the UTF-16LE coding-system to be set up. */ + if (!initialized) + { + notification_buffer_in_use = 0; + return nevents; + } + + enter_crit (); + if (notification_buffer_in_use) + { + DWORD info_size = notifications_size; + Lisp_Object cs = intern ("utf-16le"); + Lisp_Object obj = w32_get_watch_object (notifications_desc); + + /* notifications_size could be zero when the buffer of + notifications overflowed on the OS level, or when the + directory being watched was itself deleted. Do nothing in + that case. */ + if (info_size + && !NILP (obj) && CONSP (obj)) + { + Lisp_Object callback = XCDR (obj); + + EVENT_INIT (inev); + + while (info_size >= min_size) + { + Lisp_Object utf_16_fn + = make_unibyte_string ((char *)fni->FileName, + fni->FileNameLength); + /* Note: mule-conf is preloaded, so utf-16le must + already be defined at this point. */ + Lisp_Object fname + = code_convert_string_norecord (utf_16_fn, cs, 0); + Lisp_Object action = lispy_file_action (fni->Action); + + inev.kind = FILE_NOTIFY_EVENT; + inev.code = (ptrdiff_t)XINT (XIL ((EMACS_INT)notifications_desc)); + inev.timestamp = GetTickCount (); + inev.modifiers = 0; + inev.frame_or_window = callback; + inev.arg = Fcons (action, fname); + kbd_buffer_store_event_hold (&inev, hold_quit); + + if (!fni->NextEntryOffset) + break; + p += fni->NextEntryOffset; + fni = (PFILE_NOTIFY_INFORMATION)p; + info_size -= fni->NextEntryOffset; + } + } + notification_buffer_in_use = 0; + } + leave_crit (); + return nevents; +} + /* Here's an overview of how Emacs input works in non-GUI sessions on MS-Windows. (For description of the GUI input, see the commentary before w32_msg_pump in w32fns.c.) @@ -619,12 +687,16 @@ for (;;) { + int nfnotify = handle_file_notifications (hold_quit); + nev = fill_queue (0); if (nev <= 0) { /* If nev == -1, there was some kind of error - If nev == 0 then waitp must be zero and no events were available + If nev == 0 then no events were available so return. */ + if (nfnotify) + nev = 0; break; } === added file 'src/w32notify.c' --- src/w32notify.c 1970-01-01 00:00:00 +0000 +++ src/w32notify.c 2012-12-10 12:38:49 +0000 @@ -0,0 +1,631 @@ +/* Filesystem notifications support for GNU Emacs on the Microsoft Windows API. + Copyright (C) 2012 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, see . */ + +/* Written by Eli Zaretskii . + + Design overview: + + For each watch request, we launch a separate worker thread. The + worker thread runs the watch_worker function, which issues an + asynchronous call to ReadDirectoryChangesW, and then waits in + SleepEx for that call to complete. Waiting in SleepEx puts the + thread in an "alertable" state, so it wakes up when either (a) the + call to ReadDirectoryChangesW completes, or (b) the main thread + instructs the worker thread to terminate by sending it an APC, see + below. + + When the ReadDirectoryChangesW call completes, its completion + routine watch_completion is automatically called. watch_completion + stashes the received file events in a buffer used to communicate + them to the main thread (using a critical section, so that several + threads could use the same buffer), posts a special message, + WM_EMACS_FILENOTIFY, to the Emacs's message queue, and returns. + That causes the SleepEx function call inside watch_worker to + return, and watch_worker then issues another call to + ReadDirectoryChangesW. (Except when it does not, see below.) + + In a GUI session, The WM_EMACS_FILENOTIFY message, posted to the + message queue gets dispatched to the main Emacs window procedure, + which queues it for processing by w32_read_socket. When + w32_read_socket sees this message, it accesses the buffer with file + notifications (using a critical section), extracts the information, + converts it to a series of FILE_NOTIFY_EVENT events, and stuffs + them into the input event queue to be processed by keyboard.c input + machinery (read_char via a call to kbd_buffer_get_event). + + In a non-GUI session, we send the WM_EMACS_FILENOTIFY message to + the main (a.k.a. "Lisp") thread instead, since there are no window + procedures in console programs. That message wakes up + MsgWaitForMultipleObjects inside sys_select, which then signals to + its caller that some keyboard input is available. This causes + w32_console_read_socket to be called, which accesses the buffer + with file notifications and stuffs them into the input event queue + for keyboard.c to process. + + When the FILE_NOTIFY_EVENT event is processed by keyboard.c's + kbd_buffer_get_event, it is converted to a Lispy event that can be + bound to a command. The default binding is w32notify-handle-event, + defined on subr.el. + + After w32_read_socket or w32_console_read_socket are done + processing the notifications, they reset a flag signaling to all + watch worker threads that the notifications buffer is available for + more input. + + When the watch is removed by a call to w32notify-rm-watch, the main + thread requests that the worker thread terminates by queuing an APC + for the worker thread. The APC specifies the watch_end function to + be called. watch_end calls CancelIo on the outstanding + ReadDirectoryChangesW call and closes the handle on which the + watched directory was open. When watch_end returns, the + watch_completion function is called one last time with the + ERROR_OPERATION_ABORTED status, which causes it to clean up and set + a flag telling watch_worker to exit without issuing another + ReadDirectoryChangesW call. Since watch_worker is the thread + procedure of the worker thread, exiting it causes the thread to + exit. The main thread waits for some time for the worker thread to + exit, and if it doesn't, terminates it forcibly. */ + +#include +#include + +/* must include CRT headers *before* config.h */ +#include + +#include + +#include "lisp.h" +#include "w32term.h" /* for enter_crit/leave_crit and WM_EMACS_FILENOTIFY */ +#include "w32common.h" /* for OS version data */ +#include "w32.h" /* for w32_strerror */ +#include "coding.h" +#include "keyboard.h" +#include "frame.h" /* needed by termhooks.h */ +#include "termhooks.h" /* for FILE_NOTIFY_EVENT */ + +#define DIRWATCH_SIGNATURE 0x01233210 + +struct notification { + BYTE *buf; /* buffer for ReadDirectoryChangesW */ + OVERLAPPED *io_info; /* the OVERLAPPED structure for async I/O */ + BOOL subtree; /* whether to watch subdirectories */ + DWORD filter; /* bit mask for events to watch */ + char *watchee; /* the file we are interested in */ + HANDLE dir; /* handle to the watched directory */ + HANDLE thr; /* handle to the thread that watches */ + volatile int terminate; /* if non-zero, request for the thread to terminate */ + unsigned signature; +}; + +/* Used for communicating notifications to the main thread. */ +volatile int notification_buffer_in_use; +BYTE file_notifications[16384]; +DWORD notifications_size; +void *notifications_desc; + +static Lisp_Object Qfile_name, Qdirectory_name, Qattributes, Qsize; +static Lisp_Object Qlast_write_time, Qlast_access_time, Qcreation_time; +static Lisp_Object Qsecurity_desc, Qsubtree, watch_list; + +/* Signal to the main thread that we have file notifications for it to + process. */ +static void +send_notifications (BYTE *info, DWORD info_size, void *desc, + volatile int *terminate) +{ + int done = 0; + FRAME_PTR f = SELECTED_FRAME (); + + /* A single buffer is used to communicate all notifications to the + main thread. Since both the main thread and several watcher + threads could be active at the same time, we use a critical area + and an "in-use" flag to synchronize them. A watcher thread can + only put its notifications in the buffer if it acquires the + critical area and finds the "in-use" flag reset. The main thread + resets the flag after it is done processing notifications. + + FIXME: is there a better way of dealing with this? */ + while (!done && !*terminate) + { + enter_crit (); + if (!notification_buffer_in_use) + { + if (info_size) + memcpy (file_notifications, info, info_size); + notifications_size = info_size; + notifications_desc = desc; + /* If PostMessage fails, the message queue is full. If that + happens, the last thing they will worry about is file + notifications. So we effectively discard the + notification in that case. */ + if ((FRAME_TERMCAP_P (f) + /* We send the message to the main (a.k.a. "Lisp") + thread, where it will wake up MsgWaitForMultipleObjects + inside sys_select, causing it to report that there's + some keyboard input available. This will in turn cause + w32_console_read_socket to be called, which will pick + up the file notifications. */ + && PostThreadMessage (dwMainThreadId, WM_EMACS_FILENOTIFY, 0, 0)) + || (FRAME_W32_P (f) + && PostMessage (FRAME_W32_WINDOW (f), + WM_EMACS_FILENOTIFY, 0, 0))) + notification_buffer_in_use = 1; + done = 1; + } + leave_crit (); + if (!done) + Sleep (5); + } +} + +/* An APC routine to cancel outstanding directory watch. Invoked by + the main thread via QueueUserAPC. This is needed because only the + thread that issued the ReadDirectoryChangesW call can call CancelIo + to cancel that. (CancelIoEx is only available since Vista, so we + cannot use it on XP.) */ +VOID CALLBACK +watch_end (ULONG_PTR arg) +{ + HANDLE hdir = (HANDLE)arg; + + if (hdir && hdir != INVALID_HANDLE_VALUE) + { + CancelIo (hdir); + CloseHandle (hdir); + } +} + +/* A completion routine (a.k.a. "APC function") for handling events + read by ReadDirectoryChangesW. Called by the OS when the thread + which issued the asynchronous ReadDirectoryChangesW call is in the + "alertable state", i.e. waiting inside SleepEx call. */ +VOID CALLBACK +watch_completion (DWORD status, DWORD bytes_ret, OVERLAPPED *io_info) +{ + struct notification *dirwatch; + + /* Who knows what happened? Perhaps the OVERLAPPED structure was + freed by someone already? In any case, we cannot do anything + with this request, so just punt and skip it. FIXME: should we + raise the 'terminate' flag in this case? */ + if (!io_info) + return; + + /* We have a pointer to our dirwatch structure conveniently stashed + away in the hEvent member of the OVERLAPPED struct. According to + MSDN documentation of ReadDirectoryChangesW: "The hEvent member + of the OVERLAPPED structure is not used by the system, so you can + use it yourself." */ + dirwatch = (struct notification *)io_info->hEvent; + if (status == ERROR_OPERATION_ABORTED) + { + /* We've been called because the main thread told us to issue + CancelIo on the directory we watch, and watch_end did so. + The directory handle is already closed. We should clean up + and exit, signalling to the thread worker routine not to + issue another call to ReadDirectoryChangesW. Note that we + don't free the dirwatch object itself nor the memory consumed + by its buffers; this is done by the main thread in + remove_watch. Calling malloc/free from a thread other than + the main thread is a no-no. */ + dirwatch->dir = NULL; + dirwatch->terminate = 1; + } + else + { + /* Tell the main thread we have notifications for it. */ + send_notifications (dirwatch->buf, bytes_ret, dirwatch, + &dirwatch->terminate); + } +} + +/* Worker routine for the watch thread. */ +static DWORD WINAPI +watch_worker (LPVOID arg) +{ + struct notification *dirwatch = (struct notification *)arg; + + do { + BOOL status; + DWORD sleep_result; + DWORD bytes_ret = 0; + + if (dirwatch->dir) + { + status = ReadDirectoryChangesW (dirwatch->dir, dirwatch->buf, 16384, + dirwatch->subtree, dirwatch->filter, + &bytes_ret, + dirwatch->io_info, watch_completion); + if (!status) + { + DebPrint (("watch_worker, abnormal exit: %lu\n", GetLastError ())); + /* We cannot remove the dirwatch object from watch_list, + because we are in a separate thread. For the same + reason, we also cannot free memory consumed by the + buffers allocated for the dirwatch object. So we close + the directory handle, but do not free the object itself + or its buffers. We also don't touch the signature. + This way, remove_watch can still identify the object, + remove it, and free its memory. */ + CloseHandle (dirwatch->dir); + dirwatch->dir = NULL; + return 1; + } + } + /* Sleep indefinitely until awoken by the I/O completion, which + could be either a change notification or a cancellation of the + watch. */ + sleep_result = SleepEx (INFINITE, TRUE); + } while (!dirwatch->terminate); + + return 0; +} + +/* Launch a thread to watch changes to FILE in a directory open on + handle HDIR. */ +static struct notification * +start_watching (const char *file, HANDLE hdir, BOOL subdirs, DWORD flags) +{ + struct notification *dirwatch = xzalloc (sizeof (struct notification)); + HANDLE thr; + + dirwatch->signature = DIRWATCH_SIGNATURE; + dirwatch->buf = xmalloc (16384); + dirwatch->io_info = xzalloc (sizeof(OVERLAPPED)); + /* Stash a pointer to dirwatch structure for use by the completion + routine. According to MSDN documentation of ReadDirectoryChangesW: + "The hEvent member of the OVERLAPPED structure is not used by the + system, so you can use it yourself." */ + dirwatch->io_info->hEvent = dirwatch; + dirwatch->subtree = subdirs; + dirwatch->filter = flags; + dirwatch->watchee = xstrdup (file); + dirwatch->terminate = 0; + dirwatch->dir = hdir; + + /* See w32proc.c where it calls CreateThread for the story behind + the 2nd and 5th argument in the call to CreateThread. */ + dirwatch->thr = CreateThread (NULL, 64 * 1024, watch_worker, (void *)dirwatch, + 0x00010000, NULL); + + if (!dirwatch->thr) + { + xfree (dirwatch->buf); + xfree (dirwatch->io_info); + xfree (dirwatch->watchee); + xfree (dirwatch); + dirwatch = NULL; + } + return dirwatch; +} + +/* Called from the main thread to start watching FILE in PARENT_DIR, + subject to FLAGS. If SUBDIRS is TRUE, watch the subdirectories of + PARENT_DIR as well. Value is a pointer to 'struct notification' + used by the thread that watches the changes. */ +static struct notification * +add_watch (const char *parent_dir, const char *file, BOOL subdirs, DWORD flags) +{ + HANDLE hdir; + struct notification *dirwatch = NULL; + + if (!file || !*file) + return NULL; + + hdir = CreateFile (parent_dir, + FILE_LIST_DIRECTORY, + /* FILE_SHARE_DELETE doesn't preclude other + processes from deleting files inside + parent_dir. */ + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, + NULL); + if (hdir == INVALID_HANDLE_VALUE) + return NULL; + + if ((dirwatch = start_watching (file, hdir, subdirs, flags)) == NULL) + CloseHandle (hdir); + + return dirwatch; +} + +/* Stop watching a directory specified by a pointer to its dirwatch object. */ +static int +remove_watch (struct notification *dirwatch) +{ + if (dirwatch && dirwatch->signature == DIRWATCH_SIGNATURE) + { + int i; + BOOL status; + DWORD exit_code, err; + + /* Only the thread that issued the outstanding I/O call can call + CancelIo on it. (CancelIoEx is available only since Vista.) + So we need to queue an APC for the worker thread telling it + to terminate. */ + if (!QueueUserAPC (watch_end, dirwatch->thr, (ULONG_PTR)dirwatch->dir)) + DebPrint (("QueueUserAPC failed (%lu)!\n", GetLastError ())); + /* We also set the terminate flag, for when the thread is + waiting on the critical section that never gets acquired. + FIXME: is there a cleaner method? Using SleepEx there is a + no-no, as that will lead to recursive APC invocations and + stack overflow. */ + dirwatch->terminate = 1; + /* Wait for the thread to exit. FIXME: is there a better method + that is not overly complex? */ + for (i = 0; i < 50; i++) + { + if (!((status = GetExitCodeThread (dirwatch->thr, &exit_code)) + && exit_code == STILL_ACTIVE)) + break; + Sleep (10); + } + if ((status == FALSE && (err = GetLastError ()) == ERROR_INVALID_HANDLE) + || exit_code == STILL_ACTIVE) + { + if (!(status == FALSE && err == ERROR_INVALID_HANDLE)) + { + TerminateThread (dirwatch->thr, 0); + if (dirwatch->dir) + CloseHandle (dirwatch->dir); + } + } + + /* Clean up. */ + if (dirwatch->thr) + { + CloseHandle (dirwatch->thr); + dirwatch->thr = NULL; + } + xfree (dirwatch->buf); + xfree (dirwatch->io_info); + xfree (dirwatch->watchee); + xfree (dirwatch); + + return 0; + } + else + { + DebPrint (("Unknown dirwatch object!\n")); + return -1; + } +} + +static DWORD +filter_list_to_flags (Lisp_Object filter_list) +{ + DWORD flags = 0; + + if (NILP (filter_list)) + return flags; + + if (!NILP (Fmember (Qfile_name, filter_list))) + flags |= FILE_NOTIFY_CHANGE_FILE_NAME; + if (!NILP (Fmember (Qdirectory_name, filter_list))) + flags |= FILE_NOTIFY_CHANGE_DIR_NAME; + if (!NILP (Fmember (Qattributes, filter_list))) + flags |= FILE_NOTIFY_CHANGE_ATTRIBUTES; + if (!NILP (Fmember (Qsize, filter_list))) + flags |= FILE_NOTIFY_CHANGE_SIZE; + if (!NILP (Fmember (Qlast_write_time, filter_list))) + flags |= FILE_NOTIFY_CHANGE_LAST_WRITE; + if (!NILP (Fmember (Qlast_access_time, filter_list))) + flags |= FILE_NOTIFY_CHANGE_LAST_ACCESS; + if (!NILP (Fmember (Qcreation_time, filter_list))) + flags |= FILE_NOTIFY_CHANGE_CREATION; + if (!NILP (Fmember (Qsecurity_desc, filter_list))) + flags |= FILE_NOTIFY_CHANGE_SECURITY; + + return flags; +} + +DEFUN ("w32notify-add-watch", Fw32notify_add_watch, + Sw32notify_add_watch, 3, 3, 0, + doc: /* Add a watch for filesystem events pertaining to FILE. + +This arranges for filesystem events pertaining to FILE to be reported +to Emacs. Use `w32notify-rm-watch' to cancel the watch. + +Value is a descriptor for the added watch, or nil if the file +cannot be watched. + +FILTER is a list of conditions for reporting an event. It can include +the following symbols: + + 'file-name' -- report file creation, deletion, or renaming + 'directory-name' -- report directory creation, deletion, or renaming + 'attributes' -- report changes in attributes + 'size' -- report changes in file-size + 'last-write-time' -- report changes in last-write time + 'last-access-time' -- report changes in last-access time + 'creation-time' -- report changes in creation time + 'security-desc' -- report changes in security descriptor + +If FILE is a directory, and FILTER includes 'subtree', then all the +subdirectories will also be watched and changes in them reported. + +When any event happens that satisfies the conditions specified by +FILTER, Emacs will call the CALLBACK function passing it a single +argument EVENT, which is of the form + + (DESCRIPTOR ACTION FILE) + +DESCRIPTOR is the same object as the one returned by this function. +ACTION is the description of the event. It could be any one of the +following: + + 'added' -- FILE was added + 'removed' -- FILE was deleted + 'modified' -- FILE's contents or its attributes were modified + 'renamed-from' -- a file was renamed whose old name was FILE + 'renamed-to' -- a file was renamed and its new name is FILE + +FILE is the name of the file whose event is being reported. */) + (Lisp_Object file, Lisp_Object filter, Lisp_Object callback) +{ + Lisp_Object encoded_file, watch_object, watch_descriptor; + char parent_dir[MAX_PATH], *basename; + size_t fn_len; + DWORD flags; + BOOL subdirs = FALSE; + struct notification *dirwatch = NULL; + Lisp_Object lisp_errstr; + char *errstr; + + CHECK_LIST (filter); + + /* The underlying features are available only since XP. */ + if (os_subtype == OS_9X + || (w32_major_version == 5 && w32_major_version < 1)) + { + errno = ENOSYS; + report_file_error ("Watching filesystem events is not supported", + Qnil); + } + + /* We need a full absolute file name of FILE, and we need to remove + any trailing slashes from it, so that GetFullPathName below gets + the basename part correctly. */ + file = Fdirectory_file_name (Fexpand_file_name (file, Qnil)); + encoded_file = ENCODE_FILE (file); + + fn_len = GetFullPathName (SDATA (encoded_file), MAX_PATH, parent_dir, + &basename); + if (!fn_len) + { + errstr = w32_strerror (0); + errno = EINVAL; + if (!NILP (Vlocale_coding_system)) + lisp_errstr + = code_convert_string_norecord (build_unibyte_string (errstr), + Vlocale_coding_system, 0); + else + lisp_errstr = build_string (errstr); + report_file_error ("GetFullPathName failed", + Fcons (lisp_errstr, Fcons (file, Qnil))); + } + /* We need the parent directory without the slash that follows it. + If BASENAME is NULL, the argument was the root directory on its + drive. */ + if (basename) + basename[-1] = '\0'; + else + subdirs = TRUE; + + if (!NILP (Fmember (Qsubtree, filter))) + subdirs = TRUE; + + flags = filter_list_to_flags (filter); + + dirwatch = add_watch (parent_dir, basename, subdirs, flags); + if (!dirwatch) + { + DWORD err = GetLastError (); + + errno = EINVAL; + if (err) + { + errstr = w32_strerror (err); + if (!NILP (Vlocale_coding_system)) + lisp_errstr + = code_convert_string_norecord (build_unibyte_string (errstr), + Vlocale_coding_system, 0); + else + lisp_errstr = build_string (errstr); + report_file_error ("Cannot watch file", + Fcons (lisp_errstr, Fcons (file, Qnil))); + } + else + report_file_error ("Cannot watch file", Fcons (file, Qnil)); + } + /* Store watch object in watch list. */ + watch_descriptor = XIL ((EMACS_INT)dirwatch); + watch_object = Fcons (watch_descriptor, callback); + watch_list = Fcons (watch_object, watch_list); + + return watch_descriptor; +} + +DEFUN ("w32notify-rm-watch", Fw32notify_rm_watch, + Sw32notify_rm_watch, 1, 1, 0, + doc: /* Remove an existing watch specified by its WATCH-DESCRIPTOR. + +WATCH-DESCRIPTOR should be an object returned by `w32notify-add-watch'. */) + (Lisp_Object watch_descriptor) +{ + Lisp_Object watch_object; + struct notification *dirwatch; + int status = -1; + + /* Remove the watch object from watch list. Do this before freeing + the object, do that even if we fail to free it, watch_list is + kept free of junk. */ + watch_object = Fassoc (watch_descriptor, watch_list); + if (!NILP (watch_object)) + { + watch_list = Fdelete (watch_object, watch_list); + dirwatch = (struct notification *)XLI (watch_descriptor); + if (w32_valid_pointer_p (dirwatch, sizeof(struct notification))) + status = remove_watch (dirwatch); + } + + if (status == -1) + report_file_error ("Invalid watch descriptor", Fcons (watch_descriptor, + Qnil)); + + return Qnil; +} + +Lisp_Object +w32_get_watch_object (void *desc) +{ + Lisp_Object descriptor = XIL ((EMACS_INT)desc); + + /* This is called from the input queue handling code, inside a + critical section, so we cannot possibly QUIT if watch_list is not + in the right condition. */ + return NILP (watch_list) ? Qnil : assoc_no_quit (descriptor, watch_list); +} + +void +globals_of_w32notify (void) +{ + watch_list = Qnil; +} + +void +syms_of_w32notify (void) +{ + DEFSYM (Qfile_name, "file-name"); + DEFSYM (Qdirectory_name, "directory-name"); + DEFSYM (Qattributes, "attributes"); + DEFSYM (Qsize, "size"); + DEFSYM (Qlast_write_time, "last-write-time"); + DEFSYM (Qlast_access_time, "last-access-time"); + DEFSYM (Qcreation_time, "creation-time"); + DEFSYM (Qsecurity_desc, "security-desc"); + DEFSYM (Qsubtree, "subtree"); + + defsubr (&Sw32notify_add_watch); + defsubr (&Sw32notify_rm_watch); + + staticpro (&watch_list); + + Fprovide (intern_c_string ("w32notify"), Qnil); +} === modified file 'src/w32proc.c' --- src/w32proc.c 2012-12-08 02:30:51 +0000 +++ src/w32proc.c 2012-12-10 12:08:02 +0000 @@ -2018,7 +2018,24 @@ (*) Note that MsgWaitForMultipleObjects above is an internal dispatch point for messages that are sent to windows created by this thread. */ - drain_message_queue (); + if (drain_message_queue () + /* If drain_message_queue returns non-zero, that means + we received a WM_EMACS_FILENOTIFY message. If this + is a TTY frame, we must signal the caller that keyboard + input is available, so that w32_console_read_socket + will be called to pick up the notifications. If we + don't do that, file notifications will only work when + the Emacs TTY frame has focus. */ + && FRAME_TERMCAP_P (SELECTED_FRAME ()) + /* they asked for stdin reads */ + && FD_ISSET (0, &orfds) + /* the stdin handle is valid */ + && keyboard_handle) + { + FD_SET (0, rfds); + if (nr == 0) + nr = 1; + } } else if (active >= nh) { === modified file 'src/w32term.c' --- src/w32term.c 2012-12-04 15:15:30 +0000 +++ src/w32term.c 2012-12-10 12:08:02 +0000 @@ -246,6 +246,8 @@ #endif static Lisp_Object Qvendor_specific_keysyms; +static Lisp_Object Qadded, Qremoved, Qmodified; +static Lisp_Object Qrenamed_from, Qrenamed_to; /*********************************************************************** @@ -3204,6 +3206,122 @@ } +/* File event notifications (see w32notify.c). */ + +Lisp_Object +lispy_file_action (DWORD action) +{ + static char unknown_fmt[] = "unknown-action(%d)"; + Lisp_Object retval; + + switch (action) + { + case FILE_ACTION_ADDED: + retval = Qadded; + break; + case FILE_ACTION_REMOVED: + retval = Qremoved; + break; + case FILE_ACTION_MODIFIED: + retval = Qmodified; + break; + case FILE_ACTION_RENAMED_OLD_NAME: + retval = Qrenamed_from; + break; + case FILE_ACTION_RENAMED_NEW_NAME: + retval = Qrenamed_to; + break; + default: + { + char buf[sizeof(unknown_fmt) - 1 + INT_STRLEN_BOUND (DWORD)]; + + sprintf (buf, unknown_fmt, action); + retval = intern (buf); + } + break; + } + + return retval; +} + +/* Put file notifications into the Emacs input event queue. This + function runs when the WM_EMACS_FILENOTIFY message arrives from a + watcher thread. */ +static void +queue_notifications (struct input_event *event, W32Msg *msg, struct frame *f, + int *evcount) +{ + BYTE *p = file_notifications; + FILE_NOTIFY_INFORMATION *fni = (PFILE_NOTIFY_INFORMATION)p; + const DWORD min_size + = offsetof (FILE_NOTIFY_INFORMATION, FileName) + sizeof(wchar_t); + Lisp_Object frame; + + /* We cannot process notification before Emacs is fully initialized, + since we need the UTF-16LE coding-system to be set up. */ + if (!initialized) + { + notification_buffer_in_use = 0; + return; + } + + XSETFRAME (frame, f); + + enter_crit (); + if (notification_buffer_in_use) + { + DWORD info_size = notifications_size; + Lisp_Object cs = intern ("utf-16le"); + Lisp_Object obj = w32_get_watch_object (notifications_desc); + + /* notifications_size could be zero when the buffer of + notifications overflowed on the OS level, or when the + directory being watched was itself deleted. Do nothing in + that case. */ + if (info_size + && !NILP (obj) && CONSP (obj)) + { + Lisp_Object callback = XCDR (obj); + + while (info_size >= min_size) + { + Lisp_Object utf_16_fn + = make_unibyte_string ((char *)fni->FileName, + fni->FileNameLength); + /* Note: mule-conf is preloaded, so utf-16le must + already be defined at this point. */ + Lisp_Object fname + = code_convert_string_norecord (utf_16_fn, cs, 0); + Lisp_Object action = lispy_file_action (fni->Action); + + event->kind = FILE_NOTIFY_EVENT; + event->code + = (ptrdiff_t)XINT (XIL ((EMACS_INT)notifications_desc)); + event->timestamp = msg->msg.time; + event->modifiers = 0; + event->frame_or_window = callback; + event->arg = Fcons (action, fname); + kbd_buffer_store_event (event); + (*evcount)++; + + if (!fni->NextEntryOffset) + break; + p += fni->NextEntryOffset; + fni = (PFILE_NOTIFY_INFORMATION)p; + info_size -= fni->NextEntryOffset; + } + } + notification_buffer_in_use = 0; + } + else + DebPrint (("We were promised notifications, but in-use flag is zero!\n")); + leave_crit (); + + /* We've stuffed all the events ourselves, so w32_read_socket shouldn't. */ + event->kind = NO_EVENT; +} + + /* Function to report a mouse movement to the mainstream Emacs code. The input handler calls this. @@ -4836,6 +4954,12 @@ check_visibility = 1; break; + case WM_EMACS_FILENOTIFY: + f = x_window_to_frame (dpyinfo, msg.msg.hwnd); + if (f) + queue_notifications (&inev, &msg, f, &count); + break; + default: /* Check for messages registered at runtime. */ if (msg.msg.message == msh_mousewheel) @@ -6503,6 +6627,12 @@ DEFSYM (Qvendor_specific_keysyms, "vendor-specific-keysyms"); + DEFSYM (Qadded, "added"); + DEFSYM (Qremoved, "removed"); + DEFSYM (Qmodified, "modified"); + DEFSYM (Qrenamed_from, "renamed-from"); + DEFSYM (Qrenamed_to, "renamed-to"); + DEFVAR_INT ("w32-num-mouse-buttons", w32_num_mouse_buttons, doc: /* Number of physical mouse buttons. */); === modified file 'src/w32term.h' --- src/w32term.h 2012-12-06 13:48:11 +0000 +++ src/w32term.h 2012-12-10 12:08:02 +0000 @@ -602,7 +602,8 @@ #define WM_EMACS_PAINT (WM_EMACS_START + 20) #define WM_EMACS_BRINGTOTOP (WM_EMACS_START + 21) #define WM_EMACS_INPUT_READY (WM_EMACS_START + 22) -#define WM_EMACS_END (WM_EMACS_START + 23) +#define WM_EMACS_FILENOTIFY (WM_EMACS_START + 23) +#define WM_EMACS_END (WM_EMACS_START + 24) #define WND_FONTWIDTH_INDEX (0) #define WND_LINEHEIGHT_INDEX (4) @@ -652,7 +653,7 @@ extern HDC get_frame_dc (struct frame * f); extern int release_frame_dc (struct frame * f, HDC hDC); -extern void drain_message_queue (void); +extern int drain_message_queue (void); extern BOOL get_next_msg (W32Msg *, BOOL); extern BOOL post_msg (W32Msg *); @@ -662,10 +663,17 @@ extern void w32_sys_ring_bell (struct frame *f); extern void x_delete_display (struct w32_display_info *dpyinfo); + +extern volatile int notification_buffer_in_use; +extern BYTE file_notifications[16384]; +extern DWORD notifications_size; +extern void *notifications_desc; +extern Lisp_Object w32_get_watch_object (void *); +extern Lisp_Object lispy_file_action (DWORD); + extern void w32_initialize_display_info (Lisp_Object); extern void initialize_w32_display (struct terminal *); - /* Keypad command key support. W32 doesn't have virtual keys defined for the function keys on the keypad (they are mapped to the standard function keys), so we define our own. */ @@ -759,6 +767,7 @@ extern void globals_of_w32menu (void); extern void globals_of_w32fns (void); +extern void globals_of_w32notify (void); #ifdef CYGWIN extern int w32_message_fd; === modified file 'src/w32xfns.c' --- src/w32xfns.c 2012-10-07 22:31:58 +0000 +++ src/w32xfns.c 2012-10-12 09:47:00 +0000 @@ -315,16 +315,22 @@ return (TRUE); } -/* Process all messages in the current thread's queue. */ -void +/* Process all messages in the current thread's queue. Value is 1 if + one of these messages was WM_EMACS_FILENOTIFY, zero otherwise. */ +int drain_message_queue (void) { MSG msg; + int retval = 0; + while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) { + if (msg.message == WM_EMACS_FILENOTIFY) + retval = 1; TranslateMessage (&msg); DispatchMessage (&msg); } + return retval; } /* x_sync is a no-op on W32. */ ------------------------------------------------------------ revno: 111171 author: Rüdiger Sonderfeld committer: Eli Zaretskii branch nick: trunk timestamp: Mon 2012-12-10 06:17:21 -0500 message: Support filesystem notification through inotify on GNU/Linux. configure.ac (inotify): New option. (HAVE_INOTIFY): Test for inotify. src/termhooks.h (enum event_kind) [HAVE_INOTIFY]: Add FILE_NOTIFY_EVENT. src/lisp.h (syms_of_inotify) [HAVE_INOTIFY]: Add prototype. src/keyboard.c (Qfile_inotify) [HAVE_INOTIFY]: New variable. (syms_of_keyboard): DEFSYM it. (kbd_buffer_get_event) [HAVE_INOTIFY]: Generate FILE_NOTIFY_EVENT. (make_lispy_event): Support FILE_NOTIFY_EVENT by generating Qfile_inotify events. (keys_of_keyboard) [HAVE_INOTIFY]: Bind file-inotify events in special-event-map to inotify-handle-event. src/emacs.c (main) [HAVE_INOTIFY]: Call syms_of_inotify. src/Makefile.in (base_obj): Add inotify.o. src/inotify.c: New file. lisp/subr.el (inotify-event-p, inotify-handle-event): New functions. test/automated/inotify-test.el: New test. diff: === modified file 'ChangeLog' --- ChangeLog 2012-12-09 08:37:01 +0000 +++ ChangeLog 2012-12-10 11:17:21 +0000 @@ -1,3 +1,8 @@ +2012-12-10 Rüdiger Sonderfeld + + * configure.ac (inotify): New option. + (HAVE_INOTIFY): Test for inotify. + 2012-12-09 Andreas Schwab * configure.ac: Fix source command in .gdbinit. === modified file 'configure.ac' --- configure.ac 2012-12-09 08:37:01 +0000 +++ configure.ac 2012-12-10 11:17:21 +0000 @@ -185,6 +185,7 @@ OPTION_DEFAULT_ON([gsettings],[don't compile with GSettings support]) OPTION_DEFAULT_ON([selinux],[don't compile with SELinux support]) OPTION_DEFAULT_ON([gnutls],[don't use -lgnutls for SSL/TLS support]) +OPTION_DEFAULT_ON([inotify],[don't compile with inotify (file-watch) support]) ## For the times when you want to build Emacs but don't have ## a suitable makeinfo, and can live without the manuals. @@ -2175,6 +2176,18 @@ AC_SUBST(LIBGNUTLS_LIBS) AC_SUBST(LIBGNUTLS_CFLAGS) +dnl inotify is only available on GNU/Linux. +HAVE_INOTIFY=no +if test "${with_inotify}" = "yes"; then + AC_CHECK_HEADERS(sys/inotify.h) + if test "$ac_cv_header_sys_inotify_h" = yes ; then + AC_CHECK_FUNCS(inotify_init1 inotify_add_watch inotify_rm_watch, HAVE_INOTIFY=yes) + fi +fi +if test "${HAVE_INOTIFY}" = "yes"; then + AC_DEFINE(HAVE_INOTIFY, [1], [Define to 1 to use inotify]) +fi + dnl Do not put whitespace before the #include statements below. dnl Older compilers (eg sunos4 cc) choke on it. HAVE_XAW3D=no === modified file 'etc/NEWS' --- etc/NEWS 2012-12-10 02:00:42 +0000 +++ etc/NEWS 2012-12-10 11:17:21 +0000 @@ -133,6 +133,11 @@ * Lisp changes in Emacs 24.4 +** Support for filesystem notifications. +Emacs now supports notifications of filesystem changes, such as +creation, modification, and deletion of files. This requires the +'inotify' API on GNU/Linux systems. + ** Face changes *** The `face-spec-set' is now analogous to `setq' for face specs. === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2012-12-10 02:00:42 +0000 +++ lisp/ChangeLog 2012-12-10 11:17:21 +0000 @@ -1,3 +1,7 @@ +2012-12-10 Rüdiger Sonderfeld + + * subr.el (inotify-event-p, inotify-handle-event): New functions. + 2012-12-10 Dani Moncayo * simple.el (just-one-space): Doc fix. === modified file 'lisp/subr.el' --- lisp/subr.el 2012-12-07 16:25:28 +0000 +++ lisp/subr.el 2012-12-10 11:17:21 +0000 @@ -4323,6 +4323,26 @@ nil ,@(cdr (cdr spec))))) +;;;; Support for watching filesystem events. + +(defun inotify-event-p (event) + "Check if EVENT is an inotify event." + (and (listp event) + (>= (length event) 3) + (eq (car event) 'file-inotify))) + +;;;###autoload +(defun inotify-handle-event (event) + "Handle file system monitoring event. +If EVENT is a filewatch event then the callback is called. If EVENT is +not a filewatch event then a `filewatch-error' is signaled." + (interactive "e") + (unless (inotify-event-p event) + (signal 'filewatch-error (cons "Not a valid inotify event" event))) + + (funcall (nth 2 event) (nth 1 event))) + + ;;;; Comparing version strings. (defconst version-separator "." === modified file 'src/ChangeLog' --- src/ChangeLog 2012-12-10 02:00:42 +0000 +++ src/ChangeLog 2012-12-10 11:17:21 +0000 @@ -1,3 +1,24 @@ +2012-12-10 Rüdiger Sonderfeld + + * termhooks.h (enum event_kind) [HAVE_INOTIFY]: Add + FILE_NOTIFY_EVENT. + + * lisp.h (syms_of_inotify) [HAVE_INOTIFY]: Add prototype. + + * keyboard.c (Qfile_inotify) [HAVE_INOTIFY]: New variable. + (syms_of_keyboard): DEFSYM it. + (kbd_buffer_get_event) [HAVE_INOTIFY]: Generate FILE_NOTIFY_EVENT. + (make_lispy_event): Support FILE_NOTIFY_EVENT by generating + Qfile_inotify events. + (keys_of_keyboard) [HAVE_INOTIFY]: Bind file-inotify events in + special-event-map to inotify-handle-event. + + * emacs.c (main) [HAVE_INOTIFY]: Call syms_of_inotify. + + * Makefile.in (base_obj): Add inotify.o. + + * inotify.c: New file. + 2012-12-10 Jan Djärv * nsterm.m (fd_handler:): FD_ZERO fds (Bug#13103). === modified file 'src/Makefile.in' --- src/Makefile.in 2012-11-14 04:55:41 +0000 +++ src/Makefile.in 2012-12-10 11:17:21 +0000 @@ -344,7 +344,7 @@ syntax.o $(UNEXEC_OBJ) bytecode.o \ process.o gnutls.o callproc.o \ region-cache.o sound.o atimer.o \ - doprnt.o intervals.o textprop.o composite.o xml.o \ + doprnt.o intervals.o textprop.o composite.o xml.o inotify.o \ profiler.o \ $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) \ $(W32_OBJ) $(WINDOW_SYSTEM_OBJ) === modified file 'src/emacs.c' --- src/emacs.c 2012-12-08 17:19:51 +0000 +++ src/emacs.c 2012-12-10 11:17:21 +0000 @@ -1442,6 +1442,10 @@ syms_of_gnutls (); #endif +#ifdef HAVE_INOTIFY + syms_of_inotify (); +#endif /* HAVE_INOTIFY */ + #ifdef HAVE_DBUS syms_of_dbusbind (); #endif /* HAVE_DBUS */ === added file 'src/inotify.c' --- src/inotify.c 1970-01-01 00:00:00 +0000 +++ src/inotify.c 2012-12-10 11:17:21 +0000 @@ -0,0 +1,438 @@ +/* Inotify support for Emacs + +Copyright (C) 2012 + Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, see . */ + +#include + +#ifdef HAVE_INOTIFY + +#include "lisp.h" +#include "coding.h" +#include "process.h" +#include "keyboard.h" +#include "character.h" +#include "frame.h" /* Required for termhooks.h. */ +#include "termhooks.h" + +static Lisp_Object Qaccess; /* IN_ACCESS */ +static Lisp_Object Qattrib; /* IN_ATTRIB */ +static Lisp_Object Qclose_write; /* IN_CLOSE_WRITE */ +static Lisp_Object Qclose_nowrite; /* IN_CLOSE_NOWRITE */ +static Lisp_Object Qcreate; /* IN_CREATE */ +static Lisp_Object Qdelete; /* IN_DELETE */ +static Lisp_Object Qdelete_self; /* IN_DELETE_SELF */ +static Lisp_Object Qmodify; /* IN_MODIFY */ +static Lisp_Object Qmove_self; /* IN_MOVE_SELF */ +static Lisp_Object Qmoved_from; /* IN_MOVED_FROM */ +static Lisp_Object Qmoved_to; /* IN_MOVED_TO */ +static Lisp_Object Qopen; /* IN_OPEN */ + +static Lisp_Object Qall_events; /* IN_ALL_EVENTS */ +static Lisp_Object Qmove; /* IN_MOVE */ +static Lisp_Object Qclose; /* IN_CLOSE */ + +static Lisp_Object Qdont_follow; /* IN_DONT_FOLLOW */ +static Lisp_Object Qexcl_unlink; /* IN_EXCL_UNLINK */ +static Lisp_Object Qmask_add; /* IN_MASK_ADD */ +static Lisp_Object Qoneshot; /* IN_ONESHOT */ +static Lisp_Object Qonlydir; /* IN_ONLYDIR */ + +static Lisp_Object Qignored; /* IN_IGNORED */ +static Lisp_Object Qisdir; /* IN_ISDIR */ +static Lisp_Object Qq_overflow; /* IN_Q_OVERFLOW */ +static Lisp_Object Qunmount; /* IN_UNMOUNT */ + +#include +#include + +/* Ignore bits that might be undefined on old GNU/Linux systems. */ +#ifndef IN_EXCL_UNLINK +# define IN_EXCL_UNLINK 0 +#endif +#ifndef IN_DONT_FOLLOW +# define IN_DONT_FOLLOW 0 +#endif +#ifndef IN_ONLYDIR +# define IN_ONLYDIR 0 +#endif + +enum { uninitialized = -100 }; +/* File handle for inotify. */ +static int inotifyfd = uninitialized; + +/* Assoc list of files being watched. + Format: + (watch-descriptor . callback) + */ +static Lisp_Object watch_list; + +static Lisp_Object +make_watch_descriptor (int wd) +{ + /* TODO replace this with a Misc Object! */ + return make_number (wd); +} + +static Lisp_Object +mask_to_aspects (uint32_t mask) { + Lisp_Object aspects = Qnil; + if (mask & IN_ACCESS) + aspects = Fcons (Qaccess, aspects); + if (mask & IN_ATTRIB) + aspects = Fcons (Qattrib, aspects); + if (mask & IN_CLOSE_WRITE) + aspects = Fcons (Qclose_write, aspects); + if (mask & IN_CLOSE_NOWRITE) + aspects = Fcons (Qclose_nowrite, aspects); + if (mask & IN_CREATE) + aspects = Fcons (Qcreate, aspects); + if (mask & IN_DELETE) + aspects = Fcons (Qdelete, aspects); + if (mask & IN_DELETE_SELF) + aspects = Fcons (Qdelete_self, aspects); + if (mask & IN_MODIFY) + aspects = Fcons (Qmodify, aspects); + if (mask & IN_MOVE_SELF) + aspects = Fcons (Qmove_self, aspects); + if (mask & IN_MOVED_FROM) + aspects = Fcons (Qmoved_from, aspects); + if (mask & IN_MOVED_TO) + aspects = Fcons (Qmoved_to, aspects); + if (mask & IN_OPEN) + aspects = Fcons (Qopen, aspects); + if (mask & IN_IGNORED) + aspects = Fcons (Qignored, aspects); + if (mask & IN_ISDIR) + aspects = Fcons (Qisdir, aspects); + if (mask & IN_Q_OVERFLOW) + aspects = Fcons (Qq_overflow, aspects); + if (mask & IN_UNMOUNT) + aspects = Fcons (Qunmount, aspects); + return aspects; +} + +static Lisp_Object +inotifyevent_to_event (Lisp_Object watch_object, struct inotify_event const *ev) +{ + Lisp_Object name = Qnil; + if (ev->len > 0) + { + size_t const len = strlen (ev->name); + name = make_unibyte_string (ev->name, min (len, ev->len)); + name = DECODE_FILE (name); + } + + return list2 (list4 (make_watch_descriptor (ev->wd), + mask_to_aspects (ev->mask), + make_number (ev->cookie), + name), + XCDR (watch_object)); +} + +/* This callback is called when the FD is available for read. The inotify + events are read from FD and converted into input_events. */ +static void +inotify_callback (int fd, void *_) +{ + struct input_event event; + Lisp_Object watch_object; + int to_read; + char *buffer; + ssize_t n; + size_t i; + + to_read = 0; + if (ioctl (fd, FIONREAD, &to_read) == -1) + report_file_error ("Error while trying to retrieve file system events", + Qnil); + buffer = xmalloc (to_read); + n = read (fd, buffer, to_read); + if (n < 0) + { + xfree (buffer); + report_file_error ("Error while trying to read file system events", + Qnil); + } + + EVENT_INIT (event); + event.kind = FILE_NOTIFY_EVENT; + event.arg = Qnil; + + i = 0; + while (i < (size_t)n) + { + struct inotify_event *ev = (struct inotify_event*)&buffer[i]; + + watch_object = Fassoc (make_watch_descriptor (ev->wd), watch_list); + if (!NILP (watch_object)) + { + event.arg = inotifyevent_to_event (watch_object, ev); + + /* If event was removed automatically: Drop it from watch list. */ + if (ev->mask & IN_IGNORED) + watch_list = Fdelete (watch_object, watch_list); + } + + i += sizeof (*ev) + ev->len; + } + + if (!NILP (event.arg)) + kbd_buffer_store_event (&event); + + xfree (buffer); +} + +static uint32_t +symbol_to_inotifymask (Lisp_Object symb) +{ + if (EQ (symb, Qaccess)) + return IN_ACCESS; + else if (EQ (symb, Qattrib)) + return IN_ATTRIB; + else if (EQ (symb, Qclose_write)) + return IN_CLOSE_WRITE; + else if (EQ (symb, Qclose_nowrite)) + return IN_CLOSE_NOWRITE; + else if (EQ (symb, Qcreate)) + return IN_CREATE; + else if (EQ (symb, Qdelete)) + return IN_DELETE; + else if (EQ (symb, Qdelete_self)) + return IN_DELETE_SELF; + else if (EQ (symb, Qmodify)) + return IN_MODIFY; + else if (EQ (symb, Qmove_self)) + return IN_MOVE_SELF; + else if (EQ (symb, Qmoved_from)) + return IN_MOVED_FROM; + else if (EQ (symb, Qmoved_to)) + return IN_MOVED_TO; + else if (EQ (symb, Qopen)) + return IN_OPEN; + else if (EQ (symb, Qmove)) + return IN_MOVE; + else if (EQ (symb, Qclose)) + return IN_CLOSE; + + else if (EQ (symb, Qdont_follow)) + return IN_DONT_FOLLOW; + else if (EQ (symb, Qexcl_unlink)) + return IN_EXCL_UNLINK; + else if (EQ (symb, Qmask_add)) + return IN_MASK_ADD; + else if (EQ (symb, Qoneshot)) + return IN_ONESHOT; + else if (EQ (symb, Qonlydir)) + return IN_ONLYDIR; + + else if (EQ (symb, Qt) || EQ (symb, Qall_events)) + return IN_ALL_EVENTS; + else + signal_error ("Unknown aspect", symb); +} + +static uint32_t +aspect_to_inotifymask (Lisp_Object aspect) +{ + if (CONSP (aspect)) + { + Lisp_Object x = aspect; + uint32_t mask = 0; + while (CONSP (x)) + { + mask |= symbol_to_inotifymask (XCAR (x)); + x = XCDR (x); + } + return mask; + } + else + return symbol_to_inotifymask (aspect); +} + +DEFUN ("inotify-add-watch", Finotify_add_watch, Sinotify_add_watch, 3, 3, 0, + doc: /* Add a watch for FILE-NAME to inotify. + +A WATCH-DESCRIPTOR is returned on success. ASPECT might be one of the following +symbols or a list of those symbols: + +access +attrib +close-write +close-nowrite +create +delete +delete-self +modify +move-self +moved-from +moved-to +open + +all-events or t +move +close + +The following symbols can also be added to a list of aspects + +dont-follow +excl-unlink +mask-add +oneshot +onlydir + +Watching a directory is not recursive. CALLBACK gets called in case of an +event. It gets passed a single argument EVENT which contains an event structure +of the format + +(WATCH-DESCRIPTOR ASPECTS COOKIE NAME) + +WATCH-DESCRIPTOR is the same object that was returned by this function. It can +be tested for equality using `equal'. ASPECTS describes the event. It is a +list of ASPECT symbols described above and can also contain one of the following +symbols + +ignored +isdir +q-overflow +unmount + +COOKIE is an object that can be compared using `equal' to identify two matching +renames (moved-from and moved-to). + +If a directory is watched then NAME is the name of file that caused the event. + +See inotify(7) and inotify_add_watch(2) for further information. The inotify fd +is managed internally and there is no corresponding inotify_init. Use +`inotify-rm-watch' to remove a watch. + */) + (Lisp_Object file_name, Lisp_Object aspect, Lisp_Object callback) +{ + uint32_t mask; + Lisp_Object watch_object; + Lisp_Object decoded_file_name; + Lisp_Object watch_descriptor; + int watchdesc = -1; + + CHECK_STRING (file_name); + + if (inotifyfd == uninitialized) + { + inotifyfd = inotify_init1 (IN_NONBLOCK|IN_CLOEXEC); + if (inotifyfd == -1) + { + inotifyfd = uninitialized; + report_file_error ("File watching feature (inotify) is not available", + Qnil); + } + watch_list = Qnil; + add_read_fd (inotifyfd, &inotify_callback, NULL); + } + + mask = aspect_to_inotifymask (aspect); + decoded_file_name = ENCODE_FILE (file_name); + watchdesc = inotify_add_watch (inotifyfd, SSDATA (decoded_file_name), mask); + if (watchdesc == -1) + report_file_error ("Could not add watch for file", Fcons (file_name, Qnil)); + + watch_descriptor = make_watch_descriptor (watchdesc); + + /* Delete existing watch object. */ + watch_object = Fassoc (watch_descriptor, watch_list); + if (!NILP (watch_object)) + watch_list = Fdelete (watch_object, watch_list); + + /* Store watch object in watch list. */ + watch_object = Fcons (watch_descriptor, callback); + watch_list = Fcons (watch_object, watch_list); + + return watch_descriptor; +} + +DEFUN ("inotify-rm-watch", Finotify_rm_watch, Sinotify_rm_watch, 1, 1, 0, + doc: /* Remove an existing WATCH-DESCRIPTOR. + +WATCH-DESCRIPTOR should be an object returned by `inotify-add-watch'. + +See inotify_rm_watch(2) for more information. + */) + (Lisp_Object watch_descriptor) +{ + Lisp_Object watch_object; + int wd = XINT (watch_descriptor); + + if (inotify_rm_watch (inotifyfd, wd) == -1) + report_file_error ("Could not rm watch", Fcons (watch_descriptor, + Qnil)); + + /* Remove watch descriptor from watch list. */ + watch_object = Fassoc (watch_descriptor, watch_list); + if (!NILP (watch_object)) + watch_list = Fdelete (watch_object, watch_list); + + /* Cleanup if no more files are watched. */ + if (NILP (watch_list)) + { + close (inotifyfd); + delete_read_fd (inotifyfd); + inotifyfd = uninitialized; + } + + return Qt; +} + +void +syms_of_inotify (void) +{ + DEFSYM (Qaccess, "access"); + DEFSYM (Qattrib, "attrib"); + DEFSYM (Qclose_write, "close-write"); + DEFSYM (Qclose_nowrite, "close-nowrite"); + DEFSYM (Qcreate, "create"); + DEFSYM (Qdelete, "delete"); + DEFSYM (Qdelete_self, "delete-self"); + DEFSYM (Qmodify, "modify"); + DEFSYM (Qmove_self, "move-self"); + DEFSYM (Qmoved_from, "moved-from"); + DEFSYM (Qmoved_to, "moved-to"); + DEFSYM (Qopen, "open"); + + DEFSYM (Qall_events, "all-events"); + DEFSYM (Qmove, "move"); + DEFSYM (Qclose, "close"); + + DEFSYM (Qdont_follow, "dont-follow"); + DEFSYM (Qexcl_unlink, "excl-unlink"); + DEFSYM (Qmask_add, "mask-add"); + DEFSYM (Qoneshot, "oneshot"); + DEFSYM (Qonlydir, "onlydir"); + + DEFSYM (Qignored, "ignored"); + DEFSYM (Qisdir, "isdir"); + DEFSYM (Qq_overflow, "q-overflow"); + DEFSYM (Qunmount, "unmount"); + + defsubr (&Sinotify_add_watch); + defsubr (&Sinotify_rm_watch); + + staticpro (&watch_list); + + Fprovide (intern_c_string ("inotify"), Qnil); +} + +#endif /* HAVE_INOTIFY */ === modified file 'src/keyboard.c' --- src/keyboard.c 2012-12-08 02:30:51 +0000 +++ src/keyboard.c 2012-12-10 11:17:21 +0000 @@ -319,6 +319,9 @@ #ifdef HAVE_DBUS static Lisp_Object Qdbus_event; #endif +#ifdef HAVE_INOTIFY +static Lisp_Object Qfile_inotify; +#endif /* HAVE_INOTIFY */ static Lisp_Object Qconfig_changed_event; /* Lisp_Object Qmouse_movement; - also an event header */ @@ -3961,6 +3964,13 @@ kbd_fetch_ptr = event + 1; } #endif +#ifdef HAVE_INOTIFY + else if (event->kind == FILE_NOTIFY_EVENT) + { + obj = make_lispy_event (event); + kbd_fetch_ptr = event + 1; + } +#endif else if (event->kind == CONFIG_CHANGED_EVENT) { obj = make_lispy_event (event); @@ -5874,6 +5884,13 @@ } #endif /* HAVE_DBUS */ +#ifdef HAVE_INOTIFY + case FILE_NOTIFY_EVENT: + { + return Fcons (Qfile_inotify, event->arg); + } +#endif /* HAVE_INOTIFY */ + case CONFIG_CHANGED_EVENT: return Fcons (Qconfig_changed_event, Fcons (event->arg, @@ -11337,6 +11354,10 @@ DEFSYM (Qdbus_event, "dbus-event"); #endif +#ifdef HAVE_INOTIFY + DEFSYM (Qfile_inotify, "file-inotify"); +#endif /* HAVE_INOTIFY */ + DEFSYM (QCenable, ":enable"); DEFSYM (QCvisible, ":visible"); DEFSYM (QChelp, ":help"); @@ -12093,6 +12114,13 @@ "dbus-handle-event"); #endif +#ifdef HAVE_INOTIFY + /* Define a special event which is raised for inotify callback + functions. */ + initial_define_lispy_key (Vspecial_event_map, "file-inotify", + "inotify-handle-event"); +#endif /* HAVE_INOTIFY */ + initial_define_lispy_key (Vspecial_event_map, "config-changed-event", "ignore"); #if defined (WINDOWSNT) === modified file 'src/lisp.h' --- src/lisp.h 2012-12-08 17:19:51 +0000 +++ src/lisp.h 2012-12-10 11:17:21 +0000 @@ -3516,6 +3516,11 @@ extern Lisp_Object Qfont_param; #endif +/* Defined in inotify.c */ +#ifdef HAVE_INOTIFY +extern void syms_of_inotify (void); +#endif + /* Defined in xfaces.c. */ extern Lisp_Object Qdefault, Qtool_bar, Qfringe; extern Lisp_Object Qheader_line, Qscroll_bar, Qcursor; === modified file 'src/termhooks.h' --- src/termhooks.h 2012-11-12 16:02:46 +0000 +++ src/termhooks.h 2012-12-10 11:17:21 +0000 @@ -211,6 +211,11 @@ , NS_NONKEY_EVENT #endif +#ifdef HAVE_INOTIFY + /* File or directory was changed. */ + , FILE_NOTIFY_EVENT +#endif + }; /* If a struct input_event has a kind which is SELECTION_REQUEST_EVENT === modified file 'test/ChangeLog' --- test/ChangeLog 2012-12-02 06:06:32 +0000 +++ test/ChangeLog 2012-12-10 11:17:21 +0000 @@ -1,3 +1,7 @@ +2012-12-10 Rüdiger Sonderfeld + + * automated/inotify-test.el: New test. + 2012-12-02 Chong Yidong * automated/ruby-mode-tests.el === added file 'test/automated/inotify-test.el' --- test/automated/inotify-test.el 1970-01-01 00:00:00 +0000 +++ test/automated/inotify-test.el 2012-12-10 11:17:21 +0000 @@ -0,0 +1,60 @@ +;;; inotify-tests.el --- Test suite for inotify. -*- lexical-binding: t -*- + +;; Copyright (C) 2012 Free Software Foundation, Inc. + +;; Author: Rüdiger Sonderfeld +;; Keywords: internal +;; Human-Keywords: internal + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Code: + +(require 'ert) + +(when (featurep 'inotify) + + ;; (ert-deftest filewatch-file-watch-aspects-check () + ;; "Test whether `file-watch' properly checks the aspects." + ;; (let ((temp-file (make-temp-file "filewatch-aspects"))) + ;; (should (stringp temp-file)) + ;; (should-error (file-watch temp-file 'wrong nil) + ;; :type 'error) + ;; (should-error (file-watch temp-file '(modify t) nil) + ;; :type 'error) + ;; (should-error (file-watch temp-file '(modify all-modify) nil) + ;; :type 'error) + ;; (should-error (file-watch temp-file '(access wrong modify) nil) + ;; :type 'error))) + + (ert-deftest inotify-file-watch-simple () + "Test if watching a normal file works." + (let ((temp-file (make-temp-file "inotify-simple")) + (events 0)) + (let ((wd + (inotify-add-watch temp-file t (lambda (ev) + (setq events (1+ events)))))) + (unwind-protect + (progn + (with-temp-file temp-file + (insert "Foo\n")) + (sit-for 5) ;; Hacky. Wait for 5s until events are processed + (should (> events 0))) + (inotify-rm-watch wd))))) +) + +(provide 'inotify-tests) +;;; inotify-tests.el ends here. ------------------------------------------------------------ revno: 111170 [merge] committer: Glenn Morris branch nick: trunk timestamp: Sun 2012-12-09 18:00:42 -0800 message: Merge from emacs-24; up to r111014 diff: === modified file 'doc/emacs/ChangeLog' --- doc/emacs/ChangeLog 2012-12-06 08:33:32 +0000 +++ doc/emacs/ChangeLog 2012-12-10 02:00:42 +0000 @@ -1,3 +1,7 @@ +2012-12-10 Dani Moncayo + + * killing.texi (Deletion): Doc fix (Bug#12748). + 2012-12-06 Paul Eggert * doclicense.texi, gpl.texi: Update to latest version from FSF. === modified file 'doc/emacs/killing.texi' --- doc/emacs/killing.texi 2012-12-05 22:27:56 +0000 +++ doc/emacs/killing.texi 2012-12-08 03:25:28 +0000 @@ -123,7 +123,7 @@ (even if there were none before). With a numeric argument @var{n}, it leaves @var{n} spaces before point if @var{n} is positive; if @var{n} is negative, it deletes newlines in addition to spaces and tabs, -leaving a single space before point. +leaving @var{-n} spaces before point. @kbd{C-x C-o} (@code{delete-blank-lines}) deletes all blank lines after the current line. If the current line is blank, it deletes all === modified file 'doc/lispref/ChangeLog' --- doc/lispref/ChangeLog 2012-12-09 01:04:43 +0000 +++ doc/lispref/ChangeLog 2012-12-10 02:00:42 +0000 @@ -1,3 +1,10 @@ +2012-12-10 Stefan Monnier + + * control.texi (Pattern maching case statement): New node. + + * customize.texi (Variable Definitions): Mention the default :group + for defcustoms (bug#13093). + 2012-12-09 Glenn Morris * customize.texi (Variable Definitions): Mention eval-defun @@ -27,7 +34,7 @@ * display.texi (Defining Faces): * sequences.texi (Char-Tables): Fix xref. - * keymaps.texi (Key Sequences): kbd is now a function. + * keymaps.texi (Key Sequences): `kbd' is now a function. * commands.texi (Using Interactive): Fix index entry. @@ -47,16 +54,14 @@ (Windows and Frames): Fix example. Move description of window-in-direction here. (Recombining Windows): Fix example. - (Buffers and Windows): Fix description of - replace-buffer-in-windows. + (Buffers and Windows): Fix description of replace-buffer-in-windows. (Switching Buffers): Reword. (Display Action Functions): Minor adjustments. (Choosing Window Options): Minor fixes. (Window History): Minor rewording. (Dedicated Windows): Correct and reword part describing how dedicatedness affects functions removing buffers or windows. - * buffers.texi (The Buffer List): Fix description of - bury-buffer. + * buffers.texi (The Buffer List): Fix description of bury-buffer. 2012-11-24 Chong Yidong @@ -115,8 +120,8 @@ * windows.texi (Choosing Window): Rewrite description of display-buffer-alist (Bug#12167). - (Display Action Functions): Mention inhibit-switch-frame. Fix - description of display-buffer-below-selected. Reorder actions. + (Display Action Functions): Mention inhibit-switch-frame. + Fix description of display-buffer-below-selected. Reorder actions. Add example (Bug#12848). 2012-11-16 Glenn Morris @@ -215,11 +220,11 @@ switch-to-buffer-preserve-window-point. (Display Action Functions): Document window-height and window-width alist entries. - (Display Action Functions): Document - display-buffer-below-selected and + (Display Action Functions): + Document display-buffer-below-selected and display-buffer-in-previous-window. - (Quitting Windows): Document quit-restore-window. Rewrite - section. + (Quitting Windows): Document quit-restore-window. + Rewrite section. (Window Configurations): In window-state-get mention that argument window must be valid. (Window Parameters): Document quit-restore window parameter @@ -319,8 +324,8 @@ * minibuf.texi (Text from Minibuffer): Document read-regexp changes. - * nonascii.texi (Selecting a Representation): Document - set-buffer-multibyte changes. + * nonascii.texi (Selecting a Representation): + Document set-buffer-multibyte changes. * keymaps.texi (Toolkit Differences): Node deleted. (Easy Menu): New node. @@ -1092,8 +1097,8 @@ 2012-04-12 Jari Aalto - * processes.texi (Synchronous Processes): Mention - `default-directory' (bug#7515). + * processes.texi (Synchronous Processes): + Mention `default-directory' (bug#7515). 2012-04-09 Chong Yidong @@ -1116,8 +1121,8 @@ * minibuf.texi (Programmed Completion): Remove obsolete variable completion-annotate-function. - (Completion Variables): Rename from Completion Styles. Document - completion-extra-properties. Document completion-styles-alist + (Completion Variables): Rename from Completion Styles. + Document completion-extra-properties. Document completion-styles-alist change. (Reading File Names): minibuffer-local-filename-must-match-map is not used anymore. @@ -1252,8 +1257,8 @@ Minor clarifications. (Defining Faces): Copyedits. Update face example. (Attribute Functions): Mark set-face-foreground etc as commands. - (Face Remapping): Mention text-scale-adjust. Clarify - face-remapping-alist and related docs. + (Face Remapping): Mention text-scale-adjust. + Clarify face-remapping-alist and related docs. (Face Functions): Don't document make-face or copy-face. 2012-03-20 Chong Yidong @@ -1594,8 +1599,8 @@ (Syntax Properties): Document syntax-propertize-function and syntax-propertize-extend-region-functions. (Motion via Parsing): Clarify scan-lists. Fix indentation. - (Parser State): Update for the new "c" comment style. Fix - description of item 7 (comment style). + (Parser State): Update for the new "c" comment style. + Fix description of item 7 (comment style). * modes.texi (Minor Modes): Update how mode commands should treat arguments now. @@ -1673,9 +1678,9 @@ * debugging.texi (Debugging): Copyedits. Describe testcover, ERT. (Error Debugging): Note that debug-ignored-errors overrides list - values of debug-on-error too. Add xref to Signaling Errors. Note - that debug-on-signal is not customizable. Mention - condition-case-unless-debug. + values of debug-on-error too. Add xref to Signaling Errors. + Note that debug-on-signal is not customizable. + Mention condition-case-unless-debug. (Compilation Errors): Node deleted. * compile.texi (Compiler Errors): Move a paragraph here from @@ -1791,15 +1796,15 @@ 2012-02-04 Chong Yidong * functions.texi (What Is a Function): Add closures. Mention - "return value" terminology. Add xref for command-execute. Remove - unused "keystroke command" terminology. + "return value" terminology. Add xref for command-execute. + Remove unused "keystroke command" terminology. (Lambda Expressions): Give a different example than in the following subsection. Add xref to Anonymous Functions. (Function Documentation): Remove gratuitous markup. (Function Names): Move introductory text to `What Is a Function'. (Defining Functions): Fix defun argument spec. - (Anonymous Functions): Document lambda macro explicitly. Mention - effects on lexical binding. + (Anonymous Functions): Document lambda macro explicitly. + Mention effects on lexical binding. (Function Cells): Downplay direct usage of fset. (Closures): New node. (Inline Functions): Remove "open-code" terminology. @@ -1930,8 +1935,8 @@ * variables.texi (Variables, Local Variables, Void Variables): Edit to make the descriptions less specific to dynamic binding. (Local Variables): Default max-specpdl-size is now 1300. - (Defining Variables): Edits for lexical scoping. Delete - information about starting docstrings with *. De-document + (Defining Variables): Edits for lexical scoping. + Delete information about starting docstrings with *. De-document user-variable-p. (Tips for Defining): Remove an unimportant discussion of quitting in the middle of a load. @@ -2019,8 +2024,8 @@ 2012-01-06 Chong Yidong - * variables.texi (Directory Local Variables): Document - hack-dir-local-variables-non-file-buffer. + * variables.texi (Directory Local Variables): + Document hack-dir-local-variables-non-file-buffer. 2012-01-06 Glenn Morris === modified file 'doc/lispref/control.texi' --- doc/lispref/control.texi 2012-11-11 00:37:40 +0000 +++ doc/lispref/control.texi 2012-12-09 15:36:46 +0000 @@ -285,6 +285,110 @@ @end group @end example +@menu +* Pattern maching case statement:: +@end menu + +@node Pattern maching case statement +@subsection Pattern maching case statement +@cindex pcase +@cindex pattern matching + +To compare a particular value against various possible cases, the macro +@code{pcase} can come handy. It takes the following form: + +@example +(pcase @var{exp} @var{branch}1 @var{branch}2 @var{branch}3 @dots{}) +@end example + +where each @var{branch} takes the form @code{(@var{upattern} +@var{body-forms}@dots{})}. + +It will first evaluate @var{exp} and then compare the value against each +@var{upattern} to see which @var{branch} to use, after which it will run the +corresponding @var{body-forms}. A common use case is to distinguish +between a few different constant values: + +@example +(pcase (get-return-code x) + (`success (message "Done!")) + (`would-block (message "Sorry, can't do it now")) + (`read-only (message "The shmliblick is read-only")) + (`access-denied (message "You do not have the needed rights")) + (code (message "Unknown return code %S" code))) +@end example + +In the last clause, @code{code} is a variable that gets bound to the value that +was returned by @code{(get-return-code x)}. + +To give a more complex example, a simple interpreter for a little +expression language could look like: + +@example +(defun evaluate (exp env) + (pcase exp + (`(add ,x ,y) (+ (evaluate x env) (evaluate y env))) + (`(call ,fun ,arg) (funcall (evaluate fun) (evaluate arg env))) + (`(fn ,arg ,body) (lambda (val) + (evaluate body (cons (cons arg val) env)))) + ((pred numberp) exp) + ((pred symbolp) (cdr (assq exp env))) + (_ (error "Unknown expression %S" exp)))) +@end example + +Where @code{`(add ,x ,y)} is a pattern that checks that @code{exp} is a three +element list starting with the symbol @code{add}, then extracts the second and +third elements and binds them to the variables @code{x} and @code{y}. +@code{(pred numberp)} is a pattern that simply checks that @code{exp} +is a number, and @code{_} is the catch-all pattern that matches anything. + +There are two kinds of patterns involved in @code{pcase}, called +@emph{U-patterns} and @emph{Q-patterns}. The @var{upattern} mentioned above +are U-patterns and can take the following forms: + +@table @code +@item `@var{qpattern} +This is one of the most common form of patterns. The intention is to mimic the +backquote macro: this pattern matches those values that could have been built +by such a backquote expression. Since we're pattern matching rather than +building a value, the unquote does not indicate where to plug an expression, +but instead it lets one specify a U-pattern that should match the value at +that location. + +More specifically, a Q-pattern can take the following forms: +@table @code +@item (@var{qpattern1} . @var{qpattern2}) +This pattern matches any cons cell whose @code{car} matches @var{QPATTERN1} and +whose @code{cdr} matches @var{PATTERN2}. +@item @var{atom} +This pattern matches any atom @code{equal} to @var{atom}. +@item ,@var{upattern} +This pattern matches any object that matches the @var{upattern}. +@end table + +@item @var{symbol} +A mere symbol in a U-pattern matches anything, and additionally let-binds this +symbol to the value that it matched, so that you can later refer to it, either +in the @var{body-forms} or also later in the pattern. +@item _ +This so-called @emph{don't care} pattern matches anything, like the previous +one, but unless symbol patterns it does not bind any variable. +@item (pred @var{pred}) +This pattern matches if the function @var{pred} returns non-@code{nil} when +called with the object being matched. +@item (or @var{upattern1} @var{upattern2}@dots{}) +This pattern matches as soon as one of the argument patterns succeeds. +All argument patterns should let-bind the same variables. +@item (and @var{upattern1} @var{upattern2}@dots{}) +This pattern matches only if all the argument patterns succeed. +@item (guard @var{exp}) +This pattern ignores the object being examined and simply succeeds if @var{exp} +evaluates to non-@code{nil} and fails otherwise. It is typically used inside +an @code{and} pattern. For example, @code{(and x (guard (< x 10)))} +is a pattern which matches any number smaller than 10 and let-binds it to +the variable @code{x}. +@end table + @node Combining Conditions @section Constructs for Combining Conditions === modified file 'doc/lispref/customize.texi' --- doc/lispref/customize.texi 2012-12-09 01:04:43 +0000 +++ doc/lispref/customize.texi 2012-12-10 02:00:42 +0000 @@ -303,7 +303,9 @@ The argument @var{doc} specifies the documentation string for the variable. -Every @code{defcustom} should specify @code{:group} at least once. +If a @code{defcustom} does not specify any @code{:group}, the last group +defined with @code{defgroup} in the same file will be used. This way, most +@code{defcustom} do not need an explicit @code{:group}. When you evaluate a @code{defcustom} form with @kbd{C-M-x} in Emacs Lisp mode (@code{eval-defun}), a special feature of @code{eval-defun} === modified file 'etc/NEWS' --- etc/NEWS 2012-12-09 03:40:09 +0000 +++ etc/NEWS 2012-12-10 02:00:42 +0000 @@ -840,6 +840,10 @@ non-nil, instead of causing an error to be signaled. +++ +** `select-window' now always makes the window's buffer current. +It does so even if the window was selected before. + ++++ ** Docstrings starting with `*' no longer indicate user options. Only variables defined using `defcustom' are considered user options. The function `user-variable-p' is now an obsolete alias for === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2012-12-10 01:32:36 +0000 +++ lisp/ChangeLog 2012-12-10 02:00:42 +0000 @@ -1,3 +1,31 @@ +2012-12-10 Dani Moncayo + + * simple.el (just-one-space): Doc fix. + +2012-12-10 Eli Zaretskii + + * textmodes/texinfo.el (texinfo-enable-quote-envs): Add + "smallexample". + +2012-12-10 Le Wang + + * hilit-chg.el (hilit-chg-set-face-on-change): Don't burp in + narrowed buffer (bug#12361). + +2012-12-10 Juanma Barranquero + + * vc/vc-hooks.el (vc-state): Doc fix. + +2012-12-10 Glenn Morris + + * mail/rmail.el (rmail-maybe-display-summary): + Preserve buffer, in case select-window changes it. (Bug#13066) + +2012-12-10 Stefan Monnier + + * emacs-lisp/cl.el, emacs-lisp/cl-lib.el: Move cl-unload-function and + cl-load-hook where they belong. + 2012-12-10 Stefan Monnier * emacs-lisp/cl-lib.el (cl-declaim): Paren typo. @@ -4379,7 +4407,7 @@ * calendar/cal-tex.el (cal-tex-weekly-common): Restore leading blank page. -2012-08-22 Le Wang (tiny change) +2012-08-22 Le Wang * misc.el (forward-to-word, backward-to-word): Activate or extend the region under `shift-select-mode'. (Bug#12231) === modified file 'lisp/emacs-lisp/cl-lib.el' --- lisp/emacs-lisp/cl-lib.el 2012-12-10 01:32:36 +0000 +++ lisp/emacs-lisp/cl-lib.el 2012-12-10 02:00:42 +0000 @@ -113,12 +113,6 @@ This variable is not used at present, but it is defined in hopes that a future Emacs interpreter will be able to use it.") -(defun cl-unload-function () - "Stop unloading of the Common Lisp extensions." - (message "Cannot unload the feature `cl'") - ;; Stop standard unloading! - t) - ;;; Generalized variables. ;; These macros are defined here so that they ;; can safely be used in init files. @@ -746,8 +740,6 @@ (provide 'cl-lib) -(run-hooks 'cl-load-hook) - ;; Local variables: ;; byte-compile-dynamic: t ;; End: === modified file 'lisp/emacs-lisp/cl.el' --- lisp/emacs-lisp/cl.el 2012-11-13 03:00:09 +0000 +++ lisp/emacs-lisp/cl.el 2012-12-10 02:00:42 +0000 @@ -83,6 +83,12 @@ ;; (delete-region (1- (point)) (point))) ;; (save-buffer))))) +(defun cl-unload-function () + "Stop unloading of the Common Lisp extensions." + (message "Cannot unload the feature `cl'") + ;; Stop standard unloading! + t) + ;;; Aliases to cl-lib's features. (dolist (var '( @@ -735,4 +741,7 @@ (list accessor temp)))) (provide 'cl) + +(run-hooks 'cl-load-hook) + ;;; cl.el ends here === modified file 'lisp/hilit-chg.el' --- lisp/hilit-chg.el 2012-01-19 07:21:25 +0000 +++ lisp/hilit-chg.el 2012-12-07 05:00:04 +0000 @@ -569,37 +569,39 @@ highlight-changes-visible-mode) (hilit-chg-fixup beg end)) (highlight-save-buffer-state - (if (and (= beg end) (> leng-before 0)) - ;; deletion - (progn - ;; The eolp and bolp tests are a kludge! But they prevent - ;; rather nasty looking displays when deleting text at the end - ;; of line, such as normal corrections as one is typing and - ;; immediately makes a correction, and when deleting first - ;; character of a line. - ;; (if (= leng-before 1) - ;; (if (eolp) - ;; (setq beg-decr 0 end-incr 0) - ;; (if (bolp) - ;; (setq beg-decr 0)))) - ;; (setq beg (max (- beg beg-decr) (point-min))) - (setq end (min (+ end end-incr) (point-max))) - (setq type 'hilit-chg-delete)) - ;; Not a deletion. - ;; Most of the time the following is not necessary, but - ;; if the current text was marked as a deletion then - ;; the old overlay is still in effect, so if we add some - ;; text then remove the deletion marking, but set it to - ;; changed otherwise its highlighting disappears. - (if (eq (get-text-property end 'hilit-chg) 'hilit-chg-delete) - (progn - (put-text-property end (+ end 1) 'hilit-chg 'hilit-chg) - (if highlight-changes-visible-mode - (hilit-chg-fixup beg (+ end 1)))))) - (unless no-property-change - (put-text-property beg end 'hilit-chg type)) - (if (or highlight-changes-visible-mode no-property-change) - (hilit-chg-make-ov type beg end))))))) + (if (and (= beg end) (> leng-before 0)) + ;; deletion + (progn + ;; The eolp and bolp tests are a kludge! But they prevent + ;; rather nasty looking displays when deleting text at the end + ;; of line, such as normal corrections as one is typing and + ;; immediately makes a correction, and when deleting first + ;; character of a line. + ;; (if (= leng-before 1) + ;; (if (eolp) + ;; (setq beg-decr 0 end-incr 0) + ;; (if (bolp) + ;; (setq beg-decr 0)))) + ;; (setq beg (max (- beg beg-decr) (point-min))) + (setq end (min (+ end end-incr) (point-max))) + (setq type 'hilit-chg-delete)) + ;; Not a deletion. + ;; Most of the time the following is not necessary, but + ;; if the current text was marked as a deletion then + ;; the old overlay is still in effect. So if the user adds some + ;; text where she earlier deleted text, we have to remove the + ;; deletion marking, and replace it explicitly with a `changed' + ;; marking, otherwise its highlighting would disappear. + (if (eq (get-text-property end 'hilit-chg) 'hilit-chg-delete) + (save-restriction + (widen) + (put-text-property end (+ end 1) 'hilit-chg 'hilit-chg) + (if highlight-changes-visible-mode + (hilit-chg-fixup beg (+ end 1)))))) + (unless no-property-change + (put-text-property beg end 'hilit-chg type)) + (if (or highlight-changes-visible-mode no-property-change) + (hilit-chg-make-ov type beg end))))))) (defun hilit-chg-update () "Update a buffer's highlight changes when visibility changed." === modified file 'lisp/mail/rmail.el' --- lisp/mail/rmail.el 2012-12-07 11:19:45 +0000 +++ lisp/mail/rmail.el 2012-12-10 02:00:42 +0000 @@ -4225,6 +4225,7 @@ ;; Put the summary buffer back on the screen, if user wants that. (defun rmail-maybe-display-summary () (let ((selected (selected-window)) + (buffer (current-buffer)) window) ;; If requested, make sure the summary is displayed. (and rmail-summary-buffer (buffer-name rmail-summary-buffer) @@ -4246,7 +4247,8 @@ (progn (select-window window) (enlarge-window (- rmail-summary-window-size (window-height)))) - (select-window selected))))) + (select-window selected) + (set-buffer buffer))))) ;;;; *** Rmail Local Fontification *** === modified file 'lisp/simple.el' --- lisp/simple.el 2012-12-09 03:40:09 +0000 +++ lisp/simple.el 2012-12-10 02:00:42 +0000 @@ -744,7 +744,7 @@ (defun just-one-space (&optional n) "Delete all spaces and tabs around point, leaving one space (or N spaces). -If N is negative, delete newlines as well." +If N is negative, delete newlines as well, leaving -N spaces." (interactive "*p") (unless n (setq n 1)) (let ((orig-pos (point)) === modified file 'lisp/textmodes/texinfo.el' --- lisp/textmodes/texinfo.el 2012-12-01 05:09:12 +0000 +++ lisp/textmodes/texinfo.el 2012-12-10 02:00:42 +0000 @@ -678,7 +678,8 @@ (not (match-end 1))))) (defvar texinfo-enable-quote-macros "@\\(code\\|samp\\|kbd\\)\\>") -(defvar texinfo-enable-quote-envs '("example\\>" "lisp\\>")) +(defvar texinfo-enable-quote-envs + '("example\\>" "smallexample\\>" "lisp\\>")) (defun texinfo-insert-quote (&optional arg) "Insert the appropriate quote mark for Texinfo. Usually inserts the value of `texinfo-open-quote' (normally ``) or === modified file 'lisp/vc/vc-hooks.el' --- lisp/vc/vc-hooks.el 2012-12-01 13:25:13 +0000 +++ lisp/vc/vc-hooks.el 2012-12-10 02:00:42 +0000 @@ -438,8 +438,8 @@ (defun vc-state (file &optional backend) "Return the version control state of FILE. -If FILE is not registered, this function always returns nil. -For registered files, the value returned is one of: +A return of nil from this function means we have no information on the +status of this file. Otherwise, the value returned is one of: 'up-to-date The working file is unmodified with respect to the latest version on the current branch, and not locked. @@ -491,10 +491,8 @@ that any file with vc-state nil might be ignorable without VC knowing it. - 'unregistered The file is not under version control. + 'unregistered The file is not under version control." -A return of nil from this function means we have no information on the -status of this file." ;; Note: in Emacs 22 and older, return of nil meant the file was ;; unregistered. This is potentially a source of ;; backward-compatibility bugs. === modified file 'src/ChangeLog' --- src/ChangeLog 2012-12-10 01:44:32 +0000 +++ src/ChangeLog 2012-12-10 02:00:42 +0000 @@ -1,3 +1,31 @@ +2012-12-10 Jan Djärv + + * nsterm.m (fd_handler:): FD_ZERO fds (Bug#13103). + +2012-12-10 Fabrice Popineau + + * w32fns.c (cache_system_info): Cast sysinfo_cache.dwPageSize to + DWORD_PTR, for compatibility with 64-bit builds. + + * w32.c (_PROCESS_MEMORY_COUNTERS_EX): + (GetProcessWorkingSetSize_Proc, get_process_working_set_size) + (system_process_attributes): Use SIZE_T rather than DWORD, for + compatibility with 64-bit builds. + +2012-12-10 Christopher Schmidt + + * lread.c (Vload_source_file_function): Doc fix (Bug#11647). + +2012-12-10 Eli Zaretskii + + * indent.c (Fvertical_motion): If a display string will be + displayed on the left or the right margin, don't consider it as a + factor in cursor positioning. (Bug#13108) + +2012-12-10 Martin Rudalics + + * editfns.c (Fcompare_buffer_substrings): Reword doc-string. + 2012-12-10 Paul Eggert * fileio.c (Fsubstitute_in_file_name): Use ptrdiff_t, not int, === modified file 'src/editfns.c' --- src/editfns.c 2012-12-08 17:19:51 +0000 +++ src/editfns.c 2012-12-10 02:00:42 +0000 @@ -2635,10 +2635,10 @@ DEFUN ("compare-buffer-substrings", Fcompare_buffer_substrings, Scompare_buffer_substrings, 6, 6, 0, doc: /* Compare two substrings of two buffers; return result as number. -the value is -N if first string is less after N-1 chars, -+N if first string is greater after N-1 chars, or 0 if strings match. -Each substring is represented as three arguments: BUFFER, START and END. -That makes six args in all, three for each substring. +Return -N if first string is less after N-1 chars, +N if first string is +greater after N-1 chars, or 0 if strings match. Each substring is +represented as three arguments: BUFFER, START and END. That makes six +args in all, three for each substring. The value of `case-fold-search' in the current buffer determines whether case is significant or ignored. */) === modified file 'src/indent.c' --- src/indent.c 2012-11-24 01:57:09 +0000 +++ src/indent.c 2012-12-10 02:00:42 +0000 @@ -2025,7 +2025,11 @@ const char *s = SSDATA (it.string); const char *e = s + SBYTES (it.string); - disp_string_at_start_p = it.string_from_display_prop_p; + /* If it.area is anything but TEXT_AREA, we need not bother + about the display string, as it doesn't affect cursor + positioning. */ + disp_string_at_start_p = + it.string_from_display_prop_p && it.area == TEXT_AREA; while (s < e) { if (*s++ == '\n') === modified file 'src/lread.c' --- src/lread.c 2012-11-27 05:17:07 +0000 +++ src/lread.c 2012-12-10 02:00:42 +0000 @@ -4525,12 +4525,16 @@ Vload_read_function = Qnil; DEFVAR_LISP ("load-source-file-function", Vload_source_file_function, - doc: /* Function called in `load' for loading an Emacs Lisp source file. -This function is for doing code conversion before reading the source file. -If nil, loading is done without any code conversion. -Arguments are FULLNAME, FILE, NOERROR, NOMESSAGE, where - FULLNAME is the full name of FILE. -See `load' for the meaning of the remaining arguments. */); + doc: /* Function called in `load' to load an Emacs Lisp source file. +The value should be a function for doing code conversion before +reading a source file. It can also be nil, in which case loading is +done without any code conversion. + +If the value is a function, it is called with four arguments, +FULLNAME, FILE, NOERROR, NOMESSAGE. FULLNAME is the absolute name of +the file to load, FILE is the non-absolute name (for messages etc.), +and NOERROR and NOMESSAGE are the corresponding arguments passed to +`load'. The function should return t if the file was loaded. */); Vload_source_file_function = Qnil; DEFVAR_BOOL ("load-force-doc-strings", load_force_doc_strings, === modified file 'src/nsterm.m' --- src/nsterm.m 2012-12-04 15:15:30 +0000 +++ src/nsterm.m 2012-12-10 02:00:42 +0000 @@ -4575,7 +4575,7 @@ if (waiting) { SELECT_TYPE fds; - + FD_ZERO (&fds); FD_SET (selfds[0], &fds); result = select (selfds[0]+1, &fds, NULL, NULL, NULL); if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g') === modified file 'src/w32.c' --- src/w32.c 2012-12-08 18:27:37 +0000 +++ src/w32.c 2012-12-10 02:00:42 +0000 @@ -101,17 +101,17 @@ _WIN32_WINNT than what we use. w32api supplied with MinGW 3.15 defines it in psapi.h */ typedef struct _PROCESS_MEMORY_COUNTERS_EX { - DWORD cb; - DWORD PageFaultCount; - DWORD PeakWorkingSetSize; - DWORD WorkingSetSize; - DWORD QuotaPeakPagedPoolUsage; - DWORD QuotaPagedPoolUsage; - DWORD QuotaPeakNonPagedPoolUsage; - DWORD QuotaNonPagedPoolUsage; - DWORD PagefileUsage; - DWORD PeakPagefileUsage; - DWORD PrivateUsage; + DWORD cb; + DWORD PageFaultCount; + SIZE_T PeakWorkingSetSize; + SIZE_T WorkingSetSize; + SIZE_T QuotaPeakPagedPoolUsage; + SIZE_T QuotaPagedPoolUsage; + SIZE_T QuotaPeakNonPagedPoolUsage; + SIZE_T QuotaNonPagedPoolUsage; + SIZE_T PagefileUsage; + SIZE_T PeakPagefileUsage; + SIZE_T PrivateUsage; } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX; #endif @@ -351,8 +351,8 @@ DWORD cb); typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) ( HANDLE hProcess, - DWORD * lpMinimumWorkingSetSize, - DWORD * lpMaximumWorkingSetSize); + PSIZE_T lpMinimumWorkingSetSize, + PSIZE_T lpMaximumWorkingSetSize); typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) ( LPMEMORYSTATUS lpBuffer); typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) ( @@ -4685,8 +4685,8 @@ static BOOL WINAPI get_process_working_set_size (HANDLE h_proc, - DWORD *minrss, - DWORD *maxrss) + PSIZE_T minrss, + PSIZE_T maxrss) { static GetProcessWorkingSetSize_Proc s_pfn_Get_Process_Working_Set_Size = NULL; @@ -4931,7 +4931,7 @@ unsigned egid; PROCESS_MEMORY_COUNTERS mem; PROCESS_MEMORY_COUNTERS_EX mem_ex; - DWORD minrss, maxrss; + SIZE_T minrss, maxrss; MEMORYSTATUS memst; MEMORY_STATUS_EX memstex; double totphys = 0.0; @@ -5159,7 +5159,7 @@ && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex, sizeof (mem_ex))) { - DWORD rss = mem_ex.WorkingSetSize / 1024; + SIZE_T rss = mem_ex.WorkingSetSize / 1024; attrs = Fcons (Fcons (Qmajflt, make_fixnum_or_float (mem_ex.PageFaultCount)), @@ -5174,7 +5174,7 @@ else if (h_proc && get_process_memory_info (h_proc, &mem, sizeof (mem))) { - DWORD rss = mem_ex.WorkingSetSize / 1024; + SIZE_T rss = mem_ex.WorkingSetSize / 1024; attrs = Fcons (Fcons (Qmajflt, make_fixnum_or_float (mem.PageFaultCount)), === modified file 'src/w32fns.c' --- src/w32fns.c 2012-12-08 12:11:29 +0000 +++ src/w32fns.c 2012-12-10 02:00:42 +0000 @@ -7036,7 +7036,7 @@ /* Cache page size, allocation unit, processor type, etc. */ GetSystemInfo (&sysinfo_cache); - syspage_mask = sysinfo_cache.dwPageSize - 1; + syspage_mask = (DWORD_PTR)sysinfo_cache.dwPageSize - 1; /* Cache os info. */ osinfo_cache.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); ------------------------------------------------------------ Use --include-merged or -n0 to see merged revisions.