/*Kyoto Cabinet bindings for Go. Copyleft by William Waites in 2011 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 3 of the License, or 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, see <http://www.gnu.org/licenses/>.Source code: http://bitbucket.org/ww/cabinet/srcDocumentation: http://godoc.styx.org/pkg/bitbucket.org/ww/cabinetThese bindings have been tested with Kyoto Cabinet version 1.2.46.They are known not to work with 1.2.7 because of the absentkcdbreplace() function call. Once Kyoto Cabinet is installed, buildingthe bindings should be a simple matter of running: goinstall -u -v bitbucket.org/ww/cabinetSimple usage will be along the lines of, import ( "bitbucket.org/ww/cabinet ) ... kc := cabinet.New() err = kc.Open("some_db.kch", cabinet.KCOWRITER | cabinet.KCOCREATE) err = kc.Set([]byte("hello"), []byte("world")) world, err = kc.Get([]byte("hello")) err = kc.Close() kc.Del()Obviously checking the relevant errors...The API follows the Kyoto Cabinet C API closely, for some examples seehttp://fallabs.com/kyotocabinet/api/Most input and output variables are []byte and not string. This is becauseKyoto Cabinet is not particularly concerned with strings and it is possibleto use any byte array as either key or value. An example from the test suite to read an integer out of the database: var n int64 v, err = kc.Get([]byte("numbers")) binary.Read(bytes.NewBuffer(v), binary.BigEndian, &n)Some functions have been added for convenience using Go. The Keys()Values() and Items() on the cursor object return a channel over whichtheir results will be sent, for example. This probably obviates the needfor implementing the visitor-callback pattern when using Kyoto Cabinetwith Go.If you use this module please feel free to contact me, ww@styx.orgwith any questions, comments or bug reports.*/packagecabinet// #cgo CFLAGS: -I/usr/local/include// #cgo LDFLAGS: -L/usr/local/lib -lkyotocabinet// #include <kclangc.h>import"C"import("log""os""unsafe")constKCOREADERint=C.KCOREADERconstKCOWRITERint=C.KCOWRITERconstKCOCREATEint=C.KCOCREATEconstKCOTRUNCATEint=C.KCOTRUNCATEconstKCOAUTOTRANint=C.KCOAUTOTRANconstKCOAUTOSYNCint=C.KCOAUTOSYNCconstKCONOLOCKint=C.KCONOLOCKconstKCOTRYLOCKint=C.KCOTRYLOCKconstKCONOREPAIR=C.KCONOREPAIRconstKCESUCCESSint=C.KCESUCCESSconstKCENOIMPLint=C.KCENOIMPLconstKCEINVALIDint=C.KCEINVALIDconstKCENOREPOSint=C.KCENOREPOSconstKCEBROKENint=C.KCEBROKENconstKCENOPERMint=C.KCENOPERMconstKCEDUPRECint=C.KCEDUPRECconstKCENORECint=C.KCENORECconstKCELOGICint=C.KCELOGICconstKCESYSTEM=C.KCESYSTEMconstKCEMISC=C.KCEMISCconstKCMADDint=C.KCMADDconstKCMSETint=C.KCMSETconstKCMAPPENDint=C.KCMAPPENDconstKCMREPLACEint=C.KCMREPLACEtypeKCDBstruct{db*C.KCDB}funcNew()*KCDB{db:=C.kcdbnew()return&KCDB{db}}func(kc*KCDB)Ecode()int{returnint(C.kcdbecode(kc.db))}funcEcodeName(ecodeint)string{returnC.GoString(C.kcecodename(C.int32_t(ecode)))}func(kc*KCDB)error()os.Error{returnos.NewError(EcodeName(kc.Ecode()))}func(kc*KCDB)Open(filenamestring,modeint)(erros.Error){name:=C.CString(filename)deferC.free(unsafe.Pointer(name))ifC.kcdbopen(kc.db,name,C.uint32_t(mode))==0{err=kc.error()}return}func(kc*KCDB)Close()(erros.Error){ifC.kcdbclose(kc.db)==0{err=kc.error()}return}func(kc*KCDB)Del(){C.kcdbdel(kc.db)}func(kc*KCDB)Path()(pathstring,erros.Error){cpath:=C.kcdbpath(kc.db)deferC.kcfree(unsafe.Pointer(cpath))path=C.GoString(cpath)ifpath==""{err=kc.error()}return}func(kc*KCDB)Status()(statusstring,erros.Error){cstatus:=C.kcdbstatus(kc.db)ifcstatus==nil{err=kc.error()}status=C.GoString(cstatus)C.kcfree(unsafe.Pointer(cstatus))return}func(kc*KCDB)Count()(countuint64,erros.Error){ccount:=C.kcdbcount(kc.db)ifccount==-1{err=kc.error()}else{count=uint64(ccount)}return}func(kc*KCDB)Size()(sizeuint64,erros.Error){csize:=C.kcdbsize(kc.db)ifcsize==-1{err=kc.error()}else{size=uint64(csize)}return}func(kc*KCDB)Clear()(erros.Error){ifC.kcdbclear(kc.db)==0{err=kc.error()}return}func(kc*KCDB)Sync(hardbool)(erros.Error){varchardC.int32_tifhard{chard=1}else{chard=0}ifC.kcdbsync(kc.db,chard,nil,nil)==0{err=kc.error()}return}func(kc*KCDB)Copy(filenamestring)(erros.Error){name:=C.CString(filename)deferC.free(unsafe.Pointer(name))ifC.kcdbcopy(kc.db,name)==0{err=kc.error()}return}func(kc*KCDB)Merge(sdbs[]*KCDB,modeint)(erros.Error){count:=len(sdbs)csdbs:=make([]*C.KCDB,count)fori,db:=rangesdbs{csdbs[i]=db.db}ifC.kcdbmerge(kc.db,&csdbs[0],C.size_t(count),C.uint32_t(mode))==0{err=kc.error()}return}func(kc*KCDB)Dump(filenamestring)(erros.Error){name:=C.CString(filename)deferC.free(unsafe.Pointer(name))ifC.kcdbdumpsnap(kc.db,name)==0{err=kc.error()}return}func(kc*KCDB)Load(filenamestring)(erros.Error){name:=C.CString(filename)deferC.free(unsafe.Pointer(name))ifC.kcdbcopy(kc.db,name)==0{err=kc.error()}return}func(kc*KCDB)BeginTran(hardbool)(erros.Error){varchardC.int32_tifhard{chard=1}else{chard=0}ifC.kcdbbegintran(kc.db,chard)==0{err=kc.error()}return}func(kc*KCDB)BeginTranTry(hardbool)(erros.Error){varchardC.int32_tifhard{chard=1}else{chard=0}ifC.kcdbbegintrantry(kc.db,chard)==0{err=kc.error()}return}func(kc*KCDB)EndTran(commitbool)(erros.Error){varccommitC.int32_tifcommit{ccommit=1}else{ccommit=0}ifC.kcdbendtran(kc.db,ccommit)==0{err=kc.error()}return}func(kc*KCDB)Set(key,value[]byte)(erros.Error){ckey:=(*C.char)(unsafe.Pointer(&key[0]))cvalue:=(*C.char)(unsafe.Pointer(&value[0]))ifC.kcdbset(kc.db,ckey,C.size_t(len(key)),cvalue,C.size_t(len(value)))==0{err=kc.error()}return}func(kc*KCDB)Add(key,value[]byte)(erros.Error){ckey:=(*C.char)(unsafe.Pointer(&key[0]))cvalue:=(*C.char)(unsafe.Pointer(&value[0]))ifC.kcdbadd(kc.db,ckey,C.size_t(len(key)),cvalue,C.size_t(len(value)))==0{err=kc.error()}return}func(kc*KCDB)Replace(key,value[]byte)(erros.Error){ckey:=(*C.char)(unsafe.Pointer(&key[0]))cvalue:=(*C.char)(unsafe.Pointer(&value[0]))ifC.kcdbreplace(kc.db,ckey,C.size_t(len(key)),cvalue,C.size_t(len(value)))==0{err=kc.error()}return}func(kc*KCDB)Append(key,value[]byte)(erros.Error){ckey:=(*C.char)(unsafe.Pointer(&key[0]))cvalue:=(*C.char)(unsafe.Pointer(&value[0]))ifC.kcdbappend(kc.db,ckey,C.size_t(len(key)),cvalue,C.size_t(len(value)))==0{err=kc.error()}return}func(kc*KCDB)Remove(key[]byte)(erros.Error){ckey:=(*C.char)(unsafe.Pointer(&key[0]))ifC.kcdbremove(kc.db,ckey,C.size_t(len(key)))==0{err=kc.error()}return}func(kc*KCDB)Cas(key,oval,nval[]byte)(erros.Error){ckey:=(*C.char)(unsafe.Pointer(&key[0]))varcoval,cnval*C.charloval,lnval:=len(oval),len(nval)ifloval>0{coval=(*C.char)(unsafe.Pointer(&nval[0]))}iflnval>0{cnval=(*C.char)(unsafe.Pointer(&nval[0]))}ifC.kcdbcas(kc.db,ckey,C.size_t(len(key)),coval,C.size_t(loval),cnval,C.size_t(lnval))==0{err=kc.error()}return}func(kc*KCDB)IncrInt(key[]byte,amountint64)(resultint64,erros.Error){ckey:=(*C.char)(unsafe.Pointer(&key[0]))cresult:=C.kcdbincrint(kc.db,ckey,C.size_t(len(key)),C.int64_t(amount))ifcresult==C.INT64_MIN{err=kc.error()}else{result=int64(cresult)}return}func(kc*KCDB)IncrDouble(key[]byte,amountfloat64)(erros.Error){ckey:=(*C.char)(unsafe.Pointer(&key[0]))ifC.kcdbincrdouble(kc.db,ckey,C.size_t(len(key)),C.double(amount))==0{err=kc.error()}return}func(kc*KCDB)Get(key[]byte)(value[]byte,erros.Error){ckey:=(*C.char)(unsafe.Pointer(&key[0]))varvlenC.size_tcval:=C.kcdbget(kc.db,ckey,C.size_t(len(key)),&vlen)ifcval==nil{err=kc.error()}else{value=make([]byte,int(vlen))C.memcpy(unsafe.Pointer(&value[0]),unsafe.Pointer(cval),vlen)C.kcfree(unsafe.Pointer(cval))}return}typeKCCURstruct{cur*C.KCCUR}func(kc*KCDB)Cursor()(kcc*KCCUR){cur:=C.kcdbcursor(kc.db)ifcur==nil{returnnil}kcc=&KCCUR{cur}kcc.Jump()return}func(kcc*KCCUR)Ecode()int{returnint(C.kccurecode(kcc.cur))}func(kcc*KCCUR)Emsg()string{err:=C.kccuremsg(kcc.cur)returnC.GoString(err)}func(kcc*KCCUR)error()os.Error{returnos.NewError(kcc.Emsg())}func(kcc*KCCUR)Del(){C.kccurdel(kcc.cur)}func(kcc*KCCUR)Db()(kc*KCDB){kc=new(KCDB)kc.db=C.kccurdb(kcc.cur)return}func(kcc*KCCUR)Jump()(erros.Error){ifC.kccurjump(kcc.cur)==0{err=kcc.error()}return}func(kcc*KCCUR)JumpKey(key[]byte)(erros.Error){ckey:=(*C.char)(unsafe.Pointer(&key[0]))ifC.kccurjumpkey(kcc.cur,ckey,C.size_t(len(key)))==0{err=kcc.error()}return}func(kcc*KCCUR)JumpBack()(erros.Error){ifC.kccurjumpback(kcc.cur)==0{err=kcc.error()}return}func(kcc*KCCUR)JumpBackKey(key[]byte)(erros.Error){ckey:=(*C.char)(unsafe.Pointer(&key[0]))ifC.kccurjumpbackkey(kcc.cur,ckey,C.size_t(len(key)))==0{err=kcc.error()}return}func(kcc*KCCUR)Step()(erros.Error){ifC.kccurstep(kcc.cur)==0{err=kcc.error()}return}func(kcc*KCCUR)StepBack()(erros.Error){ifC.kccurstepback(kcc.cur)==0{err=kcc.error()}return}func(kcc*KCCUR)Remove()(erros.Error){ifC.kccurremove(kcc.cur)==0{err=kcc.error()}return}func(kcc*KCCUR)SetValue(value[]byte,advancebool)(erros.Error){cvalue:=(*C.char)(unsafe.Pointer(&value[0]))varcadvanceC.int32_tifadvance{cadvance=1}else{cadvance=0}ifC.kccursetvalue(kcc.cur,cvalue,C.size_t(len(value)),cadvance)==0{err=kcc.error()}return}func(kcc*KCCUR)GetKey(advancebool)(k[]byte,erros.Error){varksizC.size_tvarcadvanceC.int32_tifadvance{cadvance=1}else{cadvance=0}kp:=C.kccurgetkey(kcc.cur,&ksiz,cadvance)ifkp!=nil{k=make([]byte,ksiz)C.memcpy(unsafe.Pointer(&k[0]),unsafe.Pointer(kp),ksiz)C.kcfree(unsafe.Pointer(kp))}else{err=kcc.error()}return}func(kcc*KCCUR)GetValue(advancebool)(v[]byte,erros.Error){varvsizC.size_tvarcadvanceC.int32_tifadvance{cadvance=1}else{cadvance=0}vp:=C.kccurgetvalue(kcc.cur,&vsiz,cadvance)ifvp!=nil{v=make([]byte,vsiz)C.memcpy(unsafe.Pointer(&v[0]),unsafe.Pointer(vp),vsiz)C.kcfree(unsafe.Pointer(vp))}else{err=kcc.error()}return}func(kcc*KCCUR)Get(advancebool)(k,v[]byte,erros.Error){varksiz,vsizC.size_tvarvp*C.charvarcadvanceC.int32_tifadvance{cadvance=1}else{cadvance=0}kp:=C.kccurget(kcc.cur,&ksiz,&vp,&vsiz,cadvance)ifkp!=nil{k=make([]byte,ksiz)C.memcpy(unsafe.Pointer(&k[0]),unsafe.Pointer(kp),ksiz)v=make([]byte,vsiz)C.memcpy(unsafe.Pointer(&v[0]),unsafe.Pointer(vp),vsiz)C.kcfree(unsafe.Pointer(kp))}else{err=kcc.error()}return}func(kc*KCDB)Keys()(outchan[]byte){out=make(chan[]byte)gofunc(){cur:=kc.Cursor()for{k,err:=cur.GetKey(true)iferr!=nil{ifcur.Ecode()!=KCENOREC{log.Printf("GetKey(true): %s",err)}break}out<-k}cur.Del()close(out)}()return}func(kc*KCDB)Values()(outchan[]byte){out=make(chan[]byte)gofunc(){cur:=kc.Cursor()for{v,err:=cur.GetValue(true)iferr!=nil{ifcur.Ecode()!=KCENOREC{log.Printf("GetValue(true): %s",err)}break}out<-v}cur.Del()close(out)}()return}typeItemstruct{Key[]byteValue[]byte}func(kc*KCDB)Items()(outchan*Item){out=make(chan*Item)gofunc(){cur:=kc.Cursor()for{k,v,err:=cur.Get(true)iferr!=nil{ifcur.Ecode()!=KCENOREC{log.Printf("Get(true): %s",err)}break}out<-&Item{k,v}}cur.Del()close(out)}()return}func(kc*KCDB)MatchPrefix(prefixstring,maxint)(matches[][]byte,erros.Error){cprefix:=C.CString(prefix)strarray:=make([]*C.char,max)count:=C.kcdbmatchprefix(kc.db,cprefix,&strarray[0],C.size_t(max))ifcount==-1{matches=nilerr=kc.error()}else{matches=make([][]byte,int(count))fori:=int64(0);i<int64(count);i++{matches[i]=[]byte(C.GoString(strarray[i]))C.kcfree(unsafe.Pointer(strarray[i]))}}C.free(unsafe.Pointer(cprefix))return}func(kc*KCDB)MatchRegex(regexstring,maxint)(matches[][]byte,erros.Error){cregex:=C.CString(regex)strarray:=make([]*C.char,max)count:=C.kcdbmatchregex(kc.db,cregex,&strarray[0],C.size_t(max))ifcount==-1{matches=nilerr=kc.error()}else{matches=make([][]byte,count)fori:=int64(0);i<int64(count);i++{matches[i]=[]byte(C.GoString(strarray[i]))C.kcfree(unsafe.Pointer(strarray[i]))}}C.free(unsafe.Pointer(cregex))return}