--- /dev/null
+ 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.
--- /dev/null
+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
--- /dev/null
+#! /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)
--- /dev/null
+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
--- /dev/null
+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 :)
+
+
--- /dev/null
+# python-cdb 0.31
+
+[bdist_rpm]
+release = 1
+doc_files = ChangeLog
+ README
+ COPYING
+ Example
--- /dev/null
+#! /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/",
+ )
+
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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); */
+}
--- /dev/null
+/* 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
--- /dev/null
+/**
+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);
+
+}
--- /dev/null
+#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
--- /dev/null
+#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;
+}
--- /dev/null
+#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];
+}