cSvn-UI for SVN Repositories

cGit-UI – is a web interface for Subversion (SVN) Repositories. cSvn CGI script is writen in C and therefore it's fast enough

6 Commits   0 Branches   2 Tags
author: kx <kx@radix.pro> 2023-03-24 03:55:33 +0300 committer: kx <kx@radix.pro> 2023-03-24 03:55:33 +0300 commit: bfc1508d26c89c9a36d2d9a827fe2c4ed128884d parent: c836ae3775cf72f17e0b7e3792d156fdb389bee3
Commit Summary:
Version 0.1.4
Diffstat:
1 file changed, 729 insertions, 0 deletions
diff --git a/csvncgi/repolist.c b/csvncgi/repolist.c
new file mode 100644
index 0000000..9fe73c0
--- /dev/null
+++ b/csvncgi/repolist.c
@@ -0,0 +1,878 @@
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/sysinfo.h>
+#include <sys/types.h>
+#include <stdint.h>
+#include <dirent.h>
+#include <sys/stat.h> /* chmod(2)    */
+#include <sys/file.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <string.h>   /* strdup(3)   */
+#include <libgen.h>   /* basename(3) */
+#include <ctype.h>    /* tolower(3)  */
+#include <errno.h>
+#include <time.h>
+#include <sys/time.h>
+#include <pwd.h>
+#include <grp.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#include <defs.h>
+#include <cscm/bcf.h>
+
+#include <dlist.h>
+#include <strbuf.h>
+#include <repolist.h>
+#include <wrapper.h>
+
+
+#define RLIST_ERRMSG_SIZE 4096
+
+void rlist_error( const char *fmt, ... )
+{
+  va_list arg_ptr;
+  char  buf[RLIST_ERRMSG_SIZE];
+  char  msg[RLIST_ERRMSG_SIZE];
+  char *format = "%s: %s\n";
+
+  va_start( arg_ptr, fmt );
+
+  vsnprintf( msg, RLIST_ERRMSG_SIZE, (const void *)fmt, arg_ptr );
+
+  va_end( arg_ptr ); /* Reset variable arguments. */
+
+  snprintf( buf, RLIST_ERRMSG_SIZE, format, "rlist", msg );
+
+  (void)write( STDERR_FILENO, buf, strlen( buf ) );
+
+  exit( 1 );
+}
+
+rlist_errfunc rlist_fatal = rlist_error;
+
+
+struct dlist *config = NULL;
+
+static void *bcf = NULL;
+
+static size_t read_bcf( void )
+{
+  int fd;
+  struct stat st;
+  void *addr;
+
+  fd = shm_open( CSVN_SHM_BCF, O_RDONLY, S_IRUSR | S_IWUSR );
+  if( fd == -1 )
+  {
+    rlist_fatal( "Canot open SHM/%s data", "csvn.bcf" );
+    return 0;
+  }
+  if( !fstat( fd, (struct stat *)&st ) )
+  {
+    addr = mmap( NULL, (size_t)st.st_size, PROT_READ, MAP_SHARED, fd, 0 );
+    if( addr != MAP_FAILED )
+    {
+      bcf = malloc( (size_t)st.st_size );
+      if( !bcf )
+      {
+        (void)munmap( addr, (size_t)st.st_size );
+        rlist_fatal( "Canot allocate memory for SHM/%s data", "csvn.bcf" );
+        return 0;
+      }
+      memcpy( bcf, addr, (size_t)st.st_size );
+      (void)munmap( addr, (size_t)st.st_size );
+      return (size_t)st.st_size;
+    }
+    else
+    {
+      rlist_fatal( "Canot mmap SHM/%s data", "csvn.bcf" );
+      return 0;
+    }
+  }
+  else
+  {
+    rlist_fatal( "Canot stat SHM/%s data", "csvn.bcf" );
+    return 0;
+  }
+}
+
+
+static void check_bcf_ident( const void *bf, size_t size )
+{
+  Bcf32_fhdr *fhdr = (Bcf32_fhdr *)bf;
+
+  if( !fhdr )
+    rlist_fatal( "Invalid address of SHM/%s data", "csvn.bcf" );
+
+  if( (size_t)fhdr->b_fsize != size )
+    rlist_fatal( "Binary Config SHM/%s: invalid size", "csvn.bcf" );
+  if( memcmp( fhdr->b_ident, BCFMAG, (size_t)SZBCFMAG ) )
+    rlist_fatal( "Binary Config SHM/%s: invalid MAGIC number", "csvn.bcf" );
+  if( fhdr->b_ident[BI_CLASS] != BCF_CLASS_32 )
+    rlist_fatal( "Binary Config SHM/%s: invalid objects class", "csvn.bcf" );
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+  if( fhdr->b_ident[BI_DATA] != BCF_DATA_LSB )
+    rlist_fatal( "Binary Config SHM/%s: invalid byte-order", "csvn.bcf" );
+#else
+  if( fhdr->b_ident[BI_DATA] != BCF_DATA_MSB )
+    rlist_fatal( "Binary Config SHM/%s: invalid byte-order", "csvn.bcf" );
+#endif
+  if( fhdr->b_ident[BI_VERSION] != BV_CURRENT )
+    rlist_fatal( "Binary Config SHM/%s: invalid version", "csvn.bcf" );
+}
+
+
+/***************************************************************
+  Print config file functions:
+ */
+static void __print_global_variable( void *data, void *user_data )
+{
+  struct variable *variable = (struct variable *)data;
+  struct strbuf   *sb   = (struct strbuf *)user_data;
+
+  if( !variable || !sb ) return;
+
+  switch( variable->type )
+  {
+    case DT_NUMERICAL:
+      strbuf_addf( sb, "  %s = %d;\n", variable->name, variable->_v.val );
+      break;
+    case DT_PATH:
+      strbuf_addf( sb, "  %s = '%s';\n", variable->name, variable->_v.vptr );
+      break;
+    case DT_STRING:
+      strbuf_addf( sb, "  %s = \"%s\";\n", variable->name, variable->_v.vptr );
+      break;
+    default:
+      break;
+  }
+}
+
+static void print_global_variables( struct strbuf *sb, struct dlist *list )
+{
+  if( list ) { dlist_foreach( list, __print_global_variable, (void *)sb ); }
+}
+
+static void __print_repo_variable( void *data, void *user_data )
+{
+  struct variable *variable = (struct variable *)data;
+  struct strbuf   *sb   = (struct strbuf *)user_data;
+
+  if( !variable || !sb ) return;
+
+  switch( variable->type )
+  {
+    case DT_NUMERICAL:
+      strbuf_addf( sb, "    %s = %d;\n", variable->name, variable->_v.val );
+      break;
+    case DT_PATH:
+      strbuf_addf( sb, "    %s = '%s';\n", variable->name, variable->_v.vptr );
+      break;
+    case DT_STRING:
+      strbuf_addf( sb, "    %s = \"%s\";\n", variable->name, variable->_v.vptr );
+      break;
+    default:
+      break;
+  }
+}
+
+static void print_repo_variables( struct strbuf *sb, struct dlist *list )
+{
+  if( list ) { dlist_foreach( list, __print_repo_variable, (void *)sb ); }
+}
+
+static void __print_repo( void *data, void *user_data )
+{
+  struct repo   *repo = (struct repo *)data;
+  struct strbuf *sb   = (struct strbuf *)user_data;
+
+  if( !repo || !sb ) return;
+
+  strbuf_addf( sb, "  repo '%s' {\n", repo->path );
+  if( repo->list )
+  {
+    print_repo_variables( sb, repo->list );
+  }
+  strbuf_addf( sb, "  }\n\n" );
+}
+
+static void print_repos( struct strbuf *sb, struct dlist *list )
+{
+  if( list ) { dlist_foreach( list, __print_repo, (void *)sb ); }
+}
+
+static void __print_section( void *data, void *user_data )
+{
+  struct section *section = (struct section *)data;
+  struct strbuf  *sb      = (struct strbuf *)user_data;
+
+  if( !section || !sb ) return;
+
+  if( section->list )
+  {
+    if( section->type == ST_REPOS )
+    {
+      strbuf_addf( sb, "section \"%s\" {\n\n", section->name );
+      print_repos( sb, section->list );
+      strbuf_addf( sb, "}\n\n" );
+    }
+    else if( section->type == ST_GLOBAL )
+    {
+      strbuf_addf( sb, "section \".global\" {\n" );
+      print_global_variables( sb, section->list );
+      strbuf_addf( sb, "}\n\n" );
+    }
+  }
+}
+
+void print_config( struct strbuf *sb, struct dlist *list )
+{
+  strbuf_addf( sb, "<pre><code class='language-C'>\n" );
+  strbuf_addf( sb, "/*******************************************************\n" );
+  strbuf_addf( sb, "  Global variables are propagate into repo sections but\n" );
+  strbuf_addf( sb, "  their values overrides by correspond repo variables.\n" );
+  strbuf_addf( sb, " */\n\n" );
+  if( list ) { dlist_foreach( list, __print_section, (void *)sb ); }
+  strbuf_addf( sb, "</code></pre>\n" );
+}
+/*
+  End of print config file functions.
+ ***************************************************************/
+
+
+/**************************
+  lookup variable in repo:
+ */
+static int __compare_variables_by_name( const void *a, const void *b )
+{
+  struct variable *va = (struct variable *)a;
+  struct variable *vb = (struct variable *)b;
+
+  if( !va || !vb ) return -1;
+
+  return strcmp( (const char *)va->name, (const char *)vb->name );
+}
+
+struct variable *lookup( struct repo *repo, struct variable *variable )
+{
+  struct dlist *found = NULL;
+
+  if( !repo || !repo->list ) return NULL;
+
+  found = dlist_find_data( repo->list, __compare_variables_by_name, (const void *)variable );
+  if( found )
+    return (struct variable *)(found->data);
+  return NULL;
+}
+
+struct variable *lookup_global( struct section *section, struct variable *variable )
+{
+  struct dlist *found = NULL;
+
+  if( !section || !section->list ) return NULL;
+
+  found = dlist_find_data( section->list, __compare_variables_by_name, (const void *)variable );
+  if( found )
+    return (struct variable *)(found->data);
+  return NULL;
+}
+
+/**************
+  lookup repo:
+ */
+struct repo *lookup_repo( struct dlist *config, const char *path )
+{
+  struct dlist *list = NULL;
+
+  if( !config || !path ) return NULL;
+
+  list = config;
+  while( list )
+  {
+    struct section *section = (struct section *)list->data;
+
+    if( section->type == ST_REPOS )
+    {
+      struct dlist *rlist = section->list;
+      while( rlist )
+      {
+        struct repo *repo = (struct repo *)rlist->data;
+        if( !strcmp( (const char *)repo->path, path ) )
+          return repo;
+        rlist = dlist_next( rlist );
+      }
+    }
+    list = dlist_next( list );
+  }
+
+  return NULL;
+}
+
+/*****************
+  lookup section:
+ */
+struct section *lookup_section( struct dlist *config, const char *name )
+{
+  struct dlist *list = NULL;
+
+  if( !config || !name ) return NULL;
+
+  list = config;
+  while( list )
+  {
+    struct section *section = (struct section *)list->data;
+
+    if( section && section->type == ST_REPOS && !strcmp( (const char *)section->name, name ) )
+        return section;
+
+    list = dlist_next( list );
+  }
+
+  return NULL;
+}
+
+/************************
+  lookup global section:
+ */
+struct section *lookup_global_section( struct dlist *config )
+{
+  struct dlist *list = NULL;
+
+  if( !config ) return NULL;
+
+  list = config;
+  while( list )
+  {
+    struct section *section = (struct section *)list->data;
+
+    if( section && section->type == ST_GLOBAL )
+        return section;
+
+    list = dlist_next( list );
+  }
+
+  return NULL;
+}
+
+/******************
+  repolist length:
+ */
+int repolist_length( struct dlist *config )
+{
+  struct dlist *list = NULL;
+  int length = 0;
+
+  if( !config ) return length;
+
+  list = config;
+  while( list )
+  {
+    struct section *section = (struct section *)list->data;
+
+    if( section->type == ST_REPOS )
+    {
+      struct dlist *rlist = section->list;
+      while( rlist )
+      {
+        ++length;
+        rlist = dlist_next( rlist );
+      }
+    }
+    list = dlist_next( list );
+  }
+
+  return length;
+}
+
+/***************
+  repolist nth:
+ */
+struct repo *repolist_nth( struct dlist *config, int n )
+{
+  struct dlist *list = NULL;
+  int length = 0;
+
+  if( !config || n < 0 ) return NULL;
+
+  list = config;
+  while( list )
+  {
+    struct section *section = (struct section *)list->data;
+
+    if( section->type == ST_REPOS )
+    {
+      struct dlist *rlist = section->list;
+      while( rlist )
+      {
+        if( length == n )
+        {
+          struct repo *repo = (struct repo *)rlist->data;
+          return repo;
+        }
+        ++length;
+        rlist = dlist_next( rlist );
+      }
+    }
+    list = dlist_next( list );
+  }
+
+  return NULL;
+}
+
+/**************************
+  repo position in config:
+ */
+int repo_position( struct dlist *config, struct repo *repo )
+{
+  struct dlist *list = NULL;
+  int position = -1;
+
+  if( !config || !repo ) return position;
+
+  position = 0;
+
+  list = config;
+  while( list )
+  {
+    struct section *section = (struct section *)list->data;
+
+    if( section->type == ST_REPOS )
+    {
+      struct dlist *rlist = section->list;
+      while( rlist )
+      {
+        if( (struct repo *)rlist->data == repo )
+        {
+          return position;
+        }
+        ++position;
+        rlist = dlist_next( rlist );
+      }
+    }
+    list = dlist_next( list );
+  }
+
+  return -1;
+}
+
+
+/**************************************
+  parent section node of repolist nth:
+ */
+struct dlist *parent_section_node_repolist_nth( struct dlist *config, int n )
+{
+  struct dlist *list = NULL;
+  int length = 0;
+
+  if( !config || n < 0 ) return NULL;
+
+  list = config;
+  while( list )
+  {
+    struct section *section = (struct section *)list->data;
+
+    if( section->type == ST_REPOS )
+    {
+      struct dlist *rlist = section->list;
+      while( rlist )
+      {
+        if( length == n )
+        {
+          return list;
+        }
+        ++length;
+        rlist = dlist_next( rlist );
+      }
+    }
+    list = dlist_next( list );
+  }
+
+  return NULL;
+}
+
+/************************************
+  parent rlist node of repolist nth:
+ */
+struct dlist *parent_rlist_node_repolist_nth( struct dlist *config, int n )
+{
+  struct dlist *list = NULL;
+  int length = 0;
+
+  if( !config || n < 0 ) return NULL;
+
+  list = config;
+  while( list )
+  {
+    struct section *section = (struct section *)list->data;
+
+    if( section->type == ST_REPOS )
+    {
+      struct dlist *rlist = section->list;
+      while( rlist )
+      {
+        if( length == n )
+        {
+          return rlist;
+        }
+        ++length;
+        rlist = dlist_next( rlist );
+      }
+    }
+    list = dlist_next( list );
+  }
+
+  return NULL;
+}
+
+
+
+/**********************************************
+  Provide all global variables into each repo
+  if that variable is not present in the repo:
+ */
+static void __provide_foreach_data( void *data, void *user_data )
+{
+  struct variable *variable = (struct variable *)data;
+  struct repo     *repo     = (struct repo *)user_data;
+
+  if( !repo || !variable ) return;
+
+  if( !lookup( repo, variable ) )
+  {
+    struct variable *var = (struct variable *)xmalloc( sizeof(struct variable) );
+    memcpy( (void *)var, (void *)variable, sizeof(struct variable) );
+    repo->list = dlist_append( repo->list, (void *)var );
+  }
+}
+
+static void __provide_foreach_repos( void *data, void *user_data )
+{
+  struct section *global = (struct section *)user_data;
+
+  if( !global || !global->list ) return;
+
+  dlist_foreach( global->list, __provide_foreach_data, data );
+}
+
+static void __provide_foreach_sections( void *data, void *user_data )
+{
+  struct section *section = (struct section *)data;
+  if( !section || section->type == ST_GLOBAL || !section->list ) return;
+
+  dlist_foreach( section->list, __provide_foreach_repos, user_data );
+}
+
+static void provide_global_data( struct dlist *tree, struct section *global )
+{
+  if( tree ) { dlist_foreach( tree, __provide_foreach_sections, (void *)global ); }
+}
+/*
+ **********************************************/
+
+/**********************************************
+  Free REPO list functions:
+ */
+static void __free_variable( void *data, void *user_data )
+{
+  struct variable *variable = (struct variable *)data;
+  if( variable ) free( variable );
+}
+
+static void free_variables( struct dlist *list )
+{
+  if( list ) { dlist_free( list, __free_variable ); }
+}
+
+static void __free_repo( void *data, void *user_data )
+{
+  struct repo *repo = (struct repo *)data;
+  if( !repo ) return;
+  if( repo->list ) { free_variables( repo->list ); }
+  free( repo );
+}
+
+static void free_repos( struct dlist *list )
+{
+  if( list ) { dlist_free( list, __free_repo ); }
+}
+
+static void __free_section( void *data, void *user_data )
+{
+  struct section *section = (struct section *)data;
+  if( !section ) return;
+
+  if( section->list )
+  {
+    if( section->type == ST_GLOBAL )
+      free_variables( section->list );
+    else if( section->type == ST_REPOS )
+      free_repos( section->list );
+  }
+  free( section );
+}
+
+static void free_repolist( struct dlist *list )
+{
+  if( list ) { dlist_free( list, __free_section ); }
+}
+/*
+ **********************************************/
+
+void free_config( void )
+{
+  free_repolist( config ); config = NULL;
+  if( bcf ) { free( bcf ); bcf = NULL; }
+}
+
+static struct dlist *read_repolist( const void *bf )
+{
+  struct dlist  *tree = NULL;
+  Bcf32_fhdr    *fhdr = NULL;
+  unsigned char *ftab, *stab;
+
+  ftab = (unsigned char *)bf;
+  fhdr = (Bcf32_fhdr *)ftab;
+
+  if( !fhdr )
+    return tree;
+
+  stab = (unsigned char *)(ftab + (int)fhdr->b_stoff);
+
+#if __DEBUG__ == 1
+  fprintf( stderr, "BCF: header's size in bytes: %d\n",  fhdr->b_hsize );
+  fprintf( stderr, "BCF: Whole BCF file size in bytes: %d\n",  fhdr->b_fsize );
+  fprintf( stderr, "BCF: section header table’s file offset in bytes: %d\n",  fhdr->b_shoff );
+  fprintf( stderr, "BCF: section header's size in bytes: %d\n",  fhdr->b_shentsize );
+  fprintf( stderr, "BCF: number of entries in section headers table: %d\n",  fhdr->b_shnum );
+  fprintf( stderr, "BCF: repository header table’s file offset in bytes: %d\n",  fhdr->b_rhoff );
+  fprintf( stderr, "BCF: repository header's size in bytes: %d\n",  fhdr->b_rhentsize );
+  fprintf( stderr, "BCF: number of entries in repository headers table: %d\n",  fhdr->b_rhnum );
+  fprintf( stderr, "BCF: data entries table’s file offset in bytes: %d\n",  fhdr->b_dtoff );
+  fprintf( stderr, "BCF: data entry's size in bytes: %d\n",  fhdr->b_dtentsize );
+  fprintf( stderr, "BCF: number of entries in data entries table: %d\n",  fhdr->b_dtnum );
+  fprintf( stderr, "BCF: string table’s file offset in bytes: %d\n\n",  fhdr->b_stoff );
+#endif
+
+  {
+    Bcf32_shdr *shdr = NULL;
+    int s = 0;
+
+    struct section *global = NULL;
+
+    shdr = (Bcf32_shdr *)((unsigned char *)bf + (int)fhdr->b_shoff);
+
+    while( s < fhdr->b_shnum )
+    {
+#if __DEBUG__ == 1
+      fprintf( stderr, "SECTION: s_name: %s\n",  shdr->s_name );
+      fprintf( stderr, "SECTION: s_type: %d\n",  shdr->s_type );
+      fprintf( stderr, "SECTION: s_shdr (offset in string table): %d\n",  shdr->s_shdr );
+      fprintf( stderr, "SECTION: s_sdata (file offset to data): %d\n",  shdr->s_sdata );
+      fprintf( stderr, "SECTION: s_dnum (number of data entries): %d\n",  shdr->s_dnum );
+      fprintf( stderr, "SECTION: name: \"%s\"\n\n",  stab + (int)shdr->s_shdr );
+#endif
+
+      if( shdr->s_type == ST_GLOBAL )
+      {
+        Bcf32_dntr *dntr = NULL;
+        int d = 0;
+
+        struct section *sec = NULL;
+        sec = (struct section *)xmalloc( sizeof(struct section) );
+        sec->type = ST_GLOBAL;
+        sec->name = (unsigned char *)(stab + (int)shdr->s_shdr); /*do not allocate, all in bcf */
+        tree = dlist_append( tree, (void *)sec );
+        global = sec;
+
+        dntr = (Bcf32_dntr *)(ftab + (int)shdr->s_sdata);
+
+        while( d < shdr->s_dnum )
+        {
+#if __DEBUG__ == 1
+          fprintf( stderr, "DATA: d_name: %s\n",  stab + (int)dntr->d_name );
+#endif
+
+          switch( dntr->d_type )
+          {
+            case DT_NUMERICAL:
+#if __DEBUG__ == 1
+              fprintf( stderr, "DATA: _v.d_value: %d\n\n",  dntr->_v.d_value );
+#endif
+              {
+                struct variable *var = NULL;
+                var = (struct variable *)xmalloc( sizeof(struct variable) );
+                var->type = DT_NUMERICAL;
+                var->name = (unsigned char *)(stab + (int)dntr->d_name); /*do not allocate, all in bcf */
+                var->_v.val = (int)dntr->_v.d_value;
+                sec->list = dlist_append( sec->list, (void *)var );
+              }
+              break;
+            case DT_PATH:
+#if __DEBUG__ == 1
+              fprintf( stderr, "DATA: _v.d_valptr (path): '%s';\n\n", stab + (int)dntr->_v.d_valptr );
+#endif
+              {
+                struct variable *var = NULL;
+                var = (struct variable *)xmalloc( sizeof(struct variable) );
+                var->type = DT_PATH;
+                var->name = (unsigned char *)(stab + (int)dntr->d_name); /*do not allocate, all in bcf */
+                var->_v.vptr = (unsigned char *)(stab + (int)dntr->_v.d_valptr);
+                sec->list = dlist_append( sec->list, (void *)var );
+              }
+              break;
+            case DT_STRING:
+#if __DEBUG__ == 1
+              fprintf( stderr, "DATA: _v.d_valptr (string): \"%s\";\n\n", stab + (int)dntr->_v.d_valptr );
+#endif
+              {
+                struct variable *var = NULL;
+                var = (struct variable *)xmalloc( sizeof(struct variable) );
+                var->type = DT_STRING;
+                var->name = (unsigned char *)(stab + (int)dntr->d_name); /*do not allocate, all in bcf */
+                var->_v.vptr = (unsigned char *)(stab + (int)dntr->_v.d_valptr);
+                sec->list = dlist_append( sec->list, (void *)var );
+              }
+              break;
+            default:
+              break;
+          }
+
+          ++d;
+          ++dntr;
+
+        } /* End of while( global data ) */
+
+      }
+      else if( shdr->s_type == ST_REPOS )
+      {
+        Bcf32_rhdr *rhdr = NULL;
+        int r = 0;
+
+        struct section *sec = NULL;
+        sec = (struct section *)xmalloc( sizeof(struct section) );
+        sec->type = ST_REPOS;
+        sec->name = (unsigned char *)(stab + (int)shdr->s_shdr); /*do not allocate, all in bcf */
+        tree = dlist_append( tree, (void *)sec );
+
+        rhdr = (Bcf32_rhdr *)(ftab + (int)shdr->s_sdata);
+
+        while( r < shdr->s_dnum )
+        {
+          int d = 0;
+          Bcf32_dntr *dntr = NULL;
+
+          struct repo *repo = NULL;
+          repo = (struct repo *)xmalloc( sizeof(struct repo) );
+          repo->path = (unsigned char *)(stab + (int)rhdr->r_rhdr); /*do not allocate, all in bcf */
+          sec->list = dlist_append( sec->list, (void *)repo );
+
+#if __DEBUG__ == 1
+          fprintf( stderr, "REPO: path: %s\n",  stab + (int)rhdr->r_rhdr );
+#endif
+          dntr = (Bcf32_dntr *)(ftab + (int)rhdr->r_rdata);
+
+          while( d < rhdr->r_dnum )
+          {
+#if __DEBUG__ == 1
+            fprintf( stderr, "REPO's DATA: d_name: %s\n",  stab + (int)dntr->d_name );
+#endif
+            switch( dntr->d_type )
+            {
+              case DT_NUMERICAL:
+#if __DEBUG__ == 1
+                fprintf( stderr, "REPO's DATA: _v.d_value: %d\n\n",  dntr->_v.d_value );
+#endif
+                {
+                  struct variable *var = NULL;
+                  var = (struct variable *)xmalloc( sizeof(struct variable) );
+                  var->type = DT_NUMERICAL;
+                  var->name = (unsigned char *)(stab + (int)dntr->d_name); /*do not allocate, all in bcf */
+                  var->_v.val = (int)dntr->_v.d_value;
+                  repo->list = dlist_append( repo->list, (void *)var );
+                }
+                break;
+              case DT_PATH:
+#if __DEBUG__ == 1
+                fprintf( stderr, "REPO's DATA: _v.d_valptr (path): '%s';\n\n", stab + (int)dntr->_v.d_valptr );
+#endif
+                {
+                  struct variable *var = NULL;
+                  var = (struct variable *)xmalloc( sizeof(struct variable) );
+                  var->type = DT_PATH;
+                  var->name = (unsigned char *)(stab + (int)dntr->d_name); /*do not allocate, all in bcf */
+                  var->_v.vptr = (unsigned char *)(stab + (int)dntr->_v.d_valptr);
+                  repo->list = dlist_append( repo->list, (void *)var );
+                }
+                break;
+              case DT_STRING:
+#if __DEBUG__ == 1
+                fprintf( stderr, "REPO's DATA: _v.d_valptr (string): \"%s\";\n\n", stab + (int)dntr->_v.d_valptr );
+#endif
+                {
+                  struct variable *var = NULL;
+                  var = (struct variable *)xmalloc( sizeof(struct variable) );
+                  var->type = DT_STRING;
+                  var->name = (unsigned char *)(stab + (int)dntr->d_name); /*do not allocate, all in bcf */
+                  var->_v.vptr = (unsigned char *)(stab + (int)dntr->_v.d_valptr);
+                  repo->list = dlist_append( repo->list, (void *)var );
+                }
+                break;
+              default:
+                break;
+            }
+
+            ++d;
+            ++dntr;
+
+          } /* End of while( repo data ) */
+
+          ++r;
+          ++rhdr;
+
+        } /* End of while( repos ) */
+
+#if __DEBUG__ == 1
+        fprintf( stderr, "\n" );
+#endif
+      }
+      else
+      {
+        rlist_fatal( "Invalid section in the SHM/%s data", "csvn.bcf" );
+#if __DEBUG__ == 1
+        fprintf( stderr, "SECTION: empty\n" );
+#endif
+      }
+
+      ++s;
+      ++shdr;
+
+    } /* End of while( sections ) */
+
+    if( global )
+      provide_global_data( tree, global );
+  }
+
+  return tree;
+}
+
+
+struct dlist *read_config( void )
+{
+  size_t  bsize = 0;
+
+  if( (bsize = read_bcf()) )
+  {
+    check_bcf_ident( bcf, bsize ); /* fatal on error */
+    return read_repolist( bcf );
+  }
+
+  return NULL;
+}