chiark / gitweb /
Upstream version, from Debian archive. upstream 0.32
authorMark Wooding <mdw@distorted.org.uk>
Sat, 3 Oct 2009 22:59:50 +0000 (23:59 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 3 Oct 2009 22:59:50 +0000 (23:59 +0100)
16 files changed:
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
Example [new file with mode: 0644]
MANIFEST [new file with mode: 0644]
README [new file with mode: 0644]
setup.cfg [new file with mode: 0644]
setup.py [new file with mode: 0644]
src/cdb.c [new file with mode: 0644]
src/cdb.h [new file with mode: 0644]
src/cdb_hash.c [new file with mode: 0644]
src/cdb_make.c [new file with mode: 0644]
src/cdb_make.h [new file with mode: 0644]
src/cdbmodule.c [new file with mode: 0644]
src/uint32.h [new file with mode: 0644]
src/uint32_pack.c [new file with mode: 0644]
src/uint32_unpack.c [new file with mode: 0644]

diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..a43ea21
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+       Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program 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 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..4298f5e
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,50 @@
+python-cdb ChangeLog
+MJ Pomraning <mjp@pilcrow.madison.wi.us>
+26 Jan 2002
+
+26 Jan 2002
+  - Version 0.32
+  - fix cdb.init() occasional memory corruption
+    thx: Jason Mastaler
+  - getnext() unbroken
+    thx: <wang@rjka.com>
+  - Example updated
+
+15 Jan 2002
+  - Version 0.31; BSDish EPROTO fix
+    thx: Jason Mastaler <jason@mastaler.com>
+
+10 Jan 2002
+  - Version 0.30; GPL
+  - cdb.error Exception introduced
+  - libc analogs of DJB funcs (mostly stdio), and libowfat (GPL) uint*
+    implementation; shed cdb-0.75 tarball; distutils build now tolerable
+  - cdb_pyread improvement; fixed memory leak concerning cdb_make_finish
+    fixed
+  - small doc corrections
+
+02 Apr 2001
+  - PyMem_{Malloc,Free} API change for 2.x 
+    thx: Ben Beuchler <insyte@emt-p.org>
+  - _wrap_cdb_read():  raise Exception, avoid unneeded PyMem_Malloc
+
+13 Mar 2001
+  - Version 0.21;
+  - setup.py (yay!); c.l.py.a announcement
+  - small doc improvements
+
+12 Mar 2001
+  - Version 0.20; public release
+  - fd member to -1 on cdbmake finish()
+  - PyString attr refcount oversight corrected
+  - objects, functions, module __doc__
+  - code reorg.
+
+05 Mar 2001
+  - extended cdb_o constructor: fd or fn
+  - proper close() in cdb destructor
+  - unlink cm.fntmp if cm deallocated but unfinish()ed
+  - cdb_o methods __doc__
+
+beginnings
+  - cdb.py wrapper around _cdbmodule.so
diff --git a/Example b/Example
new file mode 100644 (file)
index 0000000..9017e35
--- /dev/null
+++ b/Example
@@ -0,0 +1,66 @@
+#! /usr/bin/env python
+
+# python-cdb 0.32 "Example"
+
+import cdb
+
+print cdb.__version__
+
+## cdbmake object
+
+fn = "f.cdb"
+
+maker = cdb.cdbmake(fn, fn + ".tmp");
+
+maker.add('flim', 'flam')        # +4,4:flim->flam
+maker.add('map', 'hash')         # +3,4:map->hash
+maker.add('spam', 'eggs')        # +4,4:spam->eggs
+maker.add('map', 'dictionary')   # +3,10:map->dictionary
+maker.add('map', 'assoc. array') # +3,12:map->assoc. array
+
+print "Added %d records to CDB %s (fd %d)" % \
+      (maker.numentries, maker.fn, maker.fd)
+
+maker.finish()
+
+del(maker)
+
+## cdb object
+
+c = cdb.init(fn)             # or init( file_obj.fileno() )
+
+print len(c)                 # 5
+
+print c['flim']              # 'flam'
+print c.get('spam')          # 'eggs'
+print c.get('map', 0)        # 'hash' -- a la cdbget utility
+print c.get('map', 1)        # 'dictionary'
+
+r = c.get('map')             # will print:
+while r is not None:         #   'hash'
+    print r                  #   'dictionary'
+    r = c.getnext()          #   'assoc. array'
+
+print c.keys()               # ['flim', 'map', 'spam']
+
+for k in c.keys():           # flim => ['flam']
+  print k, '=>', c.getall(k) # map => ['hash', 'dictionary', 'assoc. array']
+                             # spam => ['eggs']
+
+k = c.firstkey()             # same as above
+while k is not None:
+    print k, "=>", c.getall(k)
+    k = c.nextkey()
+
+
+def cdbdump(cdb_o):          # as the cdbdump utility
+    r = cdb_o.each()         # r = ('key', 'val') or None
+    while r:
+        print "+%d,%d:%s->%s" % (
+              len(r[0]), len(r[1]),
+              r[0], r[1] )
+        r = cdb_o.each()
+    print
+
+
+cdbdump(c)
diff --git a/MANIFEST b/MANIFEST
new file mode 100644 (file)
index 0000000..18cf95c
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,16 @@
+MANIFEST
+ChangeLog
+Example
+README
+COPYING
+setup.py
+setup.cfg
+src/cdb.c
+src/cdb.h
+src/cdb_make.c
+src/cdb_make.h
+src/cdb_hash.c
+src/uint32_pack.c
+src/uint32_unpack.c
+src/cdbmodule.c
+src/uint32.h
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..66b62bd
--- /dev/null
+++ b/README
@@ -0,0 +1,63 @@
+python-cdb 0.32
+MJ Pomraning <mjp@pilcrow.madison.wi.us>
+26 Jan 2002
+
+INTRO
+=====
+The python-cdb extension module is an adaptation of D. J. Bernstein's
+constant database package (see http://cr.yp.to/cdb.html).
+
+cdb files are mappings of keys to values, designed for wickedly
+fast lookups and atomic updates.  This module mimics the normal
+cdb utilities, cdb(get|dump|make), via convenient, high-level Python
+objects.
+
+
+COPYRIGHT
+=========
+python-cdb is free software, as is cdb itself.
+
+The extension module is licensed under the GNU GPL version 2 or later,
+and is copyright 2001, 2002 Michael J. Pomraning.  Ancillary files from
+Felix von Leitner's libowfat are also licensed under the GPL.  Finally,
+modifications to D. J. Bernstein's public domain cdb implementation are
+similarly released to the public domain.
+
+
+INSTALL
+=======
+
+  $ tar zxf python-cdb-$VERSION.tgz
+  $ cd python-cdb-$VERSION
+  $ python setup.py build
+  $ python setup.py install
+  # python setup.py bdist --format=rpm, if you prefer
+
+Now break it and tell me about it (or use it smoothly and tell me
+about that, too).
+
+DOCS
+====
+Consult the docstrings for module, class, and function documentation.
+
+  $ python -c 'import cdb; print cdb.__doc__'
+  $ python -c 'import cdb; print cdb.cdbmake("f.cdb","f.tmp").__doc__'
+  $ python -c 'import cdb; print cdb.init("some.cdb").__doc__'
+
+BUGS
+====
+Bug reports to MJ Pomraning <mjp@pilcrow.madison.wi.us>.
+
+
+TODO
+====
+
+  - better README/docs
+
+  - API features new with 2.2 
+
+  - formal speed benchmarks
+
+  - fix bugs, maybe :)
+
+
diff --git a/setup.cfg b/setup.cfg
new file mode 100644 (file)
index 0000000..aa849bc
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,8 @@
+# python-cdb 0.31
+
+[bdist_rpm]
+release = 1
+doc_files = ChangeLog
+            README
+            COPYING
+            Example
diff --git a/setup.py b/setup.py
new file mode 100644 (file)
index 0000000..899d17b
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,37 @@
+#! /usr/bin/env python
+
+# MJ Pomraning <mjp@pilcrow.madison.wi.us>
+# 26 Jan 2001
+# python-cdb 0.32 setup.py
+
+SRCDIR   = "src"
+SRCFILES = map(lambda f: SRCDIR + '/' + f + '.c',
+              ["cdbmodule","cdb","cdb_make","cdb_hash",
+               "uint32_pack","uint32_unpack"])
+
+from distutils.core import setup, Extension
+
+setup (# Distribution meta-data
+        name = "python-cdb",
+        version = "0.32",
+        description = "Interface to constant database files",
+        author = "MJ Pomraning",
+        author_email = "mjp@pilcrow.madison.wi.us",
+       license = "GPL",
+        long_description = \
+'''The python-cdb extension module is an adaptation of D. J. Bernstein's
+constant database package (see http://cr.yp.to/cdb.html).
+
+cdb files are mappings of keys to values, designed for wickedly
+fast lookups and atomic updates.  This module mimics the normal
+cdb utilities, cdb(get|dump|make), via convenient, high-level Python
+objects.''',
+        ext_modules = [ Extension(
+                            "cdbmodule",
+                            SRCFILES,
+                            include_dirs=[ SRCDIR + '/' ]
+                        ) 
+                      ],
+        url = "http://pilcrow.madison.wi.us/",
+      )
+
diff --git a/src/cdb.c b/src/cdb.c
new file mode 100644 (file)
index 0000000..1e0c9aa
--- /dev/null
+++ b/src/cdb.c
@@ -0,0 +1,141 @@
+/* Public domain. */
+/* Adapted from DJB's original cdb-0.75 package */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include "cdb.h"
+
+#ifndef EPROTO
+#define EPROTO -15  /* cdb 0.75's default for PROTOless systems */
+#endif
+
+void cdb_free(struct cdb *c)
+{
+  if (c->map) {
+    munmap(c->map,c->size);
+    c->map = 0;
+  }
+}
+
+void cdb_findstart(struct cdb *c)
+{
+  c->loop = 0;
+}
+
+void cdb_init(struct cdb *c,int fd)
+{
+  struct stat st;
+  char *x;
+
+  cdb_free(c);
+  cdb_findstart(c);
+  c->fd = fd;
+
+  if (fstat(fd,&st) == 0)
+    if (st.st_size <= 0xffffffff) {
+      x = mmap(0,st.st_size,PROT_READ,MAP_SHARED,fd,0);
+      if (x + 1) {
+       c->size = st.st_size;
+       c->map = x;
+      }
+    }
+}
+
+int cdb_read(struct cdb *c,char *buf,unsigned int len,uint32 pos)
+{
+  if (c->map) {
+    if ((pos > c->size) || (c->size - pos < len)) goto FORMAT;
+    memcpy(buf,c->map + pos,len);
+  }
+  else {
+    if (lseek(c->fd,pos,SEEK_SET) == -1) return -1;
+    /* if (seek_set(c->fd,pos) == -1) return -1; */
+    while (len > 0) {
+      int r;
+      do
+        r = read(c->fd,buf,len);
+      while ((r == -1) && (errno == EINTR));
+      if (r == -1) return -1;
+      if (r == 0) goto FORMAT;
+      buf += r;
+      len -= r;
+    }
+  }
+  return 0;
+
+  FORMAT:
+  errno = EPROTO;
+  return -1;
+}
+
+static int match(struct cdb *c,char *key,unsigned int len,uint32 pos)
+{
+  char buf[32];
+  int n;
+
+  while (len > 0) {
+    n = sizeof buf;
+    if (n > len) n = len;
+    if (cdb_read(c,buf,n,pos) == -1) return -1;
+    if (memcmp(buf,key,n)) return 0;
+    pos += n;
+    key += n;
+    len -= n;
+  }
+  return 1;
+}
+
+int cdb_findnext(struct cdb *c,char *key,unsigned int len)
+{
+  char buf[8];
+  uint32 pos;
+  uint32 u;
+
+  if (!c->loop) {
+    u = cdb_hash(key,len);
+    if (cdb_read(c,buf,8,(u << 3) & 2047) == -1) return -1;
+    uint32_unpack(buf + 4,&c->hslots);
+    if (!c->hslots) return 0;
+    uint32_unpack(buf,&c->hpos);
+    c->khash = u;
+    u >>= 8;
+    u %= c->hslots;
+    u <<= 3;
+    c->kpos = c->hpos + u;
+  }
+
+  while (c->loop < c->hslots) {
+    if (cdb_read(c,buf,8,c->kpos) == -1) return -1;
+    uint32_unpack(buf + 4,&pos);
+    if (!pos) return 0;
+    c->loop += 1;
+    c->kpos += 8;
+    if (c->kpos == c->hpos + (c->hslots << 3)) c->kpos = c->hpos;
+    uint32_unpack(buf,&u);
+    if (u == c->khash) {
+      if (cdb_read(c,buf,8,pos) == -1) return -1;
+      uint32_unpack(buf,&u);
+      if (u == len)
+       switch(match(c,key,len,pos + 8)) {
+         case -1:
+           return -1;
+         case 1:
+           uint32_unpack(buf + 4,&c->dlen);
+           c->dpos = pos + 8 + len;
+           return 1;
+       }
+    }
+  }
+
+  return 0;
+}
+
+int cdb_find(struct cdb *c,char *key,unsigned int len)
+{
+  cdb_findstart(c);
+  return cdb_findnext(c,key,len);
+}
diff --git a/src/cdb.h b/src/cdb.h
new file mode 100644 (file)
index 0000000..d244789
--- /dev/null
+++ b/src/cdb.h
@@ -0,0 +1,38 @@
+/* Public domain. */
+/* Adapted from DJB's original cdb-0.75 package */
+
+#ifndef CDB_H
+#define CDB_H
+
+#include "uint32.h"
+
+#define CDB_HASHSTART 5381
+extern uint32 cdb_hashadd(uint32,unsigned char);
+extern uint32 cdb_hash(char *,unsigned int);
+
+struct cdb {
+  char *map; /* 0 if no map is available */
+  int fd;
+  uint32 size; /* initialized if map is nonzero */
+  uint32 loop; /* number of hash slots searched under this key */
+  uint32 khash; /* initialized if loop is nonzero */
+  uint32 kpos; /* initialized if loop is nonzero */
+  uint32 hpos; /* initialized if loop is nonzero */
+  uint32 hslots; /* initialized if loop is nonzero */
+  uint32 dpos; /* initialized if cdb_findnext() returns 1 */
+  uint32 dlen; /* initialized if cdb_findnext() returns 1 */
+} ;
+
+extern void cdb_free(struct cdb *);
+extern void cdb_init(struct cdb *,int fd);
+
+extern int cdb_read(struct cdb *,char *,unsigned int,uint32);
+
+extern void cdb_findstart(struct cdb *);
+extern int cdb_findnext(struct cdb *,char *,unsigned int);
+extern int cdb_find(struct cdb *,char *,unsigned int);
+
+#define cdb_datapos(c) ((c)->dpos)
+#define cdb_datalen(c) ((c)->dlen)
+
+#endif
diff --git a/src/cdb_hash.c b/src/cdb_hash.c
new file mode 100644 (file)
index 0000000..551b3a3
--- /dev/null
@@ -0,0 +1,22 @@
+/* Public domain. */
+/* Adapted from DJB's original cdb-0.75 package */
+
+#include "cdb.h"
+
+uint32 cdb_hashadd(uint32 h,unsigned char c)
+{
+  h += (h << 5);
+  return h ^ c;
+}
+
+uint32 cdb_hash(char *buf,unsigned int len)
+{
+  uint32 h;
+
+  h = CDB_HASHSTART;
+  while (len) {
+    h = cdb_hashadd(h,*buf++);
+    --len;
+  }
+  return h;
+}
diff --git a/src/cdb_make.c b/src/cdb_make.c
new file mode 100644 (file)
index 0000000..bbfdfbc
--- /dev/null
@@ -0,0 +1,180 @@
+/* Public domain. */
+/* Adapted from DJB's original cdb-0.75 package */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include "cdb.h"
+#include "cdb_make.h"
+#include "uint32.h"
+
+static int cdb_make_write(struct cdb_make *c, char *buf, uint32 sz) {
+  fwrite(buf, sz, 1, c->fp);
+  return ferror(c->fp);
+}
+
+int cdb_make_start(struct cdb_make *c, FILE * f)
+{
+  c->head = 0;
+  c->split = 0;
+  c->hash = 0;
+  c->numentries = 0;
+  c->fp = f;
+  c->pos = sizeof c->final;
+  if (fseek(f,c->pos,SEEK_SET) == -1) {
+    perror("fseek failed");
+    return -1;
+  }
+  return ftell(c->fp);
+}
+
+static int posplus(struct cdb_make *c,uint32 len)
+{
+  uint32 newpos = c->pos + len;
+  if (newpos < len) { errno = ENOMEM; return -1; }
+  c->pos = newpos;
+  return 0;
+}
+
+int cdb_make_addend(struct cdb_make *c,unsigned int keylen,unsigned int datalen,uint32 h)
+{
+  struct cdb_hplist *head;
+
+  head = c->head;
+  if (!head || (head->num >= CDB_HPLIST)) {
+    head = (struct cdb_hplist *) malloc(sizeof(struct cdb_hplist));
+    if (!head) return -1;
+    head->num = 0;
+    head->next = c->head;
+    c->head = head;
+  }
+  head->hp[head->num].h = h;
+  head->hp[head->num].p = c->pos;
+  ++head->num;
+  ++c->numentries;
+  if (posplus(c,8) == -1) return -1;
+  if (posplus(c,keylen) == -1) return -1;
+  if (posplus(c,datalen) == -1) return -1;
+  return 0;
+}
+
+int cdb_make_addbegin(struct cdb_make *c,unsigned int keylen,unsigned int datalen)
+{
+  char buf[8];
+
+  if (keylen > 0xffffffff) { errno = ENOMEM; return -1; }
+  if (datalen > 0xffffffff) { errno = ENOMEM; return -1; }
+
+  uint32_pack(buf,keylen);
+  uint32_pack(buf + 4,datalen);
+  if (cdb_make_write(c,buf,8) != 0) return -1;
+  /* if (buffer_putalign(&c->b,buf,8) == -1) return -1; */
+  return 0;
+}
+
+int cdb_make_add(struct cdb_make *c,char *key,unsigned int keylen,char *data,unsigned int datalen)
+{
+  if (cdb_make_addbegin(c,keylen,datalen) == -1) return -1;
+  if (cdb_make_write(c,key,keylen) != 0) return -1;
+  if (cdb_make_write(c,data,datalen) != 0) return -1;
+  /* if (buffer_putalign(&c->b,key,keylen) == -1) return -1; */
+  /* if (buffer_putalign(&c->b,data,datalen) == -1) return -1; */
+  return cdb_make_addend(c,keylen,datalen,cdb_hash(key,keylen));
+}
+
+int cdb_make_finish(struct cdb_make *c)
+{
+  char buf[8];
+  int i;
+  uint32 len;
+  uint32 u;
+  uint32 memsize;
+  uint32 count;
+  uint32 where;
+  struct cdb_hplist *x;
+  struct cdb_hp *hp;
+
+  for (i = 0;i < 256;++i)
+    c->count[i] = 0;
+
+  for (x = c->head;x;x = x->next) {
+    i = x->num;
+    while (i--)
+      ++c->count[255 & x->hp[i].h];
+  }
+
+  memsize = 1;
+  for (i = 0;i < 256;++i) {
+    u = c->count[i] * 2;
+    if (u > memsize)
+      memsize = u;
+  }
+
+  memsize += c->numentries; /* no overflow possible up to now */
+  u = (uint32) 0 - (uint32) 1;
+  u /= sizeof(struct cdb_hp);
+  if (memsize > u) { errno = ENOMEM; return -1; }
+
+  c->split = (struct cdb_hp *) malloc(memsize * sizeof(struct cdb_hp));
+  if (!c->split) return -1;
+
+  c->hash = c->split + c->numentries;
+
+  u = 0;
+  for (i = 0;i < 256;++i) {
+    u += c->count[i]; /* bounded by numentries, so no overflow */
+    c->start[i] = u;
+  }
+
+  for (x = c->head;x;x = x->next) {
+    i = x->num;
+    while (i--)
+      c->split[--c->start[255 & x->hp[i].h]] = x->hp[i];
+  }
+
+  for (i = 0;i < 256;++i) {
+    count = c->count[i];
+
+    len = count + count; /* no overflow possible */
+    uint32_pack(c->final + 8 * i,c->pos);
+    uint32_pack(c->final + 8 * i + 4,len);
+
+    for (u = 0;u < len;++u)
+      c->hash[u].h = c->hash[u].p = 0;
+
+    hp = c->split + c->start[i];
+    for (u = 0;u < count;++u) {
+      where = (hp->h >> 8) % len;
+      while (c->hash[where].p)
+       if (++where == len)
+         where = 0;
+      c->hash[where] = *hp++;
+    }
+
+    for (u = 0;u < len;++u) {
+      uint32_pack(buf,c->hash[u].h);
+      uint32_pack(buf + 4,c->hash[u].p);
+      if (cdb_make_write(c,buf,8) != 0) return -1;
+      /* if (buffer_putalign(&c->b,buf,8) == -1) return -1; */
+      if (posplus(c,8) == -1) return -1;
+    }
+  }
+
+  if (c->split) free(c->split);
+
+  for (x = c->head;x;c->head = x) {
+    x = x->next;
+    free(c->head);
+  }
+
+  if (fflush(c->fp) != 0) return -1;
+  /* if (buffer_flush(&c->b) == -1) return -1; */
+  rewind(c->fp);
+  if (ftell(c->fp) != 0) return -1;
+  /* if (seek_begin(c->fd) == -1) return -1; */
+  if (cdb_make_write(c,c->final,sizeof c->final) != 0) return -1;
+  return fflush(c->fp);
+  /* return buffer_putflush(&c->b,c->final,sizeof c->final); */
+}
diff --git a/src/cdb_make.h b/src/cdb_make.h
new file mode 100644 (file)
index 0000000..a7757bb
--- /dev/null
@@ -0,0 +1,41 @@
+/* Public domain. */
+/* Adapted from DJB's original cdb-0.75 package */
+
+#ifndef CDB_MAKE_H
+#define CDB_MAKE_H
+
+#include <stdio.h>
+#include "uint32.h"
+
+#define CDB_HPLIST 1000
+
+struct cdb_hp { uint32 h; uint32 p; } ;
+
+struct cdb_hplist {
+  struct cdb_hp hp[CDB_HPLIST];
+  struct cdb_hplist *next;
+  int num;
+} ;
+
+struct cdb_make {
+  /* char bspace[8192]; */
+  char final[2048];
+  uint32 count[256];
+  uint32 start[256];
+  struct cdb_hplist *head;
+  struct cdb_hp *split; /* includes space for hash */
+  struct cdb_hp *hash;
+  uint32 numentries;
+  /* buffer b; */
+  uint32 pos;
+  /* int fd; */
+  FILE * fp;
+} ;
+
+extern int cdb_make_start(struct cdb_make *, FILE *);
+extern int cdb_make_addbegin(struct cdb_make *,unsigned int,unsigned int);
+extern int cdb_make_addend(struct cdb_make *,unsigned int,unsigned int,uint32);
+extern int cdb_make_add(struct cdb_make *,char *,unsigned int,char *,unsigned int);
+extern int cdb_make_finish(struct cdb_make *);
+
+#endif
diff --git a/src/cdbmodule.c b/src/cdbmodule.c
new file mode 100644 (file)
index 0000000..bdf10dc
--- /dev/null
@@ -0,0 +1,985 @@
+/**
+python-cdb 0.32
+Copyright 2001, 2002 Michael J. Pomraning <mjp@pilcrow.madison.wi.us>
+
+This program 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 2 of the License, or
+(at your option) any later version.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+**/
+
+#include <Python.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include "cdb.h"
+#include "cdb_make.h"
+
+#define open_read(x)       (open((x),O_RDONLY|O_NDELAY))
+/* ala djb's open_foo */
+
+#define VERSION     "0.32"
+#define CDBVERSION  "0.75"
+
+/* ------------------- cdb object -------------------- */
+
+static char cdbo_object_doc[] = "\
+This object represents a CDB database:  a reliable, constant\n\
+database mapping strings of bytes (\"keys\") to strings of bytes\n\
+(\"data\"), and designed for fast lookups.\n\
+\n\
+Unlike a conventional mapping, CDBs can meaningfully store multiple\n\
+records under one key (though this feature is not often used).\n\
+\n\
+A CDB object 'cdb_o' offers the following interesting attributes:\n\
+\n\
+  Dict-like Lookup Methods:\n\
+    cdb_o[key], get(key), getnext(), getall(key)\n\
+\n\
+  Key-based Iteration Methods:\n\
+    keys(), firstkey(), nextkey()\n\
+    (Key-based iteration returns only distinct keys.)\n\
+\n\
+  Raw Iteration Method:\n\
+    each()\n\
+    (\"Dumping\" may return the same key more than once.)\n\
+\n\
+  __members__:\n\
+    fd   - File descriptor of the underlying cdb.\n\
+    name - Name of the cdb, or None if not known.\n\
+    size - Size of the cdb, or None if not mmap()d.\n\
+\n\
+  __length__:\n\
+    len(cdb_o) returns the total number of items in a cdb,\n\
+    which may or may not exceed the number of distinct keys.\n";
+  
+
+typedef struct {
+    PyObject_HEAD
+    struct cdb c;
+    PyObject * name_py;  /* 'filename' or Py_None */
+    PyObject * getkey;   /* squirreled away for getnext() */
+    uint32 eod;          /* as in cdbdump */
+    uint32 iter_pos;
+    uint32 each_pos;
+    uint32 numrecords;
+} CdbObject;
+
+staticforward PyTypeObject CdbType;
+
+PyObject * CDBError;
+#define CDBerr PyErr_SetFromErrno(CDBError)
+
+static PyObject *
+cdb_pyread(CdbObject *cdb_o, unsigned int len, uint32 pos) {
+  struct cdb *c;
+  PyObject *s = NULL;
+
+  c = &cdb_o->c;
+
+  if (c->map) {
+    if ((pos > c->size) || (c->size - pos < len))
+      goto FORMAT;
+    s = PyString_FromStringAndSize(c->map + pos, len);
+  } else {
+    s = PyString_FromStringAndSize(NULL, len);
+    if (s == NULL)
+      return NULL;
+    if (lseek(c->fd,pos,SEEK_SET) == -1) goto ERRNO;
+    while (len > 0) {
+      int r;
+      char * buf = PyString_AsString(s);
+
+      do {
+        Py_BEGIN_ALLOW_THREADS
+        r = read(c->fd,buf,len);
+        Py_END_ALLOW_THREADS
+      }
+      while ((r == -1) && (errno == EINTR));
+      if (r == -1) goto ERRNO;
+      if (r == 0) goto FORMAT;
+      buf += r;
+      len -= r;
+    }
+  }
+
+  return s;
+
+  FORMAT:
+  Py_XDECREF(s);
+  PyErr_SetFromErrno(PyExc_RuntimeError);
+  return NULL;
+
+  ERRNO:
+  Py_XDECREF(s);
+  return CDBerr;
+
+}
+
+
+#define CDBO_CURDATA(x) (cdb_pyread(x, x->c.dlen, x->c.dpos))
+
+
+/* ------------------- CdbObject methods -------------------- */
+
+static char cdbo_has_key_doc[] =
+"cdb_o.has_key(k) -> 1 (or 0)\n\
+\n\
+Returns true if the CDB contains key k.";
+
+static PyObject *
+cdbo_has_key(CdbObject *self, PyObject *args) {
+
+  char * key;
+  unsigned int klen;
+  int r;
+
+  if (!PyArg_ParseTuple(args, "s#", &key, &klen))
+    return NULL;
+
+  r = cdb_find(&self->c, key, klen);
+  if (r == -1)
+    return CDBerr;
+
+  return Py_BuildValue("i", r);
+
+}
+
+static char cdbo_get_doc[] =
+"cdb_o.get(k [, i]) -> data (or None)\n\
+\n\
+Fetches the record stored under key k, skipping past the first i\n\
+records under that key (default: 0).  Prepares the next call to\n\
+getnext().\n\
+\n\
+Assuming cdb_o.has_key(k) == 1, then all of the following return:\n\
+the first record stored under key k:\n\
+\n\
+    cdb_o.get(k) == cdb_o[k] == cdb_o.getall(k)[0]\n";
+
+static PyObject *
+cdbo_get(CdbObject *self, PyObject *args) {
+
+  char * key;
+  unsigned int klen;
+  int r;
+  int i = 0;
+
+  if (!PyArg_ParseTuple(args, "s#|i:get", &key, &klen, &i))
+    return NULL;
+
+  cdb_findstart(&self->c);
+
+  for (;;) {
+    r = cdb_findnext(&self->c, key, klen);
+    if (r == -1) return CDBerr;
+    if (!r) return Py_BuildValue("");
+    if (!i) break;
+    --i;
+  }
+
+  /* prep. possibly ensuing call to getnext() */
+  Py_XDECREF(self->getkey);
+  self->getkey = PyString_FromStringAndSize(key, klen);
+  if (self->getkey == NULL)
+    return NULL;
+
+  return CDBO_CURDATA(self);
+}
+
+static char cdbo_getall_doc[] =
+"cdb_o.getall(k) -> ['data', ... ]\n\
+\n\
+Return a list of all records stored under key k.";
+
+static PyObject *
+cdbo_getall(CdbObject *self, PyObject *args) {
+
+  PyObject * list, * data;
+  char * key;
+  unsigned int klen;
+  int r, err;
+
+  if (!PyArg_ParseTuple(args, "s#:getall", &key, &klen))
+    return NULL;
+
+  list = PyList_New(0);
+
+  if (list == NULL) return NULL;
+
+  cdb_findstart(&self->c);
+
+  while ((r = cdb_findnext(&self->c, key, klen))) {
+    if (r == -1) {
+      Py_DECREF(list);
+      return CDBerr;
+    }
+    data = CDBO_CURDATA(self);
+    if (data == NULL) {
+      Py_DECREF(list);
+      return NULL;
+    }
+    err = PyList_Append(list, data);
+    Py_DECREF(data);
+    if (err != 0) {
+      Py_DECREF(list);
+      return NULL;
+    }
+  }
+
+  return list;
+
+}
+
+static char cdbo_getnext_doc[] =
+"cdb_o.getnext() -> 'data' (or None)\n\
+\n\
+For iteration over the records stored under one key, avoiding loading\n\
+all items into memory).  The \"current key\" is determined by the most\n\
+recent call to get().\n\
+\n\
+The following loops through all items stored under key k:\n\
+\n\
+    ## cdb_o.getall(k) possibly too big for memory\n\
+    rec = cdb_o.get(k)\n\
+    while rec is not None:\n\
+      do_something(rec)\n\
+      rec = cdb_o.getnext()\n";
+
+static PyObject *
+cdbo_getnext(CdbObject *self, PyObject *args) {
+
+  if (!PyArg_ParseTuple(args, ":getnext"))
+    return NULL;
+
+  if (self->getkey == NULL) {
+    PyErr_SetString(PyExc_TypeError, 
+                    "getnext() called without first calling get()");
+    return NULL;
+  }
+
+  switch(cdb_findnext(&self->c, 
+                      PyString_AsString(self->getkey), 
+                      PyString_Size(self->getkey))) {
+    case -1:
+      return CDBerr;
+    case  0:
+      Py_DECREF(self->getkey);
+      self->getkey = NULL;
+      return Py_BuildValue("");
+    default:
+      return CDBO_CURDATA(self);
+  }
+ /* not reached */
+}
+
+uint32
+_cdbo_init_eod(CdbObject *self) {
+
+  char nonce[4];
+
+  if (cdb_read(&self->c, nonce, 4, 0) == -1)
+    return 0;
+
+  uint32_unpack(nonce, &self->eod);
+
+  return self->eod;
+
+}
+
+/*
+ * _cdbo_keyiter(cdb_o)
+ *
+ * Whiz-bang all-in-one:
+ *   extract current record
+ *   compare current pos to pos implied by cdb_find(current_key)
+ *     (Different? adv. iter cursor, loop and try again)
+ *   advance iteration cursor
+ *   return key
+ */
+
+static PyObject *
+_cdbo_keyiter(CdbObject *self) {
+
+  PyObject *key;
+  char buf[8];
+  uint32 klen, dlen;
+
+  if (! self->eod)
+    _cdbo_init_eod(self);
+
+  while (self->iter_pos < self->eod) {
+    if (cdb_read(&self->c, buf, 8, self->iter_pos) == -1)
+      return CDBerr;
+
+    uint32_unpack(buf, &klen);
+    uint32_unpack(buf+4, &dlen);
+
+    key = cdb_pyread(self, klen, self->iter_pos + 8);
+
+    if (key == NULL)
+      return NULL;
+
+    switch(cdb_find(&self->c,PyString_AsString(key),PyString_Size(key))) {
+      case -1:
+        Py_DECREF(key);
+        key = NULL;
+        return CDBerr;
+      case 0:
+        /* bizarre, impossible? PyExc_RuntimeError? */
+        PyErr_SetString(PyExc_KeyError, 
+                        PyString_AS_STRING((PyStringObject *) key));
+        Py_DECREF(key);
+        key = NULL;
+      default:
+        if (key == NULL)  /* already raised error */
+          return NULL;
+
+        if (cdb_datapos(&self->c) == self->iter_pos + klen + 8) {
+          /** first occurrence of key in the cdb **/
+          self->iter_pos += 8 + klen + dlen;
+          return key;
+        }
+        Py_DECREF(key);   /* better luck next time around */
+        self->iter_pos += 8 + klen + dlen;
+    }
+  }
+
+  return Py_BuildValue("");  /* iter_pos >= eod; we're done */
+
+}
+
+static char cdbo_keys_doc[] =
+"cdb_o.keys() -> ['k1', 'k2', ... ]\n\
+\n\
+Returns a list of all (distinct) keys in the database.";
+
+static PyObject *
+cdbo_keys(CdbObject *self, PyObject *args) {
+
+  PyObject *r, *key;
+  uint32 pos;
+  int err;
+
+  if (! PyArg_ParseTuple(args, ""))
+    return NULL;
+
+  r = PyList_New(0);
+  if (r == NULL)
+    return NULL;
+
+  pos = self->iter_pos;  /* don't interrupt a manual iteration */
+
+  self->iter_pos = 2048;
+
+  key = _cdbo_keyiter(self);
+  while (key != Py_None) {
+    err = PyList_Append(r, key);
+    Py_DECREF(key);
+    if (err != 0) {
+      Py_DECREF(r);
+      self->iter_pos = pos;
+      return NULL;
+    }
+    key = _cdbo_keyiter(self);
+  }
+  Py_DECREF(key);
+
+  self->iter_pos = pos;
+
+  return r;
+
+}
+
+static char cdbo_firstkey_doc[] =
+"cdb_o.firstkey() -> key (or None)\n\
+\n\
+Return the first key in the database, resetting the internal\n\
+iteration cursor.  firstkey() and nextkey() may be used to\n\
+traverse all distinct keys in the cdb. See each() for raw\n\
+iteration.";
+
+static PyObject *
+cdbo_firstkey(CdbObject *self, PyObject *args) {
+
+  if (! PyArg_ParseTuple(args, ":firstkey"))
+    return NULL;
+
+  self->iter_pos = 2048;
+
+  return _cdbo_keyiter(self);
+
+}
+
+static char cdbo_nextkey_doc[] =
+"cdb_o.nextkey() -> key (or None)\n\
+\n\
+Return the next distinct key in the cdb.\n\
+\n\
+The following code walks the CDB one key at a time:\n\
+\n\
+    key = cdb_o.firstkey()\n\
+    while key is not None:\n\
+        print key\n\
+        key = cdb_o.nextkey()\n";
+
+static PyObject *
+cdbo_nextkey(CdbObject *self, PyObject *args) {
+
+  if (! PyArg_ParseTuple(args, ":nextkey"))
+    return NULL;
+
+  return _cdbo_keyiter(self);
+
+}
+
+static char cdbo_each_doc[] =
+"cdb_o.each() -> (key, data) (or None)\n\
+\n\
+Fetch the next ('key', 'data') record from the underlying cdb file,\n\
+returning None and resetting the iteration cursor when all records\n\
+have been fetched.\n\
+\n\
+Keys appear with each item under them -- e.g., (key,foo), (key2,bar),\n\
+(key,baz) --  order of records is determined by actual position on\n\
+disk.  Both keys() and (for GDBM fanciers) firstkey()/nextkey()-style\n\
+iteration go to pains to present the user with only distinct keys.";
+
+static PyObject *
+cdbo_each(CdbObject *self, PyObject *args) {
+
+  PyObject *tup, *key, *dat;
+  char buf[8];
+  uint32 klen, dlen;
+
+  if (! PyArg_ParseTuple(args, ":each"))
+    return NULL;
+
+  tup = PyTuple_New(2);
+  if (tup == NULL)
+    return NULL;
+
+  if (! self->eod)
+    (void) _cdbo_init_eod(self);
+
+  if (self->each_pos >= self->eod) { /* all done, reset cursor */
+    self->each_pos = 2048;
+    Py_INCREF(Py_None);
+    return Py_None;
+  }
+
+  if (cdb_read(&self->c, buf, 8, self->each_pos) == -1)
+    return CDBerr;
+
+  uint32_unpack(buf, &klen);
+  uint32_unpack(buf+4, &dlen);
+
+  key = cdb_pyread(self, klen, self->each_pos + 8);
+  dat = cdb_pyread(self, dlen, self->each_pos + 8 + klen);
+
+  self->each_pos += klen + dlen + 8;
+
+  if (key == NULL || dat == NULL) {
+    Py_XDECREF(key); Py_XDECREF(dat);
+    Py_DECREF(tup);
+    return NULL;
+  }
+
+  if (PyTuple_SetItem(tup, 0, key) || PyTuple_SetItem(tup, 1, dat)) {
+    Py_DECREF(key); Py_DECREF(dat); Py_DECREF(tup);
+    return NULL;
+  }
+
+  return tup;
+}
+
+/*** cdb object as mapping ***/
+
+static int
+cdbo_length(CdbObject *self) {
+
+  if (! self->numrecords) {
+    char buf[8];
+    uint32 pos, klen, dlen;
+
+    pos = 2048;
+
+    if (! self->eod)
+      (void) _cdbo_init_eod(self);
+
+    while (pos < self->eod) {
+      if (cdb_read(&self->c, buf, 8, pos) == -1)
+        return -1;
+      uint32_unpack(buf, &klen);
+      uint32_unpack(buf + 4, &dlen);
+      pos += 8 + klen + dlen;
+      self->numrecords++;
+    }
+  }
+  return (int) self->numrecords;
+}
+
+static PyObject *
+cdbo_subscript(CdbObject *self, PyObject *k) {
+  char * key;
+  int klen;
+
+  if (! PyArg_Parse(k, "s#", &key, &klen))
+    return NULL;
+
+  switch(cdb_find(&self->c, key, (unsigned int)klen)) {
+    case -1:
+      return CDBerr;
+    case 0:
+      PyErr_SetString(PyExc_KeyError, 
+                      PyString_AS_STRING((PyStringObject *) k));
+      return NULL;
+    default:
+      return CDBO_CURDATA(self);
+  }
+  /* not reached */
+}
+
+static PyMappingMethods cdbo_as_mapping = {
+       (inquiry)cdbo_length,
+       (binaryfunc)cdbo_subscript,
+       (objobjargproc)0
+};
+
+static PyMethodDef cdb_methods[] = { 
+
+  {"get",      (PyCFunction)cdbo_get,      METH_VARARGS,
+               cdbo_get_doc },
+  {"getnext",  (PyCFunction)cdbo_getnext,  METH_VARARGS,
+               cdbo_getnext_doc },
+  {"getall",   (PyCFunction)cdbo_getall,   METH_VARARGS,
+               cdbo_getall_doc },
+  {"has_key",  (PyCFunction)cdbo_has_key,  METH_VARARGS, 
+               cdbo_has_key_doc },
+  {"keys",     (PyCFunction)cdbo_keys,     METH_VARARGS,
+               cdbo_keys_doc },
+  {"firstkey", (PyCFunction)cdbo_firstkey, METH_VARARGS,
+               cdbo_firstkey_doc },
+  {"nextkey",  (PyCFunction)cdbo_nextkey,  METH_VARARGS,
+               cdbo_nextkey_doc },
+  {"each",     (PyCFunction)cdbo_each, METH_VARARGS,
+               cdbo_each_doc },
+  { NULL,    NULL }
+};
+
+/* ------------------- cdb operations -------------------- */
+
+static PyObject *
+_wrap_cdb_init(int fd) {  /* constructor implementation */
+
+  CdbObject *self;
+
+  self = PyObject_NEW(CdbObject, &CdbType);
+  if (self == NULL) return NULL;
+
+  self->c.map = 0; /* break encapsulation -- cdb struct init'd to zero */
+  cdb_init(&self->c, fd);
+
+  self->iter_pos   = 2048;
+  self->each_pos   = 2048;
+  self->numrecords = 0;
+  self->eod        = 0;
+  self->getkey     = NULL;
+
+  return (PyObject *) self;
+}
+
+
+static PyObject *
+cdbo_constructor(PyObject *ignore, PyObject *args) {
+
+  PyObject *self;
+  PyObject *f;
+  PyObject *name_attr = Py_None;
+  int fd;
+
+  if (! PyArg_ParseTuple(args, "O:new", &f))
+    return NULL;
+
+  if (PyString_Check(f)) {
+
+    if ((fd = open_read(PyString_AsString(f))) == -1)
+      return CDBerr;
+
+    name_attr = f;
+
+  } else if (PyInt_Check(f)) {
+
+    fd = (int) PyInt_AsLong(f);
+
+  } else {
+
+    PyErr_SetString(PyExc_TypeError,
+                    "expected filename or file descriptor");
+    return NULL;
+
+  }
+
+  self = _wrap_cdb_init(fd);
+  if (self == NULL) return NULL;
+
+  ((CdbObject *)self)->name_py = name_attr;
+  Py_INCREF(name_attr);
+
+  return self;
+}
+
+static void
+cdbo_dealloc(CdbObject *self) {  /* del(cdb_o) */
+
+  if (self->name_py != NULL) {
+
+    /* if cdb_o.name is not None:  we open()d it ourselves, so close it */
+    if (PyString_Check(self->name_py))
+      close(self->c.fd);
+
+    Py_DECREF(self->name_py);
+  }
+
+  Py_XDECREF(self->getkey);
+
+  cdb_free(&self->c);
+
+  PyMem_DEL(self);
+}
+
+static PyObject *
+cdbo_getattr(CdbObject *self, char *name) {
+
+  PyObject * r;
+
+  r = Py_FindMethod(cdb_methods, (PyObject *) self, name);
+
+  if (r != NULL)
+    return r;
+
+  PyErr_Clear();
+
+  if (!strcmp(name,"__members__"))
+    return Py_BuildValue("[sss]", "fd", "name", "size");
+
+  if (!strcmp(name,"fd")) {
+    return Py_BuildValue("i", self->c.fd);  /* cdb_o.fd */
+  } 
+
+  if (!strcmp(name,"name")) {
+    Py_INCREF(self->name_py);
+    return self->name_py;                   /* cdb_o.name */
+  } 
+
+  if (!strcmp(name,"size")) {               /* cdb_o.size */
+    return self->c.map ?  /** mmap()d ? stat.st_size : None **/
+           Py_BuildValue("l", (long) self->c.size) :
+           Py_BuildValue("");
+  } 
+
+  PyErr_SetString(PyExc_AttributeError, name);
+  return NULL;
+}
+
+
+/* ----------------- cdbmake object ------------------ */
+
+static char cdbmake_object_doc[] =
+"cdbmake objects resemble the struct cdb_make interface:\n\
+\n\
+  CDB Construction Methods:\n\
+    add(k, v), finish()\n\
+\n\
+  __members__:\n\
+    fd         - fd of underlying CDB, or -1 if finish()ed\n\
+    fn, fntmp  - as from the cdb package's cdbmake utility\n\
+    numentries - current number of records add()ed\n";
+
+typedef struct {
+    PyObject_HEAD
+    struct cdb_make cm;
+    PyObject * fn;
+    PyObject * fntmp;
+} cdbmakeobject;
+
+staticforward PyTypeObject CdbMakeType;
+
+#define CDBMAKEerr PyErr_SetFromErrno(PyExc_IOError)
+
+
+/* ----------------- CdbMake methods ------------------ */
+
+static PyObject *
+CdbMake_add(cdbmakeobject *self, PyObject *args) {
+
+  char * key, * dat;
+  unsigned int klen, dlen;
+
+  if (!PyArg_ParseTuple(args,"s#s#:add",&key,&klen,&dat,&dlen))
+    return NULL;
+
+  if (cdb_make_add(&self->cm, key, klen, dat, dlen) == -1)
+    return CDBMAKEerr;
+
+  return Py_BuildValue("");
+
+}
+
+static PyObject *
+CdbMake_finish(cdbmakeobject *self, PyObject *args) {
+
+  if (!PyArg_ParseTuple(args, ":finish"))
+    return NULL;
+
+  if (cdb_make_finish(&self->cm) == -1)
+    return CDBMAKEerr;
+
+  /* cleanup as in cdb dist's cdbmake */
+
+  if (fsync(fileno(self->cm.fp)) == -1)
+    return CDBMAKEerr;
+
+  if (fclose(self->cm.fp) != 0)
+    return CDBMAKEerr;
+
+  self->cm.fp = NULL;
+
+  if (rename(PyString_AsString(self->fntmp),
+             PyString_AsString(self->fn))    == -1)
+    return CDBMAKEerr;
+
+  return Py_BuildValue("");
+}
+
+static PyMethodDef cdbmake_methods[] = {
+  {"add",    (PyCFunction)CdbMake_add,    METH_VARARGS,
+"cm.add(key, data) -> None\n\
+\n\
+Add 'key' -> 'data' pair to the underlying CDB." },
+  {"finish", (PyCFunction)CdbMake_finish, METH_VARARGS,
+"cm.finish() -> None\n\
+\n\
+Finish safely composing a new CDB, renaming cm.fntmp to\n\
+cm.fn." },
+  { NULL,    NULL }
+};
+
+/* ----------------- cdbmake operations ------------------ */
+
+static PyObject *
+new_cdbmake(PyObject *ignore, PyObject *args) {
+
+  cdbmakeobject *self;
+  PyObject *fn, *fntmp;
+  FILE * f;
+
+  if (! PyArg_ParseTuple(args, "SS|i", &fn, &fntmp))
+    return NULL;
+
+  f = fopen(PyString_AsString(fntmp), "w+b");
+  if (f == NULL) {
+    return CDBMAKEerr;
+  }
+
+  self = PyObject_NEW(cdbmakeobject, &CdbMakeType);
+  if (self == NULL) return NULL;
+
+  self->fn = fn;
+  Py_INCREF(self->fn);
+
+  self->fntmp = fntmp;
+  Py_INCREF(fntmp);
+
+  if (cdb_make_start(&self->cm, f) == -1) {
+    Py_DECREF(self);
+    CDBMAKEerr;
+    return NULL;
+  }
+
+  return (PyObject *) self;
+}
+
+static void
+cdbmake_dealloc(cdbmakeobject *self) {
+
+  Py_XDECREF(self->fn);
+
+  if (self->fntmp != NULL) {
+    if (self->cm.fp != NULL) {
+      fclose(self->cm.fp);
+      unlink(PyString_AsString(self->fntmp));
+    }
+    Py_DECREF(self->fntmp);
+  }
+
+  PyMem_DEL(self);
+}
+
+static PyObject *
+cdbmake_getattr(cdbmakeobject *self, char *name) {
+
+  if (!strcmp(name,"__members__"))
+    return Py_BuildValue("[ssss]", "fd", "fn", "fntmp", "numentries");
+
+  if (!strcmp(name,"fd"))
+    return Py_BuildValue("i", fileno(self->cm.fp));  /* self.fd */
+
+  if (!strcmp(name,"fn")) {
+    Py_INCREF(self->fn);
+    return self->fn;                         /* self.fn */
+  }
+
+  if (!strcmp(name,"fntmp")) {
+    Py_INCREF(self->fntmp);
+    return self->fntmp;                      /* self.fntmp */
+  }
+
+  if (!strcmp(name,"numentries"))
+    return Py_BuildValue("l", self->cm.numentries); /* self.numentries */
+
+  return Py_FindMethod(cdbmake_methods, (PyObject *) self, name);
+}
+
+/* ---------------- Type delineation -------------------- */
+
+statichere PyTypeObject CdbType = {
+        /* The ob_type field must be initialized in the module init function
+         * to be portable to Windows without using C++. */
+        PyObject_HEAD_INIT(NULL)
+        0,                      /*ob_size*/
+        "cdb",              /*tp_name*/
+        sizeof(CdbObject),  /*tp_basicsize*/
+        0,                      /*tp_itemsize*/
+        /* methods */
+        (destructor)cdbo_dealloc, /*tp_dealloc*/
+        0,                      /*tp_print*/
+        (getattrfunc)cdbo_getattr, /*tp_getattr*/
+        0,                      /*tp_setattr*/
+        0,                      /*tp_compare*/
+        0,                      /*tp_repr*/
+        0,                      /*tp_as_number*/
+        0,                      /*tp_as_sequence*/
+        &cdbo_as_mapping,       /*tp_as_mapping*/
+        0,                      /*tp_hash*/
+        0,                      /*tp_call*/
+        0,                      /*tp_str*/
+        0,                      /*tp_getattro*/
+        0,                      /*tp_setattro*/
+        0,                      /*tp_as_buffer*/
+        0,                      /*tp_xxx4*/
+        cdbo_object_doc,        /*tp_doc*/
+};
+
+statichere PyTypeObject CdbMakeType = {
+        /* The ob_type field must be initialized in the module init function
+         * to be portable to Windows without using C++. */
+        PyObject_HEAD_INIT(NULL)
+        0,                      /*ob_size*/
+        "cdbmake",              /*tp_name*/
+        sizeof(cdbmakeobject),  /*tp_basicsize*/
+        0,                      /*tp_itemsize*/
+        /* methods */
+        (destructor)cdbmake_dealloc, /*tp_dealloc*/
+        0,                      /*tp_print*/
+        (getattrfunc)cdbmake_getattr, /*tp_getattr*/
+        0,                      /*tp_setattr*/
+        0,                      /*tp_compare*/
+        0,                      /*tp_repr*/
+        0,                      /*tp_as_number*/
+        0,                      /*tp_as_sequence*/
+        0,                      /*tp_as_mapping*/
+        0,                      /*tp_hash*/
+        0,                      /*tp_call*/
+        0,                      /*tp_str*/
+        0,                      /*tp_getattro*/
+        0,                      /*tp_setattro*/
+        0,                      /*tp_as_buffer*/
+        0,                      /*tp_xxx4*/
+        cdbmake_object_doc,     /*tp_doc*/
+};
+
+/* ---------------- exported functions ------------------ */
+static PyObject *
+_wrap_cdb_hash(PyObject *ignore, PyObject *args) {
+
+  char *s;
+  int sz;
+
+  if (! PyArg_ParseTuple(args, "s#:hash", &s, &sz))
+    return NULL;
+
+  return Py_BuildValue("l", cdb_hash(s, (unsigned int) sz));
+
+}
+
+/* ---------------- cdb Module -------------------- */
+
+static PyMethodDef module_functions[] = {
+  {"init",    cdbo_constructor, METH_VARARGS,
+"cdb.init(f) -> cdb_object\n\
+\n\
+Open a CDB specified by f and return a cdb object.\n\
+f may be a filename or an integral file descriptor\n\
+(e.g., init( sys.stdin.fileno() )...)."},
+  {"cdbmake", new_cdbmake,     METH_VARARGS,
+"cdb.cdbmake(cdb, tmp) -> cdbmake_object\n\
+\n\
+Interface to the creation of a new CDB file \"cdb\".\n\
+\n\
+The cdbmake object first writes records to the temporary file\n\
+\"tmp\" (records are inserted via the object's add() method).\n\
+The finish() method then atomically renames \"tmp\" to \"cdb\",\n\
+ensuring that readers of \"cdb\" need never wait for updates to\n\
+complete."
+},
+  {"hash",    _wrap_cdb_hash,  METH_VARARGS,
+"hash(s) -> hashval\n\
+\n\
+Compute the 32-bit hash value of some sequence of bytes s."},
+  {NULL,  NULL}
+};
+
+static char module_doc[] =
+"Python adaptation of D. J. Bernstein's constant database (CDB)\n\
+package.  See <http://cr.yp.to/cdb.html>\n\
+\n\
+CDB objects, created by init(), provide read-only, dict-like\n\
+access to cdb files, as well as iterative methods.\n\
+\n\
+CDBMake objects, created by cdbmake(), allow for creation and\n\
+atomic replacement of CDBs.\n\
+\n\
+This module defines a new Exception \"error\".";
+
+DL_EXPORT(void)
+initcdb() {
+  PyObject *m, *d, *v;
+
+  CdbType.ob_type = &PyType_Type;
+  CdbMakeType.ob_type = &PyType_Type;
+
+  m = Py_InitModule3("cdb", module_functions, module_doc);
+
+  d = PyModule_GetDict(m);
+
+  CDBError = PyErr_NewException("cdb.error", NULL, NULL);
+  PyDict_SetItemString(d, "error", CDBError);
+
+  PyDict_SetItemString(d, "__version__", 
+                       v = PyString_FromString(VERSION));
+  PyDict_SetItemString(d, "__cdb_version__",
+                       v = PyString_FromString(CDBVERSION));
+  Py_XDECREF(v);
+
+}
diff --git a/src/uint32.h b/src/uint32.h
new file mode 100644 (file)
index 0000000..4d96f1a
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef UINT32_H
+#define UINT32_H
+
+/* adopted from libowfat 0.9 (GPL) */
+
+typedef unsigned int uint32;
+
+extern void uint32_pack(char *out,uint32 in);
+extern void uint32_unpack(const char *in,uint32 *out);
+
+#endif
diff --git a/src/uint32_pack.c b/src/uint32_pack.c
new file mode 100644 (file)
index 0000000..fd2641e
--- /dev/null
@@ -0,0 +1,11 @@
+#define NO_UINT32_MACROS
+#include "uint32.h"
+
+/* adopted from libowfat 0.9 (GPL) */
+
+void uint32_pack(char *out,uint32 in) {
+  *out=in&0xff; in>>=8;
+  *++out=in&0xff; in>>=8;
+  *++out=in&0xff; in>>=8;
+  *++out=in&0xff;
+}
diff --git a/src/uint32_unpack.c b/src/uint32_unpack.c
new file mode 100644 (file)
index 0000000..4bd7829
--- /dev/null
@@ -0,0 +1,11 @@
+#define NO_UINT32_MACROS
+#include "uint32.h"
+
+/* adopted from libowfat 0.9 (GPL) */
+
+void uint32_unpack(const char *in,uint32 *out) {
+  *out = (((uint32)(unsigned char)in[3])<<24) |
+         (((uint32)(unsigned char)in[2])<<16) |
+         (((uint32)(unsigned char)in[1])<<8) |
+          (uint32)(unsigned char)in[0];
+}