comparison src/symbols.c @ 4502:8748a3f7ceb4

Handle varalias chains, custom variables in #'user-variable-p. src/ChangeLog addition: 2008-08-23 Aidan Kehoe <kehoea@parhasard.net> * eval.c (Fuser_variable_p): Moved to symbols.c * symbols.c (Fcustom_variable_p): Moved here from custom.el. (user_variable_alias_check_fun): Mapper function used in `user-variable-p'. (Fuser_variable_p): Moved here from eval.c, to allow it to examine the variable alias chain. Expanded to check each entry in the variable alias chain for signs of being a user variable; documentation updated, noting the differences between GNU's behaviour and ours (ours is a little more sensible) (map_varalias_chain): New. Given a C function, call it at least once for each symbol in a symbol's varalias chain, signalling an error if there's a cycle, and returning immediately if the function returns something other than Qzero. (Fdefvaralias): Correct the use of the word "alias" in the docstring and in the argument name. Motivate this in a comment. Add support for a DOCSTRING argument, something GNU has too, and document this * gc.c (vars_of_gc): Start the docstring of `garbage-collection-messages' with an asterisk, to indicate that it's a user variable. lisp/ChangeLog addition: 2008-08-23 Aidan Kehoe <kehoea@parhasard.net> * custom.el: Move #'custom-variable-p to C, since it's now called from #'user-variable-p.
author Aidan Kehoe <kehoea@parhasard.net>
date Sat, 23 Aug 2008 16:38:51 +0200
parents a2af1ff1761f
children af95657e0bfd
comparison
equal deleted inserted replaced
4501:c4fd85dd95bd 4502:8748a3f7ceb4
82 static Lisp_Object fetch_value_maybe_past_magic (Lisp_Object sym, 82 static Lisp_Object fetch_value_maybe_past_magic (Lisp_Object sym,
83 Lisp_Object follow_past_lisp_magic); 83 Lisp_Object follow_past_lisp_magic);
84 static Lisp_Object *value_slot_past_magic (Lisp_Object sym); 84 static Lisp_Object *value_slot_past_magic (Lisp_Object sym);
85 static Lisp_Object follow_varalias_pointers (Lisp_Object symbol, 85 static Lisp_Object follow_varalias_pointers (Lisp_Object symbol,
86 Lisp_Object follow_past_lisp_magic); 86 Lisp_Object follow_past_lisp_magic);
87 static Lisp_Object map_varalias_chain (Lisp_Object symbol,
88 Lisp_Object follow_past_lisp_magic,
89 Lisp_Object (*fn) (Lisp_Object arg));
87 90
88 91
89 static Lisp_Object 92 static Lisp_Object
90 mark_symbol (Lisp_Object obj) 93 mark_symbol (Lisp_Object obj)
91 { 94 {
2752 if (NILP (after_set)) 2755 if (NILP (after_set))
2753 return local_info > 0 ? Qt : Qnil; 2756 return local_info > 0 ? Qt : Qnil;
2754 else 2757 else
2755 return local_info != 0 ? Qt : Qnil; 2758 return local_info != 0 ? Qt : Qnil;
2756 } 2759 }
2760
2761 DEFUN ("custom-variable-p", Fcustom_variable_p, 1, 1, 0, /*
2762 Return non-nil if SYMBOL names a custom variable.
2763 Does not follow the variable alias chain.
2764 */
2765 (symbol))
2766 {
2767 return (!(NILP (Fget(symbol, intern ("standard-value"), Qnil)))
2768 || !(NILP (Fget(symbol, intern ("custom-autoload"), Qnil)))) ?
2769 Qt: Qnil;
2770 }
2771
2772 static Lisp_Object
2773 user_variable_alias_check_fun (Lisp_Object symbol)
2774 {
2775 Lisp_Object documentation = Fget (symbol, Qvariable_documentation, Qnil);
2776
2777 if ((INTP (documentation) && XINT (documentation) < 0) ||
2778 (STRINGP (documentation) &&
2779 (string_byte (documentation, 0) == '*')) ||
2780 /* If (STRING . INTEGER), a negative integer means a user variable. */
2781 (CONSP (documentation)
2782 && STRINGP (XCAR (documentation))
2783 && INTP (XCDR (documentation))
2784 && XINT (XCDR (documentation)) < 0) ||
2785 !NILP (Fcustom_variable_p (symbol)))
2786 {
2787 return make_int(1);
2788 }
2789
2790 return Qzero;
2791 }
2792
2793 DEFUN ("user-variable-p", Fuser_variable_p, 1, 1, 0, /*
2794 Return t if SYMBOL names a variable intended to be set and modified by users.
2795 \(The alternative is a variable used internally in a Lisp program.)
2796 A symbol names a user variable if
2797 \(1) the first character of its documentation is `*', or
2798 \(2) it is customizable (`custom-variable-p' gives t), or
2799 \(3) it names a variable alias that eventually resolves to another user variable.
2800
2801 The GNU Emacs implementation of `user-variable-p' returns nil if there is a
2802 loop in the chain of symbols. Since this is indistinguishable from the case
2803 where a symbol names a non-user variable, XEmacs signals a
2804 `cyclic-variable-indirection' error instead; use `condition-case' to catch
2805 this error if you really want to avoid this.
2806 */
2807 (symbol))
2808 {
2809 Lisp_Object mapped;
2810
2811 if (!SYMBOLP (symbol))
2812 {
2813 return Qnil;
2814 }
2815
2816 /* Called for its side-effects, we want it to signal if there's a loop. */
2817 follow_varalias_pointers (symbol, Qt);
2818
2819 /* Look through the various aliases. */
2820 mapped = map_varalias_chain (symbol, Qt, user_variable_alias_check_fun);
2821 if (EQ (Qzero, mapped))
2822 {
2823 return Qnil;
2824 }
2825
2826 assert (make_int (1) == mapped);
2827
2828 return Qt;
2829 }
2830
2831
2757 2832
2758 2833
2759 /* 2834 /*
2760 I've gone ahead and partially implemented this because it's 2835 I've gone ahead and partially implemented this because it's
2761 super-useful for dealing with the compatibility problems in supporting 2836 super-useful for dealing with the compatibility problems in supporting
3134 } 3209 }
3135 3210
3136 return hare; 3211 return hare;
3137 } 3212 }
3138 3213
3139 DEFUN ("defvaralias", Fdefvaralias, 2, 2, 0, /* 3214 /* Map FN over the chain of variable aliases for SYMBOL. If FN returns
3215 something other than Qzero for some link in the chain, return that
3216 immediately. Otherwise return Qzero (which is not a symbol).
3217
3218 FN may be called twice on the same symbol if the varalias chain is
3219 cyclic. Prevent this by calling follow_varalias_pointers first for its
3220 side-effects.
3221
3222 Signals a cyclic-variable-indirection error if a cyclic structure is
3223 detected. */
3224
3225 static Lisp_Object
3226 map_varalias_chain (Lisp_Object symbol,
3227 Lisp_Object follow_past_lisp_magic,
3228 Lisp_Object (*fn) (Lisp_Object arg))
3229 {
3230 #define VARALIAS_INDIRECTION_SUSPICION_LENGTH 16
3231 Lisp_Object tortoise, hare, val, res;
3232 int count;
3233
3234 assert (fn);
3235
3236 /* quick out just in case */
3237 if (!SYMBOL_VALUE_MAGIC_P (XSYMBOL (symbol)->value))
3238 {
3239 return (fn)(symbol);
3240 }
3241
3242 /* Compare implementation of indirect_function(). */
3243 for (hare = tortoise = symbol, count = 0;
3244 val = fetch_value_maybe_past_magic (hare, follow_past_lisp_magic),
3245 SYMBOL_VALUE_VARALIAS_P (val);
3246 hare = symbol_value_varalias_aliasee (XSYMBOL_VALUE_VARALIAS (val)),
3247 count++)
3248 {
3249 res = (fn) (hare);
3250 if (Qzero != res)
3251 {
3252 return res;
3253 }
3254
3255 if (count < VARALIAS_INDIRECTION_SUSPICION_LENGTH) continue;
3256
3257 if (count & 1)
3258 tortoise = symbol_value_varalias_aliasee
3259 (XSYMBOL_VALUE_VARALIAS (fetch_value_maybe_past_magic
3260 (tortoise, follow_past_lisp_magic)));
3261 if (EQ (hare, tortoise))
3262 return Fsignal (Qcyclic_variable_indirection, list1 (symbol));
3263 }
3264
3265 return (fn) (hare);
3266 }
3267
3268 /*
3269
3270 OED entry, 2nd edition, IPA transliterated using Kirshenbaum:
3271
3272 alias ('eIlI@s, '&lI@s), adv. and n.
3273 [...]
3274 B. n. (with pl. aliases.)
3275 1. Another name, an assumed name.
3276 1605 Camden Rem. (1614) 147 An Alias or double name cannot preiudice the honest.
3277 1831 Edin. Rev. LIII. 364 He has been assuming various aliases.
3278 1861 Macaulay Hist. Eng. V. 92 The monk who was sometimes called Harrison
3279 and sometimes went by the alias of Johnson.
3280
3281 The alias is the fake name. Let's try to follow that usage in our
3282 documentation.
3283
3284 */
3285
3286 DEFUN ("defvaralias", Fdefvaralias, 2, 3, 0, /*
3140 Define a variable as an alias for another variable. 3287 Define a variable as an alias for another variable.
3141 Thenceforth, any operations performed on VARIABLE will actually be 3288 Thenceforth, any operations performed on VARIABLE will actually be
3142 performed on ALIAS. Both VARIABLE and ALIAS should be symbols. 3289 performed on ALIASED. Both VARIABLE and ALIASED should be symbols.
3143 If ALIAS is nil, remove any aliases for VARIABLE. 3290 If ALIASED is nil and VARIABLE is an existing alias, remove that alias.
3144 ALIAS can itself be aliased, and the chain of variable aliases 3291 ALIASED can itself be an alias, and the chain of variable aliases
3145 will be followed appropriately. 3292 will be followed appropriately.
3146 If VARIABLE already has a value, this value will be shadowed 3293 If VARIABLE already has a value, this value will be shadowed
3147 until the alias is removed, at which point it will be restored. 3294 until the alias is removed, at which point it will be restored.
3148 Currently VARIABLE cannot be a built-in variable, a variable that 3295 Currently VARIABLE cannot be a built-in variable, a variable that
3149 has a buffer-local value in any buffer, or the symbols nil or t. 3296 has a buffer-local value in any buffer, or the symbols nil or t.
3150 \(ALIAS, however, can be any type of variable.) 3297 \(ALIASED, however, can be any type of variable.)
3151 */ 3298
3152 (variable, alias)) 3299 Optional argument DOCSTRING is documentation for VARIABLE in its use as an
3300 alias for ALIASED. The XEmacs help code ignores this documentation, using
3301 the documentation of ALIASED instead, and the docstring, if specified, is
3302 not shadowed in the same way that the value is. Only use it if you know
3303 what you're doing.
3304 */
3305 (variable, aliased, docstring))
3153 { 3306 {
3154 struct symbol_value_varalias *bfwd; 3307 struct symbol_value_varalias *bfwd;
3155 Lisp_Object valcontents; 3308 Lisp_Object valcontents;
3156 3309
3157 CHECK_SYMBOL (variable); 3310 CHECK_SYMBOL (variable);
3158 reject_constant_symbols (variable, Qunbound, 0, Qt); 3311 reject_constant_symbols (variable, Qunbound, 0, Qt);
3159 3312
3160 valcontents = XSYMBOL (variable)->value; 3313 valcontents = XSYMBOL (variable)->value;
3161 3314
3162 if (NILP (alias)) 3315 if (NILP (aliased))
3163 { 3316 {
3164 if (SYMBOL_VALUE_VARALIAS_P (valcontents)) 3317 if (SYMBOL_VALUE_VARALIAS_P (valcontents))
3165 { 3318 {
3166 XSYMBOL (variable)->value = 3319 XSYMBOL (variable)->value =
3167 symbol_value_varalias_shadowed 3320 symbol_value_varalias_shadowed
3168 (XSYMBOL_VALUE_VARALIAS (valcontents)); 3321 (XSYMBOL_VALUE_VARALIAS (valcontents));
3169 } 3322 }
3170 return Qnil; 3323 return Qnil;
3171 } 3324 }
3172 3325
3173 CHECK_SYMBOL (alias); 3326 CHECK_SYMBOL (aliased);
3327
3328 if (!NILP (docstring))
3329 Fput (variable, Qvariable_documentation, docstring);
3330
3174 if (SYMBOL_VALUE_VARALIAS_P (valcontents)) 3331 if (SYMBOL_VALUE_VARALIAS_P (valcontents))
3175 { 3332 {
3176 /* transmogrify */ 3333 /* transmogrify */
3177 XSYMBOL_VALUE_VARALIAS (valcontents)->aliasee = alias; 3334 XSYMBOL_VALUE_VARALIAS (valcontents)->aliasee = aliased;
3178 return Qnil; 3335 return Qnil;
3179 } 3336 }
3180 3337
3181 if (SYMBOL_VALUE_MAGIC_P (valcontents) 3338 if (SYMBOL_VALUE_MAGIC_P (valcontents)
3182 && !UNBOUNDP (valcontents)) 3339 && !UNBOUNDP (valcontents))
3184 reject_constant_symbols (variable, Qunbound, 0, Qt); 3341 reject_constant_symbols (variable, Qunbound, 0, Qt);
3185 3342
3186 bfwd = ALLOC_LCRECORD_TYPE (struct symbol_value_varalias, 3343 bfwd = ALLOC_LCRECORD_TYPE (struct symbol_value_varalias,
3187 &lrecord_symbol_value_varalias); 3344 &lrecord_symbol_value_varalias);
3188 bfwd->magic.type = SYMVAL_VARALIAS; 3345 bfwd->magic.type = SYMVAL_VARALIAS;
3189 bfwd->aliasee = alias; 3346 bfwd->aliasee = aliased;
3190 bfwd->shadowed = valcontents; 3347 bfwd->shadowed = valcontents;
3191 3348
3192 valcontents = wrap_symbol_value_magic (bfwd); 3349 valcontents = wrap_symbol_value_magic (bfwd);
3193 XSYMBOL (variable)->value = valcontents; 3350 XSYMBOL (variable)->value = valcontents;
3194 return Qnil; 3351 return Qnil;
3195 } 3352 }
3196 3353
3197 DEFUN ("variable-alias", Fvariable_alias, 1, 2, 0, /* 3354 DEFUN ("variable-alias", Fvariable_alias, 1, 2, 0, /*
3198 If VARIABLE is aliased to another variable, return that variable. 3355 If VARIABLE is an alias of another variable, return that variable.
3199 VARIABLE should be a symbol. If VARIABLE is not aliased, return nil. 3356 VARIABLE should be a symbol. If VARIABLE is not an alias, return nil.
3200 Variable aliases are created with `defvaralias'. See also 3357 Variable aliases are created with `defvaralias'. See also
3201 `indirect-variable'. 3358 `indirect-variable'.
3202 */ 3359 */
3203 (variable, follow_past_lisp_magic)) 3360 (variable, follow_past_lisp_magic))
3204 { 3361 {
3753 DEFSUBR (Fmake_variable_buffer_local); 3910 DEFSUBR (Fmake_variable_buffer_local);
3754 DEFSUBR (Fmake_local_variable); 3911 DEFSUBR (Fmake_local_variable);
3755 DEFSUBR (Fkill_local_variable); 3912 DEFSUBR (Fkill_local_variable);
3756 DEFSUBR (Fkill_console_local_variable); 3913 DEFSUBR (Fkill_console_local_variable);
3757 DEFSUBR (Flocal_variable_p); 3914 DEFSUBR (Flocal_variable_p);
3915 DEFSUBR (Fcustom_variable_p);
3916 DEFSUBR (Fuser_variable_p);
3758 DEFSUBR (Fdefvaralias); 3917 DEFSUBR (Fdefvaralias);
3759 DEFSUBR (Fvariable_alias); 3918 DEFSUBR (Fvariable_alias);
3760 DEFSUBR (Findirect_variable); 3919 DEFSUBR (Findirect_variable);
3761 DEFSUBR (Fvariable_binding_locus); 3920 DEFSUBR (Fvariable_binding_locus);
3762 DEFSUBR (Fdontusethis_set_symbol_value_handler); 3921 DEFSUBR (Fdontusethis_set_symbol_value_handler);