1 /* Zile variables handling functions
2 
3    Copyright (c) 1997-2011 Free Software Foundation, Inc.
4 
5    This file is part of GNU Zile.
6 
7    GNU Zile is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3, or (at your option)
10    any later version.
11 
12    GNU Zile is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with GNU Zile; see the file COPYING.  If not, write to the
19    Free Software Foundation, Fifth Floor, 51 Franklin Street, Boston,
20    MA 02111-1301, USA.  */
21 
22 #include <config.h>
23 
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include "hash.h"
29 
30 #include "main.h"
31 #include "extern.h"
32 
33 /*
34  * Variable type.
35  */
36 struct var_entry
37 {
38   char *var;			/* Variable name. */
39   char *defval;			/* Default value. */
40   char *val;			/* Current value, if any. */
41   bool local;			/* If true, becomes local when set. */
42   const char *doc;              /* Documentation */
43 };
44 typedef struct var_entry *var_entry;
45 
46 static Hash_table *main_vars;
47 
48 static size_t
var_hash(const void * v,size_t n)49 var_hash (const void *v, size_t n)
50 {
51   return hash_string (((var_entry) v)->var, n);
52 }
53 
54 static bool
var_cmp(const void * v,const void * w)55 var_cmp (const void *v, const void *w)
56 {
57   return STREQ (((var_entry) v)->var, ((var_entry) w)->var);
58 }
59 
60 static void
init_builtin_var(const char * var,const char * defval,bool local,const char * doc)61 init_builtin_var (const char *var, const char *defval, bool local, const char *doc)
62 {
63   var_entry p = XZALLOC (struct var_entry);
64   p->var = xstrdup (var);
65   p->defval = xstrdup (defval);
66   p->val = xstrdup (defval);
67   p->local = local;
68   p->doc = doc;
69   assert (hash_insert (main_vars, p));
70 }
71 
72 static Hash_table *
new_varlist(void)73 new_varlist (void)
74 {
75   /* Initial size is big enough for default variables and some more */
76   return hash_initialize (32, NULL, var_hash, var_cmp, NULL);
77 }
78 
79 void
init_variables(void)80 init_variables (void)
81 {
82   main_vars = new_varlist ();
83 #define X(var, defval, local, doc)              \
84   init_builtin_var (var, defval, local, doc);
85 #include "tbl_vars.h"
86 #undef X
87 }
88 
89 void
set_variable(const char * var,const char * val)90 set_variable (const char *var, const char *val)
91 {
92   Hash_table *var_list;
93   var_entry ent, key = XZALLOC (struct var_entry);
94   var_entry p = XZALLOC (struct var_entry), q;
95 
96   /* Find whether variable is buffer-local when set, and if needed
97      create a buffer-local variable list. */
98   key->var = xstrdup (var);
99   ent = hash_lookup (main_vars, key);
100   if (ent && ent->local && get_buffer_vars (cur_bp) == NULL)
101     set_buffer_vars (cur_bp, new_varlist ());
102   var_list = (ent && ent->local) ? get_buffer_vars (cur_bp) : main_vars;
103 
104   /* Insert variable if it doesn't already exist. */
105   p->var = xstrdup (var);
106   q = hash_insert (var_list, p);
107 
108   /* Update value */
109   q->val = xstrdup (val);
110 
111   /* If variable is new, initialise other fields. */
112   if (q == p)
113     {
114       if (var_list == main_vars)
115         {
116           p->defval = xstrdup (val);
117           p->local = false;
118           p->doc = "";
119         }
120     }
121 }
122 
123 static var_entry
get_variable_entry(Buffer bp,const char * var)124 get_variable_entry (Buffer bp, const char *var)
125 {
126   var_entry p = NULL, key = XZALLOC (struct var_entry);
127 
128   key->var = xstrdup (var);
129 
130   if (bp && get_buffer_vars (bp))
131     p = hash_lookup (get_buffer_vars (bp), key);
132 
133   return p ? p : hash_lookup (main_vars, key);
134 }
135 
136 const char *
get_variable_doc(const char * var,const char ** defval)137 get_variable_doc (const char *var, const char **defval)
138 {
139   var_entry p = get_variable_entry (NULL, var);
140   if (p == NULL)
141     return NULL;
142 
143   *defval = p->defval;
144   return p->doc;
145 }
146 
147 const char *
get_variable_bp(Buffer bp,const char * var)148 get_variable_bp (Buffer bp, const char *var)
149 {
150   var_entry p = get_variable_entry (bp, var);
151   return p ? p->val : NULL;
152 }
153 
154 const char *
get_variable(const char * var)155 get_variable (const char *var)
156 {
157   return get_variable_bp (cur_bp, var);
158 }
159 
160 bool
get_variable_bool(const char * var)161 get_variable_bool (const char *var)
162 {
163   const char *p = get_variable (var);
164   if (p != NULL)
165     return !STREQ (p, "nil");
166 
167   return false;
168 }
169 
170 const_astr
minibuf_read_variable_name(const char * fmt,...)171 minibuf_read_variable_name (const char *fmt, ...)
172 {
173   Completion cp = completion_new (false);
174 
175   for (var_entry p = hash_get_first (main_vars);
176        p != NULL;
177        p = hash_get_next (main_vars, p))
178     {
179       gl_sortedlist_add (get_completion_completions (cp), completion_strcmp,
180                          xstrdup (p->var));
181     }
182 
183   va_list ap;
184   va_start (ap, fmt);
185   const_astr ms = minibuf_vread_completion (fmt, "", cp, NULL,
186                                             "No variable name given",
187                                             minibuf_test_in_completions,
188                                             "Undefined variable name `%s'", ap);
189   va_end (ap);
190 
191   return ms;
192 }
193 
194 DEFUN_ARGS ("set-variable", set_variable,
195             STR_ARG (var)
196             STR_ARG (val))
197 /*+
198 Set a variable value to the user-specified value.
199 +*/
200 {
201   STR_INIT (var)
202   else
203     var = minibuf_read_variable_name ("Set variable: ");
204   if (var == NULL)
205     return leNIL;
206   STR_INIT (val)
207   else
208     val = minibuf_read ("Set %s to value: ", "", astr_cstr (var));
209   if (val == NULL)
210     ok = FUNCALL (keyboard_quit);
211 
212   if (ok == leT)
213     set_variable (astr_cstr (var), astr_cstr (val));
214 }
215 END_DEFUN
216