aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog20
-rw-r--r--NEWS10
-rw-r--r--configure.ac8
-rw-r--r--doc/gdbm.texinfo55
-rw-r--r--src/Makefile.am1
-rw-r--r--src/bucket.c43
-rw-r--r--src/gdbm.h.in6
-rw-r--r--src/gdbmcount.c65
-rw-r--r--src/gdbmdefs.h2
-rw-r--r--src/gdbmopen.c2
-rw-r--r--src/gdbmseq.c4
-rw-r--r--src/gdbmtool.c99
-rw-r--r--src/proto.h3
-rw-r--r--src/var.c53
14 files changed, 311 insertions, 60 deletions
diff --git a/ChangeLog b/ChangeLog
index cb37efc..b733844 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2013-05-21 Sergey Poznyakoff <gray@gnu.org.ua>
+
+ New function gdbm_count.
+
+ * configure.ac: Check for unsigned long long, define
+ substitution variable GDBM_COUNT_T.
+ * src/gdbmcount.c: New file.
+ * src/Makefile.am (libgdbm_la_SOURCES): Add gdbmcount.c.
+ * src/bucket.c (_gdbm_read_bucket_at): New function.
+ * src/gdbm.h.in (gdbm_count_t): New typedef.
+ (gdbm_count): New proto.
+ * src/gdbmdefs.h (GDBM_DIR_COUNT): New define.
+ * src/proto.h (_gdbm_read_bucket_at): New proto.
+ * src/var.c: New variable "filemode".
+
+ * src/gdbmtool.c: Use gdbm_count. Various bugfixes.
+
+ * NEWS: Update.
+ * doc/gdbm.texinfo: Update.
+
2013-05-17 Sergey Poznyakoff <gray@gnu.org.ua>
Update the docs.
diff --git a/NEWS b/NEWS
index 17bb8fe..b81ca6f 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-GNU dbm NEWS -- history of user-visible changes. 2013-05-17
+GNU dbm NEWS -- history of user-visible changes. 2013-05-21
Copyright (C) 1990-2013 Free Software Foundation, Inc.
See the end of file for copying conditions.
@@ -7,6 +7,14 @@ Please send gdbm bug reports to <bug-gdbm@gnu.org>.
Version 1.10.90 (Git)
* Improved dump format.
+
+* New function: gdbm_count
+
+ int gdbm_count (GDBM_FILE *file, gdbm_count *count);
+
+Counts records in `file' and stores the result in the memory location
+pointed to by `count'.
+
* New utilities: gdbm_dump and gdbm_load.
Gdbm_dump create a plain-text dump of the GDBM database. This dump
diff --git a/configure.ac b/configure.ac
index f2a37e5..b534654 100644
--- a/configure.ac
+++ b/configure.ac
@@ -87,6 +87,14 @@ AC_SYS_LARGEFILE
AC_PROG_YACC
AC_PROG_LEX
AC_C_CONST
+AC_TYPE_UNSIGNED_LONG_LONG_INT
+
+AC_SUBST(GDBM_COUNT_T)
+if test $ac_cv_type_unsigned_long_long_int = yes; then
+ GDBM_COUNT_T="unsigned long long int"
+else
+ GDBM_COUNT_T="unsigned long"
+fi
dnl Internationalization macros.
AM_GNU_GETTEXT([external], [need-ngettext])
diff --git a/doc/gdbm.texinfo b/doc/gdbm.texinfo
index 6353dd8..5c962d5 100644
--- a/doc/gdbm.texinfo
+++ b/doc/gdbm.texinfo
@@ -101,6 +101,7 @@ Functions:
* Open:: Opening the database.
* Close:: Closing the database.
+* Count:: Counting records in the database.
* Store:: Inserting and replacing records in the database.
* Fetch:: Searching records in the database.
* Delete:: Removing records from the database.
@@ -224,6 +225,12 @@ int gdbm_exists(dbf, key);
char *gdbm_strerror(errno);
int gdbm_setopt(dbf, option, value, size);
int gdbm_fdesc(dbf);
+int gdbm_export (GDBM_FILE, const char *, int, int);
+int gdbm_export_to_file (GDBM_FILE dbf, FILE *fp);
+int gdbm_import (GDBM_FILE, const char *, int);
+int gdbm_import_from_file (GDBM_FILE dbf, FILE *fp, int flag);
+int gdbm_count (GDBM_FILE dbf, gdbm_count_t *pcount);
+int gdbm_version_cmp (int const a[], int const b[]);
@end example
The @code{gdbm.h} include file is often in the @file{/usr/local/include}
@@ -343,6 +350,17 @@ The pointer returned by @code{gdbm_open}.
@end table
@end deftypefn
+@node Count
+@chapter Number of Records
+@cindex number of records
+@deftypefn {gdbm interface} int gdbm_count (GDBM_FILE @var{dbf}, @
+ gdbm_count_t *@var{pcount})
+Counts number of records in the database @var{dbf}. On success,
+stores it in the memory location pointed to by @var{pcount} and return
+0. On error, sets @code{gdbm_errno} (if relevant, also @code{errno})
+and returns -1.
+@end deftypefn
+
@node Store
@chapter Inserting and replacing records in the database.
@cindex storing records
@@ -833,6 +851,12 @@ is entirely equivalent to
gdbm_dump(@var{dbf}, @var{exportfile}, GDBM_DUMP_FMT_BINARY,
@var{flag}, @var{mode})
@end example
+
+@end deftypefn
+
+@deftypefn {gdbm interface} int gdbm_export_to_file (GDBM_FILE @var{dbf}, FILE *@var{fp})
+This is an alternative entry point to @code{gdbm_export}. This
+function writes to file @var{fp} a binary dump of the database @var{dbf}.
@end deftypefn
@deftypefn {gdbm interface} int gdbm_import (GDBM_FILE @var{dbf}, @
@@ -847,8 +871,24 @@ following construct:
@var{flag} == GDBM_REPLACE ?
GDBM_WRCREAT : GDBM_NEWDB,
0600, NULL);
-gdbm_load (&@var{dbf}, @var{exportfile}, GDBM_DUMP_FMT_BINARY,
- @var{flag}, NULL)
+gdbm_load (&@var{dbf}, @var{exportfile}, 0, @var{flag}, NULL)
+@end example
+@end deftypefn
+
+@deftypefn {gdbm interface} int gdbm_import_from_file (GDBM_FILE @var{dbf}, @
+ FILE *@var{fp}, int @var{flag})
+An alternative entry point to @code{gdbm_import}. Reads the binary
+dump from the file @var{fp} and stores the key/value pairs to
+@var{dbf}. @xref{Store}, for a description of @var{flag}.
+
+This function is equivalent to:
+
+@example
+@var{dbf} = gdbm_open (@var{importfile}, 0,
+ @var{flag} == GDBM_REPLACE ?
+ GDBM_WRCREAT : GDBM_NEWDB,
+ 0600, NULL);
+gdbm_load_from_file (@var{dbf}, @var{fp}, @var{flag}, 0, NULL);
@end example
@end deftypefn
@@ -1894,6 +1934,12 @@ Attempting to set any other value or to unset this variable produces
an error.
@end deftypevr
+@anchor{filemode}
+@deftypevr {gdbmtool variable} number filemode
+File mode (in octal) for creating new database files and database
+dumps.
+@end deftypevr
+
@deftypevr {gdbmtool variable} bool lock
Lock the database. This is the default.
@@ -2013,6 +2059,9 @@ command will not overwrite an existing file, unless the
determines the type of the dump (@pxref{Flat files}). By default, ASCII
dump is created.
+The global variable @code{filemode} specifies the permissions to use
+for the created output file.
+
See also @ref{gdbmexport}.
@end deffn
@@ -2081,6 +2130,8 @@ Whether or not to lock the database. Default is @samp{on}.
Use the memory mapping. Default is @samp{on}.
@item sync
Synchronize after each write. Default is @samp{off}.
+@item filemode
+Specifies the permissions to use in case a new file is created.
@end table
@xref{open parameters}, for a detailed description of these variables.
diff --git a/src/Makefile.am b/src/Makefile.am
index b8bebde..6a05634 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -38,6 +38,7 @@ libgdbm_la_LIBADD = @LTLIBINTL@
libgdbm_la_SOURCES = \
gdbmclose.c\
+ gdbmcount.c\
gdbmdelete.c\
gdbmdump.c\
gdbmerrno.c\
diff --git a/src/bucket.c b/src/bucket.c
index 0c87759..0934d16 100644
--- a/src/bucket.c
+++ b/src/bucket.c
@@ -104,6 +104,44 @@ _gdbm_get_bucket (GDBM_FILE dbf, int dir_index)
return;
}
+int
+_gdbm_read_bucket_at (GDBM_FILE dbf, off_t off, hash_bucket *bucket,
+ size_t size)
+{
+ off_t file_pos;
+ int i, rc;
+
+ if (dbf->cache_entry && dbf->cache_entry->ca_adr == off)
+ {
+ memcpy (bucket, dbf->bucket, size);
+ return 0;
+ }
+
+ /* Look in the cache. */
+ for (i = 0; i < dbf->cache_size; i++)
+ {
+ if (dbf->bucket_cache[i].ca_adr == off)
+ {
+ memcpy (bucket, dbf->bucket_cache[i].ca_bucket, size);
+ return 0;
+ }
+ }
+
+ /* Read the bucket. */
+ file_pos = __lseek (dbf, off, SEEK_SET);
+ if (file_pos != off)
+ {
+ gdbm_errno = GDBM_FILE_SEEK_ERROR;
+ return -1;
+ }
+ rc = _gdbm_full_read (dbf, bucket, size);
+ if (rc)
+ {
+ gdbm_errno = rc;
+ return -1;
+ }
+ return 0;
+}
/* Split the current bucket. This includes moving all items in the bucket to
a new bucket. This doesn't require any disk reads because all hash values
@@ -177,8 +215,6 @@ _gdbm_split_bucket (GDBM_FILE dbf, int next_insert)
adr_1 = _gdbm_alloc (dbf, dbf->header->bucket_size);
dbf->bucket_cache[cache_1].ca_adr = adr_1;
-
-
/* Double the directory size if necessary. */
if (dbf->header->dir_bits == dbf->bucket->bucket_bits)
{
@@ -186,8 +222,7 @@ _gdbm_split_bucket (GDBM_FILE dbf, int next_insert)
dir_adr = _gdbm_alloc (dbf, dir_size);
new_dir = (off_t *) malloc (dir_size);
if (new_dir == NULL) _gdbm_fatal (dbf, _("malloc error"));
- for (index = 0;
- index < dbf->header->dir_size/sizeof (off_t); index++)
+ for (index = 0; index < GDBM_DIR_COUNT (dbf); index++)
{
new_dir[2*index] = dbf->dir[index];
new_dir[2*index+1] = dbf->dir[index];
diff --git a/src/gdbm.h.in b/src/gdbm.h.in
index 7789d7e..f8238b9 100644
--- a/src/gdbm.h.in
+++ b/src/gdbm.h.in
@@ -79,6 +79,8 @@ extern "C" {
# define GDBM_GETMAXMAPSIZE 14 /* Get maximum mapped memory size */
# define GDBM_GETDBNAME 15 /* Return database file name */
+typedef @GDBM_COUNT_T@ gdbm_count_t;
+
/* The data and key structure. */
typedef struct {
char *dptr;
@@ -86,7 +88,7 @@ typedef struct {
} datum;
-/* The file information header. This is good enough for most applications. */
+/* A pointer to the GDBM file. */
typedef struct gdbm_file_info *GDBM_FILE;
/* External variable, the gdbm build release string. */
@@ -120,6 +122,8 @@ extern int gdbm_export_to_file (GDBM_FILE dbf, FILE *fp);
extern int gdbm_import (GDBM_FILE, const char *, int);
extern int gdbm_import_from_file (GDBM_FILE dbf, FILE *fp, int flag);
+extern int gdbm_count (GDBM_FILE dbf, gdbm_count_t *pcount);
+
#define GDBM_DUMP_FMT_BINARY 0
#define GDBM_DUMP_FMT_ASCII 1
diff --git a/src/gdbmcount.c b/src/gdbmcount.c
new file mode 100644
index 0000000..aa09f61
--- /dev/null
+++ b/src/gdbmcount.c
@@ -0,0 +1,65 @@
+/* gdbmcount.c - get number of items in a gdbm file. */
+
+/* This file is part of GDBM, the GNU data base manager.
+ Copyright (C) 1993, 1994, 2007, 2011 Free Software Foundation, Inc.
+
+ GDBM 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, or (at your option)
+ any later version.
+
+ GDBM 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 GDBM. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Include system configuration before all else. */
+#include "autoconf.h"
+#include "gdbmdefs.h"
+
+static int
+compoff (const void *a, const void *b)
+{
+ if (*(off_t*)a < *(off_t*)b)
+ return -1;
+ if (*(off_t*)a > *(off_t*)b)
+ return 1;
+ return 0;
+}
+
+int
+gdbm_count (GDBM_FILE dbf, gdbm_count_t *pcount)
+{
+ hash_bucket bucket;
+ int nbuckets = GDBM_DIR_COUNT (dbf);
+ off_t *sdir;
+ gdbm_count_t count = 0;
+ int i, last;
+
+ sdir = malloc (dbf->header->dir_size);
+ if (!sdir)
+ {
+ gdbm_errno = GDBM_MALLOC_ERROR;
+ return -1;
+ }
+
+ memcpy (sdir, dbf->dir, dbf->header->dir_size);
+ qsort (sdir, nbuckets, sizeof (off_t), compoff);
+
+ for (i = last = 0; i < nbuckets; i++)
+ {
+ if (i == 0 || sdir[i] != sdir[last])
+ {
+ if (_gdbm_read_bucket_at (dbf, sdir[i], &bucket, sizeof bucket))
+ return -1;
+ count += bucket.count;
+ last = i;
+ }
+ }
+ free (sdir);
+ *pcount = count;
+ return 0;
+}
diff --git a/src/gdbmdefs.h b/src/gdbmdefs.h
index 83a71c1..c62413b 100644
--- a/src/gdbmdefs.h
+++ b/src/gdbmdefs.h
@@ -207,6 +207,8 @@ struct gdbm_file_info {
begins */
};
+#define GDBM_DIR_COUNT(db) ((db)->header->dir_size / sizeof (off_t))
+
/* Execute CODE without clobbering errno */
#define SAVE_ERRNO(code) \
do \
diff --git a/src/gdbmopen.c b/src/gdbmopen.c
index 67db9c2..111e76f 100644
--- a/src/gdbmopen.c
+++ b/src/gdbmopen.c
@@ -277,7 +277,7 @@ gdbm_open (const char *file, int block_size, int flags, int mode,
dbf->bucket->bucket_avail[0].av_size = dbf->header->block_size;
/* Set table entries to point to hash buckets. */
- for (index = 0; index < dbf->header->dir_size / sizeof (off_t); index++)
+ for (index = 0; index < GDBM_DIR_COUNT (dbf); index++)
dbf->dir[index] = 2*dbf->header->block_size;
/* Initialize the active avail block. */
diff --git a/src/gdbmseq.c b/src/gdbmseq.c
index 4323185..bae60a3 100644
--- a/src/gdbmseq.c
+++ b/src/gdbmseq.c
@@ -49,12 +49,12 @@ get_next_key (GDBM_FILE dbf, int elem_loc, datum *return_val)
/* Find the next bucket. It is possible several entries in
the bucket directory point to the same bucket. */
- while (dbf->bucket_dir < dbf->header->dir_size / sizeof (off_t)
+ while (dbf->bucket_dir < GDBM_DIR_COUNT (dbf)
&& dbf->cache_entry->ca_adr == dbf->dir[dbf->bucket_dir])
dbf->bucket_dir++;
/* Check to see if there was a next bucket. */
- if (dbf->bucket_dir < dbf->header->dir_size / sizeof (off_t))
+ if (dbf->bucket_dir < GDBM_DIR_COUNT (dbf))
_gdbm_get_bucket (dbf, dbf->bucket_dir);
else
/* No next key, just return. */
diff --git a/src/gdbmtool.c b/src/gdbmtool.c
index 66db2ed..68a7e1d 100644
--- a/src/gdbmtool.c
+++ b/src/gdbmtool.c
@@ -49,6 +49,7 @@ opendb (char *dbname)
int cache_size = 0;
int block_size = 0;
int flags = 0;
+ int filemode;
GDBM_FILE db;
switch (variable_get ("cachesize", VART_INT, (void**) &cache_size))
@@ -85,7 +86,10 @@ opendb (char *dbname)
}
}
- db = gdbm_open (dbname, block_size, open_mode | flags, 0644, NULL);
+ if (variable_get ("filemode", VART_INT, (void**) &filemode))
+ abort ();
+
+ db = gdbm_open (dbname, block_size, open_mode | flags, filemode, NULL);
if (db == NULL)
{
@@ -320,22 +324,6 @@ get_screen_lines ()
return -1;
}
-int
-get_record_count ()
-{
- datum key, data;
- int count = 0;
- data = gdbm_firstkey (gdbm_file);
- while (data.dptr != NULL)
- {
- count++;
- key = data;
- data = gdbm_nextkey (gdbm_file, key);
- free (key.dptr);
- }
- return count;
-}
-
#define ARG_UNUSED __attribute__ ((__unused__))
@@ -367,19 +355,55 @@ close_handler (struct handler_param *param)
{
if (!gdbm_file)
terror (_("nothing to close"));
- gdbm_close (gdbm_file);
- gdbm_file = NULL;
+ else
+ {
+ gdbm_close (gdbm_file);
+ gdbm_file = NULL;
+ }
}
+static char *
+count_to_str (gdbm_count_t count, char *buf, size_t bufsize)
+{
+ char *p = buf + bufsize;
+
+ *--p = 0;
+ if (count == 0)
+ *--p = '0';
+ else
+ while (count)
+ {
+ if (p == buf)
+ return NULL;
+ *--p = '0' + count % 10;
+ count /= 10;
+ }
+ return p;
+}
+
/* count - count items in the database */
void
count_handler (struct handler_param *param)
{
- int count = get_record_count ();
- fprintf (param->fp, ngettext ("There is %d item in the database.\n",
- "There are %d items in the database.\n", count),
- count);
+ gdbm_count_t count;
+
+ if (gdbm_count (gdbm_file, &count))
+ terror ("gdbm_count: %s", gdbm_strerror (gdbm_errno));
+ else
+ {
+ char buf[128];
+ char *p = count_to_str (count, buf, sizeof buf);
+
+ if (!p)
+ terror (_("count buffer overflow"));
+ else
+ fprintf (param->fp,
+ ngettext ("There is %s item in the database.\n",
+ "There are %s items in the database.\n",
+ count),
+ p);
+ }
}
/* delete KEY - delete a key*/
@@ -389,9 +413,9 @@ delete_handler (struct handler_param *param)
if (gdbm_delete (gdbm_file, param->argv[0]->v.dat) != 0)
{
if (gdbm_errno == GDBM_ITEM_NOT_FOUND)
- terror (0, _("Item not found"));
+ terror (_("Item not found"));
else
- terror (0, _("Can't delete: %s"), gdbm_strerror (gdbm_errno));
+ terror (_("Can't delete: %s"), gdbm_strerror (gdbm_errno));
}
}
@@ -562,7 +586,7 @@ print_bucket_begin (struct handler_param *param, size_t *exp_count)
if (getnum (&temp, param->argv[0]->v.string, NULL))
return 1;
- if (temp >= gdbm_file->header->dir_size / 4)
+ if (temp >= GDBM_DIR_COUNT (gdbm_file))
{
fprintf (stderr, _("Not a bucket.\n"));
return 1;
@@ -581,7 +605,7 @@ print_dir_begin (struct handler_param *param ARG_UNUSED, size_t *exp_count)
if (checkdb ())
return 1;
if (exp_count)
- *exp_count = gdbm_file->header->dir_size / 4 + 3;
+ *exp_count = GDBM_DIR_COUNT (gdbm_file) + 3;
return 0;
}
@@ -594,7 +618,7 @@ print_dir_handler (struct handler_param *param)
fprintf (param->fp, _(" Size = %d. Bits = %d. \n\n"),
gdbm_file->header->dir_size, gdbm_file->header->dir_bits);
- for (i = 0; i < gdbm_file->header->dir_size / 4; i++)
+ for (i = 0; i < GDBM_DIR_COUNT (gdbm_file); i++)
fprintf (param->fp, " %10d: %12lu\n",
i, (unsigned long) gdbm_file->dir[i]);
}
@@ -671,7 +695,17 @@ list_begin (struct handler_param *param ARG_UNUSED, size_t *exp_count)
if (checkdb ())
return 1;
if (exp_count)
- *exp_count = get_record_count ();
+ {
+ gdbm_count_t count;
+
+ if (gdbm_count (gdbm_file, &count))
+ *exp_count = 0;
+ else if (count > SIZE_T_MAX)
+ *exp_count = SIZE_T_MAX;
+ else
+ *exp_count = count;
+ }
+
return 0;
}
@@ -722,6 +756,7 @@ export_handler (struct handler_param *param)
int format = GDBM_DUMP_FMT_ASCII;
int flags = GDBM_WRCREAT;
int i;
+ int filemode;
for (i = 1; i < param->argc; i++)
{
@@ -739,7 +774,9 @@ export_handler (struct handler_param *param)
}
}
- if (gdbm_dump (gdbm_file, param->argv[0]->v.string, format, flags, 0600))
+ if (variable_get ("filemode", VART_INT, (void**) &filemode))
+ abort ();
+ if (gdbm_dump (gdbm_file, param->argv[0]->v.string, format, flags, filemode))
{
terror (_("error dumping database: %s"),
gdbm_strerror (gdbm_errno));
@@ -1570,7 +1607,7 @@ main (int argc, char *argv[])
progname);
exit (EXIT_USAGE);
}
-
+
argc -= optind;
argv += optind;
diff --git a/src/proto.h b/src/proto.h
index f7a1a1a..83ec671 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -21,6 +21,9 @@
/* From bucket.c */
void _gdbm_new_bucket (GDBM_FILE, hash_bucket *, int);
void _gdbm_get_bucket (GDBM_FILE, int);
+int _gdbm_read_bucket_at (GDBM_FILE dbf, off_t off, hash_bucket *bucket,
+ size_t size);
+
void _gdbm_split_bucket (GDBM_FILE, int);
void _gdbm_write_bucket (GDBM_FILE, cache_elem *);
diff --git a/src/var.c b/src/var.c
index 54122eb..fb6ecf0 100644
--- a/src/var.c
+++ b/src/var.c
@@ -17,10 +17,11 @@
#include "gdbmtool.h"
-#define VARF_DFL 0x00
-#define VARF_SET 0x01
-#define VARF_INIT 0x02
-#define VARF_PROT 0x04
+#define VARF_DFL 0x00 /* Default flags -- everything disabled */
+#define VARF_SET 0x01 /* Variable is set */
+#define VARF_INIT 0x02 /* Variable is initialized */
+#define VARF_PROT 0x04 /* Variable is protected, i.e. cannot be unset */
+#define VARF_OCTAL 0x08 /* For integer variables -- use octal base */
#define VAR_IS_SET(v) ((v)->flags & (VARF_SET|VARF_INIT))
@@ -38,7 +39,6 @@ struct variable
int flags;
union value v;
int (*hook) (struct variable *, union value *);
- void *hook_data;
};
static int open_hook (struct variable *, union value *);
@@ -59,6 +59,7 @@ static struct variable vartab[] = {
{ "lock", VART_BOOL, VARF_INIT, { num: 1 } },
{ "mmap", VART_BOOL, VARF_INIT, { num: 1 } },
{ "sync", VART_BOOL, VARF_INIT, { num: 0 } },
+ { "filemode", VART_INT, VARF_INIT|VARF_OCTAL|VARF_PROT, { num: 0644 } },
{ "pager", VART_STRING, VARF_DFL },
{ "quiet", VART_BOOL, VARF_DFL },
{ NULL }
@@ -105,24 +106,24 @@ varfind (const char *name)
return NULL;
}
-typedef int (*setvar_t) (union value *, void *);
+typedef int (*setvar_t) (union value *, void *, int);
static int
-s2s (union value *vp, void *val)
+s2s (union value *vp, void *val, int flags)
{
vp->string = estrdup (val);
return VAR_OK;
}
static int
-b2s (union value *vp, void *val)
+b2s (union value *vp, void *val, int flags)
{
vp->string = estrdup (*(int*)val ? "true" : "false");
return VAR_OK;
}
static int
-i2s (union value *vp, void *val)
+i2s (union value *vp, void *val, int flags)
{
char buf[128];
snprintf (buf, sizeof buf, "%d", *(int*)val);
@@ -131,7 +132,7 @@ i2s (union value *vp, void *val)
}
static int
-s2b (union value *vp, void *val)
+s2b (union value *vp, void *val, int flags)
{
static char *trueval[] = { "on", "true", "yes", NULL };
static char *falseval[] = { "off", "false", "no", NULL };
@@ -161,10 +162,10 @@ s2b (union value *vp, void *val)
}
static int
-s2i (union value *vp, void *val)
+s2i (union value *vp, void *val, int flags)
{
char *p;
- int n = strtoul (val, &p, 0);
+ int n = strtoul (val, &p, (flags & VARF_OCTAL) ? 8 : 10);
if (*p)
return VAR_ERR_BADTYPE;
@@ -174,28 +175,28 @@ s2i (union value *vp, void *val)
}
static int
-b2b (union value *vp, void *val)
+b2b (union value *vp, void *val, int flags)
{
vp->bool = !!*(int*)val;
return VAR_OK;
}
static int
-b2i (union value *vp, void *val)
+b2i (union value *vp, void *val, int flags)
{
vp->num = *(int*)val;
return VAR_OK;
}
static int
-i2i (union value *vp, void *val)
+i2i (union value *vp, void *val, int flags)
{
vp->num = *(int*)val;
return VAR_OK;
}
static int
-i2b (union value *vp, void *val)
+i2b (union value *vp, void *val, int flags)
{
vp->bool = *(int*)val;
return VAR_OK;
@@ -221,7 +222,7 @@ variable_set (const char *name, int type, void *val)
if (val)
{
memset (&v, 0, sizeof (v));
- rc = setvar[vp->type][type] (&v, val);
+ rc = setvar[vp->type][type] (&v, val, vp->flags);
if (rc)
return rc;
valp = &v;
@@ -304,11 +305,26 @@ variable_get (const char *name, int type, void **val)
return VAR_OK;
}
+static int
+varcmp (const void *a, const void *b)
+{
+ return strcmp (((struct variable const *)a)->name,
+ ((struct variable const *)b)->name);
+}
+
void
variable_print_all (FILE *fp)
{
struct variable *vp;
char *s;
+ static int sorted;
+
+ if (!sorted)
+ {
+ qsort (vartab, sizeof (vartab) / sizeof (vartab[0]) - 1,
+ sizeof (vartab[0]), varcmp);
+ sorted = 1;
+ }
for (vp = vartab; vp->name; vp++)
{
@@ -321,7 +337,8 @@ variable_print_all (FILE *fp)
switch (vp->type)
{
case VART_INT:
- fprintf (fp, "%s=%d", vp->name, vp->v.num);
+ fprintf (fp, (vp->flags & VARF_OCTAL) ? "%s=%03o" : "%s=%d",
+ vp->name, vp->v.num);
break;
case VART_BOOL:

Return to:

Send suggestions and report system problems to the System administrator.