]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
Some updated to bundle/settings to integrate the two. Settings can now be seamlessly...
authorAdam Sutton <dev@adamsutton.me.uk>
Fri, 3 Aug 2012 11:30:32 +0000 (12:30 +0100)
committerAdam Sutton <dev@adamsutton.me.uk>
Tue, 14 Aug 2012 19:02:38 +0000 (20:02 +0100)
12 files changed:
Makefile
data/conf/epggrab/opentv/dict/skyeng [moved from data/epggrab/opentv/dict/skyeng with 100% similarity]
data/conf/epggrab/opentv/dict/skyit [moved from data/epggrab/opentv/dict/skyit with 100% similarity]
data/conf/epggrab/opentv/genre/skyuk [moved from data/epggrab/opentv/genre/skyuk with 100% similarity]
data/conf/epggrab/opentv/prov/ausat [moved from data/epggrab/opentv/prov/ausat with 100% similarity]
data/conf/epggrab/opentv/prov/skyit [moved from data/epggrab/opentv/prov/skyit with 100% similarity]
data/conf/epggrab/opentv/prov/skyuk [moved from data/epggrab/opentv/prov/skyuk with 100% similarity]
src/filebundle.c
src/filebundle.h
src/settings.c
support/mkbundle
support/mkbundle.py [deleted file]

index 78aa0e79acb03ac2dc009923a938a6417889792d..29f17e3b0afd104027461b6fba5cc8047bc2e96e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -169,7 +169,7 @@ CFLAGS_com  = -g -funsigned-char -O2
 CFLAGS_com += -D_FILE_OFFSET_BITS=64
 CFLAGS_com += -I${BUILDDIR} -I${CURDIR}/src -I${CURDIR}
 
-MKBUNDLE = $(CURDIR)/support/mkbundle.py
+MKBUNDLE = $(CURDIR)/support/mkbundle
 
 ifndef V
 ECHO   = printf "$(1)\t\t%s\n" $(2)
index a7cb2f634d903dcd50076b4a1518cb7286644678..b054e6df4c14ba6bfd066b3e9a46088f56d46a79 100644 (file)
  * Opaque data types
  * *************************************************************************/
 
-/* Bundle or Direct */
-typedef enum filebundle_handle_type
-{
-  FB_BUNDLE,
-  FB_DIRECT
-} fb_type;
-
 /* File bundle dir handle */
 typedef struct filebundle_dir
 {
@@ -142,6 +135,42 @@ static uint8_t *_fb_deflate ( const uint8_t *data, size_t orig, size_t *size )
   return bufout;
 }
 
+/* **************************************************************************
+ * Miscellanous
+ * *************************************************************************/
+
+/* Get path stats */
+// TODO: this could do with being more efficient
+int fb_stat ( const char *path, struct filebundle_stat *st )
+{
+  int ret = 1;
+  fb_dir *dir;
+  fb_file *fp;
+
+  if (*path == '/') {
+    struct stat _st;
+    if (!lstat(path, &_st)) {
+      st->type   = FB_DIRECT;
+      st->is_dir = S_ISDIR(_st.st_mode) ? 1 : 0;
+      st->size   = _st.st_size;
+      ret        = 0;
+    }
+  } else if ((dir = fb_opendir(path))) {
+    st->type   = dir->type;
+    st->is_dir = 1;
+    st->size   = 0;
+    ret = 0;
+    fb_closedir(dir);
+  } else if ((fp = fb_open(path, 0, 0))) {
+    st->type   = fp->type;
+    st->is_dir = 0;
+    st->size   = fp->size;
+    ret = 0;
+    fb_close(fp);
+  }
+  return ret;
+}
+
 /* **************************************************************************
  * Directory processing
  * *************************************************************************/
@@ -213,7 +242,7 @@ fb_dirent *fb_readdir ( fb_dir *dir )
   fb_dirent *ret = NULL;
   if (dir->type == FB_BUNDLE) {
     if (dir->b.cur) {
-      dir->dirent.name = dir->b.cur->name;
+      strcpy(dir->dirent.name, dir->b.cur->name);
       dir->dirent.type = dir->b.cur->type;
       dir->b.cur       = dir->b.cur->next;
       ret              = &dir->dirent;
@@ -225,7 +254,7 @@ fb_dirent *fb_readdir ( fb_dir *dir )
       struct stat st;
       char buf[512];
       snprintf(buf, sizeof(buf), "%s/%s", dir->d.root, de->d_name);
-      dir->dirent.name = de->d_name;
+      strcpy(dir->dirent.name, de->d_name);
       dir->dirent.type = FB_UNKNOWN;
       if (!lstat(buf, &st))
         dir->dirent.type = S_ISDIR(st.st_mode) ? FB_DIR : FB_FILE;
@@ -235,6 +264,50 @@ fb_dirent *fb_readdir ( fb_dir *dir )
   return ret;
 }
 
+/* Get entry list */
+int fb_scandir ( const char *path, fb_dirent ***list )
+{
+  int i, ret = -1;
+  struct dirent **de;
+  struct filebundle_stat st;
+  if (fb_stat(path, &st)) return -1;
+  if (!st.is_dir) return -1;
+
+  /* Direct */
+  if (st.type == FB_DIRECT) {
+    if ((ret = scandir(path, &de, NULL, NULL)) != -1) {
+      if (ret == 0) return 0;
+      *list = malloc(sizeof(fb_dirent*)*ret);
+      for (i = 0; i < ret; i++) {
+        (*list)[i] = calloc(1, sizeof(fb_dirent));
+        strcpy((*list)[i]->name, de[i]->d_name);
+        (*list)[i]->type = FB_DIRECT;
+        free(de[i]);
+      }
+      free(de);
+    }
+
+  /* Bundle */
+  } else {
+    fb_dir *dir;
+    if ((dir = fb_opendir(path))) {
+      const filebundle_entry_t *fb;
+      ret = dir->b.root->d.count;
+      fb  = dir->b.root->d.child;
+      *list = malloc(ret * sizeof(fb_dirent));
+      i = 0;
+      while (fb) {
+        (*list)[i] = calloc(1, sizeof(fb_dirent));
+        strcpy((*list)[i]->name, fb->name);
+        fb = fb->next;
+        i++;
+      }
+      fb_closedir(dir);
+    }
+  }
+  return ret;
+}
+
 /* **************************************************************************
  * Directory processing
  * *************************************************************************/
@@ -344,6 +417,7 @@ fb_file *fb_open ( const char *path, int decompress, int compress )
 
   /* Open */
   ret = fb_open2(dir, pos+1, decompress, compress);
+  fb_closedir(dir);
   free(tmp);
   return ret;
 }
@@ -351,8 +425,9 @@ fb_file *fb_open ( const char *path, int decompress, int compress )
 /* Close file */
 void fb_close ( fb_file *fp )
 {
-  if (fp->type == FB_DIRECT && fp->d.cur)
+  if (fp->type == FB_DIRECT && fp->d.cur) {
     fclose(fp->d.cur);
+  }
   if (fp->buf)
     free(fp->buf);
   free(fp);
@@ -387,7 +462,6 @@ ssize_t fb_read ( fb_file *fp, void *buf, size_t count )
     fp->pos += count;
   } else if (fp->type == FB_DIRECT) {
     fp->pos += fread(buf, 1, count, fp->d.cur);
-    return -1;
   } else {
     count = MIN(count, fp->b.root->f.size - fp->pos);
     memcpy(buf, fp->b.root->f.data + fp->pos, count);
index 315bc3fbd90d0f2a8c029375716ca14bd9601171..d25ca8339a95c48af772ac0567075dd49b69302d 100644 (file)
 #include <dirent.h>
 #include <stdio.h>
 
+/* Bundle or Direct */
+typedef enum filebundle_handle_type
+{
+  FB_BUNDLE,
+  FB_DIRECT
+} fb_type;
+
 /* File bundle entry type */
 enum filebundle_type
 {
@@ -39,6 +46,7 @@ typedef struct filebundle_entry
   const char          *name;
   union {
     struct {
+      size_t count;
       struct filebundle_entry *child;
     } d;
     struct {
@@ -53,10 +61,18 @@ typedef struct filebundle_entry
 /* File bundle directory entry */
 typedef struct filebundle_dirent
 {
-  const char           *name;
-  enum filebundle_type  type;
+  char                 name[256];
+  enum filebundle_type type;
 } fb_dirent;
 
+/* File bundle stat */
+struct filebundle_stat
+{
+  fb_type  type;
+  uint8_t  is_dir;
+  size_t   size;
+};
+
 /* Opaque types */
 typedef struct filebundle_dir  fb_dir;
 typedef struct filebundle_file fb_file;
@@ -64,10 +80,14 @@ typedef struct filebundle_file fb_file;
 /* Root of bundle */
 extern filebundle_entry_t *filebundle_root;
 
+/* Miscellaneous */
+int fb_stat ( const char *path, struct filebundle_stat *st );
+
 /* Directory processing wrappers */
 fb_dir    *fb_opendir  ( const char *path );
 fb_dirent *fb_readdir  ( fb_dir *fb );
 void       fb_closedir ( fb_dir *fb );
+int        fb_scandir  ( const char *path, fb_dirent ***list );
 
 /* File processing wrappers */
 // Note: all access is read-only
index e2c54779e57e127873a5c4dfd17c953aef3345e5..8f2088dc636e258df3f8b014299525761eecb4b7 100644 (file)
@@ -31,6 +31,7 @@
 #include "htsmsg_json.h"
 #include "settings.h"
 #include "tvheadend.h"
+#include "filebundle.h"
 
 static char *settingspath;
 
@@ -43,7 +44,6 @@ hts_settings_get_root(void)
   return settingspath ?: "No settings dir";
 }
 
-
 /**
  *
  */
@@ -56,17 +56,12 @@ hts_settings_init(const char *confpath)
 
   if(confpath != NULL) {
     settingspath = strdup(confpath);
-  } else {
-
-    if(homedir != NULL) {
-      snprintf(buf, sizeof(buf), "%s/.hts", homedir);
-      if(stat(buf, &st) == 0 || mkdir(buf, 0700) == 0) {
-      
-       snprintf(buf, sizeof(buf), "%s/.hts/tvheadend", homedir);
-      
-       if(stat(buf, &st) == 0 || mkdir(buf, 0700) == 0)
-         settingspath = strdup(buf);
-      }
+  } else if(homedir != NULL) {
+    snprintf(buf, sizeof(buf), "%s/.hts", homedir);
+    if(stat(buf, &st) == 0 || mkdir(buf, 0700) == 0) {
+           snprintf(buf, sizeof(buf), "%s/.hts/tvheadend", homedir);
+           if(stat(buf, &st) == 0 || mkdir(buf, 0700) == 0)
+             settingspath = strdup(buf);
     }
   }
   if(settingspath == NULL) {
@@ -82,6 +77,51 @@ hts_settings_init(const char *confpath)
   }
 }
 
+/**
+ *
+ */
+static int
+hts_settings_makedirs ( char *path )
+{
+  size_t x;
+  struct stat st;
+  size_t l = strlen(path);
+  for(x = 0; x < l; x++) {
+    if(path[x] == '/' && x != 0) {
+      path[x] = 0;
+      if(stat(path, &st) && mkdir(path, 0700)) {
+             tvhlog(LOG_ALERT, "settings", "Unable to create dir \"%s\": %s",
+                    path, strerror(errno));
+             return -1;
+      }
+      path[x] = '/';
+    }
+  }
+  return 0;
+}
+
+/**
+ *
+ */
+static void
+hts_settings_buildpath
+  (char *dst, size_t dstsize, const char *fmt, va_list ap, const char *prefix)
+{
+  char tmp[256];
+  char *n = dst;
+
+  vsnprintf(tmp, sizeof(tmp), fmt, ap);
+  if (*tmp != '/' && prefix)
+    snprintf(dst, dstsize, "%s/%s", prefix, tmp);
+  else
+    strncpy(dst, tmp, dstsize);
+
+  while(*n) {
+    if(*n == ':' || *n == '?' || *n == '*' || *n > 127 || *n < 32)
+      *n = '_';
+    n++;
+  }
+}
 
 /**
  *
@@ -90,81 +130,54 @@ void
 hts_settings_save(htsmsg_t *record, const char *pathfmt, ...)
 {
   char path[256];
-  char fullpath[256];
-  char fullpath2[256];
-  int x, l, fd;
+  char tmppath[256];
+  int fd;
   va_list ap;
-  struct stat st;
   htsbuf_queue_t hq;
   htsbuf_data_t *hd;
-  char *n;
   int ok;
 
   if(settingspath == NULL)
     return;
 
+  /* Clean the path */
   va_start(ap, pathfmt);
-  vsnprintf(path, sizeof(path), pathfmt, ap);
+  hts_settings_buildpath(path, sizeof(path), pathfmt, ap, settingspath);
   va_end(ap);
 
-  n = path;
-
-  while(*n) {
-    if(*n == ':' || *n == '?' || *n == '*' || *n > 127 || *n < 32)
-      *n = '_';
-    n++;
-  }
-
-  l = strlen(path);
-
-  for(x = 0; x < l; x++) {
-    if(path[x] == '/') {
-      /* It's a directory here */
-
-      path[x] = 0;
-      snprintf(fullpath, sizeof(fullpath), "%s/%s", settingspath, path);
-
-      if(stat(fullpath, &st) && mkdir(fullpath, 0700)) {
-       tvhlog(LOG_ALERT, "settings", "Unable to create dir \"%s\": %s",
-              fullpath, strerror(errno));
-       return;
-      }
-      path[x] = '/';
-    }
-  }
-
-  snprintf(fullpath, sizeof(fullpath), "%s/%s.tmp", settingspath, path);
+  /* Create directories */
+  if (hts_settings_makedirs(path)) return;
 
-  if((fd = tvh_open(fullpath, O_CREAT | O_TRUNC | O_RDWR, 0700)) < 0) {
+  /* Create tmp file */
+  snprintf(tmppath, sizeof(tmppath), "%s.tmp", path);
+  if((fd = tvh_open(tmppath, O_CREAT | O_TRUNC | O_RDWR, 0700)) < 0) {
     tvhlog(LOG_ALERT, "settings", "Unable to create \"%s\" - %s",
-           fullpath, strerror(errno));
+           tmppath, strerror(errno));
     return;
   }
 
+  /* Store data */
   ok = 1;
-
   htsbuf_queue_init(&hq, 0);
   htsmsg_json_serialize(record, &hq, 1);
   TAILQ_FOREACH(hd, &hq.hq_q, hd_link)
     if(write(fd, hd->hd_data + hd->hd_data_off, hd->hd_data_len) != 
        hd->hd_data_len) {
       tvhlog(LOG_ALERT, "settings", "Failed to write file \"%s\" - %s",
-             fullpath, strerror(errno));
+             tmppath, strerror(errno));
       ok = 0;
       break;
     }
-
   close(fd);
-
-  snprintf(fullpath2, sizeof(fullpath2), "%s/%s", settingspath, path);
-
-  if(ok)
-    rename(fullpath, fullpath2);
-  else
-    unlink(fullpath);
-          
   htsbuf_queue_flush(&hq);
+
+  /* Move */
+  if(ok) {
+    rename(tmppath, path);
+  
+  /* Delete tmp */
+  } else
+    unlink(tmppath);
 }
 
 /**
@@ -173,28 +186,23 @@ hts_settings_save(htsmsg_t *record, const char *pathfmt, ...)
 static htsmsg_t *
 hts_settings_load_one(const char *filename)
 {
-  struct stat st;
-  int fd;
+  ssize_t n;
   char *mem;
-  htsmsg_t *r;
-  int n;
-
-  if(stat(filename, &st) < 0)
-    return NULL;
-
-  if((fd = tvh_open(filename, O_RDONLY, 0)) < 0)
-    return NULL;
-
-  mem = malloc(st.st_size + 1);
-  mem[st.st_size] = 0;
+  fb_file *fp;
+  htsmsg_t *r = NULL;
 
-  n = read(fd, mem, st.st_size);
-  close(fd);
-  if(n == st.st_size)
+  /* Open */
+  if (!(fp = fb_open(filename, 1, 0))) return NULL;
+  
+  /* Load data */
+  mem    = malloc(fb_size(fp)+1);
+  n      = fb_read(fp, mem, fb_size(fp));
+  if (n >= 0) mem[n] = 0;
+  fb_close(fp);
+
+  /* Decode */
+  if(n == fb_size(fp))
     r = htsmsg_json_deserialize(mem);
-  else
-    r = NULL;
-
   free(mem);
 
   return r;
@@ -203,69 +211,39 @@ hts_settings_load_one(const char *filename)
 /**
  *
  */
-static int
-hts_settings_buildpath(char *dst, size_t dstsize, const char *fmt, va_list ap)
-{
-  char tmp[256];
-  char *n = dst;
-
-  if(settingspath == NULL)
-     return -1;
-  
-  vsnprintf(tmp, sizeof(tmp), fmt, ap);
-  if (*tmp != '/')
-    snprintf(dst, dstsize, "%s/%s", settingspath, tmp);
-  else
-    strncpy(dst, tmp, dstsize);
-
-  while(*n) {
-    if(*n == ':' || *n == '?' || *n == '*' || *n > 127 || *n < 32)
-      *n = '_';
-    n++;
-  }
-  return 0;
-}
-
-/**
- *
- */
-htsmsg_t *
-hts_settings_load(const char *pathfmt, ...)
+static htsmsg_t *
+_hts_settings_load(const char *fullpath)
 {
-  char fullpath[256];
   char child[256];
-  va_list ap;
-  struct stat st;
-  struct dirent **namelist, *d;
+  struct filebundle_stat st;
+  fb_dirent **namelist, *d;
   htsmsg_t *r, *c;
   int n, i;
 
-  va_start(ap, pathfmt);
-  if(hts_settings_buildpath(fullpath, sizeof(fullpath), pathfmt, ap) < 0)
-    return NULL;
-
-  if(stat(fullpath, &st) != 0)
-    return NULL;
+  /* Invalid */
+  if (fb_stat(fullpath, &st)) return NULL;
 
-  if(S_ISDIR(st.st_mode)) {
+  /* Directory */
+  if (st.is_dir) {
 
-    if((n = scandir(fullpath, &namelist, NULL, NULL)) < 0)
+    /* Get file list */
+    if((n = fb_scandir(fullpath, &namelist)) < 0)
       return NULL;
-     
-    r = htsmsg_create_map();
 
+    /* Read files */
+    r = htsmsg_create_map();
     for(i = 0; i < n; i++) {
       d = namelist[i];
-      if(d->d_name[0] != '.') {
-       snprintf(child, sizeof(child), "%s/%s", fullpath, d->d_name);
-       c = hts_settings_load_one(child);
-       if(c != NULL)
-         htsmsg_add_msg(r, d->d_name, c);
+      if(d->name[0] != '.') {
+             snprintf(child, sizeof(child), "%s/%s", fullpath, d->name);
+             if ((c = hts_settings_load_one(child)))
+          htsmsg_add_msg(r, d->name, c);
       }
       free(d);
     }
     free(namelist);
 
+  /* File */
   } else {
     r = hts_settings_load_one(fullpath);
   }
@@ -273,6 +251,35 @@ hts_settings_load(const char *pathfmt, ...)
   return r;
 }
 
+/**
+ *
+ */
+htsmsg_t *
+hts_settings_load(const char *pathfmt, ...)
+{
+  htsmsg_t *ret = NULL;
+  char fullpath[256];
+  va_list ap;
+
+  /* Try normal path */
+  va_start(ap, pathfmt);
+  hts_settings_buildpath(fullpath, sizeof(fullpath), 
+                         pathfmt, ap, settingspath);
+  va_end(ap);
+  ret = _hts_settings_load(fullpath);
+
+  /* Try bundle path */
+  if (!ret && *pathfmt != '/') {
+    va_start(ap, pathfmt);
+    hts_settings_buildpath(fullpath, sizeof(fullpath),
+                           pathfmt, ap, "data/conf");
+    va_end(ap);
+    ret = _hts_settings_load(fullpath);
+  }
+  
+  return ret;
+}
+
 /**
  *
  */
@@ -283,12 +290,12 @@ hts_settings_remove(const char *pathfmt, ...)
   va_list ap;
 
   va_start(ap, pathfmt);
-  if(hts_settings_buildpath(fullpath, sizeof(fullpath), pathfmt, ap) < 0)
-    return;
+   hts_settings_buildpath(fullpath, sizeof(fullpath),
+                          pathfmt, ap, settingspath);
+  va_end(ap);
   unlink(fullpath);
 }
 
-
 /**
  *
  */
@@ -296,48 +303,19 @@ int
 hts_settings_open_file(int for_write, const char *pathfmt, ...)
 {
   char path[256];
-  char fullpath[256];
-  int x, l;
   va_list ap;
-  struct stat st;
-  char *n;
-
-  if(settingspath == NULL)
-    return -1;
 
+  /* Build path */
   va_start(ap, pathfmt);
-  vsnprintf(path, sizeof(path), pathfmt, ap);
+  hts_settings_buildpath(path, sizeof(path), pathfmt, ap, settingspath);
   va_end(ap);
 
-  n = path;
-
-  while(*n) {
-    if(*n == ':' || *n == '?' || *n == '*' || *n > 127 || *n < 32)
-      *n = '_';
-    n++;
-  }
-
-  l = strlen(path);
-
-  for(x = 0; x < l; x++) {
-    if(path[x] == '/') {
-      /* It's a directory here */
-
-      path[x] = 0;
-      snprintf(fullpath, sizeof(fullpath), "%s/%s", settingspath, path);
-
-      if(stat(fullpath, &st) && mkdir(fullpath, 0700)) {
-       tvhlog(LOG_ALERT, "settings", "Unable to create dir \"%s\": %s",
-              fullpath, strerror(errno));
-       return -1;
-      }
-      path[x] = '/';
-    }
-  }
-
-  snprintf(fullpath, sizeof(fullpath), "%s/%s", settingspath, path);
+  /* Create directories */
+  if (for_write)
+    if (hts_settings_makedirs(path)) return -1;
 
+  /* Open file */
   int flags = for_write ? O_CREAT | O_TRUNC | O_WRONLY : O_RDONLY;
 
-  return tvh_open(fullpath, flags, 0700);
+  return tvh_open(path, flags, 0700);
 }
index 2a7801bc2eae86589e701a874fa46ab2b79b8e8b..68741008e514e055509718e51bc928c6ba61de0b 100755 (executable)
-#!/bin/bash
+#!/usr/bin/env python
 #
-#  Filebundle generator
-#  Copyright (C) 2009 Andreas Ă–man
-#
-#  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
-#  (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, see <http://www.gnu.org/licenses/>.
+# Replacement for old mkbundle script that creates a full file heirarchy
 #
 
-set -u # Fail on undefined vars
-
-READER="cat"
-SOURCE=
-DEPFILE=
-OUTPUT=
-PREFIX=
-COMPRESS=false
-usage()
-{
-cat << EOF
-usage: $0 options
-
-Generate a filebundle .c-file from a directory
-
-OPTIONS:
-   -h      Show this message
-   -s      Source path
-   -d      Dependency file (for use with make)
-   -o      Output file (.c file)
-   -z      Compress individual files using gzip
-   -p      Filebundle prefix
-EOF
-}
-
-
-while getopts "s:d:o:zhp:" OPTION
-do
-  case $OPTION in
-      h)
-         usage
-         exit 1
-         ;;
-      z)
-         READER="gzip -9"
-         COMPRESS=true
-         ;;
-      d)
-         DEPFILE="$OPTARG"
-         ;;
-      s)
-         SOURCE="$OPTARG"
-         ;;
-      o)
-         OUTPUT="$OPTARG"
-         ;;
-      p)
-         PREFIX="$OPTARG"
-         ;;
-      esac
-  done
-
-
-if [[ -z $SOURCE ]] || [[ -z $OUTPUT ]] || [[ -z $PREFIX ]]; then
-     usage
-     exit 1
-fi
-
-FILES=`find "${SOURCE}" \( \( -name .svn -or -name *~ \) -and -prune \) -or -printf "%P "`
-
-echo >${OUTPUT} "// auto-generated by $0"
-
-for file in $FILES; do
-
-    if [ -f ${SOURCE}/$file ]; then
-
-       name=`echo $file | perl -pe s#[^a-z0-9A-Z]#_#g`
-       
-       echo >>${OUTPUT} "// ${SOURCE}/$file"
-       echo >>${OUTPUT} "static const unsigned char embedded_$name[]={"
-       $READER <${SOURCE}/$file | od -v -An -b | sed s/^\ */0/ | sed s/\ *$$/,/| sed s/\ /,\ 0/g|sed s/$/,/ >>${OUTPUT}
-       echo >>${OUTPUT} "};"
-    fi
-done
-
-echo >>${OUTPUT} "#include <filebundle.h>"
-echo >>${OUTPUT} "static const struct filebundle_entry filebundle_entries[] = {"
-[[ -z $DEPFILE ]] || echo >${DEPFILE} -n "${OUTPUT}: "
-
-for file in $FILES; do
-    [[ -z $DEPFILE ]] || echo >>${DEPFILE} -n "${SOURCE}/$file "
-
-    if [ -f ${SOURCE}/$file ]; then
-
-       if $COMPRESS; then
-           ORIGINAL_SIZE=`stat -c "%s" ${SOURCE}/$file`
-       else
-           ORIGINAL_SIZE="-1"
-       fi
-
-       N=`echo $file | perl -pe s#[^a-z0-9A-Z]#_#g`
-       echo >>${OUTPUT} "{\"$file\", embedded_$N, sizeof(embedded_$N),${ORIGINAL_SIZE}},"
-    fi
-done
-
-echo >>${OUTPUT}  "{(void *)0, 0, 0, 0}};"
-[[ -z $DEPFILE ]] || echo >>${DEPFILE} ""
-
-cat >>${OUTPUT} <<EOF
-
-static struct filebundle fb = {
-  .entries = &filebundle_entries[0],
-  .prefix = "${PREFIX}"
-};
-
-static void  __attribute__((constructor)) filebundle_init(void)
-{
-  extern struct filebundle *filebundles;
-
-  fb.next = filebundles;
-  filebundles = &fb;
-}
-
-EOF
\ No newline at end of file
+import os, sys, re
+import gzip, cStringIO
+from optparse import OptionParser
+
+# Add reverse path split
+def rsplit ( p ):
+  i = p.find(os.path.sep)
+  if i != -1:
+    return (p[:i], p[i+1:])
+  else:
+    return (p, '')
+
+# Process command line
+optp = OptionParser()
+optp.add_option('-z', '--gzip', action='store_true',
+                help='Compress the files with gzip')
+optp.add_option('-l', '--gzlevel', type='int', default=9,
+                help='Specify compression level if using gzip')
+optp.add_option('-o', '--output', default=None,
+                help='Specify output file (default /dev/stdout)')
+optp.add_option('-d', '--deps', default=None,
+                help='Specify deps file to update during run')
+(opts, args) = optp.parse_args()
+
+# Setup
+outf = sys.stdout
+if opts.output:
+  outf = open(opts.output, 'w')
+depf = None
+if opts.deps:
+  depf = open(opts.deps, 'w')
+  print >>depf, '%s: \\' % opts.output
+
+# Build heirarchy
+root  = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '..'))
+ents  = {}
+for path in args:
+  for (p, ds, fs) in os.walk(path):
+    p = os.path.abspath(p)
+    n = p.replace(root+'/', '')
+    t = ents
+    while True:
+      (d,n) = rsplit(n)
+      if d not in t:
+        t[d] = {}
+      t = t[d]
+      if not n: break
+    for f in fs:
+      t[f] = None
+
+# Output a file
+def output_file ( path, name, idx, next = -1 ):
+  n = 'NULL'
+  if next >= 0: n = '&filebundle_entry_%06d' % next
+  p = os.path.join(root, path, name);
+
+  # Dep file
+  if depf: print >>depf, '  %s\\' % p
+
+  # First the data
+  print >>outf, '// FILE : %s %s %d %d' % (path, name, idx, next)
+  print >>outf, 'static const uint8_t filebundle_data_%06d[] = {' % idx,
+  o = -1
+  d = open(p, 'rb').read()
+  if opts.gzip:
+    o = len(d)
+    l = opts.gzlevel
+    t = cStringIO.StringIO()
+    if l < 0: l = 1
+    if l > 9: l = 9
+    z = gzip.GzipFile(filename=name, mode='w', compresslevel=l, fileobj=t)
+    z.write(d)
+    z.close()
+    d = t.getvalue()
+    t.close()
+  i = 0
+  for b in d:
+    if not (i % 12): print >>outf, '\n  ',
+    print >>outf, '0x%02x,' % ord(b),
+    i = i + 1
+  print >>outf, ''
+  print >>outf, '};'
+  
+  print >>outf, 'static filebundle_entry_t filebundle_entry_%06d = {' % idx
+  print >>outf, '  .type    = FB_FILE,'
+  print >>outf, '  .name    = "%s",'  % name
+  print >>outf, '  .next    = %s,' % n
+  print >>outf, '  .f.size  = %d,' % len(d)
+  print >>outf, '  .f.orig  = %d,' % o
+  print >>outf, '  .f.data  = filebundle_data_%06d,' % idx
+  print >>outf, '};'
+  print >>outf, ''
+
+# Output a directory
+def output_dir ( path, name, idx, child, count, next = -1 ):
+  n = 'NULL'
+  if next >= 0: n = '&filebundle_entry_%06d' % next
+  print >>outf, '// DIR: %s %s %d %d %d %d'\
+  % (path, name, idx, child, count, next)
+  print >>outf, 'static filebundle_entry_t filebundle_entry_%06d = {' % idx
+  print >>outf, '  .type    = FB_DIR,'
+  print >>outf, '  .name    = "%s",'  % name
+  print >>outf, '  .next    = %s,' % n
+  print >>outf, '  .d.count = %d,' % count
+  print >>outf, '  .d.child = &filebundle_entry_%06d,' % child
+  print >>outf, '};'
+  print >>outf, ''
+
+# Create output
+def add_entry ( ents, path = "", name = "", idx = -1, next = -1 ):
+
+  # Add children
+  d = os.path.join(path, name)
+  p = -1
+  c = 0
+  for k in ents:
+    
+    # File
+    if not ents[k]:
+      output_file(d, k, idx+1, p)
+      p = idx = idx + 1
+      c = c + 1
+      
+    # Directory
+    else:
+      tmp = add_entry(ents[k], d, k, idx, p)
+      if tmp != idx:
+        p = idx = tmp
+        c = c + 1
+
+  # Add directory
+  if p >= 0:
+    if name:
+      output_dir(path, name, idx+1, p, c, next)
+      idx = idx + 1
+
+  return idx
+
+# Output header
+print >>outf, '// Auto-generated - DO NOT EDIT'
+print >>outf, '// COMMAND: [%s]' % (' '.join(sys.argv))
+print >>outf, ''
+print >>outf, '#include "filebundle.h"'
+print >>outf, ''
+
+# Output entries
+idx = add_entry(ents)
+
+# Output top link
+print >>outf, 'filebundle_entry_t *filebundle_root = &filebundle_entry_%06d;'  % idx
diff --git a/support/mkbundle.py b/support/mkbundle.py
deleted file mode 100755 (executable)
index e1fb053..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-#!/usr/bin/env python
-#
-# Replacement for old mkbundle script that creates a full file heirarchy
-#
-
-import os, sys, re
-import gzip, cStringIO
-from optparse import OptionParser
-
-# Add reverse path split
-def rsplit ( p ):
-  i = p.find(os.path.sep)
-  if i != -1:
-    return (p[:i], p[i+1:])
-  else:
-    return (p, '')
-
-# Process command line
-optp = OptionParser()
-optp.add_option('-z', '--gzip', action='store_true',
-                help='Compress the files with gzip')
-optp.add_option('-l', '--gzlevel', type='int', default=9,
-                help='Specify compression level if using gzip')
-optp.add_option('-o', '--output', default=None,
-                help='Specify output file (default /dev/stdout)')
-optp.add_option('-d', '--deps', default=None,
-                help='Specify deps file to update during run')
-(opts, args) = optp.parse_args()
-
-# Setup
-outf = sys.stdout
-if opts.output:
-  outf = open(opts.output, 'w')
-depf = None
-if opts.deps:
-  depf = open(opts.deps, 'w')
-  print >>depf, '%s: \\' % opts.output
-
-# Build heirarchy
-root  = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '..'))
-ents  = {}
-for path in args:
-  for (p, ds, fs) in os.walk(path):
-    p = os.path.abspath(p)
-    n = p.replace(root+'/', '')
-    t = ents
-    while True:
-      (d,n) = rsplit(n)
-      if d not in t:
-        t[d] = {}
-      t = t[d]
-      if not n: break
-    for f in fs:
-      t[f] = None
-
-# Output a file
-def output_file ( path, name, idx, next = -1 ):
-  n = 'NULL'
-  if next >= 0: n = '&filebundle_entry_%06d' % next
-  p = os.path.join(root, path, name);
-
-  # Dep file
-  if depf: print >>depf, '  %s\\' % p
-
-  # First the data
-  print >>outf, '// FILE : %s %s %d %d' % (path, name, idx, next)
-  print >>outf, 'static const uint8_t filebundle_data_%06d[] = {' % idx,
-  o = -1
-  d = open(p, 'rb').read()
-  if opts.gzip:
-    o = len(d)
-    l = opts.gzlevel
-    t = cStringIO.StringIO()
-    if l < 0: l = 1
-    if l > 9: l = 9
-    z = gzip.GzipFile(filename=name, mode='w', compresslevel=l, fileobj=t)
-    z.write(d)
-    z.close()
-    d = t.getvalue()
-    t.close()
-  i = 0
-  for b in d:
-    if not (i % 12): print >>outf, '\n  ',
-    print >>outf, '0x%02x,' % ord(b),
-    i = i + 1
-  print >>outf, ''
-  print >>outf, '};'
-  
-  print >>outf, 'static filebundle_entry_t filebundle_entry_%06d = {' % idx
-  print >>outf, '  .type    = FB_FILE,'
-  print >>outf, '  .name    = "%s",'  % name
-  print >>outf, '  .next    = %s,' % n
-  print >>outf, '  .f.size  = %d,' % len(d)
-  print >>outf, '  .f.orig  = %d,' % o
-  print >>outf, '  .f.data  = filebundle_data_%06d,' % idx
-  print >>outf, '};'
-  print >>outf, ''
-
-# Output a directory
-def output_dir ( path, name, idx, child, next = -1 ):
-  n = 'NULL'
-  if next >= 0: n = '&filebundle_entry_%06d' % next
-  print >>outf, '// DIR: %s %s %d %d %d' % (path, name, idx, child, next)
-  print >>outf, 'static filebundle_entry_t filebundle_entry_%06d = {' % idx
-  print >>outf, '  .type    = FB_DIR,'
-  print >>outf, '  .name    = "%s",'  % name
-  print >>outf, '  .next    = %s,' % n
-  print >>outf, '  .d.child = &filebundle_entry_%06d,' % child
-  print >>outf, '};'
-  print >>outf, ''
-
-# Create output
-def add_entry ( ents, path = "", name = "", idx = -1, next = -1 ):
-
-  # Add children
-  d = os.path.join(path, name)
-  p = -1
-  for k in ents:
-    
-    # File
-    if not ents[k]:
-      output_file(d, k, idx+1, p)
-      p = idx = idx + 1
-      
-    # Directory
-    else:
-      tmp = add_entry(ents[k], d, k, idx, p)
-      if tmp != idx:
-        p = idx = tmp
-
-  # Add directory
-  if p >= 0:
-    if name:
-      output_dir(path, name, idx+1, p, next)
-      idx = idx + 1
-
-  return idx
-
-# Output header
-print >>outf, '// Auto-generated - DO NOT EDIT'
-print >>outf, '// COMMAND: [%s]' % (' '.join(sys.argv))
-print >>outf, ''
-print >>outf, '#include "filebundle.h"'
-print >>outf, ''
-
-# Output entries
-idx = add_entry(ents)
-
-# Output top link
-print >>outf, 'filebundle_entry_t *filebundle_root = &filebundle_entry_%06d;'  % idx