Now on revision 112106. ------------------------------------------------------------ revno: 112106 committer: Paul Eggert branch nick: trunk timestamp: Thu 2013-03-21 13:56:22 -0700 message: Use functions and constants to manipulate Lisp_Save_Value objects. This replaces code that used macros and strings and token-pasting. The change makes the C source a bit easier to follow, and shrinks the Emacs executable a bit. * alloc.c: Verify some properties of Lisp_Save_Value's representation. (make_save_value): Change 1st arg from string to enum. All callers changed. (INTX): Remove. (mark_object): Use if, not #if, for GC_MARK_STACK. * lisp.h (SAVE_VALUEP, XSAVE_VALUE, XSAVE_POINTER, XSAVE_INTEGER) (XSAVE_OBJECT): Now functions, not macros. (STRING_BYTES_BOUND): Now just a macro, not a constant too; the constant was never used. (SAVE_SLOT_BITS, SAVE_VALUE_SLOTS, SAVE_TYPE_BITS, SAVE_TYPE_INT_INT) (SAVE_TYPE_INT_INT_INT, SAVE_TYPE_OBJ_OBJ, SAVE_TYPE_OBJ_OBJ_OBJ) (SAVE_TYPE_OBJ_OBJ_OBJ_OBJ, SAVE_TYPE_PTR_INT, SAVE_TYPE_PTR_OBJ) (SAVE_TYPE_PTR_PTR, SAVE_TYPE_PTR_PTR_OBJ, SAVE_TYPE_MEMORY): New constants. (struct Lisp_Save_Value): Replace members area, type0, type1, type2, type3 with a single member save_type. All uses changed. (save_type, set_save_pointer, set_save_integer): New functions. * print.c (PRINTX): Remove. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2013-03-21 18:28:50 +0000 +++ src/ChangeLog 2013-03-21 20:56:22 +0000 @@ -1,5 +1,28 @@ 2013-03-21 Paul Eggert + Use functions and constants to manipulate Lisp_Save_Value objects. + This replaces code that used macros and strings and token-pasting. + The change makes the C source a bit easier to follow, + and shrinks the Emacs executable a bit. + * alloc.c: Verify some properties of Lisp_Save_Value's representation. + (make_save_value): Change 1st arg from string to enum. All callers + changed. + (INTX): Remove. + (mark_object): Use if, not #if, for GC_MARK_STACK. + * lisp.h (SAVE_VALUEP, XSAVE_VALUE, XSAVE_POINTER, XSAVE_INTEGER) + (XSAVE_OBJECT): Now functions, not macros. + (STRING_BYTES_BOUND): Now just a macro, not a constant too; + the constant was never used. + (SAVE_SLOT_BITS, SAVE_VALUE_SLOTS, SAVE_TYPE_BITS, SAVE_TYPE_INT_INT) + (SAVE_TYPE_INT_INT_INT, SAVE_TYPE_OBJ_OBJ, SAVE_TYPE_OBJ_OBJ_OBJ) + (SAVE_TYPE_OBJ_OBJ_OBJ_OBJ, SAVE_TYPE_PTR_INT, SAVE_TYPE_PTR_OBJ) + (SAVE_TYPE_PTR_PTR, SAVE_TYPE_PTR_PTR_OBJ, SAVE_TYPE_MEMORY): + New constants. + (struct Lisp_Save_Value): Replace members area, type0, type1, type2, + type3 with a single member save_type. All uses changed. + (save_type, set_save_pointer, set_save_integer): New functions. + * print.c (PRINTX): Remove. + * alloc.c: Remove redundant static declarations. 2013-03-20 Dmitry Antipov === modified file 'src/alloc.c' --- src/alloc.c 2013-03-21 18:28:50 +0000 +++ src/alloc.c 2013-03-21 20:56:22 +0000 @@ -3326,56 +3326,50 @@ total_free_markers++; } +/* Verify properties of Lisp_Save_Value's representation + that are assumed here and elsewhere. */ + +verify (SAVE_UNUSED == 0); +verify ((SAVE_INTEGER | SAVE_POINTER | SAVE_OBJECT) >> SAVE_SLOT_BITS == 0); + /* Return a Lisp_Save_Value object with the data saved according to - FMT. Format specifiers are `i' for an integer, `p' for a pointer - and `o' for Lisp_Object. Up to 4 objects can be specified. */ + DATA_TYPE. DATA_TYPE should be one of SAVE_TYPE_INT_INT, etc. */ Lisp_Object -make_save_value (const char *fmt, ...) +make_save_value (enum Lisp_Save_Type save_type, ...) { va_list ap; - int len = strlen (fmt); + int i; Lisp_Object val = allocate_misc (Lisp_Misc_Save_Value); struct Lisp_Save_Value *p = XSAVE_VALUE (val); - eassert (0 < len && len < 5); - va_start (ap, fmt); - -#define INITX(index) \ - do { \ - if (len <= index) \ - p->type ## index = SAVE_UNUSED; \ - else \ - { \ - if (fmt[index] == 'i') \ - { \ - p->type ## index = SAVE_INTEGER; \ - p->data[index].integer = va_arg (ap, ptrdiff_t); \ - } \ - else if (fmt[index] == 'p') \ - { \ - p->type ## index = SAVE_POINTER; \ - p->data[index].pointer = va_arg (ap, void *); \ - } \ - else if (fmt[index] == 'o') \ - { \ - p->type ## index = SAVE_OBJECT; \ - p->data[index].object = va_arg (ap, Lisp_Object); \ - } \ - else \ - emacs_abort (); \ - } \ - } while (0) - - INITX (0); - INITX (1); - INITX (2); - INITX (3); - -#undef INITX + eassert (0 < save_type + && (save_type < 1 << (SAVE_TYPE_BITS - 1) + || save_type == SAVE_TYPE_MEMORY)); + p->save_type = save_type; + va_start (ap, save_type); + save_type &= ~ (1 << (SAVE_TYPE_BITS - 1)); + + for (i = 0; save_type; i++, save_type >>= SAVE_SLOT_BITS) + switch (save_type & ((1 << SAVE_SLOT_BITS) - 1)) + { + case SAVE_POINTER: + p->data[i].pointer = va_arg (ap, void *); + break; + + case SAVE_INTEGER: + p->data[i].integer = va_arg (ap, ptrdiff_t); + break; + + case SAVE_OBJECT: + p->data[i].object = va_arg (ap, Lisp_Object); + break; + + default: + emacs_abort (); + } va_end (ap); - p->area = 0; return val; } @@ -3386,11 +3380,8 @@ { Lisp_Object val = allocate_misc (Lisp_Misc_Save_Value); struct Lisp_Save_Value *p = XSAVE_VALUE (val); - - p->area = 0; - p->type0 = SAVE_POINTER; + p->save_type = SAVE_POINTER; p->data[0].pointer = pointer; - p->type1 = p->type2 = p->type3 = SAVE_UNUSED; return val; } @@ -5958,12 +5949,11 @@ case Lisp_Misc_Save_Value: XMISCANY (obj)->gcmarkbit = 1; { - register struct Lisp_Save_Value *ptr = XSAVE_VALUE (obj); - /* If `area' is nonzero, `data[0].pointer' is the address + struct Lisp_Save_Value *ptr = XSAVE_VALUE (obj); + /* If `save_type' is zero, `data[0].pointer' is the address of a memory area containing `data[1].integer' potential Lisp_Objects. */ -#if GC_MARK_STACK - if (ptr->area) + if (GC_MARK_STACK && ptr->save_type == SAVE_TYPE_MEMORY) { Lisp_Object *p = ptr->data[0].pointer; ptrdiff_t nelt; @@ -5971,17 +5961,12 @@ mark_maybe_object (*p); } else -#endif /* GC_MARK_STACK */ { /* Find Lisp_Objects in `data[N]' slots and mark them. */ - if (ptr->type0 == SAVE_OBJECT) - mark_object (ptr->data[0].object); - if (ptr->type1 == SAVE_OBJECT) - mark_object (ptr->data[1].object); - if (ptr->type2 == SAVE_OBJECT) - mark_object (ptr->data[2].object); - if (ptr->type3 == SAVE_OBJECT) - mark_object (ptr->data[3].object); + int i; + for (i = 0; i < SAVE_VALUE_SLOTS; i++) + if (save_type (ptr, i) == SAVE_OBJECT) + mark_object (ptr->data[i].object); } } break; === modified file 'src/editfns.c' --- src/editfns.c 2013-03-08 09:34:35 +0000 +++ src/editfns.c 2013-03-21 20:56:22 +0000 @@ -839,7 +839,7 @@ save_excursion_save (void) { return make_save_value - ("oooo", + (SAVE_TYPE_OBJ_OBJ_OBJ_OBJ, Fpoint_marker (), /* Do not copy the mark if it points to nowhere. */ (XMARKER (BVAR (current_buffer, mark))->buffer @@ -4241,7 +4241,10 @@ memcpy (buf, initial_buffer, used); } else - XSAVE_POINTER (buf_save_value, 0) = buf = xrealloc (buf, bufsize); + { + buf = xrealloc (buf, bufsize); + set_save_pointer (buf_save_value, 0, buf); + } p = buf + used; } === modified file 'src/fileio.c' --- src/fileio.c 2013-03-13 18:42:22 +0000 +++ src/fileio.c 2013-03-21 20:56:22 +0000 @@ -4218,7 +4218,8 @@ to be signaled after decoding the text we read. */ nbytes = internal_condition_case_1 (read_non_regular, - make_save_value ("iii", (ptrdiff_t) fd, inserted, trytry), + make_save_value (SAVE_TYPE_INT_INT_INT, (ptrdiff_t) fd, + inserted, trytry), Qerror, read_non_regular_quit); if (NILP (nbytes)) === modified file 'src/ftfont.c' --- src/ftfont.c 2013-03-04 07:41:01 +0000 +++ src/ftfont.c 2013-03-21 20:56:22 +0000 @@ -393,7 +393,7 @@ cache_data = xmalloc (sizeof *cache_data); cache_data->ft_face = NULL; cache_data->fc_charset = NULL; - val = make_save_value ("pi", cache_data, 0); + val = make_save_value (SAVE_TYPE_PTR_INT, cache_data, 0); cache = Fcons (Qnil, val); Fputhash (key, cache, ft_face_cache); } @@ -1211,7 +1211,7 @@ return Qnil; } } - XSAVE_INTEGER (val, 1)++; + set_save_integer (val, 1, XSAVE_INTEGER (val, 1) + 1); size = XINT (AREF (entity, FONT_SIZE_INDEX)); if (size == 0) size = pixel_size; @@ -1326,7 +1326,7 @@ cache = ftfont_lookup_cache (val, FTFONT_CACHE_FOR_FACE); eassert (CONSP (cache)); val = XCDR (cache); - XSAVE_INTEGER (val, 1)--; + set_save_integer (val, 1, XSAVE_INTEGER (val, 1) - 1); if (XSAVE_INTEGER (val, 1) == 0) { struct ftfont_cache_data *cache_data = XSAVE_POINTER (val, 0); === modified file 'src/keymap.c' --- src/keymap.c 2013-03-13 07:27:34 +0000 +++ src/keymap.c 2013-03-21 20:56:22 +0000 @@ -611,7 +611,8 @@ } else if (CHAR_TABLE_P (binding)) map_char_table (map_keymap_char_table_item, Qnil, binding, - make_save_value ("ppo", fun, data, args)); + make_save_value (SAVE_TYPE_PTR_PTR_OBJ, + fun, data, args)); } UNGCPRO; return tail; === modified file 'src/lisp.h' --- src/lisp.h 2013-03-19 14:09:05 +0000 +++ src/lisp.h 2013-03-21 20:56:22 +0000 @@ -551,6 +551,12 @@ return num < lower ? lower : num <= upper ? num : upper; } + +/* Forward declarations. */ + +LISP_INLINE bool SAVE_VALUEP (Lisp_Object); +LISP_INLINE struct Lisp_Save_Value *XSAVE_VALUE (Lisp_Object); + /* Extract a value or address from a Lisp_Object. */ #define XCONS(a) (eassert (CONSP (a)), \ @@ -571,7 +577,6 @@ #define XMISCTYPE(a) (XMISCANY (a)->type) #define XMARKER(a) (eassert (MARKERP (a)), &(XMISC (a)->u_marker)) #define XOVERLAY(a) (eassert (OVERLAYP (a)), &(XMISC (a)->u_overlay)) -#define XSAVE_VALUE(a) (eassert (SAVE_VALUEP (a)), &(XMISC (a)->u_save_value)) /* Forwarding object types. */ @@ -781,13 +786,10 @@ would expose alloc.c internal details that we'd rather keep private. - This is a macro for use in static initializers, and a constant for - visibility to GDB. The cast to ptrdiff_t ensures that - the macro is signed. */ -static ptrdiff_t const STRING_BYTES_BOUND = + This is a macro for use in static initializers. The cast to + ptrdiff_t ensures that the macro is signed. */ #define STRING_BYTES_BOUND \ ((ptrdiff_t) min (MOST_POSITIVE_FIXNUM, min (SIZE_MAX, PTRDIFF_MAX) - 1)) - STRING_BYTES_BOUND; /* Mark STR as a unibyte string. */ #define STRING_SET_UNIBYTE(STR) \ @@ -1392,6 +1394,35 @@ SAVE_OBJECT }; +/* Number of bits needed to store one of the above values. */ +enum { SAVE_SLOT_BITS = 2 }; + +/* Number of slots in a save value where save_type is nonzero. */ +enum { SAVE_VALUE_SLOTS = 4 }; + +/* Bit-width and values for struct Lisp_Save_Value's save_type member. */ + +enum { SAVE_TYPE_BITS = SAVE_VALUE_SLOTS * SAVE_SLOT_BITS + 1 }; + +enum Lisp_Save_Type + { + SAVE_TYPE_INT_INT = SAVE_INTEGER + (SAVE_INTEGER << SAVE_SLOT_BITS), + SAVE_TYPE_INT_INT_INT + = (SAVE_INTEGER + (SAVE_TYPE_INT_INT << SAVE_SLOT_BITS)), + SAVE_TYPE_OBJ_OBJ = SAVE_OBJECT + (SAVE_OBJECT << SAVE_SLOT_BITS), + SAVE_TYPE_OBJ_OBJ_OBJ = SAVE_OBJECT + (SAVE_TYPE_OBJ_OBJ << SAVE_SLOT_BITS), + SAVE_TYPE_OBJ_OBJ_OBJ_OBJ + = SAVE_OBJECT + (SAVE_TYPE_OBJ_OBJ_OBJ << SAVE_SLOT_BITS), + SAVE_TYPE_PTR_INT = SAVE_POINTER + (SAVE_INTEGER << SAVE_SLOT_BITS), + SAVE_TYPE_PTR_OBJ = SAVE_POINTER + (SAVE_OBJECT << SAVE_SLOT_BITS), + SAVE_TYPE_PTR_PTR = SAVE_POINTER + (SAVE_POINTER << SAVE_SLOT_BITS), + SAVE_TYPE_PTR_PTR_OBJ + = SAVE_POINTER + (SAVE_TYPE_PTR_OBJ << SAVE_SLOT_BITS), + + /* This has an extra bit indicating it's raw memory. */ + SAVE_TYPE_MEMORY = SAVE_TYPE_PTR_INT + (1 << (SAVE_TYPE_BITS - 1)) + }; + /* Special object used to hold a different values for later use. This is mostly used to package C integers and pointers to call @@ -1412,73 +1443,96 @@ If yon need to pass more than just one C pointer, you should use make_save_value. This function allows you to pack up to - 4 integers, pointers or Lisp_Objects and conveniently get them - back with XSAVE_POINTER, XSAVE_INTEGER and XSAVE_OBJECT macros: + SAVE_VALUE_SLOTS integers, pointers or Lisp_Objects and + conveniently get them back with XSAVE_POINTER, XSAVE_INTEGER and + XSAVE_OBJECT macros: ... struct my_data *md = get_my_data (); - ptrdiff_t my_offset = get_my_offset (); Lisp_Object my_object = get_my_object (); record_unwind_protect - (my_unwind, make_save_value ("pio", md, my_offset, my_object)); + (my_unwind, make_save_value (SAVE_TYPE_PTR_OBJ, md, my_object)); ... Lisp_Object my_unwind (Lisp_Object arg) { struct my_data *md = XSAVE_POINTER (arg, 0); - ptrdiff_t my_offset = XSAVE_INTEGER (arg, 1); - Lisp_Object my_object = XSAVE_OBJECT (arg, 2); + Lisp_Object my_object = XSAVE_OBJECT (arg, 1); ... } If ENABLE_CHECKING is in effect, XSAVE_xxx macros do type checking of the saved objects and raise eassert if type of the saved object doesn't match the type which is extracted. In the example above, XSAVE_INTEGER (arg, 2) - or XSAVE_OBJECT (arg, 1) are wrong because integer was saved in slot 1 and - Lisp_Object was saved in slot 2 of ARG. */ + or XSAVE_OBJECT (arg, 0) are wrong because nothing was saved in slot 2 and + Lisp_Object was saved in slot 1 of ARG. */ struct Lisp_Save_Value { ENUM_BF (Lisp_Misc_Type) type : 16; /* = Lisp_Misc_Save_Value */ unsigned gcmarkbit : 1; - int spacer : 6; - /* If `area' is nonzero, `data[0].pointer' is the address of a memory area - containing `data[1].integer' potential Lisp_Objects. The rest of `data' - fields are unused. */ - unsigned area : 1; - /* If `area' is zero, `data[N]' may hold different objects which type is - encoded in `typeN' fields as described by the anonymous enum above. - E.g. if `type0' is SAVE_INTEGER, `data[0].integer' is in use. */ - unsigned type0 : 2; - unsigned type1 : 2; - unsigned type2 : 2; - unsigned type3 : 2; + int spacer : 32 - (16 + 1 + SAVE_TYPE_BITS); + + /* DATA[N] may hold up to SAVE_VALUE_SLOTS entries. The type of + V's Ith entry is given by save_type (V, I). E.g., if save_type + (V, 3) == SAVE_INTEGER, V->data[3].integer is in use. + + If SAVE_TYPE == SAVE_TYPE_MEMORY, DATA[0].pointer is the address of + a memory area containing DATA[1].integer potential Lisp_Objects. */ + ENUM_BF (Lisp_Save_Type) save_type : SAVE_TYPE_BITS; union { void *pointer; ptrdiff_t integer; Lisp_Object object; - } data[4]; + } data[SAVE_VALUE_SLOTS]; }; -/* Macro to set and extract Nth saved pointer. Type - checking is ugly because it's used as an lvalue. */ - -#define XSAVE_POINTER(obj, n) \ - XSAVE_VALUE (obj)->data[(eassert (XSAVE_VALUE (obj)->type \ - ## n == SAVE_POINTER), n)].pointer +/* Return the type of V's Nth saved value. */ +LISP_INLINE int +save_type (struct Lisp_Save_Value *v, int n) +{ + eassert (0 <= n && n < SAVE_VALUE_SLOTS); + return (v->save_type >> (SAVE_SLOT_BITS * n) & ((1 << SAVE_SLOT_BITS) - 1)); +} + +/* Get and set the Nth saved pointer. */ + +LISP_INLINE void * +XSAVE_POINTER (Lisp_Object obj, int n) +{ + eassert (save_type (XSAVE_VALUE (obj), n) == SAVE_POINTER); + return XSAVE_VALUE (obj)->data[n].pointer;; +} +LISP_INLINE void +set_save_pointer (Lisp_Object obj, int n, void *val) +{ + eassert (save_type (XSAVE_VALUE (obj), n) == SAVE_POINTER); + XSAVE_VALUE (obj)->data[n].pointer = val; +} /* Likewise for the saved integer. */ -#define XSAVE_INTEGER(obj, n) \ - XSAVE_VALUE (obj)->data[(eassert (XSAVE_VALUE (obj)->type \ - ## n == SAVE_INTEGER), n)].integer - -/* Macro to extract Nth saved object. This is never used as - an lvalue, so we can do more convenient type checking. */ - -#define XSAVE_OBJECT(obj, n) \ - (eassert (XSAVE_VALUE (obj)->type ## n == SAVE_OBJECT), \ - XSAVE_VALUE (obj)->data[n].object) +LISP_INLINE ptrdiff_t +XSAVE_INTEGER (Lisp_Object obj, int n) +{ + eassert (save_type (XSAVE_VALUE (obj), n) == SAVE_INTEGER); + return XSAVE_VALUE (obj)->data[n].integer; +} +LISP_INLINE void +set_save_integer (Lisp_Object obj, int n, ptrdiff_t val) +{ + eassert (save_type (XSAVE_VALUE (obj), n) == SAVE_INTEGER); + XSAVE_VALUE (obj)->data[n].integer = val; +} + +/* Extract Nth saved object. */ + +LISP_INLINE Lisp_Object +XSAVE_OBJECT (Lisp_Object obj, int n) +{ + eassert (save_type (XSAVE_VALUE (obj), n) == SAVE_OBJECT); + return XSAVE_VALUE (obj)->data[n].object; +} /* A miscellaneous object, when it's on the free list. */ struct Lisp_Free @@ -1501,6 +1555,13 @@ struct Lisp_Save_Value u_save_value; }; +LISP_INLINE struct Lisp_Save_Value * +XSAVE_VALUE (Lisp_Object a) +{ + eassert (SAVE_VALUEP (a)); + return & XMISC (a)->u_save_value; +} + /* Forwarding pointer to an int variable. This is allowed only in the value cell of a symbol, and it means that the symbol's value really lives in the @@ -1786,7 +1847,12 @@ #define VECTORP(x) (VECTORLIKEP (x) && !(ASIZE (x) & PSEUDOVECTOR_FLAG)) #define OVERLAYP(x) (MISCP (x) && XMISCTYPE (x) == Lisp_Misc_Overlay) #define MARKERP(x) (MISCP (x) && XMISCTYPE (x) == Lisp_Misc_Marker) -#define SAVE_VALUEP(x) (MISCP (x) && XMISCTYPE (x) == Lisp_Misc_Save_Value) + +LISP_INLINE bool +SAVE_VALUEP (Lisp_Object x) +{ + return MISCP (x) && XMISCTYPE (x) == Lisp_Misc_Save_Value; +} #define AUTOLOADP(x) (CONSP (x) && EQ (Qautoload, XCAR (x))) @@ -3105,7 +3171,7 @@ extern Lisp_Object make_float (double); extern void display_malloc_warning (void); extern ptrdiff_t inhibit_garbage_collection (void); -extern Lisp_Object make_save_value (const char *, ...); +extern Lisp_Object make_save_value (enum Lisp_Save_Type, ...); extern Lisp_Object make_save_pointer (void *); extern Lisp_Object build_overlay (Lisp_Object, Lisp_Object, Lisp_Object); extern void free_marker (Lisp_Object); @@ -3822,8 +3888,7 @@ { \ Lisp_Object arg_; \ buf = xmalloc ((nelt) * word_size); \ - arg_ = make_save_value ("pi", buf, nelt); \ - XSAVE_VALUE (arg_)->area = 1; \ + arg_ = make_save_value (SAVE_TYPE_MEMORY, buf, nelt); \ sa_must_free = 1; \ record_unwind_protect (safe_alloca_unwind, arg_); \ } \ === modified file 'src/print.c' --- src/print.c 2013-03-19 14:09:05 +0000 +++ src/print.c 2013-03-21 20:56:22 +0000 @@ -2042,17 +2042,15 @@ strout ("#area) + if (v->save_type == SAVE_TYPE_MEMORY) { ptrdiff_t amount = v->data[1].integer; #if GC_MARK_STACK - /* If GC_MARK_STACK, valid_lisp_object_p is quite reliable, - and so we try to print up to 8 objects we have saved. - Although valid_lisp_object_p is slow, this shouldn't be - a real bottleneck because we do not use this code under - normal circumstances. */ + /* valid_lisp_object_p is reliable, so try to print up + to 8 saved objects. This code is rarely used, so + it's OK that valid_lisp_object_p is slow. */ int limit = min (amount, 8); Lisp_Object *area = v->data[0].pointer; @@ -2077,9 +2075,8 @@ #else /* not GC_MARK_STACK */ - /* If !GC_MARK_STACK, we have no reliable way to find - whether Lisp_Object pointers points to an initialized - objects, and so we do not ever trying to print them. */ + /* There is no reliable way to determine whether the objects + are initialized, so do not try to print them. */ i = sprintf (buf, "with %"pD"d objects", amount); strout (buf, i, i, printcharfun); @@ -2088,33 +2085,37 @@ } else { - /* Print each `data[N]' slot according to its type. */ - -#define PRINTX(index) \ - do { \ - i = 0; \ - if (v->type ## index == SAVE_UNUSED) \ - i = sprintf (buf, ""); \ - else if (v->type ## index == SAVE_INTEGER) \ - i = sprintf (buf, "", v->data[index].integer); \ - else if (v->type ## index == SAVE_POINTER) \ - i = sprintf (buf, "", v->data[index].pointer); \ - else /* SAVE_OBJECT */ \ - print_object (v->data[index].object, printcharfun, escapeflag); \ - if (i) \ - strout (buf, i, i, printcharfun); \ - } while (0) - - PRINTX (0); - PRINTCHAR (' '); - PRINTX (1); - PRINTCHAR (' '); - PRINTX (2); - PRINTCHAR (' '); - PRINTX (3); - -#undef PRINTX - + /* Print each slot according to its type. */ + int index; + for (index = 0; index < SAVE_VALUE_SLOTS; index++) + { + if (index) + PRINTCHAR (' '); + + switch (save_type (v, index)) + { + case SAVE_UNUSED: + i = sprintf (buf, ""); + break; + + case SAVE_POINTER: + i = sprintf (buf, "", + v->data[index].pointer); + break; + + case SAVE_INTEGER: + i = sprintf (buf, "", + v->data[index].integer); + break; + + case SAVE_OBJECT: + print_object (v->data[index].object, printcharfun, + escapeflag); + continue; + } + + strout (buf, i, i, printcharfun); + } } PRINTCHAR ('>'); } === modified file 'src/xmenu.c' --- src/xmenu.c 2013-01-17 06:29:40 +0000 +++ src/xmenu.c 2013-03-21 20:56:22 +0000 @@ -2479,7 +2479,7 @@ #endif record_unwind_protect (pop_down_menu, - make_save_value ("pp", f, menu)); + make_save_value (SAVE_TYPE_PTR_PTR, f, menu)); /* Help display under X won't work because XMenuActivate contains a loop that doesn't give Emacs a chance to process it. */ ------------------------------------------------------------ revno: 112105 committer: Paul Eggert branch nick: trunk timestamp: Thu 2013-03-21 11:28:50 -0700 message: * alloc.c: Remove redundant static declarations. diff: === modified file 'src/ChangeLog' --- src/ChangeLog 2013-03-20 11:29:37 +0000 +++ src/ChangeLog 2013-03-21 18:28:50 +0000 @@ -1,3 +1,7 @@ +2013-03-21 Paul Eggert + + * alloc.c: Remove redundant static declarations. + 2013-03-20 Dmitry Antipov * window.h (struct window): Convert left_col, top_line, total_lines === modified file 'src/alloc.c' --- src/alloc.c 2013-03-19 04:41:53 +0000 +++ src/alloc.c 2013-03-21 18:28:50 +0000 @@ -323,20 +323,7 @@ static struct mem_node mem_z; #define MEM_NIL &mem_z -static struct Lisp_Vector *allocate_vectorlike (ptrdiff_t); -static void lisp_free (void *); -static void mark_stack (void); -static bool live_vector_p (struct mem_node *, void *); -static bool live_buffer_p (struct mem_node *, void *); -static bool live_string_p (struct mem_node *, void *); -static bool live_cons_p (struct mem_node *, void *); -static bool live_symbol_p (struct mem_node *, void *); -static bool live_float_p (struct mem_node *, void *); -static bool live_misc_p (struct mem_node *, void *); -static void mark_maybe_object (Lisp_Object); -static void mark_memory (void *, void *); #if GC_MARK_STACK || defined GC_MALLOC_CHECK -static void mem_init (void); static struct mem_node *mem_insert (void *, void *, enum mem_type); static void mem_insert_fixup (struct mem_node *); static void mem_rotate_left (struct mem_node *); @@ -346,11 +333,6 @@ static struct mem_node *mem_find (void *); #endif - -#if GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS -static void check_gcpros (void); -#endif - #endif /* GC_MARK_STACK || GC_MALLOC_CHECK */ #ifndef DEADP ------------------------------------------------------------ revno: 112104 committer: Ted Zlatanov branch nick: quickfixes timestamp: Thu 2013-03-21 12:11:13 -0400 message: * progmodes/cfengine.el (cfengine-common-syntax): Add "_" to word syntax. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2013-03-20 23:04:40 +0000 +++ lisp/ChangeLog 2013-03-21 16:11:13 +0000 @@ -1,3 +1,8 @@ +2013-03-21 Teodor Zlatanov + + * progmodes/cfengine.el (cfengine-common-syntax): Add "_" to word + syntax for both `cfengine2-mode' and `cfengine3-mode'. + 2013-03-20 Juri Linkov * info.el (Info-next-reference-or-link) === modified file 'lisp/progmodes/cfengine.el' --- lisp/progmodes/cfengine.el 2013-03-12 15:49:26 +0000 +++ lisp/progmodes/cfengine.el 2013-03-21 16:11:13 +0000 @@ -516,6 +516,7 @@ (defun cfengine-common-syntax (table) ;; The syntax defaults seem OK to give reasonable word movement. + (modify-syntax-entry ?w "_" table) (modify-syntax-entry ?# "<" table) (modify-syntax-entry ?\n ">#" table) (modify-syntax-entry ?\" "\"" table) ; "string" ------------------------------------------------------------ revno: 112103 fixes bug: http://debbugs.gnu.org/13989 committer: Juri Linkov branch nick: trunk timestamp: Thu 2013-03-21 01:04:40 +0200 message: Info footnote fontification and navigation. * lisp/info.el (Info-next-reference-or-link) (Info-prev-reference-or-link): New functions. (Info-next-reference, Info-prev-reference): Use them. (Info-try-follow-nearest-node): Handle footnote navigation. (Info-fontify-node): Fontify footnotes. diff: === modified file 'lisp/ChangeLog' --- lisp/ChangeLog 2013-03-20 18:13:00 +0000 +++ lisp/ChangeLog 2013-03-20 23:04:40 +0000 @@ -1,3 +1,11 @@ +2013-03-20 Juri Linkov + + * info.el (Info-next-reference-or-link) + (Info-prev-reference-or-link): New functions. + (Info-next-reference, Info-prev-reference): Use them. + (Info-try-follow-nearest-node): Handle footnote navigation. + (Info-fontify-node): Fontify footnotes. (Bug#13989) + 2013-03-20 Stefan Monnier * subr.el (posn-point, posn-string): Fix it here instead (bug#13979). === modified file 'lisp/info.el' --- lisp/info.el 2013-02-21 06:55:19 +0000 +++ lisp/info.el 2013-03-20 23:04:40 +0000 @@ -3057,6 +3057,38 @@ (select-window (posn-window (event-start e)))) (Info-scroll-down))) +(defun Info-next-reference-or-link (pat prop) + "Move point to the next pattern-based cross-reference or property-based link. +The next cross-reference is searched using the regexp PAT, and the next link +is searched using the text property PROP. Move point to the closest found position +of either a cross-reference found by `re-search-forward' or a link found by +`next-single-char-property-change'. Return the new position of point, or nil." + (let ((pcref (save-excursion (re-search-forward pat nil t))) + (plink (next-single-char-property-change (point) prop))) + (when (and (< plink (point-max)) (not (get-char-property plink prop))) + (setq plink (next-single-char-property-change plink prop))) + (if (< plink (point-max)) + (if (and pcref (<= pcref plink)) + (goto-char (or (match-beginning 1) (match-beginning 0))) + (goto-char plink)) + (if pcref (goto-char (or (match-beginning 1) (match-beginning 0))))))) + +(defun Info-prev-reference-or-link (pat prop) + "Move point to the previous pattern-based cross-reference or property-based link. +The previous cross-reference is searched using the regexp PAT, and the previous link +is searched using the text property PROP. Move point to the closest found position +of either a cross-reference found by `re-search-backward' or a link found by +`previous-single-char-property-change'. Return the new position of point, or nil." + (let ((pcref (save-excursion (re-search-backward pat nil t))) + (plink (previous-single-char-property-change (point) prop))) + (when (and (> plink (point-min)) (not (get-char-property plink prop))) + (setq plink (previous-single-char-property-change plink prop))) + (if (> plink (point-min)) + (if (and pcref (>= pcref plink)) + (goto-char (or (match-beginning 1) (match-beginning 0))) + (goto-char plink)) + (if pcref (goto-char (or (match-beginning 1) (match-beginning 0))))))) + (defun Info-next-reference (&optional recur count) "Move cursor to the next cross-reference or menu item in the node. If COUNT is non-nil (interactively with a prefix arg), jump over @@ -3071,14 +3103,13 @@ (old-pt (point)) (case-fold-search t)) (or (eobp) (forward-char 1)) - (or (re-search-forward pat nil t) + (or (Info-next-reference-or-link pat 'link) (progn (goto-char (point-min)) - (or (re-search-forward pat nil t) + (or (Info-next-reference-or-link pat 'link) (progn (goto-char old-pt) (user-error "No cross references in this node"))))) - (goto-char (or (match-beginning 1) (match-beginning 0))) (if (looking-at "\\* Menu:") (if recur (user-error "No cross references in this node") @@ -3099,14 +3130,13 @@ (let ((pat "\\*note[ \n\t]+\\([^:]+\\):\\|^\\* .*:\\|[hf]t?tps?://") (old-pt (point)) (case-fold-search t)) - (or (re-search-backward pat nil t) + (or (Info-prev-reference-or-link pat 'link) (progn (goto-char (point-max)) - (or (re-search-backward pat nil t) + (or (Info-prev-reference-or-link pat 'link) (progn (goto-char old-pt) (user-error "No cross references in this node"))))) - (goto-char (or (match-beginning 1) (match-beginning 0))) (if (looking-at "\\* Menu:") (if recur (user-error "No cross references in this node") @@ -3840,7 +3870,25 @@ ((setq node (Info-get-token (point) "File: " "File: \\([^,\n\t]*\\)")) (Info-goto-node "Top" fork)) ((setq node (Info-get-token (point) "Prev: " "Prev: \\([^,\n\t]*\\)")) - (Info-goto-node node fork))) + (Info-goto-node node fork)) + ;; footnote + ((setq node (Info-get-token (point) "(" "\\(([0-9]+)\\)")) + (let ((old-point (point)) new-point) + (save-excursion + (goto-char (point-min)) + (when (re-search-forward "^[ \t]*-+ Footnotes -+$" nil t) + (setq new-point (if (< old-point (point)) + ;; Go to footnote reference + (and (search-forward node nil t) + ;; Put point at beginning of link + (match-beginning 0)) + ;; Go to footnote definition + (search-backward node nil t))))) + (if new-point + (progn + (goto-char new-point) + (setq node t)) + (setq node nil))))) node)) (defun Info-mouse-follow-link (click) @@ -4896,6 +4944,21 @@ mouse-face highlight help-echo "mouse-2: go to this URL")))) + ;; Fontify footnotes + (goto-char (point-min)) + (when (and not-fontified-p (re-search-forward "^[ \t]*-+ Footnotes -+$" nil t)) + (let ((limit (point))) + (goto-char (point-min)) + (while (re-search-forward "\\(([0-9]+)\\)" nil t) + (add-text-properties (match-beginning 0) (match-end 0) + `(font-lock-face info-xref + link t + mouse-face highlight + help-echo + ,(if (< (point) limit) + "mouse-2: go to footnote definition" + "mouse-2: go to footnote reference")))))) + ;; Hide empty lines at the end of the node. (goto-char (point-max)) (skip-chars-backward "\n")