Blame src/keyvalue.cc

Packit Service a2489d
/*
Packit Service a2489d
 * lftp - file transfer program
Packit Service a2489d
 *
Packit Service a2489d
 * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net)
Packit Service a2489d
 *
Packit Service a2489d
 * This program is free software; you can redistribute it and/or modify
Packit Service a2489d
 * it under the terms of the GNU General Public License as published by
Packit Service a2489d
 * the Free Software Foundation; either version 3 of the License, or
Packit Service a2489d
 * (at your option) any later version.
Packit Service a2489d
 *
Packit Service a2489d
 * This program is distributed in the hope that it will be useful,
Packit Service a2489d
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a2489d
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service a2489d
 * GNU General Public License for more details.
Packit Service a2489d
 *
Packit Service a2489d
 * You should have received a copy of the GNU General Public License
Packit Service a2489d
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit Service a2489d
 */
Packit Service a2489d
Packit Service a2489d
#include <config.h>
Packit Service a2489d
#include "keyvalue.h"
Packit Service a2489d
#include <unistd.h>
Packit Service a2489d
#include "trio.h"
Packit Service a2489d
#include <fcntl.h>
Packit Service a2489d
#include <errno.h>
Packit Service a2489d
Packit Service a2489d
int KeyValueDB::Read(int fd)
Packit Service a2489d
{
Packit Service a2489d
   xstring key;
Packit Service a2489d
   xstring value;
Packit Service a2489d
Packit Service a2489d
   int c;
Packit Service a2489d
Packit Service a2489d
   FILE *f=fdopen(fd,"r");
Packit Service a2489d
Packit Service a2489d
   for(;;)
Packit Service a2489d
   {
Packit Service a2489d
      c=getc(f);
Packit Service a2489d
Packit Service a2489d
      // skip leading space
Packit Service a2489d
      while(c!=EOF && (c==' ' || c=='\t'))
Packit Service a2489d
	 c=getc(f);
Packit Service a2489d
Packit Service a2489d
      if(c==EOF)
Packit Service a2489d
	 break;
Packit Service a2489d
      if(c=='\n')
Packit Service a2489d
	 continue;   // next line
Packit Service a2489d
Packit Service a2489d
      key.truncate(0);
Packit Service a2489d
      for(;;)
Packit Service a2489d
      {
Packit Service a2489d
	 key.append(c);
Packit Service a2489d
	 c=getc(f);
Packit Service a2489d
	 if(c==EOF)
Packit Service a2489d
	    break;
Packit Service a2489d
	 if(c==' ' || c=='\t' || c=='\n')
Packit Service a2489d
	    break;
Packit Service a2489d
      }
Packit Service a2489d
Packit Service a2489d
      if(c==EOF || c=='\n' || key.length()==0)
Packit Service a2489d
	 break;	// invalid line
Packit Service a2489d
Packit Service a2489d
      // skip space in mid
Packit Service a2489d
      while(c!=EOF && (c==' ' || c=='\t'))
Packit Service a2489d
	 c=getc(f);
Packit Service a2489d
Packit Service a2489d
      if(c==EOF || c=='\n')
Packit Service a2489d
	 break;
Packit Service a2489d
Packit Service a2489d
      value.truncate(0);
Packit Service a2489d
      for(;;)
Packit Service a2489d
      {
Packit Service a2489d
	 value.append(c);
Packit Service a2489d
	 c=getc(f);
Packit Service a2489d
	 if(c==EOF)
Packit Service a2489d
	    break;
Packit Service a2489d
	 if(c=='\n')
Packit Service a2489d
	    break;
Packit Service a2489d
      }
Packit Service a2489d
Packit Service a2489d
      Add(key,value);
Packit Service a2489d
Packit Service a2489d
      if(c==EOF)
Packit Service a2489d
	 break;
Packit Service a2489d
   }
Packit Service a2489d
   fclose(f);
Packit Service a2489d
   return 0;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
int KeyValueDB::VKeyCompare(const void *a,const void *b)
Packit Service a2489d
{
Packit Service a2489d
   KeyValueDB::Pair *pa=*(KeyValueDB::Pair*const*)a;
Packit Service a2489d
   KeyValueDB::Pair *pb=*(KeyValueDB::Pair*const*)b;
Packit Service a2489d
   return KeyValueDB::KeyCompare(pa,pb);
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
void KeyValueDB::Sort()
Packit Service a2489d
{
Packit Service a2489d
   int count=0;
Packit Service a2489d
   Pair *scan;
Packit Service a2489d
   for(scan=chain; scan; scan=scan->next)
Packit Service a2489d
      count++;
Packit Service a2489d
Packit Service a2489d
   if(count==0)
Packit Service a2489d
      return;
Packit Service a2489d
Packit Service a2489d
   Pair **arr=(Pair**)alloca(count*sizeof(*arr));
Packit Service a2489d
   count=0;
Packit Service a2489d
   for(scan=chain; scan; scan=scan->next)
Packit Service a2489d
      arr[count++]=scan;
Packit Service a2489d
Packit Service a2489d
   qsort(arr,count,sizeof(*arr),&KeyValueDB::VKeyCompare);
Packit Service a2489d
Packit Service a2489d
   chain=0;
Packit Service a2489d
   while(count--)
Packit Service a2489d
   {
Packit Service a2489d
      arr[count]->next=chain;
Packit Service a2489d
      chain=arr[count];
Packit Service a2489d
   }
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
char *KeyValueDB::Format(StringMangler value_mangle)
Packit Service a2489d
{
Packit Service a2489d
   Sort();
Packit Service a2489d
Packit Service a2489d
   Pair *p;
Packit Service a2489d
   int max_key_len=0;
Packit Service a2489d
Packit Service a2489d
   for(p=chain; p; p=p->next)
Packit Service a2489d
   {
Packit Service a2489d
      int len=strlen(p->key);
Packit Service a2489d
      if(len>max_key_len)
Packit Service a2489d
	 max_key_len=len;
Packit Service a2489d
   }
Packit Service a2489d
   max_key_len&=~7;  // save some bytes
Packit Service a2489d
Packit Service a2489d
   xstring buf("");
Packit Service a2489d
   for(p=chain; p; p=p->next)
Packit Service a2489d
      buf.appendf("%-*s\t%s\n",max_key_len,p->key.get(),value_mangle(p->value));
Packit Service a2489d
   return buf.borrow();
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
int KeyValueDB::Write(int fd)
Packit Service a2489d
{
Packit Service a2489d
   xstring_ca buf(Format());
Packit Service a2489d
   int res=write(fd,buf,strlen(buf));
Packit Service a2489d
   close(fd);
Packit Service a2489d
   return res;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
void KeyValueDB::Add(const char *key,const char *value)
Packit Service a2489d
{
Packit Service a2489d
   Pair **p=LookupPair(key);
Packit Service a2489d
   if(!p)
Packit Service a2489d
      AddPair(NewPair(key,value));
Packit Service a2489d
   else
Packit Service a2489d
      p[0]->SetValue(value);
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
void KeyValueDB::Remove(const char *key)
Packit Service a2489d
{
Packit Service a2489d
   Pair **p=LookupPair(key);
Packit Service a2489d
   if(p)
Packit Service a2489d
      Purge(p);
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
KeyValueDB::Pair **KeyValueDB::LookupPair(const char *key) const
Packit Service a2489d
{
Packit Service a2489d
   for(const Pair * const*p=&chain; *p; p=&(*p)->next)
Packit Service a2489d
   {
Packit Service a2489d
      if((*p)->KeyCompare(key)==0)
Packit Service a2489d
	 return const_cast<KeyValueDB::Pair **>(p);
Packit Service a2489d
   }
Packit Service a2489d
   return 0;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
const char *KeyValueDB::Lookup(const char *key) const
Packit Service a2489d
{
Packit Service a2489d
   const Pair * const*p=LookupPair(key);
Packit Service a2489d
   return p ? (*p)->value.get() : 0;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
int KeyValueDB::Lock(int fd,int type)
Packit Service a2489d
{
Packit Service a2489d
   struct flock	lk;
Packit Service a2489d
   lk.l_type=type;
Packit Service a2489d
   lk.l_whence=0;
Packit Service a2489d
   lk.l_start=0;
Packit Service a2489d
   lk.l_len=0;
Packit Service a2489d
   int res=fcntl(fd,F_SETLK,&lk;;
Packit Service a2489d
   if(res==-1 && E_RETRY(errno))
Packit Service a2489d
   {
Packit Service a2489d
      int retries=5;
Packit Service a2489d
      bool echo=true;
Packit Service a2489d
      for(int i=0; i
Packit Service a2489d
      {
Packit Service a2489d
	 sleep(1);
Packit Service a2489d
	 if(echo && write(2,".",1)==-1)
Packit Service a2489d
	    echo=false;
Packit Service a2489d
	 res=fcntl(fd,F_SETLK,&lk;;
Packit Service a2489d
	 if(res==0)
Packit Service a2489d
	    break;
Packit Service a2489d
      }
Packit Service a2489d
      if(echo && write(2,"\r",1)==-1)
Packit Service a2489d
	 echo=false;
Packit Service a2489d
   }
Packit Service a2489d
   if(res==-1 && E_LOCK_IGNORE(errno))
Packit Service a2489d
      return 0;
Packit Service a2489d
   return res;
Packit Service a2489d
}