Imported Upstream version 1.11
[platform/upstream/gdbm.git] / src / var.c
1 /* This file is part of GDBM, the GNU data base manager.
2    Copyright (C) 1990, 1991, 1993, 2007, 2011, 2013 Free Software Foundation,
3    Inc.
4
5    GDBM is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3, or (at your option)
8    any later version.
9
10    GDBM is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with GDBM. If not, see <http://www.gnu.org/licenses/>.    */
17
18 #include "gdbmtool.h"
19
20 #define VARF_DFL    0x00   /* Default flags -- everything disabled */
21 #define VARF_SET    0x01   /* Variable is set */
22 #define VARF_INIT   0x02   /* Variable is initialized */
23 #define VARF_PROT   0x04   /* Variable is protected, i.e. cannot be unset */
24 #define VARF_OCTAL  0x08   /* For integer variables -- use octal base */
25
26 #define VAR_IS_SET(v) ((v)->flags & (VARF_SET|VARF_INIT))
27
28 union value
29 {
30   char *string;
31   int bool;
32   int num;
33 };
34
35 struct variable
36 {
37   char *name;
38   int type;
39   int flags;
40   union value v;
41   int (*hook) (struct variable *, union value *);
42 };
43
44 static int open_hook (struct variable *, union value *);
45
46 static struct variable vartab[] = {
47   /* Top-level prompt */
48   { "ps1", VART_STRING, VARF_INIT, { "%p>%_" } },
49   /* Second-level prompt (used within "def" block) */
50   { "ps2", VART_STRING, VARF_INIT, { "%_>%_" } },
51   /* This delimits array members */
52   { "delim1", VART_STRING, VARF_INIT|VARF_PROT, { "," } },
53   /* This delimits structure members */
54   { "delim2", VART_STRING, VARF_INIT|VARF_PROT, { "," } },
55   { "confirm", VART_BOOL, VARF_INIT, { num: 1 } },
56   { "cachesize", VART_INT, VARF_DFL },
57   { "blocksize", VART_INT, VARF_DFL },
58   { "open", VART_STRING, VARF_DFL, { NULL }, open_hook },
59   { "lock", VART_BOOL, VARF_INIT, { num: 1 } },
60   { "mmap", VART_BOOL, VARF_INIT, { num: 1 } },
61   { "sync", VART_BOOL, VARF_INIT, { num: 0 } },
62   { "filemode", VART_INT, VARF_INIT|VARF_OCTAL|VARF_PROT, { num: 0644 } },
63   { "pager", VART_STRING, VARF_DFL },
64   { "quiet", VART_BOOL, VARF_DFL },
65   { NULL }
66 };
67
68 static int
69 open_hook (struct variable *var, union value *v)
70 {
71   static struct {
72     char *s;
73     int t;
74   } trans[] = {
75     { "newdb", GDBM_NEWDB },
76     { "wrcreat", GDBM_WRCREAT },
77     { "rw", GDBM_WRCREAT },
78     { "reader", GDBM_READER },
79     { "readonly", GDBM_READER },
80     { NULL }
81   };
82   int i;
83
84   if (!v)
85     return VAR_ERR_BADVALUE;
86   
87   for (i = 0; trans[i].s; i++)
88     if (strcmp (trans[i].s, v->string) == 0)
89       {
90         open_mode = trans[i].t;
91         return VAR_OK;
92       }
93
94   return VAR_ERR_BADVALUE;
95 }
96             
97 static struct variable *
98 varfind (const char *name)
99 {
100   struct variable *vp;
101
102   for (vp = vartab; vp->name; vp++)
103     if (strcmp (vp->name, name) == 0)
104       return vp;
105   
106   return NULL;
107 }
108
109 typedef int (*setvar_t) (union value *, void *, int);
110
111 static int
112 s2s (union value *vp, void *val, int flags)
113 {
114   vp->string = estrdup (val);
115   return VAR_OK;
116 }
117
118 static int
119 b2s (union value *vp, void *val, int flags)
120 {
121   vp->string = estrdup (*(int*)val ? "true" : "false");
122   return VAR_OK;
123 }
124
125 static int
126 i2s (union value *vp, void *val, int flags)
127 {
128   char buf[128];
129   snprintf (buf, sizeof buf, "%d", *(int*)val);
130   vp->string = estrdup (buf);
131   return VAR_OK;
132 }
133
134 static int
135 s2b (union value *vp, void *val, int flags)
136 {
137   static char *trueval[] = { "on", "true", "yes", NULL };
138   static char *falseval[] = { "off", "false", "no", NULL };
139   int i;
140   unsigned long n;
141   char *p;
142   
143   for (i = 0; trueval[i]; i++)
144     if (strcasecmp (trueval[i], val) == 0)
145       {
146         vp->bool = 1;
147         return VAR_OK;
148       }
149   
150   for (i = 0; falseval[i]; i++)
151     if (strcasecmp (falseval[i], val) == 0)
152       {
153         vp->bool = 0;
154         return VAR_OK;
155       }
156   
157   n = strtoul (val, &p, 0);
158   if (*p)
159     return VAR_ERR_BADTYPE;
160   vp->bool = !!n;
161   return VAR_OK;
162 }
163   
164 static int
165 s2i (union value *vp, void *val, int flags)
166 {
167   char *p;
168   int n = strtoul (val, &p, (flags & VARF_OCTAL) ? 8 : 10);
169
170   if (*p)
171     return VAR_ERR_BADTYPE;
172
173   vp->num = n;
174   return VAR_OK;
175 }
176
177 static int
178 b2b (union value *vp, void *val, int flags)
179 {
180   vp->bool = !!*(int*)val;
181   return VAR_OK;
182 }
183
184 static int
185 b2i (union value *vp, void *val, int flags)
186 {
187   vp->num = *(int*)val;
188   return VAR_OK;
189 }
190
191 static int
192 i2i (union value *vp, void *val, int flags)
193 {
194   vp->num = *(int*)val;
195   return VAR_OK;
196 }
197
198 static int
199 i2b (union value *vp, void *val, int flags)
200 {
201   vp->bool = *(int*)val;
202   return VAR_OK;
203 }
204
205 static setvar_t setvar[3][3] = {
206             /*    s     b    i */
207   /* s */    {   s2s,  b2s, i2s },
208   /* b */    {   s2b,  b2b, i2b },
209   /* i */    {   s2i,  b2i, i2i }
210 };
211
212 int
213 variable_set (const char *name, int type, void *val)
214 {
215   struct variable *vp = varfind (name);
216   int rc;
217   union value v, *valp;
218   
219   if (!vp)
220     return VAR_ERR_NOTDEF;
221
222   if (val)
223     {
224       memset (&v, 0, sizeof (v));
225       rc = setvar[vp->type][type] (&v, val, vp->flags);
226       if (rc)
227         return rc;
228       valp = &v; 
229     }
230   else
231     {
232       if (vp->flags & VARF_PROT)
233         return VAR_ERR_BADVALUE;
234       valp = NULL;
235     }
236   
237   if (vp->hook && (rc = vp->hook (vp, valp)) != VAR_OK)
238     return rc;
239
240   if (vp->type == VART_STRING && (vp->flags & VARF_SET))
241     free (vp->v.string);
242
243   if (!val)
244     {
245       vp->flags &= (VARF_INIT|VARF_SET);
246     }
247   else
248     {
249       vp->v = v;
250       vp->flags &= ~VARF_INIT;
251       vp->flags |= VARF_SET;
252     }
253   
254   return VAR_OK;
255 }
256
257 int
258 variable_unset (const char *name)
259 {
260   struct variable *vp = varfind (name);
261   int rc;
262     
263   if (!vp)
264     return VAR_ERR_NOTDEF;
265   if (vp->flags & VARF_PROT)
266     return VAR_ERR_BADVALUE;
267
268   if (vp->hook && (rc = vp->hook (vp, NULL)) != VAR_OK)
269     return rc;
270
271   vp->flags &= ~(VARF_INIT|VARF_SET);
272
273   return VAR_OK;
274 }
275
276 int
277 variable_get (const char *name, int type, void **val)
278 {
279   struct variable *vp = varfind (name);
280
281   if (!vp)
282     return VAR_ERR_NOTDEF;
283   
284   if (type != vp->type)
285     return VAR_ERR_BADTYPE;
286
287   if (!VAR_IS_SET (vp))
288     return VAR_ERR_NOTSET;
289   
290   switch (vp->type)
291     {
292     case VART_STRING:
293       *val = vp->v.string;
294       break;
295
296     case VART_BOOL:
297       *(int*)val = vp->v.bool;
298       break;
299       
300     case VART_INT:
301       *(int*)val = vp->v.num;
302       break;
303     }
304
305   return VAR_OK;
306 }
307
308 static int
309 varcmp (const void *a, const void *b)
310 {
311   return strcmp (((struct variable const *)a)->name,
312                  ((struct variable const *)b)->name);
313 }
314
315 void
316 variable_print_all (FILE *fp)
317 {
318   struct variable *vp;
319   char *s;
320   static int sorted;
321   
322   if (!sorted)
323     {
324       qsort (vartab, sizeof (vartab) / sizeof (vartab[0]) - 1,
325              sizeof (vartab[0]), varcmp);
326       sorted = 1;
327     }
328   
329   for (vp = vartab; vp->name; vp++)
330     {
331       if (!VAR_IS_SET (vp))
332         {
333           fprintf (fp, "# %s is unset", vp->name);
334         }
335       else
336         {
337           switch (vp->type)
338             {
339             case VART_INT:
340               fprintf (fp, (vp->flags & VARF_OCTAL) ? "%s=%03o" : "%s=%d",
341                        vp->name, vp->v.num);
342               break;
343               
344             case VART_BOOL:
345               fprintf (fp, "%s%s", vp->v.bool ? "" : "no", vp->name);
346               break;
347               
348             case VART_STRING:
349               fprintf (fp, "%s=\"", vp->name);
350               for (s = vp->v.string; *s; s++)
351                 {
352                   int c;
353                   
354                   if (isprint (*s))
355                     fputc (*s, fp);
356                   else if ((c = escape (*s)))
357                     fprintf (fp, "\\%c", c);
358                   else
359                     fprintf (fp, "\\%03o", *s);
360                 }
361               fprintf (fp, "\"");
362             }
363         }
364       fputc ('\n', fp);
365     }
366 }
367
368 int
369 variable_is_set (const char *name)
370 {
371   struct variable *vp = varfind (name);
372
373   if (!vp)
374     return 0;
375   return VAR_IS_SET (vp);
376 }
377
378 int
379 variable_is_true (const char *name)
380 {
381   int n;
382
383   if (variable_get (name, VART_BOOL, (void **) &n) == VAR_OK)
384     return n;
385   return 0;
386 }