Logo Search packages:      
Sourcecode: qbankmanager version File versions  Download package

xastorage.c

/***************************************************************************
 $RCSfile: xastorage.c,v $
                             -------------------
    cvs         : $Id: xastorage.c,v 1.8 2005/03/28 08:48:41 aquamaniac Exp $
    begin       : Mon Apr 05 2004
    copyright   : (C) 2004 by Martin Preuss
    email       : martin@libchipcard.de

 ***************************************************************************
 *          Please see toplevel file COPYING for license details           *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif


#include "xastorage_p.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/misc.h>
#include <gwenhywfar/directory.h>

#include <stdlib.h>
#include <assert.h>
#include <string.h>

#ifdef WIN32
# define snprintf _snprintf
#endif


GWEN_LIST_FUNCTIONS(AH_STORAGE_DAY, AH_Storage_Day);
GWEN_LIST_FUNCTIONS(AH_STORAGE_HANDLE, AH_StorageHandle);



GWEN_TYPE_UINT32 AH_Storage__MakeId(int year,
                                     int month,
                                     int day){
  GWEN_TYPE_UINT32 id;

  id=((year&0xffff)<<16) + ((month&0xff)<<8) + (day&0xff);
  return id;
}



AH_STORAGE_HANDLE *AH_StorageHandle_new(AH_STORAGE_DAY *day,
                                        GWEN_TYPE_UINT32 id){
  AH_STORAGE_HANDLE *sh;

  GWEN_NEW_OBJECT(AH_STORAGE_HANDLE, sh);
  GWEN_LIST_INIT(AH_STORAGE_HANDLE, sh);
  sh->id=id;
  sh->day=day;
  AH_Storage_Day_Attach(sh->day);
  return sh;
}



void AH_StorageHandle_free(AH_STORAGE_HANDLE *sh){
  if (sh) {
    GWEN_LIST_FINI(AH_STORAGE_HANDLE, sh);
    AH_Storage_Day_free(sh->day);
    GWEN_FREE_OBJECT(sh);
  }
}




AH_STORAGE_DAY *AH_Storage_Day_new(int year,
                                   int month,
                                   int day,
                                   const char *file,
                                   int readOnly,
                                   GWEN_DB_NODE *transactions){
  AH_STORAGE_DAY *dy;

  GWEN_NEW_OBJECT(AH_STORAGE_DAY, dy);
  GWEN_LIST_INIT(AH_STORAGE_DAY, dy);
  dy->year=year;
  dy->month=month;
  dy->day=day;
  dy->file=strdup(file);
  dy->readOnly=readOnly;
  dy->fixed=GWEN_DB_GetIntValue(transactions, "fixed", 0, 0);
  dy->transactions=transactions;
  dy->id=AH_Storage__MakeId(year, month, day);
  DBG_DEBUG(0, "Created day with id %08x", dy->id);
  AH_Storage_Day_SetChanged(dy, 0);
  dy->usage=1;
  return dy;
}



void AH_Storage_Day_free(AH_STORAGE_DAY *dy){
  if (dy) {
    assert(dy->usage);
    if (--(dy->usage)==0) {
      GWEN_LIST_FINI(AH_STORAGE_DAY, dy);
      free(dy->file);
      GWEN_DB_Group_free(dy->transactions);
      GWEN_FREE_OBJECT(dy);
    }
  }
}



void AH_Storage_Day_Attach(AH_STORAGE_DAY *dy){
  assert(dy);
  dy->usage++;
}



int AH_Storage_Day_GetYear(const AH_STORAGE_DAY *dy){
  assert(dy);
  return dy->year;
}



int AH_Storage_Day_GetMonth(const AH_STORAGE_DAY *dy){
  assert(dy);
  return dy->month;
}



int AH_Storage_Day_GetDay(const AH_STORAGE_DAY *dy){
  assert(dy);
  return dy->day;
}



GWEN_TYPE_UINT32 AH_Storage_Day_GetId(const AH_STORAGE_DAY *dy){
  assert(dy);
  return dy->id;
}



const char *AH_Storage_Day_GetFileName(const AH_STORAGE_DAY *dy){
  assert(dy);
  return dy->file;
}



int AH_Storage_Day_GetReadOnly(const AH_STORAGE_DAY *dy){
  assert(dy);
  return dy->readOnly;
}



int AH_Storage_Day_GetChanged(const AH_STORAGE_DAY *dy){
  assert(dy);
  if (dy->changed ||
      (GWEN_DB_GetNodeFlags(dy->transactions) & GWEN_DB_NODE_FLAGS_DIRTY))
    return 1;
  return 0;
}



void AH_Storage_Day_SetChanged(AH_STORAGE_DAY *dy, int chg){
  assert(dy);
  dy->changed=chg;
  GWEN_DB_ModifyBranchFlagsDown(dy->transactions,
                        0,
                        GWEN_DB_NODE_FLAGS_DIRTY);
}



GWEN_DB_NODE *AH_Storage_Day_GetTransactions(AH_STORAGE_DAY *dy){
  assert(dy);
  return dy->transactions;
}



int AH_Storage_Day_AddTransaction(AH_STORAGE_DAY *dy, GWEN_DB_NODE *t){
  GWEN_DB_NODE *n;

  assert(dy);
  assert(dy->transactions);
  DBG_DEBUG(0, "Adding a transaction");
  n=GWEN_DB_GetGroup(dy->transactions, GWEN_PATH_FLAGS_CREATE_GROUP,
                     "transaction");
  assert(n);
  GWEN_DB_AddGroupChildren(n, t);
  AH_Storage_Day_SetChanged(dy, 1);
  return 0;
}



void AH_Storage_Day_FixDay(AH_STORAGE_DAY *dy){
  assert(dy);
  GWEN_DB_SetIntValue(dy->transactions,
                      GWEN_DB_FLAGS_OVERWRITE_VARS,
                      "fixed", 1);
  dy->fixed=1;
  dy->changed=1;
}



int AH_Storage_Day_IsDayFixed(const AH_STORAGE_DAY *dy){
  assert(dy);
  return dy->fixed;
}







const char *AH_Storage_GetPath(const AH_STORAGE *st){
  assert(st);
  return st->path;
}



AH_STORAGE_DAY *AH_Storage_FindDay(const AH_STORAGE *st,
                                   GWEN_TYPE_UINT32 id) {
  AH_STORAGE_DAY *dy;

  assert(st);

  dy=AH_Storage_Day_List_First(st->days);
  while(dy) {
    if (AH_Storage_Day_GetId(dy)==id)
      break;
    dy=AH_Storage_Day_List_Next(dy);
  } /* while */

  return dy;
}



AH_STORAGE_DAY *AH_Storage_GetDay(AH_STORAGE *st,
                                  int year,
                                  int month,
                                  int day,
                                  int ro) {
  GWEN_BUFFER *pbuf;
  char numbuf[64];
  GWEN_DB_NODE *n;
  AH_STORAGE_DAY *dy;

  pbuf=GWEN_Buffer_new(0, 128, 0, 1);
  GWEN_Buffer_AppendString(pbuf, st->path);
  snprintf(numbuf, sizeof(numbuf)-1, "/%04d/%02d/%02d", year, month, day);
  numbuf[sizeof(numbuf)-1]=0;
  GWEN_Buffer_AppendString(pbuf, numbuf);
  GWEN_Buffer_AppendString(pbuf, ".trans");
  n=GWEN_DB_Group_new("transactions");

  if (GWEN_Directory_GetPath(GWEN_Buffer_GetStart(pbuf),
                             GWEN_PATH_FLAGS_VARIABLE |
                             GWEN_PATH_FLAGS_NAMEMUSTEXIST)==0) {
    if (GWEN_DB_ReadFile(n, GWEN_Buffer_GetStart(pbuf),
                         GWEN_DB_FLAGS_DEFAULT |
                         GWEN_PATH_FLAGS_CREATE_GROUP)){
      if (ro) {
        DBG_ERROR(0, "Could not load file \"%s\"", GWEN_Buffer_GetStart(pbuf));
        GWEN_DB_Group_free(n);
        GWEN_Buffer_free(pbuf);
        return 0;
      }
    }
  }
  dy=AH_Storage_Day_new(year, month, day,
                        GWEN_Buffer_GetStart(pbuf), ro,
                        n);
  GWEN_Buffer_free(pbuf);
  return dy;
}



int AH_Storage_SaveDay(AH_STORAGE *st, AH_STORAGE_DAY *dy) {
  if (GWEN_Directory_GetPath(AH_Storage_Day_GetFileName(dy),
                             GWEN_PATH_FLAGS_VARIABLE)) {
    DBG_ERROR(0, "Path \"%s\" unavailable",
              AH_Storage_Day_GetFileName(dy));
    return -1;
  }

  if (GWEN_DB_WriteFile(AH_Storage_Day_GetTransactions(dy),
                        AH_Storage_Day_GetFileName(dy),
                        GWEN_DB_FLAGS_DEFAULT)) {
    DBG_ERROR(0, "Could not save day \"%s\"",
              AH_Storage_Day_GetFileName(dy));
    return -1;
  }

  return 0;
}










AH_STORAGE *AH_Storage_new(const char *path){
  AH_STORAGE *st;

  assert(path);
  GWEN_NEW_OBJECT(AH_STORAGE, st);
  st->path=strdup(path);
  st->days=AH_Storage_Day_List_new();
  st->handles=AH_StorageHandle_List_new();

  return st;
}



void AH_Storage_free(AH_STORAGE *st){
  if (st) {
    AH_StorageHandle_List_free(st->handles);
    AH_Storage_Day_List_free(st->days);
    free(st->path);

    GWEN_FREE_OBJECT(st);
  }
}



GWEN_IDLIST *AH_Storage_BuildIndex(AH_STORAGE *st) {
  GWEN_DIRECTORYDATA *dyears;
  GWEN_IDLIST *idl;
  GWEN_BUFFER *nbuf;
  int ypos;

  idl=GWEN_IdList_new();
  dyears=GWEN_Directory_new();
  nbuf=GWEN_Buffer_new(0, 128, 0, 1);
  GWEN_Buffer_AppendString(nbuf, st->path);
  ypos=GWEN_Buffer_GetPos(nbuf);
  if (!GWEN_Directory_Open(dyears, st->path)) {
    char nbuffer[256];

    // check for years
    while(!GWEN_Directory_Read(dyears,
                               nbuffer,
                               sizeof(nbuffer))) {
      int year;

      if (1==sscanf(nbuffer, "%d", &year)) {
        GWEN_DIRECTORYDATA *dmonths;
        int mpos;

        GWEN_Buffer_Crop(nbuf, 0, ypos);
        GWEN_Buffer_SetPos(nbuf, ypos);
        GWEN_Buffer_AppendByte(nbuf, '/');
        GWEN_Buffer_AppendString(nbuf, nbuffer);
        mpos=GWEN_Buffer_GetPos(nbuf);

        // found a year, check it further
        dmonths=GWEN_Directory_new();
        if (!GWEN_Directory_Open(dmonths, GWEN_Buffer_GetStart(nbuf))) {

          // check for months
          while(!GWEN_Directory_Read(dmonths,
                                     nbuffer,
                                     sizeof(nbuffer))) {
            int month;

            if (1==sscanf(nbuffer, "%d", &month)) {
              GWEN_DIRECTORYDATA *ddays;

              // found a month, check it further
              GWEN_Buffer_Crop(nbuf, 0, mpos);
              GWEN_Buffer_SetPos(nbuf, mpos);
              GWEN_Buffer_AppendByte(nbuf, '/');
              GWEN_Buffer_AppendString(nbuf, nbuffer);

              ddays=GWEN_Directory_new();
              if (!GWEN_Directory_Open(ddays, GWEN_Buffer_GetStart(nbuf))) {
                while(!GWEN_Directory_Read(ddays,
                                           nbuffer,
                                           sizeof(nbuffer))) {
                  int i;

                  i=strlen(nbuffer);
                  if (i>6) {
                    if (strcmp(nbuffer+i-6, ".trans")==0) {
                      int day;

                      nbuffer[i-6]=0;
                      if (1==sscanf(nbuffer, "%d", &day)) {
                        GWEN_TYPE_UINT32 id;

                        // found a day, save it
                        id=AH_Storage__MakeId(year, month, day);
                        DBG_DEBUG(0, "Found day %d/%d/%d (%08x)",
                                  year, month, day, id);
                        GWEN_IdList_AddId(idl, id);
                      } // if entry is a day
                    } // if filename ends with ".trans"
                  } // if filename is long enough
                } // while still days
                if (GWEN_Directory_Close(ddays)) {
                  DBG_ERROR(0, "Error closing day");
                  GWEN_IdList_free(idl);
                  GWEN_Buffer_free(nbuf);
                  return 0;
                }
              } // if open
              GWEN_Directory_free(ddays);
            } // if entry is a month
          } // while still months
          if (GWEN_Directory_Close(dmonths)) {
            DBG_ERROR(0, "Error closing month");
            GWEN_IdList_free(idl);
            GWEN_Buffer_free(nbuf);
            return 0;
          }
        } // if monthpath ok
        GWEN_Directory_free(dmonths);
      } // if entry is a year
    } /* while years */
    if (GWEN_Directory_Close(dyears)) {
      DBG_ERROR(0, "Error closing year");
      GWEN_IdList_free(idl);
      GWEN_Buffer_free(nbuf);
      return 0;
    }
  } // if open is ok
  GWEN_Directory_free(dyears);
  GWEN_Buffer_free(nbuf);

  GWEN_IdList_Sort(idl);

  return idl;
}



AH_STORAGE_HANDLE *AH_Storage_FindHandle(AH_STORAGE *st,
                                         GWEN_TYPE_UINT32 id) {
  AH_STORAGE_HANDLE *sh;

  assert(st);
  sh=AH_StorageHandle_List_First(st->handles);
  while(sh) {
    if (sh->id==id)
      break;
    sh=AH_StorageHandle_List_Next(sh);
  }
  return sh;
}




GWEN_TYPE_UINT32 AH_Storage_OpenDay(AH_STORAGE *st,
                                    int year,
                                    int month,
                                    int day,
                                    int ro){
  GWEN_TYPE_UINT32 id;
  AH_STORAGE_DAY *dy;
  AH_STORAGE_HANDLE *sh;

  id=AH_Storage__MakeId(year, month, day);
  dy=AH_Storage_FindDay(st, id);
  if (!dy) {
    dy=AH_Storage_GetDay(st, year, month, day, ro);
  }
  if (!dy) {
    DBG_INFO(0, "Day %04d/%02d/%02d not found",
             year, month, day);
    return 0;
  }
  DBG_DEBUG(0, "Day found");
  sh=AH_StorageHandle_new(dy, ++(st->lastHandleId));
  assert(sh);
  AH_StorageHandle_List_Add(sh, st->handles);
  return sh->id;
}



int AH_Storage_CloseDay(AH_STORAGE *st, GWEN_TYPE_UINT32 hdl){
  AH_STORAGE_HANDLE *sh;
  AH_STORAGE_DAY *dy;

  sh=AH_Storage_FindHandle(st, hdl);
  if (!sh) {
    DBG_ERROR(0, "Day not open (handle %08x)", hdl);
    return -1;
  }
  dy=sh->day;
  assert(dy);

  if (AH_Storage_Day_GetChanged(dy)) {
    DBG_INFO(0, "Day modified, saving");
    if (AH_Storage_SaveDay(st, dy)) {
      DBG_INFO(0, "Error saving day (handle %08x)", hdl);
      return -1;
    }
    AH_Storage_Day_SetChanged(dy, 0);
  }
  AH_StorageHandle_free(sh);
  return 0;
}



void AH_Storage_AbandonDay(AH_STORAGE *st, GWEN_TYPE_UINT32 hdl){
  AH_STORAGE_HANDLE *sh;
  AH_STORAGE_DAY *dy;

  sh=AH_Storage_FindHandle(st, hdl);
  if (!sh) {
    DBG_ERROR(0, "Day not open (handle %08x)", hdl);
    return;
  }
  dy=sh->day;
  assert(dy);

  AH_StorageHandle_free(sh);
}



int AH_Storage_ClearDay(AH_STORAGE *st, GWEN_TYPE_UINT32 hdl){
  AH_STORAGE_HANDLE *sh;
  AH_STORAGE_DAY *dy;

  sh=AH_Storage_FindHandle(st, hdl);
  if (!sh) {
    DBG_ERROR(0, "Day not open (handle %08x)", hdl);
    return -1;
  }
  dy=sh->day;
  assert(dy);
  GWEN_DB_ClearGroup(AH_Storage_Day_GetTransactions(dy), 0);
  return 0;
}



int AH_Storage_AddTransaction(AH_STORAGE *st,
                              GWEN_TYPE_UINT32 hdl,
                              GWEN_DB_NODE *t){
  AH_STORAGE_HANDLE *sh;
  AH_STORAGE_DAY *dy;

  sh=AH_Storage_FindHandle(st, hdl);
  if (!sh) {
    DBG_ERROR(0, "Day not open (handle %08x)", hdl);
    return -1;
  }
  dy=sh->day;
  assert(dy);

  return AH_Storage_Day_AddTransaction(dy, t);
}




GWEN_DB_NODE *AH_Storage_GetFirstTransaction(AH_STORAGE *st,
                                             GWEN_TYPE_UINT32 hdl){
  AH_STORAGE_HANDLE *sh;
  AH_STORAGE_DAY *dy;
  GWEN_DB_NODE *db;

  sh=AH_Storage_FindHandle(st, hdl);
  if (!sh) {
    DBG_ERROR(0, "Day not open (handle %08x)", hdl);
    return 0;
  }
  dy=sh->day;
  assert(dy);

  db=AH_Storage_Day_GetTransactions(dy);
  assert(db);
  sh->current=GWEN_DB_FindFirstGroup(db, "transaction");
  return sh->current;
}



GWEN_DB_NODE *AH_Storage_GetNextTransaction(AH_STORAGE *st,
                                            GWEN_TYPE_UINT32 hdl){
  AH_STORAGE_HANDLE *sh;
  AH_STORAGE_DAY *dy;

  sh=AH_Storage_FindHandle(st, hdl);
  if (!sh) {
    DBG_ERROR(0, "Day not open (handle %08x)", hdl);
    return 0;
  }
  dy=sh->day;
  assert(dy);

  if (!sh->current)
    return 0;
  sh->current=GWEN_DB_FindNextGroup(sh->current, "transaction");
  return sh->current;
}



GWEN_IDLIST *AH_Storage_GetAvailableDays(AH_STORAGE *st){
  GWEN_IDLIST *idl;

  assert(st);
  DBG_INFO(0, "(Re)building index");
  idl=AH_Storage_BuildIndex(st);
  if (!idl) {
    DBG_ERROR(0, "Error building index");
    return 0;
  }
  return idl;
}



int AH_Storage_GetFirstDay(AH_STORAGE *st,
                           GWEN_IDLIST *availDays,
                           int *year,
                           int *month,
                           int *day){
  GWEN_TYPE_UINT32 id;

  id=GWEN_IdList_GetFirstId(availDays);
  if (!id) {
    DBG_INFO(0, "No days");
    return -1;
  }

  *year=(id>>16)&0xffff;
  *month=(id>>8)&0xff;
  *day=(id&0xff);
  return 0;
}



int AH_Storage_GetNextDay(AH_STORAGE *st,
                          GWEN_IDLIST *availDays,
                          int *year,
                          int *month,
                          int *day){
  GWEN_TYPE_UINT32 id;

  assert(st);
  assert(year);
  assert(month);
  assert(day);
  assert(availDays);

  id=GWEN_IdList_GetNextId(availDays);
  if (!id) {
    DBG_INFO(0, "No more days");
    return -1;
  }

  *year=(id>>16)&0xffff;
  *month=(id>>8)&0xff;
  *day=(id&0xff);
  return 0;
}



int AH_Storage_GetLastDay(AH_STORAGE *st,
                          GWEN_IDLIST *availDays,
                          int *year,
                          int *month,
                          int *day){
  GWEN_TYPE_UINT32 lastId;

  assert(st);
  assert(year);
  assert(month);
  assert(day);
  assert(availDays);

  lastId=GWEN_IdList_GetFirstId(availDays);
  if (!lastId) {
    DBG_INFO(0, "No days");
    return -1;
  }

  for (;;) {
    GWEN_TYPE_UINT32 id;

    id=GWEN_IdList_GetNextId(availDays);
    if (!id) {
      break;
    }
    lastId=id;
  }

  *year=(lastId>>16)&0xffff;
  *month=(lastId>>8)&0xff;
  *day=(lastId&0xff);
  return 0;
}



int AH_Storage_FixDay(AH_STORAGE *st, GWEN_TYPE_UINT32 hdl){
  AH_STORAGE_DAY *dy;

  dy=AH_Storage_FindDay(st, hdl);
  if (!dy) {
    DBG_ERROR(0, "Day not open (handle %08x)", hdl);
    return -1;
  }
  AH_Storage_Day_FixDay(dy);
  return 0;
}



int AH_Storage_IsDayFixed(const AH_STORAGE *st, GWEN_TYPE_UINT32 hdl){
  AH_STORAGE_DAY *dy;

  dy=AH_Storage_FindDay(st, hdl);
  if (!dy) {
    DBG_ERROR(0, "Day not open (handle %08x)", hdl);
    return -1;
  }
  return AH_Storage_Day_IsDayFixed(dy);
}
























Generated by  Doxygen 1.6.0   Back to index