summaryrefslogtreecommitdiff
path: root/db-4.8.30/examples_c/csv
diff options
context:
space:
mode:
Diffstat (limited to 'db-4.8.30/examples_c/csv')
-rw-r--r--db-4.8.30/examples_c/csv/DbRecord.c470
-rw-r--r--db-4.8.30/examples_c/csv/Makefile75
-rw-r--r--db-4.8.30/examples_c/csv/README408
-rw-r--r--db-4.8.30/examples_c/csv/code.c405
-rw-r--r--db-4.8.30/examples_c/csv/csv.h101
-rw-r--r--db-4.8.30/examples_c/csv/csv_extern.h37
-rw-r--r--db-4.8.30/examples_c/csv/db.c244
-rw-r--r--db-4.8.30/examples_c/csv/load.c346
-rw-r--r--db-4.8.30/examples_c/csv/load_main.c117
-rw-r--r--db-4.8.30/examples_c/csv/query.c241
-rw-r--r--db-4.8.30/examples_c/csv/query_main.c99
-rw-r--r--db-4.8.30/examples_c/csv/sample.csv8
-rw-r--r--db-4.8.30/examples_c/csv/sample.desc10
-rw-r--r--db-4.8.30/examples_c/csv/util.c309
14 files changed, 2870 insertions, 0 deletions
diff --git a/db-4.8.30/examples_c/csv/DbRecord.c b/db-4.8.30/examples_c/csv/DbRecord.c
new file mode 100644
index 0000000..56af9d4
--- /dev/null
+++ b/db-4.8.30/examples_c/csv/DbRecord.c
@@ -0,0 +1,470 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2005-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+#include "csv.h"
+#include "csv_local.h"
+#include "csv_extern.h"
+
+static int DbRecord_field(DbRecord *, u_int, void *, datatype);
+static int DbRecord_search_field(DbField *, char *, OPERATOR);
+static int DbRecord_search_recno(char *, OPERATOR);
+
+/*
+ * DbRecord_print --
+ * Display a DbRecord structure.
+ */
+void
+DbRecord_print(DbRecord *recordp, FILE *fp)
+{
+ DbField *f;
+ void *faddr;
+
+ if (fp == NULL)
+ fp = stdout;
+
+ fprintf(fp, "Record: %lu:\n", (u_long)recordp->recno);
+ for (f = fieldlist; f->name != NULL; ++f) {
+ faddr = (u_int8_t *)recordp + f->offset;
+ fprintf(fp, "\t%s: ", f->name);
+ switch (f->type) {
+ case NOTSET:
+ /* NOTREACHED */
+ abort();
+ break;
+ case DOUBLE:
+ fprintf(fp, "%f\n", *(double *)faddr);
+ break;
+ case STRING:
+ fprintf(fp, "%s\n", *(char **)faddr);
+ break;
+ case UNSIGNED_LONG:
+ fprintf(fp, "%lu\n", *(u_long *)faddr);
+ break;
+ }
+ }
+}
+
+/*
+ * DbRecord_read --
+ * Read a specific record from the database.
+ */
+int
+DbRecord_read(u_long recno_ulong, DbRecord *recordp)
+{
+ DBT key, data;
+ u_int32_t recno;
+ int ret;
+
+ /*
+ * XXX
+ * This code assumes a record number (typed as u_int32_t) is the same
+ * size as an unsigned long, and there's no reason to believe that.
+ */
+ recno = recno_ulong;
+
+ /*
+ * Retrieve the requested record from the primary database. Have
+ * Berkeley DB allocate memory for us, keeps the DB handle thread
+ * safe.
+ *
+ * We have the Berkeley DB library allocate memory for the record,
+ * which we own and must eventually free. The reason is so we can
+ * have the string fields in the structure point into the actual
+ * record, rather than allocating structure local memory to hold them
+ * and copying them out of the record.
+ */
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+ key.data = &recno;
+ key.size = sizeof(recno);
+ data.flags = DB_DBT_MALLOC;
+ if ((ret = db->get(db, NULL, &key, &data, 0)) != 0)
+ return (ret);
+
+ if ((ret = DbRecord_init(&key, &data, recordp)) != 0)
+ return (ret);
+
+ return (0);
+}
+
+/*
+ * DbRecord_discard --
+ * Discard a DbRecord structure.
+ */
+int
+DbRecord_discard(DbRecord *recordp)
+{
+ /* Free the allocated memory. */
+ free(recordp->raw);
+ recordp->raw = NULL;
+
+ return (0);
+}
+
+/*
+ * DbRecord_init --
+ * Fill in a DbRecord from the database key/data pair.
+ */
+int
+DbRecord_init(const DBT *key, const DBT *data, DbRecord *recordp)
+{
+ DbField *f;
+ u_int32_t skip;
+ void *faddr;
+
+ /* Initialize the structure (get the pre-set index values). */
+ *recordp = DbRecord_base;
+
+ /* Fill in the ID and version. */
+ memcpy(&recordp->recno, key->data, sizeof(u_int32_t));
+ memcpy(&recordp->version,
+ (u_int32_t *)data->data + 1, sizeof(u_int32_t));
+
+ /* Set up the record references. */
+ recordp->raw = data->data;
+ recordp->offset = (u_int32_t *)data->data + 1;
+ skip = (recordp->field_count + 2) * sizeof(u_int32_t);
+ recordp->record = (u_int8_t *)data->data + skip;
+ recordp->record_len = data->size - skip;
+
+ for (f = fieldlist; f->name != NULL; ++f) {
+ faddr = (u_int8_t *)recordp + f->offset;
+ if (DbRecord_field(
+ recordp, f->fieldno, faddr, f->type) != 0)
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * DbRecord_field --
+ * Fill in an individual field of the DbRecord.
+ */
+static int
+DbRecord_field(
+ DbRecord *recordp, u_int field, void *addr, datatype type)
+{
+ size_t len;
+ char number_buf[20];
+
+ /*
+ * The offset table is 0-based, the field numbers are 1-based.
+ * Correct.
+ */
+ --field;
+
+ switch (type) {
+ case NOTSET:
+ /* NOTREACHED */
+ abort();
+ break;
+ case STRING:
+ *((u_char **)addr) = recordp->record + recordp->offset[field];
+ recordp->record[recordp->offset[field] +
+ OFFSET_LEN(recordp->offset, field)] = '\0';
+ break;
+ case DOUBLE:
+ case UNSIGNED_LONG:
+ /* This shouldn't be possible -- 2^32 is only 10 digits. */
+ len = OFFSET_LEN(recordp->offset, field);
+ if (len > sizeof(number_buf) - 1) {
+ dbenv->errx(dbenv,
+ "record %lu field %lu: numeric field is %lu bytes and too large to copy",
+ recordp->recno, field, (u_long)len);
+ return (1);
+ }
+ memcpy(number_buf,
+ recordp->record + recordp->offset[field], len);
+ number_buf[len] = '\0';
+
+ if (type == DOUBLE) {
+ if (len == 0)
+ *(double *)addr = 0;
+ else if (strtod_err(number_buf, (double *)addr) != 0)
+ goto fmt_err;
+ } else
+ if (len == 0)
+ *(u_long *)addr = 0;
+ else if (strtoul_err(number_buf, (u_long *)addr) != 0) {
+fmt_err: dbenv->errx(dbenv,
+ "record %lu: numeric field %u error: %s",
+ recordp->recno, field, number_buf);
+ return (1);
+ }
+ break;
+ }
+ return (0);
+}
+
+/*
+ * DbRecord_search_field_name --
+ * Search, looking for a record by field name.
+ */
+int
+DbRecord_search_field_name(char *field, char *value, OPERATOR op)
+{
+ DbField *f;
+
+ for (f = fieldlist; f->name != NULL; ++f)
+ if (strcasecmp(field, f->name) == 0)
+ return (DbRecord_search_field(f, value, op));
+
+ /* Record numbers aren't handled as fields. */
+ if (strcasecmp(field, "id") == 0)
+ return (DbRecord_search_recno(value, op));
+
+ dbenv->errx(dbenv, "unknown field name: %s", field);
+ return (1);
+}
+
+/*
+ * DbRecord_search_field_number --
+ * Search, looking for a record by field number.
+ */
+int
+DbRecord_search_field_number(u_int32_t fieldno, char *value, OPERATOR op)
+{
+ DbField *f;
+
+ for (f = fieldlist; f->name != NULL; ++f)
+ if (fieldno == f->fieldno)
+ return (DbRecord_search_field(f, value, op));
+
+ dbenv->errx(dbenv, "field number %lu not configured", (u_long)fieldno);
+ return (1);
+}
+
+/*
+ * DbRecord_search_recno --
+ * Search, looking for a record by record number.
+ */
+static int
+DbRecord_search_recno(char *value, OPERATOR op)
+{
+ DBC *dbc;
+ DbRecord record;
+ DBT key, data;
+ u_int32_t recno;
+ u_long recno_ulong;
+ int ret;
+
+ /*
+ * XXX
+ * This code assumes a record number (typed as u_int32_t) is the same
+ * size as an unsigned long, and there's no reason to believe that.
+ */
+ if (strtoul_err(value, &recno_ulong) != 0)
+ return (1);
+
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+ key.data = &recno;
+ key.size = sizeof(recno);
+
+ if ((ret = db->cursor(db, NULL, &dbc, 0)) != 0)
+ return (ret);
+
+ /*
+ * Retrieve the first record that interests us. The range depends on
+ * the operator:
+ *
+ * ~ error
+ * != beginning to end
+ * < beginning to first match
+ * <= beginning to last match
+ * = first match to last match
+ * > record after last match to end
+ * >= first match to end
+ */
+ if (op == LT || op == LTEQ || op == NEQ || op == WC || op == NWC)
+ recno = 1;
+ else if (op == WC || op == NWC) {
+ dbenv->errx(dbenv,
+ "wildcard operator only supported for string fields");
+ return (1);
+ } else {
+ recno = recno_ulong;
+ if (op == GT)
+ ++recno;
+ }
+ if ((ret = dbc->c_get(dbc, &key, &data, DB_SET)) != 0)
+ goto err;
+
+ for (;;) {
+ if ((ret = DbRecord_init(&key, &data, &record)) != 0)
+ break;
+ if (field_cmp_ulong(&record.recno, &recno_ulong, op))
+ DbRecord_print(&record, NULL);
+ else
+ if (op == LT || op == LTEQ || op == EQ)
+ break;
+ if ((ret = dbc->c_get(dbc, &key, &data, DB_NEXT)) != 0)
+ break;
+ }
+
+err: return (ret == DB_NOTFOUND ? 0 : ret);
+}
+
+/*
+ * DbRecord_search_field --
+ * Search, looking for a record by field.
+ */
+static int
+DbRecord_search_field(DbField *f, char *value, OPERATOR op)
+{
+#ifdef HAVE_WILDCARD_SUPPORT
+ regex_t preq;
+#endif
+ DBC *dbc;
+ DbRecord record;
+ DBT key, data, pkey;
+ double value_double;
+ u_long value_ulong;
+ u_int32_t cursor_flags;
+ int ret, t_ret;
+ int (*cmp)(void *, void *, OPERATOR);
+ void *faddr, *valuep;
+
+ dbc = NULL;
+ memset(&key, 0, sizeof(key));
+ memset(&pkey, 0, sizeof(pkey));
+ memset(&data, 0, sizeof(data));
+
+ /*
+ * Initialize the comparison function, crack the value. Wild cards
+ * are always strings, otherwise we follow the field type.
+ */
+ if (op == WC || op == NWC) {
+#ifdef HAVE_WILDCARD_SUPPORT
+ if (f->type != STRING) {
+ dbenv->errx(dbenv,
+ "wildcard operator only supported for string fields");
+ return (1);
+ }
+ if (regcomp(&preq, value, 0) != 0) {
+ dbenv->errx(dbenv, "regcomp of pattern failed");
+ return (1);
+ }
+ valuep = &preq;
+ cmp = field_cmp_re;
+#else
+ dbenv->errx(dbenv,
+ "wildcard operators not supported in this build");
+ return (1);
+#endif
+ } else
+ switch (f->type) {
+ case DOUBLE:
+ if (strtod_err(value, &value_double) != 0)
+ return (1);
+ cmp = field_cmp_double;
+ valuep = &value_double;
+ key.size = sizeof(double);
+ break;
+ case STRING:
+ valuep = value;
+ cmp = field_cmp_string;
+ key.size = strlen(value);
+ break;
+ case UNSIGNED_LONG:
+ if (strtoul_err(value, &value_ulong) != 0)
+ return (1);
+ cmp = field_cmp_ulong;
+ valuep = &value_ulong;
+ key.size = sizeof(u_long);
+ break;
+ default:
+ case NOTSET:
+ abort();
+ /* NOTREACHED */
+ }
+
+ /*
+ * Retrieve the first record that interests us. The range depends on
+ * the operator:
+ *
+ * ~ beginning to end
+ * != beginning to end
+ * < beginning to first match
+ * <= beginning to last match
+ * = first match to last match
+ * > record after last match to end
+ * >= first match to end
+ *
+ * If we have a secondary, set a cursor in the secondary, else set the
+ * cursor to the beginning of the primary.
+ *
+ * XXX
+ * If the wildcard string has a leading non-magic character we should
+ * be able to do a range search instead of a full-database search.
+ *
+ * Step through records to the first non-match or to the end of the
+ * database, depending on the operation. If the comparison function
+ * returns success for a key/data pair, print the pair.
+ */
+ if (f->secondary == NULL || op == NEQ || op == WC || op == NWC) {
+ if ((ret = db->cursor(db, NULL, &dbc, 0)) != 0)
+ goto err;
+ while ((ret = dbc->c_get(dbc, &key, &data, DB_NEXT)) == 0) {
+ if ((ret = DbRecord_init(&key, &data, &record)) != 0)
+ break;
+ faddr = (u_int8_t *)&record + f->offset;
+ if (cmp(faddr, valuep, op))
+ DbRecord_print(&record, NULL);
+ else
+ if (op == EQ || op == LT || op == LTEQ)
+ break;
+ }
+ } else {
+ if ((ret =
+ f->secondary->cursor(f->secondary, NULL, &dbc, 0)) != 0)
+ goto err;
+ key.data = valuep;
+ cursor_flags = op == LT || op == LTEQ ? DB_FIRST : DB_SET_RANGE;
+ if ((ret =
+ dbc->c_pget(dbc, &key, &pkey, &data, cursor_flags)) != 0)
+ goto done;
+ if (op == GT) {
+ while ((ret = dbc->c_pget(
+ dbc, &key, &pkey, &data, DB_NEXT)) == 0) {
+ if ((ret =
+ DbRecord_init(&pkey, &data, &record)) != 0)
+ break;
+ faddr = (u_int8_t *)&record + f->offset;
+ if (cmp(faddr, valuep, op) != 0)
+ break;
+ }
+ if (ret != 0)
+ goto done;
+ }
+ do {
+ if ((ret = DbRecord_init(&pkey, &data, &record)) != 0)
+ break;
+ faddr = (u_int8_t *)&record + f->offset;
+ if (cmp(faddr, valuep, op))
+ DbRecord_print(&record, NULL);
+ else
+ if (op == EQ || op == LT || op == LTEQ)
+ break;
+ } while ((ret =
+ dbc->c_pget(dbc, &key, &pkey, &data, DB_NEXT)) == 0);
+ }
+
+done: if (ret == DB_NOTFOUND)
+ ret = 0;
+
+err: if (dbc != NULL && (t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
+ ret = t_ret;
+
+#ifdef HAVE_WILDCARD_SUPPORT
+ if (op == WC || op == NWC)
+ regfree(&preq);
+#endif
+
+ return (ret);
+}
diff --git a/db-4.8.30/examples_c/csv/Makefile b/db-4.8.30/examples_c/csv/Makefile
new file mode 100644
index 0000000..9d46cc7
--- /dev/null
+++ b/db-4.8.30/examples_c/csv/Makefile
@@ -0,0 +1,75 @@
+# $Id$
+
+# Berkeley DB installation.
+DB_INCLUDE=../../build_unix
+LIBS= -L../../build_unix -L../../build_unix/.libs/ -ldb
+
+INC= -I. -I$(DB_INCLUDE)
+CFLAGS= $(INC) -g -W -Wall -Wpointer-arith -Wmissing-prototypes
+
+PROGS= csv_code csv_load csv_query
+SRCS= DbRecord.c code.c csv_local.c db.c load.c load_main.c query.c \
+ query_main.c util.c
+
+all: csv_load csv_query
+
+csv_code: code.o
+ $(CC) -o $@ $? $(LIBS)
+
+LOAD_OBJS=DbRecord.o csv_local.o db.o load.o load_main.o util.o
+csv_load: $(LOAD_OBJS)
+ $(CC) -o $@ $(LOAD_OBJS) $(LIBS)
+
+QUERY_OBJS=DbRecord.o csv_local.o db.o query.o query_main.o util.o
+csv_query: $(QUERY_OBJS)
+ $(CC) -o $@ $(QUERY_OBJS) $(LIBS)
+
+clean distclean realclean:
+ rm -rf $(PROGS) TESTDIR eBay tags *.o *.core csv_local.[ch]
+
+tags:
+ rm -f tags
+ ctags $(SRCS) code.c
+
+DbRecord.o csv_local.o db.o load.o load_main.o query.o: csv_local.h csv.h
+query_main.o util.o: csv_local.h csv.h
+
+csv_local.c csv_local.h: csv_code
+ ./csv_code -c csv_local.c -h csv_local.h -f sample.desc
+
+lint_code:
+ flexelint +fll \
+ "-e801" \
+ "-e818" \
+ "-esym(534,fprintf)" \
+ "-esym(534,memcpy)" \
+ "-esym(534,memmove)" \
+ "-esym(534,memset)" \
+ "-esym(534,printf)" \
+ "-wlib(1)" \
+ -i$(DB_INCLUDE) "-i/usr/include" \
+ code.c
+lint_load:
+ flexelint +fll \
+ "-e801" \
+ "-e818" \
+ "-esym(534,fprintf)" \
+ "-esym(534,memcpy)" \
+ "-esym(534,memmove)" \
+ "-esym(534,memset)" \
+ "-esym(534,printf)" \
+ "-wlib(1)" \
+ -i$(DB_INCLUDE) "-i/usr/include" \
+ DbRecord.c csv_local.c db.c load.c load_main.c util.c
+lint_query:
+ flexelint +fll \
+ "-e801" \
+ "-e818" \
+ "-esym(534,fprintf)" \
+ "-esym(534,memcpy)" \
+ "-esym(534,memmove)" \
+ "-esym(534,memset)" \
+ "-esym(534,printf)" \
+ "-wlib(1)" \
+ -i$(DB_INCLUDE) "-i/usr/include" \
+ DbRecord.c csv_local.c db.c query.c query_main.c util.c
diff --git a/db-4.8.30/examples_c/csv/README b/db-4.8.30/examples_c/csv/README
new file mode 100644
index 0000000..6a5fd13
--- /dev/null
+++ b/db-4.8.30/examples_c/csv/README
@@ -0,0 +1,408 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2005-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+The "comma-separated value" (csv) directory is a suite of three programs:
+
+ csv_code: write "helper" code on which to build applications,
+ csv_load: import csv files into a Berkeley DB database,
+ csv_query: query databases created by csv_load.
+
+The goal is to allow programmers to easily build applications for using
+csv databases.
+
+You can build the three programs, and run a sample application in this
+directory.
+
+First, there's the sample.csv file:
+
+ Adams,Bob,01/02/03,green,apple,37
+ Carter,Denise Ann,04/05/06,blue,banana,38
+ Eidel,Frank,07/08/09,red,cherry,38
+ Grabel,Harriet,10/11/12,purple,date,40
+ Indals,Jason,01/03/05,pink,orange,32
+ Kilt,Laura,07/09/11,yellow,grape,38
+ Moreno,Nancy,02/04/06,black,strawberry,38
+ Octon,Patrick,08/10/12,magenta,kiwi,15
+
+The fields are:
+ Last name,
+ First name,
+ Birthdate,
+ Favorite color,
+ Favorite fruit,
+ Age
+
+Second, there's a "description" of that csv file in sample.desc:
+
+ version 1 {
+ LastName string
+ FirstName string
+ BirthDate
+ Color string index
+ Fruit string index
+ Age unsigned_long index
+ }
+
+The DESCRIPTION file maps one-to-one to the fields in the csv file, and
+provides a data type for any field the application wants to use. (If
+the application doesn't care about a field, don't specify a data type
+and the csv code will ignore it.) The string "index" specifies there
+should be a secondary index based on the field.
+
+The "field" names in the DESCRIPTION file don't have to be the same as
+the ones in the csv file (and, as they may not have embedded spaces,
+probably won't be).
+
+To build in the sample directory, on POSIX-like systems, type "make".
+This first builds the program csv_code, which it then run, with the file
+DESCRIPTION as an input. Running csv_code creates two additional files:
+csv_local.c and csv_local.h. Those two files are then used as part of
+the build process for two more programs: csv_load and csv_query.
+
+You can load now load the csv file into a Berkeley DB database with the
+following command:
+
+ % ./csv_load -h TESTDIR < sample.csv
+
+The csv_load command will create a directory and four databases:
+
+ primary primary database
+ Age secondary index on Age field
+ Color secondary index on Color field
+ Fruit secondary index on Fruit field
+
+You can then query the database:
+
+ % ./csv_query -h TESTDIR
+ Query: id=2
+ Record: 2:
+ LastName: Carter
+ FirstName: Denise
+ Color: blue
+ Fruit: banana
+ Age: 38
+ Query: color==green
+ Record: 1:
+ LastName: Adams
+ FirstName: Bob
+ Color: green
+ Fruit: apple
+ Age: 37
+
+and so on.
+
+The csv_code process also creates source code modules that support
+building your own applications based on this database. First, there
+is the local csv_local.h include file:
+
+ /*
+ * DO NOT EDIT: automatically built by csv_code.
+ *
+ * Record structure.
+ */
+ typedef struct __DbRecord {
+ u_int32_t recno; /* Record number */
+
+ /*
+ * Management fields
+ */
+ void *raw; /* Memory returned by DB */
+ char *record; /* Raw record */
+ size_t record_len; /* Raw record length */
+
+ u_int32_t field_count; /* Field count */
+ u_int32_t version; /* Record version */
+
+ u_int32_t *offset; /* Offset table */
+
+ /*
+ * Indexed fields
+ */
+ #define CSV_INDX_LASTNAME 1
+ char *LastName;
+
+ #define CSV_INDX_FIRSTNAME 2
+ char *FirstName;
+
+ #define CSV_INDX_COLOR 4
+ char *Color;
+
+ #define CSV_INDX_FRUIT 5
+ char *Fruit;
+
+ #define CSV_INDX_AGE 6
+ u_long Age;
+ } DbRecord;
+
+This defines the DbRecord structure that is the primary object for this
+csv file. As you can see, the intersting fields in the csv file have
+mappings in this structure.
+
+Also, there are routines in the Dbrecord.c file your application can use
+to handle DbRecord structures. When you retrieve a record from the
+database the DbRecord structure will be filled in based on that record.
+
+Here are the helper routines:
+
+ int
+ DbRecord_print(DbRecord *recordp, FILE *fp)
+ Display the contents of a DbRecord structure to the specified
+ output stream.
+
+ int
+ DbRecord_init(const DBT *key, DBT *data, DbRecord *recordp)
+ Fill in a DbRecord from a returned database key/data pair.
+
+ int
+ DbRecord_read(u_long key, DbRecord *recordp)
+ Read the specified record (DbRecord_init will be called
+ to fill in the DbRecord).
+
+ int
+ DbRecord_discard(DbRecord *recordp)
+ Discard the DbRecord structure (must be called after the
+ DbRecord_read function), when the application no longer
+ needs the returned DbRecord.
+
+ int
+ DbRecord_search_field_name(char *field, char *value, OPERATOR op)
+ Display the DbRecords where the field (named by field) has
+ the specified relationship to the value. For example:
+
+ DbRecord_search_field_name("Age", "35", GT)
+
+ would search for records with a "Age" field greater than
+ 35.
+
+ int
+ DbRecord_search_field_number(
+ u_int32_t fieldno, char *value, OPERATOR op)
+ Display the DbRecords where the field (named by field)
+ has the specified relationship to the value. The field
+ number used as an argument comes from the csv_local.h
+ file, for example, CSV_INDX_AGE is the field index for
+ the "Age" field in this csv file. For example:
+
+ DbRecord_search_field_number(CSV_INDX_AGE, 35, GT)
+
+ would search for records with a "Age" field greater than
+ 35.
+
+ Currently, the csv code only supports three types of data:
+ strings, unsigned longs and doubles. Others can easily be
+ added.
+
+The usage of the csv_code program is as follows:
+
+ usage: csv_code [-v] [-c source-file] [-f input] [-h header-file]
+ -c output C source code file
+ -h output C header file
+ -f input file
+ -v verbose (defaults to off)
+
+ -c A file to which to write the C language code. By default,
+ the file "csv_local.c" is used.
+
+ -f A file to read for a description of the fields in the
+ csv file. By default, csv_code reads from stdin.
+
+ -h A file to which to write the C language header structures.
+ By default, the file "csv_local.h" is used.
+
+ -v The -v verbose flag outputs potentially useful debugging
+ information.
+
+There are two applications built on top of the code produced by
+csv_code, csv_load and csv_query.
+
+The usage of the csv_load program is as follows:
+
+ usage: csv_load [-v] [-F format] [-f csv-file] [-h home] [-V version]
+ -F format (currently supports "excel")
+ -f input file
+ -h database environment home directory
+ -v verbose (defaults to off)
+
+ -F See "Input format" below.
+
+ -f If an input file is specified using the -f flag, the file
+ is read and the records in the file are stored into the
+ database. By default, csv_load reads from stdin.
+
+ -h If a database environment home directory is specified
+ using the -h flag, that directory is used as the
+ Berkeley DB directory. The default for -h is the
+ current working directory or the value of the DB_HOME
+ environment variable.
+
+ -V Specify a version number for the input (the default is 1).
+
+ -v The -v verbose flag outputs potentially useful debugging
+ information. It can be specified twice for additional
+ information.
+
+The usage of csv_query program is as follows:
+
+ usage: csv_query [-v] [-c cmd] [-h home]
+
+ -c A command to run, otherwise csv_query will enter
+ interactive mode and prompt for user input.
+
+ -h If a database environment home directory is specified
+ using the -h flag, that directory is used as the
+ Berkeley DB directory. The default for -h is the
+ current working directory or the value of the DB_HOME
+ environment variable.
+
+ -v The -v verbose flag outputs potentially useful debugging
+ information. It can be specified twice for additional
+ information.
+
+The query program currently supports the following commands:
+
+ ? Display help screen
+ exit Exit program
+ fields Display list of field names
+ help Display help screen
+ quit Exit program
+ version Display database format version
+ field[op]value Display fields by value (=, !=, <, <=, >, >=, ~, !~)
+
+The "field[op]value" command allows you to specify a field and a
+relationship to a value. For example, you could run the query:
+
+ csv_query -c "price < 5"
+
+to list all of the records with a "price" field less than "5".
+
+Field names and all string comparisons are case-insensitive.
+
+The operators ~ and !~ do match/no-match based on the IEEE Std 1003.2
+(POSIX.2) Basic Regular Expression standard.
+
+As a special case, every database has the field "Id", which matches the
+record number of the primary key.
+
+Input format:
+ The input to the csv_load utility is a text file, containing
+ lines of comma-separated fields.
+
+ Blank lines are ignored. All non-blank lines must be comma-separated
+ lists of fields.
+
+ By default:
+ <nul> (\000) bytes and unprintable characters are stripped,
+ input lines are <nl> (\012) separated,
+ commas cannot be escaped.
+
+ If "-F excel" is specified:
+ <nul> (\000) bytes and unprintable characters are stripped,
+ input lines are <cr> (\015) separated,
+ <nl> bytes (\012) characters are stripped from the input,
+ commas surrounded by double-quote character (") are not
+ treated as field separators.
+
+Storage format:
+ Records in the primary database are stored with a 32-bit unsigned
+ record number as the key.
+
+ Key/Data pair 0 is of the format:
+ [version] 32-bit unsigned int
+ [field count] 32-bit unsigned int
+ [raw record] byte array
+
+ For example:
+ [1]
+ [5]
+ [field1,field2,field3,field4,field5]
+
+ All other Key/Data pairs are of the format:
+ [version] 32-bit unsigned int
+ [offset to field 1] 32-bit unsigned int
+ [offset to field 2] 32-bit unsigned int
+ [offset to field 3] 32-bit unsigned int
+ ... 32-bit unsigned int
+ [offset to field N] 32-bit unsigned int
+ [offset past field N] 32-bit unsigned int
+ [raw record] byte array
+
+ For example:
+ [1]
+ [0]
+ [2]
+ [5]
+ [9]
+ [14]
+ [19]
+ [a,ab,abc,abcd,abcde]
+ 012345678901234567890 << byte offsets
+ 0 1 2
+
+ So, field 3 of the data can be directly accessed by using
+ the "offset to field 3", and the length of the field is
+ the "((offset to field 4) - (offset to field 3)) - 1".
+
+Limits:
+ The csv program stores the primary key in a 32-bit unsigned
+ value, limiting the number of records in the database. New
+ records are inserted after the last existing record, that is,
+ new records are not inserted into gaps left by any deleted
+ records. This will limit the total number of records stored in
+ any database.
+
+Versioning:
+ Versioning is when a database supports multiple versions of the
+ records. This is likely to be necessary when dealing with large
+ applications and databases, as record fields change over time.
+
+ The csv application suite does not currently support versions,
+ although all of the necessary hooks are there.
+
+ The way versioning will work is as follows:
+
+ The XXX.desc file needs to support multiple version layouts.
+
+ The generated C language structure defined should be a superset
+ of all of the interesting fields from all of the version
+ layouts, regardless of which versions of the csv records those
+ fields exist in.
+
+ When the csv layer is asked for a record, the record's version
+ will provide a lookup into a separate database of field lists.
+ That is, there will be another database which has key/data pairs
+ where the key is a version number, and the data is the field
+ list. At that point, it's relatively easy to map the fields
+ to the structure as is currently done, except that some of the
+ fields may not be filled in.
+
+ To determine if a field is filled in, in the structure, the
+ application has to have an out-of-band value to put in that
+ field during DbRecord initialization. If that's a problem, the
+ alternative would be to add an additional field for each listed
+ field -- if the additional field is set to 1, the listed field
+ has been filled in, otherwise it hasn't. The csv code will
+ support the notion of required fields, so in most cases the
+ application won't need to check before simply using the field,
+ it's only if a field isn't required and may be filled in that
+ the check will be necessary.
+
+TODO:
+ Csv databases are not portable between machines of different
+ byte orders. To make them portable, all of the 32-bit unsigned
+ int fields currently written into the database should be
+ converted to a standard byte order. This would include the
+ version number and field count in the column-map record, and the
+ version and field offsets in the other records.
+
+ Add Extended RE string matches.
+
+ Add APIs to replace the reading of a schema file, allow users to
+ fill in a DbRecord structure and do a put on it. (Hard problem:
+ how to flag fields that aren't filled in.)
+
+ Add a second sample file, and write the actual versioning code.
diff --git a/db-4.8.30/examples_c/csv/code.c b/db-4.8.30/examples_c/csv/code.c
new file mode 100644
index 0000000..a6a3878
--- /dev/null
+++ b/db-4.8.30/examples_c/csv/code.c
@@ -0,0 +1,405 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2005-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+#include "csv.h"
+
+typedef struct {
+ char *name; /* Field name */
+ char *upper; /* Field name in upper-case */
+ datatype type; /* Data type */
+ int indx; /* Index */
+} FIELD;
+
+int code_source(void);
+int code_header(void);
+int desc_dump(void);
+int desc_load(void);
+char *type_to_string(datatype);
+int usage(void);
+
+/*
+ * Globals
+ */
+FILE *cfp; /* C source file */
+FILE *hfp; /* C source file */
+char *progname; /* Program name */
+int verbose; /* Verbose flag */
+
+u_int field_cnt; /* Count of fields */
+FIELD *fields; /* Field list */
+
+int
+main(int argc, char *argv[])
+{
+ int ch;
+ char *cfile, *hfile;
+
+ /* Initialize globals. */
+ if ((progname = strrchr(argv[0], '/')) == NULL)
+ progname = argv[0];
+ else
+ ++progname;
+
+ /* Initialize arguments. */
+ cfile = "csv_local.c"; /* Default header/source files */
+ hfile = "csv_local.h";
+
+ /* Process arguments. */
+ while ((ch = getopt(argc, argv, "c:f:h:v")) != EOF)
+ switch (ch) {
+ case 'c':
+ cfile = optarg;
+ break;
+ case 'f':
+ if (freopen(optarg, "r", stdin) == NULL) {
+ fprintf(stderr,
+ "%s: %s\n", optarg, strerror(errno));
+ return (EXIT_FAILURE);
+ }
+ break;
+ case 'h':
+ hfile = optarg;
+ break;
+ case 'v':
+ ++verbose;
+ break;
+ case '?':
+ default:
+ return (usage());
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (*argv != NULL)
+ return (usage());
+
+ /* Load records from the input file. */
+ if (desc_load())
+ return (EXIT_FAILURE);
+
+ /* Dump records for debugging. */
+ if (verbose && desc_dump())
+ return (EXIT_FAILURE);
+
+ /* Open output files. */
+ if ((cfp = fopen(cfile, "w")) == NULL) {
+ fprintf(stderr,
+ "%s: %s: %s\n", progname, cfile, strerror(errno));
+ return (EXIT_FAILURE);
+ }
+ if ((hfp = fopen(hfile, "w")) == NULL) {
+ fprintf(stderr,
+ "%s: %s: %s\n", progname, hfile, strerror(errno));
+ return (EXIT_FAILURE);
+ }
+
+ /* Build the source and header files. */
+ if (code_header())
+ return (EXIT_FAILURE);
+ if (code_source())
+ return (EXIT_FAILURE);
+
+ return (EXIT_SUCCESS);
+}
+
+/*
+ * desc_load --
+ * Load a description file.
+ */
+int
+desc_load()
+{
+ u_int field_alloc;
+ int version;
+ char *p, *t, save_ch, buf[256];
+
+ field_alloc = version = 0;
+ while (fgets(buf, sizeof(buf), stdin) != NULL) {
+ if ((p = strchr(buf, '\n')) == NULL) {
+ fprintf(stderr, "%s: input line too long\n", progname);
+ return (1);
+ }
+ *p = '\0';
+
+ /* Skip leading whitespace. */
+ for (p = buf; isspace(*p); ++p)
+ ;
+
+ /* Skip empty lines or lines beginning with '#'. */
+ if (*p == '\0' || *p == '#')
+ continue;
+
+ /* Get a version. */
+ if (!version) {
+ if (strncasecmp(
+ p, "version", sizeof("version") - 1) == 0) {
+ version = 1;
+ continue;
+ }
+ fprintf(stderr,
+ "%s: expected \"version\" line\n", progname);
+ return (1);
+ }
+
+ /*
+ * Skip block close -- not currently useful, but when this
+ * code supports versioned descriptions, it will matter.
+ */
+ if (*p == '}') {
+ version = 0;
+ continue;
+ }
+
+ /* Allocate a new field structure as necessary. */
+ if (field_cnt == field_alloc &&
+ (fields = realloc(fields, field_alloc += 100)) == NULL) {
+ fprintf(stderr, "%s: %s\n", progname, strerror(errno));
+ return (1);
+ }
+
+ /* Find the end of the field name. */
+ for (t = p; *t != '\0' && !isspace(*t); ++t)
+ ;
+ save_ch = *t;
+ *t = '\0';
+ if ((fields[field_cnt].name = strdup(p)) == NULL ||
+ (fields[field_cnt].upper = strdup(p)) == NULL) {
+ fprintf(stderr, "%s: %s\n", progname, strerror(errno));
+ return (1);
+ }
+ *t = save_ch;
+ p = t;
+
+ fields[field_cnt].indx = 0;
+ fields[field_cnt].type = NOTSET;
+ for (;;) {
+ /* Skip to the next field, if any. */
+ for (; *p != '\0' && isspace(*p); ++p)
+ ;
+ if (*p == '\0')
+ break;
+
+ /* Find the end of the field. */
+ for (t = p; *t != '\0' && !isspace(*t); ++t)
+ ;
+ save_ch = *t;
+ *t = '\0';
+ if (strcasecmp(p, "double") == 0)
+ fields[field_cnt].type = DOUBLE;
+ else if (strcasecmp(p, "index") == 0)
+ fields[field_cnt].indx = 1;
+ else if (strcasecmp(p, "string") == 0)
+ fields[field_cnt].type = STRING;
+ else if (strcasecmp(p, "unsigned_long") == 0)
+ fields[field_cnt].type = UNSIGNED_LONG;
+ else {
+ fprintf(stderr,
+ "%s: unknown keyword: %s\n", progname, p);
+ return (1);
+ }
+ *t = save_ch;
+ p = t;
+ }
+
+ /* Create a copy of the field name that's upper-case. */
+ for (p = fields[field_cnt].upper; *p != '\0'; ++p)
+ if (islower(*p))
+ *p = (char)toupper(*p);
+ ++field_cnt;
+ }
+ if (ferror(stdin)) {
+ fprintf(stderr, "%s: stdin: %s\n", progname, strerror(errno));
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * desc_dump --
+ * Dump a set of FIELD structures.
+ */
+int
+desc_dump()
+{
+ FIELD *f;
+ u_int i;
+
+ for (f = fields, i = 0; i < field_cnt; ++i, ++f) {
+ fprintf(stderr, "field {%s}: (", f->name);
+ switch (f->type) {
+ case NOTSET:
+ fprintf(stderr, "ignored");
+ break;
+ case DOUBLE:
+ fprintf(stderr, "double");
+ break;
+ case STRING:
+ fprintf(stderr, "string");
+ break;
+ case UNSIGNED_LONG:
+ fprintf(stderr, "unsigned_long");
+ break;
+ }
+ if (f->indx)
+ fprintf(stderr, ", indexed");
+ fprintf(stderr, ")\n");
+ }
+ return (0);
+}
+
+/*
+ * code_header --
+ * Print out the C #include file.
+ */
+int
+code_header()
+{
+ FIELD *f;
+ u_int i;
+
+ fprintf(hfp, "/*\n");
+ fprintf(hfp, " * DO NOT EDIT: automatically built by %s.\n", progname);
+ fprintf(hfp, " *\n");
+ fprintf(hfp, " * Record structure.\n");
+ fprintf(hfp, " */\n");
+ fprintf(hfp, "typedef struct __DbRecord {\n");
+ fprintf(hfp, "\tu_int32_t\t recno;\t\t/* Record number */\n");
+ fprintf(hfp, "\n");
+ fprintf(hfp, "\t/*\n");
+ fprintf(hfp, "\t * Management fields\n");
+ fprintf(hfp, "\t */\n");
+ fprintf(hfp, "\tvoid\t\t*raw;\t\t/* Memory returned by DB */\n");
+ fprintf(hfp, "\tu_char\t\t*record;\t/* Raw record */\n");
+ fprintf(hfp, "\tsize_t\t\t record_len;\t/* Raw record length */\n\n");
+ fprintf(hfp, "\tu_int32_t\t field_count;\t/* Field count */\n");
+ fprintf(hfp, "\tu_int32_t\t version;\t/* Record version */\n\n");
+ fprintf(hfp, "\tu_int32_t\t*offset;\t/* Offset table */\n");
+ fprintf(hfp, "\n");
+
+ fprintf(hfp, "\t/*\n");
+ fprintf(hfp, "\t * Indexed fields\n");
+ fprintf(hfp, "\t */\n");
+ for (f = fields, i = 0; i < field_cnt; ++i, ++f) {
+ if (f->type == NOTSET)
+ continue;
+ if (i != 0)
+ fprintf(hfp, "\n");
+ fprintf(hfp, "#define CSV_INDX_%s\t%d\n", f->upper, i + 1);
+ switch (f->type) {
+ case NOTSET:
+ /* NOTREACHED */
+ abort();
+ break;
+ case DOUBLE:
+ fprintf(hfp, "\tdouble\t\t %s;\n", f->name);
+ break;
+ case STRING:
+ fprintf(hfp, "\tchar\t\t*%s;\n", f->name);
+ break;
+ case UNSIGNED_LONG:
+ fprintf(hfp, "\tu_long\t\t %s;\n", f->name);
+ break;
+ }
+ }
+ fprintf(hfp, "} DbRecord;\n");
+
+ return (0);
+}
+
+/*
+ * code_source --
+ * Print out the C structure initialization.
+ */
+int
+code_source()
+{
+ FIELD *f;
+ u_int i;
+
+ fprintf(cfp, "/*\n");
+ fprintf(cfp,
+ " * DO NOT EDIT: automatically built by %s.\n", progname);
+ fprintf(cfp, " *\n");
+ fprintf(cfp, " * Initialized record structure.\n");
+ fprintf(cfp, " */\n");
+ fprintf(cfp, "\n");
+ fprintf(cfp, "#include \"csv.h\"\n");
+ fprintf(cfp, "#include \"csv_local.h\"\n");
+ fprintf(cfp, "\n");
+ fprintf(cfp, "DbRecord DbRecord_base = {\n");
+ fprintf(cfp, "\t0,\t\t/* Record number */\n");
+ fprintf(cfp, "\tNULL,\t\t/* Memory returned by DB */\n");
+ fprintf(cfp, "\tNULL,\t\t/* Raw record */\n");
+ fprintf(cfp, "\t0,\t\t/* Raw record length */\n");
+ fprintf(cfp, "\t%d,\t\t/* Field count */\n", field_cnt);
+ fprintf(cfp, "\t0,\t\t/* Record version */\n");
+ fprintf(cfp, "\tNULL,\t\t/* Offset table */\n");
+ fprintf(cfp, "\n");
+ for (f = fields, i = 0; i < field_cnt; ++i, ++f) {
+ if (f->type == NOTSET)
+ continue;
+ switch (f->type) {
+ case NOTSET:
+ abort();
+ /* NOTREACHED */
+ break;
+ case DOUBLE:
+ case UNSIGNED_LONG:
+ fprintf(cfp, "\t0,\t\t/* %s */\n", f->name);
+ break;
+ case STRING:
+ fprintf(cfp, "\tNULL,\t\t/* %s */\n", f->name);
+ break;
+ }
+ }
+ fprintf(cfp, "};\n");
+
+ fprintf(cfp, "\n");
+ fprintf(cfp, "DbField fieldlist[] = {\n");
+ for (f = fields, i = 0; i < field_cnt; ++i, ++f) {
+ if (f->type == NOTSET)
+ continue;
+ fprintf(cfp, "\t{ \"%s\",", f->name);
+ fprintf(cfp, " CSV_INDX_%s,", f->upper);
+ fprintf(cfp, "\n\t %s,", type_to_string(f->type));
+ fprintf(cfp, " %d,", f->indx ? 1 : 0);
+ fprintf(cfp, " NULL,");
+ fprintf(cfp, " FIELD_OFFSET(%s)},\n", f->name);
+ }
+ fprintf(cfp, "\t{NULL, 0, STRING, 0, NULL, 0}\n};\n");
+
+ return (0);
+}
+
+char *
+type_to_string(type)
+ datatype type;
+{
+ switch (type) {
+ case NOTSET:
+ return ("NOTSET");
+ case DOUBLE:
+ return ("DOUBLE");
+ case STRING:
+ return ("STRING");
+ case UNSIGNED_LONG:
+ return ("UNSIGNED_LONG");
+ }
+
+ abort();
+ /* NOTREACHED */
+}
+
+int
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: %s [-v] [-c source-file] [-f input] [-h header-file]\n",
+ progname);
+ exit(1);
+}
diff --git a/db-4.8.30/examples_c/csv/csv.h b/db-4.8.30/examples_c/csv/csv.h
new file mode 100644
index 0000000..fb0a66a
--- /dev/null
+++ b/db-4.8.30/examples_c/csv/csv.h
@@ -0,0 +1,101 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2005-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN 1
+
+#include <direct.h>
+#include <db.h>
+
+extern int getopt(int, char * const *, const char *);
+extern char *optarg;
+extern int optind;
+#else
+#define HAVE_WILDCARD_SUPPORT 1
+
+#include <regex.h>
+#include <unistd.h>
+#endif
+
+#include "db.h"
+
+/*
+ * MAP_VERSION
+ * This code has hooks for versioning, but does not directly support it.
+ * See the README file for details.
+ */
+#define MAP_VERSION 1
+
+/*
+ * Supported formats.
+ *
+ * FORMAT_NL: <nl> separated
+ * FORMAT_EXCEL: Excel dumped flat text.
+ */
+typedef enum { FORMAT_EXCEL, FORMAT_NL } input_fmt;
+
+/*
+ * OFFSET_LEN
+ * The length of any item can be calculated from the two offset fields.
+ * OFFSET_OOB
+ * An offset that's illegal, used to detect unavailable fields.
+ */
+#define OFFSET_LEN(offset, indx) \
+ (((offset)[(indx) + 1] - (offset)[(indx)]) - 1)
+
+#define OFFSET_OOB 0
+
+/*
+ * Field comparison operators.
+ */
+typedef enum { EQ=1, NEQ, GT, GTEQ, LT, LTEQ, WC, NWC } OPERATOR;
+
+/*
+ * Supported data types.
+ */
+typedef enum { NOTSET=1, DOUBLE, STRING, UNSIGNED_LONG } datatype;
+
+/*
+ * C structure that describes the csv fields.
+ */
+typedef struct {
+ char *name; /* Field name */
+ u_int32_t fieldno; /* Field index */
+ datatype type; /* Data type */
+
+ int indx; /* Indexed */
+ DB *secondary; /* Secondary index handle */
+
+#define FIELD_OFFSET(field) ((size_t)(&(((DbRecord *)0)->field)))
+ size_t offset; /* DbRecord field offset */
+} DbField;
+
+/*
+ * Globals
+ */
+extern DB *db; /* Primary database */
+extern DbField fieldlist[]; /* Field list */
+extern DB_ENV *dbenv; /* Database environment */
+extern char *progname; /* Program name */
+extern int verbose; /* Program verbosity */
+#ifdef _WIN32
+#undef strcasecmp
+#define strcasecmp _stricmp
+#undef strncasecmp
+#define strncasecmp _strnicmp
+#define mkdir(d, perm) _mkdir(d)
+#endif
diff --git a/db-4.8.30/examples_c/csv/csv_extern.h b/db-4.8.30/examples_c/csv/csv_extern.h
new file mode 100644
index 0000000..8bd0653
--- /dev/null
+++ b/db-4.8.30/examples_c/csv/csv_extern.h
@@ -0,0 +1,37 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2005-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+extern DbRecord DbRecord_base; /* Initialized structure. */
+
+/*
+ * Prototypes
+ */
+extern int DbRecord_discard(DbRecord *);
+extern int DbRecord_init(const DBT *, const DBT *, DbRecord *);
+extern void DbRecord_print(DbRecord *, FILE *);
+extern int DbRecord_read(u_long, DbRecord *);
+extern int DbRecord_search_field_name(char *, char *, OPERATOR);
+extern int DbRecord_search_field_number(u_int, char *, OPERATOR);
+extern int compare_double(DB *, const DBT *, const DBT *);
+extern int compare_string(DB *, const DBT *, const DBT *);
+extern int compare_ulong(DB *, const DBT *, const DBT *);
+extern int csv_env_close(void);
+extern int csv_env_open(const char *, int);
+extern int csv_secondary_close(void);
+extern int csv_secondary_open(void);
+extern int entry_print(void *, size_t, u_int32_t);
+extern int field_cmp_double(void *, void *, OPERATOR);
+extern int field_cmp_re(void *, void *, OPERATOR);
+extern int field_cmp_string(void *, void *, OPERATOR);
+extern int field_cmp_ulong(void *, void *, OPERATOR);
+extern int input_load(input_fmt, u_long);
+extern int query(char *, int *);
+extern int query_interactive(void);
+extern int secondary_callback(DB *, const DBT *, const DBT *, DBT *);
+extern int strtod_err(char *, double *);
+extern int strtoul_err(char *, u_long *);
diff --git a/db-4.8.30/examples_c/csv/db.c b/db-4.8.30/examples_c/csv/db.c
new file mode 100644
index 0000000..efa9208
--- /dev/null
+++ b/db-4.8.30/examples_c/csv/db.c
@@ -0,0 +1,244 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2005-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+#include "csv.h"
+#include "csv_local.h"
+#include "csv_extern.h"
+
+static int compare_uint32(DB *, const DBT *, const DBT *);
+
+/*
+ * csv_env_init --
+ * Initialize the database environment.
+ */
+int
+csv_env_open(const char *home, int is_rdonly)
+{
+ int ret;
+
+ dbenv = NULL;
+ db = NULL;
+
+ /* Create a database environment handle. */
+ if ((ret = db_env_create(&dbenv, 0)) != 0) {
+ fprintf(stderr,
+ "%s: db_env_create: %s\n", progname, db_strerror(ret));
+ return (1);
+ }
+
+ /*
+ * Configure Berkeley DB error reporting to stderr, with our program
+ * name as the prefix.
+ */
+ dbenv->set_errfile(dbenv, stderr);
+ dbenv->set_errpfx(dbenv, progname);
+
+ /*
+ * The default Berkeley DB cache size is fairly small; configure a
+ * 1MB cache for now. This value will require tuning in the future.
+ */
+ if ((ret = dbenv->set_cachesize(dbenv, 0, 1048576, 1)) != 0) {
+ dbenv->err(dbenv, ret, "DB_ENV->set_cachesize");
+ return (1);
+ }
+
+ /*
+ * We may be working with an existing environment -- try and join it.
+ * If that fails, create a new database environment; for now, we only
+ * need a cache, no logging, locking, or transactions.
+ */
+ if ((ret = dbenv->open(dbenv, home,
+ DB_JOINENV | DB_USE_ENVIRON, 0)) != 0 &&
+ (ret = dbenv->open(dbenv, home,
+ DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_USE_ENVIRON, 0)) != 0) {
+ dbenv->err(dbenv, ret, "DB_ENV->open");
+ return (1);
+ }
+
+ /* Create the primary database handle. */
+ if ((ret = db_create(&db, dbenv, 0)) != 0) {
+ dbenv->err(dbenv, ret, "db_create");
+ return (1);
+ }
+
+ /*
+ * Records may be relatively large -- use a large page size.
+ */
+ if ((ret = db->set_pagesize(db, 32 * 1024)) != 0) {
+ dbenv->err(dbenv, ret, "DB->set_pagesize");
+ return (1);
+ }
+
+ /*
+ * The primary database uses an integer as its key; on little-endian
+ * machines, integers sort badly using the default Berkeley DB sort
+ * function (which is lexicographic). Specify a comparison function
+ * for the database.
+ */
+ if ((ret = db->set_bt_compare(db, compare_uint32)) != 0) {
+ dbenv->err(dbenv, ret, "DB->set_bt_compare");
+ return (1);
+ }
+
+ /* Open the primary database. */
+ if ((ret = db->open(db, NULL,
+ "primary", NULL, DB_BTREE, is_rdonly ? 0 : DB_CREATE, 0)) != 0) {
+ dbenv->err(dbenv, ret, "DB->open: primary");
+ return (1);
+ }
+
+ /* Open the secondaries. */
+ if ((ret = csv_secondary_open()) != 0)
+ return (1);
+
+ return (0);
+}
+
+/*
+ * csv_env_close --
+ * Discard the database environment.
+ */
+int
+csv_env_close()
+{
+ int ret, t_ret;
+
+ ret = 0;
+
+ /* Close the secondaries. */
+ ret = csv_secondary_close();
+
+ /* Close the primary handle. */
+ if (db != NULL && (t_ret = db->close(db, 0)) != 0) {
+ dbenv->err(dbenv, ret, "DB->close");
+ if (ret == 0)
+ ret = t_ret;
+ }
+ if ((t_ret = dbenv->close(dbenv, 0)) != 0) {
+ fprintf(stderr,
+ "%s: DB_ENV->close: %s\n", progname, db_strerror(ret));
+ if (ret == 0)
+ ret = t_ret;
+ }
+
+ return (ret);
+}
+
+/*
+ * csv_secondary_open --
+ * Open any secondary indices.
+ */
+int
+csv_secondary_open()
+{
+ DB *sdb;
+ DbField *f;
+ int ret, (*fcmp)(DB *, const DBT *, const DBT *);
+
+ /*
+ * Create secondary database handles.
+ */
+ for (f = fieldlist; f->name != NULL; ++f) {
+ if (f->indx == 0)
+ continue;
+
+ if ((ret = db_create(&sdb, dbenv, 0)) != 0) {
+ dbenv->err(dbenv, ret, "db_create");
+ return (1);
+ }
+ sdb->app_private = f;
+
+ /* Keys are small, use a relatively small page size. */
+ if ((ret = sdb->set_pagesize(sdb, 8 * 1024)) != 0) {
+ dbenv->err(dbenv, ret, "DB->set_pagesize");
+ return (1);
+ }
+
+ /*
+ * Sort the database based on the underlying type. Skip
+ * strings, Berkeley DB defaults to lexicographic sort.
+ */
+ switch (f->type) {
+ case DOUBLE:
+ fcmp = compare_double;
+ break;
+ case UNSIGNED_LONG:
+ fcmp = compare_ulong;
+ break;
+ case NOTSET:
+ case STRING:
+ default:
+ fcmp = NULL;
+ break;
+ }
+ if (fcmp != NULL &&
+ (ret = sdb->set_bt_compare(sdb, fcmp)) != 0) {
+ dbenv->err(dbenv, ret, "DB->set_bt_compare");
+ return (1);
+ }
+
+ /* Always configure secondaries for sorted duplicates. */
+ if ((ret = sdb->set_flags(sdb, DB_DUPSORT)) != 0) {
+ dbenv->err(dbenv, ret, "DB->set_flags");
+ return (1);
+ }
+ if ((ret = sdb->set_dup_compare(sdb, compare_ulong)) != 0) {
+ dbenv->err(dbenv, ret, "DB->set_dup_compare");
+ return (1);
+ }
+
+ if ((ret = sdb->open(
+ sdb, NULL, f->name, NULL, DB_BTREE, DB_CREATE, 0)) != 0) {
+ dbenv->err(dbenv, ret, "DB->open: %s", f->name);
+ return (1);
+ }
+ if ((ret = sdb->associate(
+ db, NULL, sdb, secondary_callback, DB_CREATE)) != 0) {
+ dbenv->err(dbenv, ret, "DB->set_associate");
+ return (1);
+ }
+ f->secondary = sdb;
+ }
+
+ return (0);
+}
+
+/*
+ * csv_secondary_close --
+ * Close any secondary indices.
+ */
+int
+csv_secondary_close()
+{
+ DbField *f;
+ int ret, t_ret;
+
+ ret = 0;
+ for (f = fieldlist; f->name != NULL; ++f)
+ if (f->secondary != NULL && (t_ret =
+ f->secondary->close(f->secondary, 0)) != 0 && ret == 0)
+ ret = t_ret;
+
+ return (ret);
+}
+
+/*
+ * compare_uint32 --
+ * Compare two keys.
+ */
+static int
+compare_uint32(DB *db_arg, const DBT *a_arg, const DBT *b_arg)
+{
+ u_int32_t a, b;
+
+ db_arg = db_arg; /* Quiet compiler. */
+
+ memcpy(&a, a_arg->data, sizeof(u_int32_t));
+ memcpy(&b, b_arg->data, sizeof(u_int32_t));
+ return (a > b ? 1 : ((a < b) ? -1 : 0));
+}
diff --git a/db-4.8.30/examples_c/csv/load.c b/db-4.8.30/examples_c/csv/load.c
new file mode 100644
index 0000000..34d8cc1
--- /dev/null
+++ b/db-4.8.30/examples_c/csv/load.c
@@ -0,0 +1,346 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2005-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+#include "csv.h"
+#include "csv_local.h"
+#include "csv_extern.h"
+
+typedef enum { GL_OK, GL_EOF, GL_FAIL } getline_status;
+
+static int input_field_count(const char *, size_t, u_int32_t *);
+static getline_status
+ input_getline(char **, size_t *, size_t *);
+static int input_put_alloc(u_int32_t **, size_t *, size_t, u_int32_t);
+static int input_set_offset(u_int32_t *, char *, size_t, u_int32_t);
+
+static input_fmt ifmt; /* Input format. */
+static u_long record_count = 0; /* Input record count for errors. */
+static u_long version; /* Version we're loading. */
+
+/*
+ * input_load --
+ * Read the input file and load new records into the database.
+ */
+int
+input_load(input_fmt ifmt_arg, u_long version_arg)
+{
+ getline_status gtl_status;
+ DBT key, data;
+ DBC *cursor;
+ u_int32_t field_count, primary_key, *put_line;
+ size_t input_len, len, put_len;
+ int is_first, ret;
+ char *input_line;
+
+ field_count = 0; /* Shut the compiler up. */
+
+ /* ifmt and version are global to this file. */
+ ifmt = ifmt_arg;
+ version = version_arg;
+
+ /*
+ * The primary key for the database is a unique number. Find out the
+ * last unique number allocated in this database by opening a cursor
+ * and fetching the last record.
+ */
+ if ((ret = db->cursor(db, NULL, &cursor, 0)) != 0) {
+ dbenv->err(dbenv, ret, "DB->cursor");
+ return (1);
+ }
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+ if ((ret = cursor->c_get(cursor, &key, &data, DB_LAST)) != 0)
+ if (ret == DB_NOTFOUND)
+ primary_key = 0;
+ else {
+ dbenv->err(dbenv, ret, "DB->cursor: DB_LAST");
+ return (1);
+ }
+ else
+ memcpy(&primary_key, key.data, sizeof(primary_key));
+ if ((ret = cursor->c_close(cursor)) != 0) {
+ dbenv->err(dbenv, ret, "DBC->close");
+ return (1);
+ }
+ if (verbose)
+ dbenv->errx(dbenv,
+ "maximum existing record in the database is %lu",
+ (u_long)primary_key);
+
+ key.data = &primary_key;
+ key.size = sizeof(primary_key);
+ input_line = NULL;
+ put_line = NULL;
+ input_len = put_len = 0;
+
+ /*
+ * See the README file for a description of the file input format.
+ */
+ for (is_first = 1; (gtl_status =
+ input_getline(&input_line, &input_len, &len)) == GL_OK;) {
+ ++record_count;
+ if (verbose > 1)
+ dbenv->errx(dbenv, "reading %lu", (u_long)record_count);
+
+ /* The first non-blank line of the input is a column map. */
+ if (is_first) {
+ is_first = 0;
+
+ /* Count the fields we're expecting in the input. */
+ if (input_field_count(
+ input_line, len, &field_count) != 0)
+ return (1);
+
+ }
+
+ /* Allocate room for the table of offsets. */
+ if (input_put_alloc(
+ &put_line, &put_len, len, field_count) != 0)
+ return (1);
+
+ /*
+ * Build the offset table and create the record we're
+ * going to store.
+ */
+ if (input_set_offset(put_line,
+ input_line, len, field_count) != 0)
+ return (1);
+
+ ++primary_key;
+
+ memcpy(put_line + (field_count + 2), input_line, len);
+ data.data = put_line;
+ data.size = (field_count + 2) * sizeof(u_int32_t) + len;
+
+ if (verbose > 1)
+ (void)entry_print(
+ data.data, data.size, field_count);
+
+ /* Load the key/data pair into the database. */
+ if ((ret = db->put(db, NULL, &key, &data, 0)) != 0) {
+ dbenv->err(dbenv, ret,
+ "DB->put: %lu", (u_long)primary_key);
+ return (1);
+ }
+ }
+
+ if (gtl_status != GL_EOF)
+ return (1);
+
+ if (verbose)
+ dbenv->errx(dbenv,
+ "%lu records read from the input file into the database",
+ record_count);
+
+ /*
+ * This program isn't transactional, limit the window for corruption.
+ */
+ if ((ret = db->sync(db, 0)) != 0) {
+ dbenv->err(dbenv, ret, "DB->sync");
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * input_getline --
+ * Read in a line of input into a buffer.
+ */
+static getline_status
+input_getline(char **input_linep, size_t *input_lenp, size_t *lenp)
+{
+ size_t input_len, len;
+ int ch;
+ char *input_line, *p, *endp;
+
+ input_line = *input_linep;
+ input_len = *input_lenp;
+
+ p = input_line;
+ endp = input_line + input_len;
+
+ for (len = 0; (ch = getchar()) != EOF;) {
+ if (ch == '\0') /* Strip <nul> (\000) bytes. */
+ continue;
+ switch (ifmt) {
+ case FORMAT_NL:
+ if (ch == '\n')
+ goto end;
+ break;
+ case FORMAT_EXCEL:
+ /* Strip <nl> (\012) bytes. */
+ if (ch == '\n')
+ continue;
+ /*
+ * <cr> (\015) bytes terminate lines.
+ * Skip blank lines.
+ */
+ if (ch == '\015') {
+ if (len == 0)
+ continue;
+ goto end;
+ }
+ }
+ if (input_line == endp) {
+ input_len += 256;
+ input_len *= 2;
+ if ((input_line =
+ realloc(input_line, input_len)) == NULL) {
+ dbenv->err(dbenv, errno,
+ "unable to allocate %lu bytes for record",
+ (u_long)input_len);
+ return (GL_FAIL);
+ }
+ p = input_line;
+ endp = p + input_len;
+ }
+
+ if (isprint(ch)) { /* Strip unprintables. */
+ *p++ = (char)ch;
+ ++len;
+ }
+ }
+
+end: if (len == 0)
+ return (GL_EOF);
+
+ *lenp = len;
+ *input_linep = input_line;
+ *input_lenp = input_len;
+
+ return (GL_OK);
+}
+
+/*
+ * input_field_count --
+ * Count the fields in the line.
+ */
+static int
+input_field_count(const char *line, size_t len, u_int32_t *field_countp)
+{
+ u_int32_t field_count;
+ int quoted;
+
+ field_count = 1;
+
+ /*
+ * There are N-1 separators for N fields, that is, "a,b,c" is three
+ * fields, with two comma separators.
+ */
+ switch (ifmt) {
+ case FORMAT_EXCEL:
+ quoted = 0;
+ for (field_count = 1; len > 0; ++line, --len)
+ if (*line == '"')
+ quoted = !quoted;
+ else if (*line == ',' && !quoted)
+ ++field_count;
+ break;
+ case FORMAT_NL:
+ for (field_count = 1; len > 0; ++line, --len)
+ if (*line == ',')
+ ++field_count;
+ break;
+ }
+ *field_countp = field_count;
+
+ if (verbose)
+ dbenv->errx(dbenv,
+ "input file made up of %lu fields", (u_int)field_count);
+
+ return (0);
+}
+
+/*
+ * input_put_alloc --
+ * Allocate room for the offset table plus the input.
+ */
+static int
+input_put_alloc(u_int32_t **put_linep,
+ size_t *put_lenp, size_t len, u_int32_t field_count)
+{
+ size_t total;
+
+ total = (field_count + 2) * sizeof(u_int32_t) + len;
+ if (total > *put_lenp &&
+ (*put_linep = realloc(*put_linep, *put_lenp += total)) == NULL) {
+ dbenv->err(dbenv, errno,
+ "unable to allocate %lu bytes for record",
+ (u_long)*put_lenp);
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * input_set_offset --
+ * Build an offset table and record combination.
+ */
+static int
+input_set_offset(u_int32_t *put_line,
+ char *input_line, size_t len, u_int32_t field_count)
+{
+ u_int32_t *op;
+ int quoted;
+ char *p, *endp;
+
+ op = put_line;
+
+ /* The first field is the version number. */
+ *op++ = version;
+
+ /*
+ * Walk the input line, looking for comma separators. It's an error
+ * to have too many or too few fields.
+ */
+ *op++ = 0;
+ quoted = 0;
+ for (p = input_line, endp = input_line + len;; ++p) {
+ if (ifmt == FORMAT_EXCEL && p < endp) {
+ if (*p == '"')
+ quoted = !quoted;
+ if (quoted)
+ continue;
+ }
+ if (*p == ',' || p == endp) {
+ if (field_count == 0) {
+ dbenv->errx(dbenv,
+ "record %lu: too many fields in the record",
+ record_count);
+ return (1);
+ }
+ --field_count;
+
+ *op++ = (u_int32_t)(p - input_line) + 1;
+
+ if (verbose > 1)
+ dbenv->errx(dbenv,
+ "offset %lu: {%.*s}", op[-1],
+ OFFSET_LEN(op, -2), input_line + op[-2]);
+
+ /*
+ * Don't insert a new field if the input lines ends
+ * in a comma.
+ */
+ if (p == endp || p + 1 == endp)
+ break;
+ }
+ }
+ *op++ = (u_int32_t)(p - input_line);
+
+ if (field_count != 0) {
+ dbenv->errx(dbenv,
+ "record %lu: not enough fields in the record",
+ record_count);
+ return (1);
+ }
+ memcpy(op, input_line, len);
+
+ return (0);
+}
diff --git a/db-4.8.30/examples_c/csv/load_main.c b/db-4.8.30/examples_c/csv/load_main.c
new file mode 100644
index 0000000..4ff4dd4
--- /dev/null
+++ b/db-4.8.30/examples_c/csv/load_main.c
@@ -0,0 +1,117 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2005-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+#include "csv.h"
+#include "csv_local.h"
+#include "csv_extern.h"
+
+static int usage(void);
+
+/*
+ * Globals
+ */
+DB_ENV *dbenv; /* Database environment */
+DB *db; /* Primary database */
+DB **secondary; /* Secondaries */
+int verbose; /* Program verbosity */
+char *progname; /* Program name */
+
+int
+main(int argc, char *argv[])
+{
+ input_fmt ifmt;
+ u_long version;
+ int ch, ret, t_ret;
+ char *home;
+
+ /* Initialize globals. */
+ dbenv = NULL;
+ db = NULL;
+ if ((progname = strrchr(argv[0], '/')) == NULL)
+ progname = argv[0];
+ else
+ ++progname;
+ verbose = 0;
+
+ /* Initialize arguments. */
+ home = NULL;
+ ifmt = FORMAT_NL;
+ version = 1;
+
+ /* Process arguments. */
+ while ((ch = getopt(argc, argv, "F:f:h:V:v")) != EOF)
+ switch (ch) {
+ case 'f':
+ if (freopen(optarg, "r", stdin) == NULL) {
+ fprintf(stderr,
+ "%s: %s\n", optarg, db_strerror(errno));
+ return (EXIT_FAILURE);
+ }
+ break;
+ case 'F':
+ if (strcasecmp(optarg, "excel") == 0) {
+ ifmt = FORMAT_EXCEL;
+ break;
+ }
+ return (usage());
+ case 'h':
+ home = optarg;
+ break;
+ case 'V':
+ if (strtoul_err(optarg, &version))
+ return (EXIT_FAILURE);
+ break;
+ case 'v':
+ ++verbose;
+ break;
+ case '?':
+ default:
+ return (usage());
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (*argv != NULL)
+ return (usage());
+
+ /*
+ * The home directory may not exist -- try and create it. We don't
+ * bother to distinguish between failure to create it and it already
+ * existing, as the database environment open will fail if we aren't
+ * successful.
+ */
+ if (home == NULL)
+ home = getenv("DB_HOME");
+ if (home != NULL)
+ (void)mkdir(home, S_IRWXU);
+
+ /* Create or join the database environment. */
+ if (csv_env_open(home, 0) != 0)
+ return (EXIT_FAILURE);
+
+ /* Load records into the database. */
+ ret = input_load(ifmt, version);
+
+ /* Close the database environment. */
+ if ((t_ret = csv_env_close()) != 0 && ret == 0)
+ ret = t_ret;
+
+ return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+}
+
+/*
+ * usage --
+ * Program usage message.
+ */
+static int
+usage(void)
+{
+ (void)fprintf(stderr,
+ "usage: %s [-v] [-F excel] [-f csv-file] [-h home]\n", progname);
+ return (EXIT_FAILURE);
+}
diff --git a/db-4.8.30/examples_c/csv/query.c b/db-4.8.30/examples_c/csv/query.c
new file mode 100644
index 0000000..c6eee8c
--- /dev/null
+++ b/db-4.8.30/examples_c/csv/query.c
@@ -0,0 +1,241 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2005-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+#include "csv.h"
+#include "csv_local.h"
+#include "csv_extern.h"
+
+static int query_by_field(char *);
+static int query_fieldlist(char *);
+static int query_help(char *);
+static int query_usage(void);
+
+typedef struct _cmdtab {
+ char *cmd; /* Command name */
+ int (*f)(char *); /* Underlying function. */
+ char *help; /* Help message. */
+} CMDTAB;
+
+static CMDTAB cmdtab[] = {
+ { "?",
+ query_help,
+ "?\t\tDisplay help screen" },
+ { "exit",
+ NULL,
+ "exit\t\tExit program" },
+ { "fields",
+ query_fieldlist,
+ "fields\t\tDisplay list of field names" },
+ { "help",
+ query_help,
+ "help\t\tDisplay help screen" },
+ { "quit",
+ NULL,
+ "quit\t\tExit program" },
+ { NULL,
+ query_by_field,
+ "field[op]value\tDisplay fields by value (=, !=, <, <=, >, >=, ~, !~)" },
+ { NULL, NULL, NULL }
+};
+
+/*
+ * query_interactive --
+ * Allow the user to interactively query the database.
+ */
+int
+query_interactive()
+{
+ int done;
+ char *p, input[256];
+
+ for (;;) {
+ printf("Query: ");
+ (void)fflush(stdout);
+ if (fgets(input, sizeof(input), stdin) == NULL) {
+ printf("\n");
+ if (ferror(stdin)) {
+ dbenv->err(dbenv, errno,
+ "error occurred reading from stdin");
+ return (1);
+ }
+ break;
+ }
+ if ((p = strchr(input, '\n')) == NULL) {
+ dbenv->errx(dbenv, "input buffer too small");
+ return (1);
+ }
+ *p = '\0';
+ if (query(input, &done) != 0)
+ return (1);
+ if (done != 0)
+ break;
+ }
+ return (0);
+}
+
+/*
+ * query --
+ * Process a query.
+ */
+int
+query(char *cmd, int *donep)
+{
+ CMDTAB *p;
+
+ if (donep != NULL)
+ *donep = 0;
+
+ for (p = cmdtab; p->cmd != NULL; ++p)
+ if (p->cmd != NULL &&
+ strncasecmp(cmd, p->cmd, strlen(p->cmd)) == 0)
+ break;
+
+ if (p->cmd == NULL)
+ return (query_by_field(cmd));
+
+ if (p->f == NULL) {
+ if (donep != NULL)
+ *donep = 1;
+ return (0);
+ }
+
+ return (p->f(cmd));
+}
+
+/*
+ * query_by_field --
+ * Query the primary database by field.
+ */
+static int
+query_by_field(char *input)
+{
+ OPERATOR operator;
+ size_t len;
+ char *field, *op, *value;
+
+ /*
+ * We expect to see "field [op] value" -- figure it out.
+ *
+ * Skip leading whitespace.
+ */
+ while (isspace(*input))
+ ++input;
+
+ /*
+ * Find an operator, and it better not start the string.
+ */
+ if ((len = strcspn(field = input, "<>!=~")) == 0)
+ return (query_usage());
+ op = field + len;
+
+ /* Figure out the operator, and find the start of the value. */
+ switch (op[0]) {
+ case '~':
+ operator = WC;
+ value = op + 1;
+ break;
+ case '!':
+ if (op[1] == '=') {
+ operator = NEQ;
+ value = op + 2;
+ break;
+ }
+ if (op[1] == '~') {
+ operator = NWC;
+ value = op + 2;
+ break;
+ }
+ return (query_usage());
+ case '<':
+ if (op[1] == '=') {
+ operator = LTEQ;
+ value = op + 2;
+ } else {
+ operator = LT;
+ value = op + 1;
+ }
+ break;
+ case '=':
+ operator = EQ;
+ if (op[1] == '=')
+ value = op + 2;
+ else
+ value = op + 1;
+ break;
+ case '>':
+ if (op[1] == '=') {
+ operator = GTEQ;
+ value = op + 2;
+ } else {
+ operator = GT;
+ value = op + 1;
+ }
+ break;
+ default:
+ return (query_usage());
+ }
+
+ /* Terminate the field name, and there better be a field name. */
+ while (--op > input && isspace(*op))
+ ;
+ if (op == input)
+ return (query_usage());
+ op[1] = '\0';
+
+ /* Make sure there is a value field. */
+ while (isspace(*value))
+ ++value;
+ if (*value == '\0')
+ return (query_usage());
+
+ return (DbRecord_search_field_name(field, value, operator));
+}
+
+/*
+ * query_fieldlist --
+ * Display list of field names.
+ */
+static int
+query_fieldlist(char *input)
+{
+ DbField *f;
+
+ input = input; /* Quiet compiler. */
+
+ for (f = fieldlist; f->name != NULL; ++f)
+ printf("field %3d: %s\n", f->fieldno, f->name);
+ return (0);
+}
+
+/*
+ * query_help --
+ * Query command list.
+ */
+static int
+query_help(char *input)
+{
+ CMDTAB *p;
+
+ input = input; /* Quiet compiler. */
+
+ printf("Query commands:\n");
+ for (p = cmdtab; p->help != NULL; ++p)
+ printf("\t%s\n", p->help);
+ return (0);
+}
+
+/*
+ * query_usage --
+ * Query usage message.
+ */
+static int
+query_usage(void)
+{
+ fprintf(stderr, "%s: query syntax error\n", progname);
+ return (query_help(NULL));
+}
diff --git a/db-4.8.30/examples_c/csv/query_main.c b/db-4.8.30/examples_c/csv/query_main.c
new file mode 100644
index 0000000..30376cd
--- /dev/null
+++ b/db-4.8.30/examples_c/csv/query_main.c
@@ -0,0 +1,99 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2005-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+#include "csv.h"
+#include "csv_local.h"
+#include "csv_extern.h"
+
+static int usage(void);
+
+/*
+ * Globals
+ */
+DB_ENV *dbenv; /* Database environment */
+DB *db; /* Primary database */
+int verbose; /* Program verbosity */
+char *progname; /* Program name */
+
+int
+main(int argc, char *argv[])
+{
+ int ch, done, ret, t_ret;
+ char **clist, **clp, *home;
+
+ /* Initialize globals. */
+ dbenv = NULL;
+ db = NULL;
+ if ((progname = strrchr(argv[0], '/')) == NULL)
+ progname = argv[0];
+ else
+ ++progname;
+ verbose = 0;
+
+ /* Initialize arguments. */
+ home = NULL;
+ ret = 0;
+
+ /* Allocate enough room for command-list arguments. */
+ if ((clp = clist =
+ (char **)calloc((size_t)argc + 1, sizeof(char *))) == NULL) {
+ fprintf(stderr, "%s: %s\n", progname, strerror(ENOMEM));
+ return (EXIT_FAILURE);
+ }
+
+ /* Process arguments. */
+ while ((ch = getopt(argc, argv, "c:h:v")) != EOF)
+ switch (ch) {
+ case 'c':
+ *clp++ = optarg;
+ break;
+ case 'h':
+ home = optarg;
+ break;
+ case 'v':
+ ++verbose;
+ break;
+ case '?':
+ default:
+ return (usage());
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (*argv != NULL)
+ return (usage());
+
+ /* Create or join the database environment. */
+ if (csv_env_open(home, 1) != 0)
+ return (EXIT_FAILURE);
+
+ /* Handle the queries. */
+ if (clp == clist)
+ ret = query_interactive();
+ else
+ for (clp = clist, done = 0; *clp != NULL && !done; ++clp)
+ if ((ret = query(*clp, &done)) != 0)
+ break;
+
+ /* Close the database environment. */
+ if ((t_ret = csv_env_close()) != 0 && ret == 0)
+ ret = t_ret;
+
+ return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+}
+
+/*
+ * usage --
+ * Program usage message.
+ */
+static int
+usage(void)
+{
+ (void)fprintf(stderr, "usage: %s [-v] [-c cmd] [-h home]\n", progname);
+ return (EXIT_FAILURE);
+}
diff --git a/db-4.8.30/examples_c/csv/sample.csv b/db-4.8.30/examples_c/csv/sample.csv
new file mode 100644
index 0000000..b3f0970
--- /dev/null
+++ b/db-4.8.30/examples_c/csv/sample.csv
@@ -0,0 +1,8 @@
+Adams,Bob,01/02/03,green,apple,37
+Carter,Denise Ann,04/05/06,blue,banana,38
+Eidel,Frank,07/08/09,red,cherry,38
+Grabel,Harriet,10/11/12,purple,date,40
+Indals,Jason,01/03/05,pink,orange,32
+Kilt,Laura,07/09/11,yellow,grape,38
+Moreno,Nancy,02/04/06,black,strawberry,38
+Octon,Patrick,08/10/12,magenta,kiwi,15
diff --git a/db-4.8.30/examples_c/csv/sample.desc b/db-4.8.30/examples_c/csv/sample.desc
new file mode 100644
index 0000000..65aa939
--- /dev/null
+++ b/db-4.8.30/examples_c/csv/sample.desc
@@ -0,0 +1,10 @@
+# $Id$
+
+version 1 {
+ LastName string
+ FirstName string
+ BirthDate
+ Color string index
+ Fruit string index
+ Age unsigned_long index
+}
diff --git a/db-4.8.30/examples_c/csv/util.c b/db-4.8.30/examples_c/csv/util.c
new file mode 100644
index 0000000..eed03f0
--- /dev/null
+++ b/db-4.8.30/examples_c/csv/util.c
@@ -0,0 +1,309 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2005-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+#include "csv.h"
+#include "csv_local.h"
+#include "csv_extern.h"
+
+/*
+ * entry_print --
+ * Display the primary database's data item.
+ */
+int
+entry_print(void *data, size_t len, u_int32_t field_count)
+{
+ u_int32_t a, *offset;
+ u_int i;
+ char *raw;
+
+ memcpy(&a, data, sizeof(u_int32_t));
+ printf("\tversion: %lu\n", (u_long)a);
+
+ offset = (u_int32_t *)data + 1;
+ if (field_count == 0) {
+ memcpy(&a, offset++, sizeof(u_int32_t));
+ printf("\tcolumn map: %lu fields: {%.*s}\n", (u_long)a,
+ (int)(len - 2 * sizeof(u_int32_t)),
+ (u_int8_t *)data + 2 * sizeof(u_int32_t));
+ } else {
+ raw = (char *)(offset + (field_count + 1));
+ for (i = 0; i < field_count; ++i) {
+ memcpy(&a, &offset[i], sizeof(u_int32_t));
+ len = OFFSET_LEN(offset, i);
+ printf("\toffset %4lu: len %4lu: {%.*s}\n",
+ (u_long)offset[i],
+ (u_long)len, (int)len, raw + a);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * strtod_err --
+ * strtod(3) with error checking.
+ */
+int
+strtod_err(char *input, double *valp)
+{
+ double val;
+ char *end;
+
+ /*
+ * strtoul requires setting errno to detect errors.
+ */
+ errno = 0;
+ val = strtod(input, &end);
+ if (errno == ERANGE) {
+ dbenv->err(dbenv, ERANGE, "%s", input);
+ return (1);
+ }
+ if (input[0] == '\0' ||
+ (end[0] != '\0' && end[0] != '\n' && !isspace(end[0]))) {
+ dbenv->errx(dbenv,
+ "%s: invalid floating point argument", input);
+ return (1);
+ }
+
+ *valp = val;
+ return (0);
+}
+
+/*
+ * strtoul_err --
+ * strtoul(3) with error checking.
+ */
+int
+strtoul_err(char *input, u_long *valp)
+{
+ u_long val;
+ char *end;
+
+ /*
+ * strtoul requires setting errno to detect errors.
+ */
+ errno = 0;
+ val = strtoul(input, &end, 10);
+ if (errno == ERANGE) {
+ dbenv->err(dbenv, ERANGE, "%s", input);
+ return (1);
+ }
+ if (input[0] == '\0' ||
+ (end[0] != '\0' && end[0] != '\n' && !isspace(end[0]))) {
+ dbenv->errx(dbenv, "%s: invalid unsigned long argument", input);
+ return (1);
+ }
+
+ *valp = val;
+ return (0);
+}
+
+int
+secondary_callback(DB *db_arg, const DBT *key, const DBT *data, DBT *result)
+{
+ DbField *f;
+ DbRecord record;
+ void *faddr, *addr;
+
+ /* Populate the field. */
+ if (DbRecord_init(key, data, &record) != 0)
+ return (-1);
+
+ f = db_arg->app_private;
+ faddr = (u_int8_t *)&record + f->offset;
+
+ /*
+ * If necessary, copy the field into separate memory.
+ * Set up the result DBT.
+ */
+ switch (f->type) {
+ case STRING:
+ result->data = *(char **)faddr;
+ result->size = strlen(*(char **)faddr) + 1;
+ break;
+ case DOUBLE:
+ if ((addr = malloc(sizeof(double))) == NULL)
+ return (-1);
+ result->data = addr;
+ result->size = sizeof(double);
+ result->flags = DB_DBT_APPMALLOC;
+ memcpy(addr, faddr, sizeof(double));
+ break;
+ case UNSIGNED_LONG:
+ if ((addr = malloc(sizeof(u_long))) == NULL)
+ return (-1);
+ result->data = addr;
+ result->size = sizeof(u_long);
+ result->flags = DB_DBT_APPMALLOC;
+ memcpy(addr, faddr, sizeof(u_long));
+ break;
+ default:
+ case NOTSET:
+ abort();
+ /* NOTREACHED */
+ }
+
+ return (0);
+}
+
+/*
+ * compare_double --
+ * Compare two keys.
+ */
+int
+compare_double(DB *db_arg, const DBT *a_arg, const DBT *b_arg)
+{
+ double a, b;
+
+ db_arg = db_arg; /* Quiet compiler. */
+
+ memcpy(&a, a_arg->data, sizeof(double));
+ memcpy(&b, b_arg->data, sizeof(double));
+ return (a > b ? 1 : ((a < b) ? -1 : 0));
+}
+
+/*
+ * compare_ulong --
+ * Compare two keys.
+ */
+int
+compare_ulong(DB *db_arg, const DBT *a_arg, const DBT *b_arg)
+{
+ u_long a, b;
+
+ db_arg = db_arg; /* Quiet compiler. */
+
+ memcpy(&a, a_arg->data, sizeof(u_long));
+ memcpy(&b, b_arg->data, sizeof(u_long));
+ return (a > b ? 1 : ((a < b) ? -1 : 0));
+}
+
+/*
+ * field_cmp_double --
+ * Compare two double.
+ */
+int
+field_cmp_double(void *a, void *b, OPERATOR op)
+{
+ switch (op) {
+ case GT:
+ return (*(double *)a > *(double *)b);
+ case GTEQ:
+ return (*(double *)a >= *(double *)b);
+ case LT:
+ return (*(double *)a < *(double *)b);
+ case LTEQ:
+ return (*(double *)a <= *(double *)b);
+ case NEQ:
+ return (*(double *)a != *(double *)b);
+ case EQ:
+ return (*(double *)a == *(double *)b);
+ case WC:
+ case NWC:
+ break;
+ }
+
+ abort();
+ /* NOTREACHED */
+}
+
+/*
+ * field_cmp_re --
+ * Compare against regular expression.
+ */
+int
+field_cmp_re(void *a, void *b, OPERATOR op)
+{
+ op = op; /* Quiet compiler. */
+
+ switch (op) {
+#ifdef HAVE_WILDCARD_SUPPORT
+ case WC:
+ return (regexec(b, *(char **)a, 0, NULL, 0) == 0);
+ case NWC:
+ return (regexec(b, *(char **)a, 0, NULL, 0) != 0);
+#else
+ case WC:
+ case NWC:
+ a = a;
+ b = b; /* Quiet compiler. */
+ /* FALLTHROUGH */
+#endif
+ case GT:
+ case GTEQ:
+ case LT:
+ case LTEQ:
+ case NEQ:
+ case EQ:
+ break;
+ }
+
+ abort();
+ /* NOTREACHED */
+}
+
+/*
+ * field_cmp_string --
+ * Compare two strings.
+ */
+int
+field_cmp_string(void *a, void *b, OPERATOR op)
+{
+ int v;
+
+ v = strcasecmp(*(char **)a, b);
+ switch (op) {
+ case GT:
+ return (v > 0 ? 1 : 0);
+ case GTEQ:
+ return (v >= 0 ? 1 : 0);
+ case LT:
+ return (v < 0 ? 1 : 0);
+ case LTEQ:
+ return (v <= 0 ? 1 : 0);
+ case NEQ:
+ return (v ? 1 : 0);
+ case EQ:
+ return (v ? 0 : 1);
+ case WC:
+ case NWC:
+ break;
+ }
+
+ abort();
+ /* NOTREACHED */
+}
+
+/*
+ * field_cmp_ulong --
+ * Compare two ulongs.
+ */
+int
+field_cmp_ulong(void *a, void *b, OPERATOR op)
+{
+ switch (op) {
+ case GT:
+ return (*(u_long *)a > *(u_long *)b);
+ case GTEQ:
+ return (*(u_long *)a >= *(u_long *)b);
+ case LT:
+ return (*(u_long *)a < *(u_long *)b);
+ case LTEQ:
+ return (*(u_long *)a <= *(u_long *)b);
+ case NEQ:
+ return (*(u_long *)a != *(u_long *)b);
+ case EQ:
+ return (*(u_long *)a == *(u_long *)b);
+ case WC:
+ case NWC:
+ break;
+ }
+
+ abort();
+ /* NOTREACHED */
+}