]> git.mxchange.org Git - flightgear.git/commitdiff
Rework by Frederic for better windows support.
authorcurt <curt>
Mon, 16 Feb 2004 00:27:03 +0000 (00:27 +0000)
committercurt <curt>
Mon, 16 Feb 2004 00:27:03 +0000 (00:27 +0000)
Added MSVC7 workspace files.
Switch from libtar to untarka for it's better windows support.

utils/fgadmin/configure.ac
utils/fgadmin/src/Makefile.am
utils/fgadmin/src/config.h
utils/fgadmin/src/fgadmin.fl
utils/fgadmin/src/fgadmin_funcs.cxx
utils/fgadmin/src/tar_utils.cxx [deleted file]
utils/fgadmin/src/tar_utils.hxx [deleted file]
utils/fgadmin/src/untarka.c [new file with mode: 0644]
utils/fgadmin/src/untarka.h [new file with mode: 0644]
utils/fgadmin/visualc/fgadmin.sln [new file with mode: 0644]
utils/fgadmin/visualc/fgadmin/fgadmin.vcproj [new file with mode: 0644]

index 9aeb6df78ccf6476ccbfd988ced12c9c5a54e177..026267a9f99ac0ccf442bf5bbcce3c95e1cf6932 100644 (file)
@@ -10,7 +10,7 @@ dnl Require at least automake 2.52
 AC_PREREQ(2.52)
 
 dnl Initialize the automake stuff
-AM_INIT_AUTOMAKE(fgadmin, 1.0)
+AM_INIT_AUTOMAKE(fgadmin, 1.0.0)
 
 dnl Checks for programs.
 AC_PROG_MAKE_SET
@@ -162,6 +162,8 @@ if test "x$ac_cv_header_zlib_h" != "xyes"; then
     echo "configure aborted."
     echo
     exit
+else
+    AC_DEFINE([HAVE_ZLIB], 1, [Define to enable gz compressed tar archives])
 fi
 
 dnl Check for system installed zlib
index 8db1c72c7248a955516e71ca2f3b64f30436c9b2..c00b291e769b0beb184478c667cfa6b85c7648c7 100644 (file)
@@ -6,7 +6,9 @@ fgadmin_SOURCES = \
        fgadmin.cxx fgadmin.h \
        fgadmin_funcs.cxx \
        main.cxx \
-       tar_utils.cxx tar_utils.hxx
+       untarka.c untarka.h
 
 fgadmin_LDADD = -lsgmisc -lplibul -ltar -lz
 
+fgadmin.cxx fgadmin.h: fgadmin.fl
+       fluid -c fgadmin.fl
index 1e74f6e01a8f8ea8df70a4860c37996a9236ec10..4f79640a435b93100dbec1f8cb10a97d5e2ecc6a 100644 (file)
@@ -40,6 +40,9 @@
 /* Define to 1 if you have the `unlink' function. */
 #define HAVE_UNLINK 1
 
+/* Define to enable gz compressed tar archives */
+#define HAVE_ZLIB 1
+
 /* Name of package */
 #define PACKAGE "fgadmin"
 
@@ -68,7 +71,7 @@
 /* #undef TM_IN_SYS_TIME */
 
 /* Version number of package */
-#define VERSION "1.0"
+#define VERSION "1.0.0"
 
 /* Define to empty if `const' does not conform to ANSI C. */
 /* #undef const */
index 84a13f87b42dcae061e741c1d6d65a4f0278f6c8..536bd52008e6961c3c9ed35624894547b93e87a7 100644 (file)
@@ -20,7 +20,7 @@ class FGAdminUI {open selected
   } {
     Fl_Window main_window {
       label {FlightGear Admin Wizard} open
-      xywh {186 521 465 435} type Double visible
+      xywh {187 544 465 435} type Double visible
     } {
       Fl_Button quit_b {
         label Quit
index 91a44924b766d3f78d229103d573aa3b5ae0a6a2..d17d7fd22c59d73ed904c4932a848e261bace128 100644 (file)
 #include <string>
 #include <vector>
 
+#ifdef _MSC_VER
+#  include <direct.h>
+#endif
+
 #include <FL/Fl_File_Chooser.H>
 #include <plib/ul.h>
 
 #include <simgear/misc/sg_path.hxx>
 
 #include "fgadmin.h"
-#include "tar_utils.hxx"
+#include "untarka.h"
 
 using std::cout;
 using std::endl;
@@ -221,13 +225,13 @@ void FGAdminUI::install_selected() {
     char *f;
 
     // traverse install box and install each item
-    for ( int i = 0; i < install_box->nitems(); ++i ) {
+    for ( int i = 0; i <= install_box->nitems(); ++i ) {
         if ( install_box->checked( i ) ) {
             f = install_box->text( i );
             SGPath file( source );
             file.append( f );
             cout << "installing " << file.str() << endl;
-            tarextract( (char *)file.c_str(), (char *)dest.c_str(), true );
+            tarextract( (char *)file.c_str(), (char *)dest.c_str(), true, 0 );
         }
     }
 
@@ -263,7 +267,7 @@ void FGAdminUI::remove_selected() {
     char *f;
 
     // traverse remove box and recursively remove each item
-    for ( int i = 0; i < remove_box->nitems(); ++i ) {
+    for ( int i = 0; i <= remove_box->nitems(); ++i ) {
         if ( remove_box->checked( i ) ) {
             f = remove_box->text( i );
             SGPath dir( dest );
diff --git a/utils/fgadmin/src/tar_utils.cxx b/utils/fgadmin/src/tar_utils.cxx
deleted file mode 100644 (file)
index fbe1cb2..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <tar.h>
-
-#include <libtar.h>
-#include <zlib.h>
-
-#include "tar_utils.hxx"
-
-
-int gzopen_frontend( char *pathname, int oflags, int mode ) {
-    char *gzoflags;
-    gzFile gzf;
-    int fd;
-
-    switch (oflags & O_ACCMODE)
-        {
-        case O_WRONLY:
-            gzoflags = "wb";
-            break;
-        case O_RDONLY:
-            gzoflags = "rb";
-            break;
-        default:
-        case O_RDWR:
-            errno = EINVAL;
-            return -1;
-        }
-
-    fd = open(pathname, oflags, mode);
-    if (fd == -1)
-        return -1;
-
-    if ((oflags & O_CREAT) && fchmod(fd, mode))
-        return -1;
-
-    gzf = gzdopen(fd, gzoflags);
-    if (!gzf) {
-        errno = ENOMEM;
-        return -1;
-    }
-
-    return (int)gzf;
-}
-
-
-tartype_t gztype = {
-    (openfunc_t) gzopen_frontend,
-    (closefunc_t) gzclose,
-    (readfunc_t) gzread,
-    (writefunc_t) gzwrite
-};
-
-
-// list the contents of the specified tar file
-bool tarlist( char *tarfile, char *destdir, bool verbose ) {
-    TAR *t;
-    int i;
-
-    int tarflags = TAR_GNU;
-    if ( verbose ) {
-        tarflags |= TAR_VERBOSE;
-    }
-
-    if ( tar_open( &t, tarfile, &gztype, O_RDONLY, 0, tarflags ) == -1) {
-        fprintf(stderr, "tar_open(): %s\n", strerror(errno));
-        return -1;
-    }
-
-    while ((i = th_read(t)) == 0) {
-        th_print_long_ls(t);
-#ifdef DEBUG
-        th_print(t);
-#endif
-        if (TH_ISREG(t) && tar_skip_regfile(t) != 0) {
-            fprintf(stderr, "tar_skip_regfile(): %s\n",
-                    strerror(errno));
-            return -1;
-        }
-    }
-
-#ifdef DEBUG
-    printf( "th_read() returned %d\n", i);
-    printf( "EOF mark encountered after %ld bytes\n",
-            gzseek((gzFile) t->fd, 0, SEEK_CUR)
-            );
-#endif
-
-    if (tar_close(t) != 0) {
-        fprintf(stderr, "tar_close(): %s\n", strerror(errno));
-        return -1;
-    }
-
-    return 0;
-}
-
-
-// extract the specified tar file into the specified destination
-// directory
-int tarextract( char *tarfile, char *destdir, bool verbose ) {
-    TAR *t;
-
-#ifdef DEBUG
-    puts("opening tarfile...");
-#endif
-
-    int tarflags = TAR_GNU;
-    if ( verbose ) {
-        tarflags |= TAR_VERBOSE;
-    }
-
-    if ( tar_open(&t, tarfile, &gztype, O_RDONLY, 0, tarflags) == -1 ) {
-        fprintf(stderr, "tar_open(): %s\n", strerror(errno));
-        return -1;
-    }
-
-#ifdef DEBUG
-    puts("extracting tarfile...");
-#endif
-    if (tar_extract_all(t, destdir) != 0) {
-        fprintf(stderr, "tar_extract_all(): %s\n", strerror(errno));
-        return -1;
-    }
-
-#ifdef DEBUG
-    puts("closing tarfile...");
-#endif
-    if (tar_close(t) != 0) {
-        fprintf(stderr, "tar_close(): %s\n", strerror(errno));
-        return -1;
-    }
-
-    return 0;
-}
diff --git a/utils/fgadmin/src/tar_utils.hxx b/utils/fgadmin/src/tar_utils.hxx
deleted file mode 100644 (file)
index e207554..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#include <string>
-
-using std::string;
-
-// list the contents of the specified tar file
-bool tarlist( char *tarfile, char *destdir, bool verbose );
-
-// extract the specified tar file into the specified destination
-// directory
-int tarextract( char *tarfile, char *destdir, bool verbose );
diff --git a/utils/fgadmin/src/untarka.c b/utils/fgadmin/src/untarka.c
new file mode 100644 (file)
index 0000000..a65d1c6
--- /dev/null
@@ -0,0 +1,1464 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define DUMMY \
+  WFLAGS="-ansi -pedantic -W -Wall -Wstrict-prototypes -Wtraditional -Wnested-externs -Winline -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wmissing-prototypes -Wmissing-declarations -Wunused"; \
+  set -ex; \
+  gcc -s -O2 $WFLAGS -DHAVE_ZLIB -DHAVE_BZ2LIB untarka.c -o untarka -lz -lbz2; \
+  exit 0
+/*
+ * untarka.c -- Display contents and/or extract file from a tar file (possibly
+ * gzip'd, bzip'd or compress'd)
+ * by pts@fazekas.hu Wed Jan 29 00:38:31 CET 2003
+ * Z compiles fine at Wed Jan 29 14:20:32 CET 2003
+ * all run file at Wed Jan 29 15:50:39 CET 2003
+ * 0.34 Win32 runs fine at Wed Jan 29 16:02:57 GMT 2003
+ *
+ * Untarka extracts TAR (UNIX Tape ARchive) files without calling any
+ * external programs. It supports and autodetects multiple compression
+ * methods (.tar, .tar.Z, .tar.gz, .tar.bz2, .Z, .gz and .bz2). UNIX
+ * devices, sockets, hard links, symlinks, owners and permissions are
+ * ignored during extraction.
+ *
+ * written by "Pedro A. Aranda Guti\irrez" <paag@tid.es>
+ * adaptation to Unix by Jean-loup Gailly <jloup@gzip.org>
+ * adaptation to bzip2 by José Fonseca <em96115@fe.up.pt>
+ * merged comressors by Szabó Péter <pts@fazekas.hu> at Tue Jan 28 23:40:23 CET 2003
+ * compiles on Win32 under MinGW, Linux with gcc.
+ *
+ * To get gzip (zlib) support, pass to gcc: -DHAVE_ZLIB -lz
+ * To get bzip2 (bzlib2) support, pass to gcc: -DHAVE_BZ2LIB -lbz2
+ * To get compress (lz) support, relax, since it's the default.
+ *
+ * Compile memory-checking with checkergcc -g -ansi -pedantic -W -Wall -Wstrict-prototypes -Wtraditional -Wnested-externs -Winline -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wmissing-prototypes -Wmissing-declarations -Wunused untarka.c -o untarka
+ */
+/* Imp: symlink()
+ * Imp: mknod() device, socket
+ * Imp: hard link()
+ * Imp: chmod()
+ * Imp: chown()
+ * Imp: allow force non-tar gzipped file
+ * Imp: command line options
+ * Imp: uncompress ZIP files
+ * Dat: zlib is able to read uncompressed files, libbz2 isn't
+ * Dat: magic numbers:
+ *  257     string          ustar\0         POSIX tar archive
+ *  257     string          ustar\040\040\0 GNU tar archive
+ *  0       string          BZh             bzip2 compressed data
+ *  0       string          \037\213        gzip compressed data
+ *  0       string          \037\235        compress'd data
+ *  is_tar.c() from file(1)
+ */
+
+#undef DOSISH
+#if defined(WIN32) || defined(__MINGW32__) || defined(__CYGWIN__) || MSC_VER > 1000
+#  include <windows.h>
+#  define DOSISH 1
+#  undef __STRICT_ANSI__
+#endif
+#ifdef MSDOS
+#  define DOSISH 1
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef DOSISH
+# include <direct.h>
+# include <io.h>
+#else
+# include <unistd.h>
+#endif
+
+#if DOSISH
+#  ifndef F_OK
+#    define F_OK (0)
+#  endif
+#  ifdef _MSC_VER
+#    define mkdir(dirname,mode) _mkdir(dirname)
+#    define unlink(fn)          _unlink(fn)
+#    define access(path,mode)   _access(path,mode)
+#  else
+#    define mkdir(dirname,mode) _mkdir(dirname)
+#  endif
+#else
+#  include <utime.h>
+#  include <sys/stat.h> /* mkdir() */
+#endif
+
+#ifndef OF /* function prototypes */
+#  if defined(__STDC__) || defined(__PROTOTYPES__) || defined(__cplusplus)
+#    define OF(args)  args
+#  else
+#    define OF(args)  args
+#  endif
+#endif
+
+static void error OF((const char *msg));
+
+/* #define TAR_GZ 1 */
+
+typedef struct Readable {
+  /*private*/ void *f;
+  /** @return 0 on success, 1 on failure */
+  int (*xOpen4Read)(struct Readable* self, char const* filename);
+  /** @return 0 on success */
+  int (*xClose)(struct Readable* self);
+  /** @return (unsigned)-1 on error */
+  unsigned (*xRead)(struct Readable* self, void* buf, unsigned len);
+  char const* (*xError)(struct Readable* self, int *errnum_ret);
+} Readable;
+
+enum { FMT_U=1, FMT_Z=2, FMT_GZ=3, FMT_BZ2=4 };
+
+/* #define xFILE FILE* */
+static int xU_Open4Read(struct Readable* self, char const* filename) { return NULL==(self->f=fopen(filename,"rb")); }
+static int xU_Close(struct Readable* self) { return fclose((FILE*)self->f); }
+static unsigned xU_Read(struct Readable* self, void* buf, unsigned len) {
+  unsigned got=fread(buf,1,len,(FILE*)self->f);
+  return got>0 ? got : ferror((FILE*)self->f) ? 0U-1 : 0;
+}
+static char const* xU_Error(struct Readable* self, int *errnum_ret) { return (*errnum_ret=ferror((FILE*)self->f))?"I/O error":"OK"; }
+
+/* #define xFILE struct lz_reader_t* */
+struct lz_reader_t;
+static struct lz_reader_t* lz_read_new(FILE* inf);
+static int lz_read_init(struct lz_reader_t* reader, FILE* inf);
+static int lz_close(struct lz_reader_t* reader);
+static unsigned lz_read(struct lz_reader_t* reader, char*buf, unsigned len);
+
+static int xZ_Open4Read(struct Readable* self, char const* filename) {
+  FILE *f=fopen(filename,"rb");
+  if (NULL==f) return 1;
+  return NULL==(self->f=lz_read_new(f));
+}
+static int xZ_Close(struct Readable* self) {
+  int ret=lz_close((struct lz_reader_t*)self->f);
+  free((struct lz_reader_t*)self->f);
+  return ret;
+}
+static unsigned xZ_Read(struct Readable* self, void* buf, unsigned len) {
+  return lz_read((struct lz_reader_t*)self->f, buf, len);
+}
+static char const* xZ_Error(struct Readable* self, int *errnum_ret) {
+  (void)self;
+  *errnum_ret=0;
+  return "lzw error";
+}
+
+#if HAVE_ZLIB
+#include "zlib.h"
+/* #define xFILE gzFile */
+static int xGZ_Open4Read(struct Readable* self, char const* filename) { return NULL==(self->f=gzopen(filename,"rb")); }
+static int xGZ_Close(struct Readable* self) { return gzclose((gzFile)self->f); }
+static unsigned xGZ_Read(struct Readable* self, void* buf, unsigned len) { return gzread((gzFile)self->f,buf,len); }
+static char const* xGZ_Error(struct Readable* self, int *errnum_ret) { return gzerror((gzFile)self->f, errnum_ret); }
+#endif
+
+#if HAVE_BZ2LIB
+#include "bzlib.h"
+/* #define xFILE BZFILE* */
+static int xBZ2_Open4Read(struct Readable* self, char const* filename) { return NULL==(self->f=BZ2_bzopen(filename,"rb")); }
+static int xBZ2_Close(struct Readable* self) { BZ2_bzclose((BZFILE*)self->f); return 0; }
+static unsigned xBZ2_Read(struct Readable* self, void* buf, unsigned len) { return BZ2_bzread((BZFILE*)self->f,buf,len); }
+static char const* xBZ2_Error(struct Readable* self, int *errnum_ret) { return BZ2_bzerror((BZFILE*)self->f, errnum_ret); }
+#endif
+
+/* -- is_tar() */
+
+/*
+ * is_tar() -- figure out whether file is a tar archive.
+ *
+ * Stolen (by the author!) from the public domain tar program:
+ * Public Domain version written 26 Aug 1985 John Gilmore (ihnp4!hoptoad!gnu).
+ *
+ * @(#)list.c 1.18 9/23/86 Public Domain - gnu
+ * $Id$
+ *
+ * Comments changed and some code/comments reformatted
+ * for file command by Ian Darwin.
+ */
+
+/* The magic field is filled with this if uname and gname are valid. */
+#define        TMAGIC          "ustar  "       /* 7 chars and a null */
+
+/*
+ * Header block on tape.
+ *
+ * I'm going to use traditional DP naming conventions here.
+ * A "block" is a big chunk of stuff that we do I/O on.
+ * A "record" is a piece of info that we care about.
+ * Typically many "record"s fit into a "block".
+ */
+#define        RECORDSIZE      512
+#define        NAMSIZ  100
+#define        TUNMLEN 32
+#define        TGNMLEN 32
+
+union tar_record {
+       char            charptr[RECORDSIZE];
+       struct header {
+               char    name[NAMSIZ];
+               char    mode[8];
+               char    uid[8];
+               char    gid[8];
+               char    size[12];
+               char    mtime[12];
+               char    chksum[8];
+               char    linkflag;
+               char    linkname[NAMSIZ];
+               char    magic[8];
+               char    uname[TUNMLEN];
+               char    gname[TGNMLEN];
+               char    devmajor[8];
+               char    devminor[8];
+       } header;
+};
+
+#define        isodigit(c)     ( ((c) >= '0') && ((c) <= '7') )
+
+static int from_oct(int, char *);      /* Decode octal number */
+
+/*
+ * Return
+ *     0 if the checksum is bad (i.e., probably not a tar archive),
+ *     1 for old UNIX tar file,
+ *     2 for Unix Std (POSIX) tar file.
+ */
+static int
+is_tar(char *buf, unsigned nbytes)
+{
+       union tar_record *header = (union tar_record *)buf;
+       int     i;
+       int     sum, recsum;
+       char    *p;
+
+       if (nbytes < sizeof(union tar_record))
+               return 0;
+
+       recsum = from_oct(8,  header->header.chksum);
+
+       sum = 0;
+       p = header->charptr;
+       for (i = sizeof(union tar_record); --i >= 0;) {
+               /*
+                * We can't use unsigned char here because of old compilers,
+                * e.g. V7.
+                */
+               sum += 0xFF & *p++;
+       }
+
+       /* Adjust checksum to count the "chksum" field as blanks. */
+       for (i = sizeof(header->header.chksum); --i >= 0;)
+               sum -= 0xFF & header->header.chksum[i];
+       sum += ' '* sizeof header->header.chksum;
+
+       if (sum != recsum)
+               return 0;       /* Not a tar archive */
+
+       if (0==strcmp(header->header.magic, TMAGIC))
+               return 2;               /* Unix Standard tar archive */
+
+       return 1;                       /* Old fashioned tar archive */
+}
+
+
+/*
+ * Quick and dirty octal conversion.
+ *
+ * Result is -1 if the field is invalid (all blank, or nonoctal).
+ */
+static int
+from_oct(int digs, char *where)
+{
+       int     value;
+
+       while (*where==' ' || *where=='\f' || *where=='\n' || *where=='\r' || *where=='\t' || *where=='\v') {
+               where++;
+               if (--digs <= 0)
+                       return -1;              /* All blank field */
+       }
+       value = 0;
+       while (digs > 0 && isodigit(*where)) {  /* Scan til nonoctal */
+               value = (value << 3) | (*where++ - '0');
+               --digs;
+       }
+
+       if (digs > 0 && *where!='\0' && *where!=' ' && *where!='\f' && *where!='\n' && *where!='\r' && *where!='\t' && *where!='\v')
+               return -1;                      /* Ended on non-space/nul */
+
+       return value;
+}
+
+
+/* --- */
+
+/** Constructor.
+ * @return 0 on success, positive for various failure reasons
+ */
+static int xOpen4Read(struct Readable *self, char const* filename) {
+  unsigned i;
+  char buf[RECORDSIZE];
+  FILE *f=fopen(filename, "rb");
+  if (f==NULL) return 4;
+  i=sizeof(buf); while (i--!=0) buf[i]='\0';
+  if (5>fread(buf, 1, sizeof(buf), f)) return 2;
+  if (0) {
+  } else if (buf[0]==0102 && buf[1]==0132 && buf[2]==0150) {
+#if HAVE_BZ2LIB
+    fclose(f);
+    self->xOpen4Read=xBZ2_Open4Read;
+    self->xClose=xBZ2_Close;
+    self->xRead=xBZ2_Read;
+    self->xError=xBZ2_Error;
+    if (xBZ2_Open4Read(self, filename)!=0) return 1;
+#else
+    error("bzip2 compression not compiled in");
+#endif
+  } else if (buf[0]==0037 && (buf[1]&255)==0213 && (buf[2]&255)<=8) {
+#if HAVE_ZLIB
+    fclose(f);
+    self->xOpen4Read=xGZ_Open4Read;
+    self->xClose=xGZ_Close;
+    self->xRead=xGZ_Read;
+    self->xError=xGZ_Error;
+    if (xGZ_Open4Read(self, filename)!=0) return 1;
+#else
+    error("gzip compression not compiled in");
+#endif
+  } else if (buf[0]==0037 && (buf[1]&255)==0235) {
+    fclose(f);
+    self->xOpen4Read=xZ_Open4Read;
+    self->xClose=xZ_Close;
+    self->xRead=xZ_Read;
+    self->xError=xZ_Error;
+    if (xZ_Open4Read(self, filename)!=0) return 1;
+  } else if ((buf[257]==0165 && buf[258]==0163 && buf[259]==0164
+           && buf[260]==0141 && buf[261]==0162
+           && (buf[262]==0000 || (buf[262]==0040 && buf[263]==0040 && buf[264]==0))
+             ) || is_tar(buf, sizeof(buf))
+            ) {
+    rewind(f);
+    self->f=f; /* shortcut */
+    self->xOpen4Read=xU_Open4Read;
+    self->xClose=xU_Close;
+    self->xRead=xU_Read;
+    self->xError=xU_Error;
+  } else return 3;
+  return 0;
+}
+
+/* --- .Z LZ uncompression */
+
+/* code derived from
+ * (N)compress42.c - File compression ala IEEE Computer, Mar 1992.
+ * Modified by pts@fazekas.hu at Wed Jul 18 17:25:38 CEST 2001.
+ *
+ * Authors:
+ *   Spencer W. Thomas   (decvax!harpo!utah-cs!utah-gr!thomas)
+ *   Jim McKie           (decvax!mcvax!jim)
+ *   Steve Davies        (decvax!vax135!petsd!peora!srd)
+ *   Ken Turkowski       (decvax!decwrl!turtlevax!ken)
+ *   James A. Woods      (decvax!ihnp4!ames!jaw)
+ *   Joe Orost           (decvax!vax135!petsd!joe)
+ *   Dave Mack           (csu@alembic.acs.com)
+ *   Peter Jannesen, Network Communication Systems
+ *                       (peter@ncs.nl)
+ *
+ * Revision 4.2.3  92/03/14 peter@ncs.nl
+ *   Optimise compress and decompress function and a lot of cleanups.
+ *   New fast hash algoritme added (if more than 800Kb available).
+ */
+#define IBUFSIZ 4096
+
+#define NOFUNCDEF
+#undef DOS
+#undef COMPATIBLE
+#undef DONTPTS /* `#define DONTPTS 1' means original uncompress */
+#undef DIRENT
+#undef RECURSIVE
+#undef SYSDIR
+#undef UTIME_H
+#undef BYTEORDER
+#define BITS 16 /* _must_ be able to handle this many bits, anyway */
+#define FAST
+#if 1 /* !! */
+#  define ASSERT(x) do { if (!(x)) abort(); } while(0)
+#else
+#  define ASSERT(x)
+#endif
+
+#include <stdio.h>
+#include <string.h> /* memcpy(), memset() */
+#include <stdlib.h> /* abort(), exit() */
+
+/* #define fx_write(a,b,c) fwrite((b),1,(c),(a)) */
+#define fx_read(a,b,c)  fread( (b),1,(c),(a))
+#define fx_stdin        stdin
+#define fx_stdout       stdout
+#define fx_type         FILE*
+
+#ifndef NOFUNCDEF
+#define    LARGS(a)    ()    /* Relay on include files for libary func defs. */
+    extern    void    *malloc LARGS((int));
+    extern    void    free    LARGS((void *));
+#ifndef _IBMR2
+    extern    int        open    LARGS((char const *,int,...));
+#endif
+    extern    int        close    LARGS((int));
+    extern    int        read    LARGS((int,void *,int));
+    extern    int        write    LARGS((int,void const *,int));
+    extern    int        chmod    LARGS((char const *,int));
+    extern    int        unlink    LARGS((char const *));
+    extern    int        chown    LARGS((char const *,int,int));
+    extern    int        utime    LARGS((char const *,struct utimbuf const *));
+    extern    char    *strcpy    LARGS((char *,char const *));
+    extern    char    *strcat    LARGS((char *,char const *));
+    extern    int        strcmp    LARGS((char const *,char const *));
+    extern    unsigned strlen    LARGS((char const *));
+    extern    void    *memset    LARGS((void *,char,unsigned int));
+    extern    void    *memcpy    LARGS((void *,void const *,unsigned int));
+    extern    int        atoi    LARGS((char const *));
+    extern    void    exit    LARGS((int));
+    extern    int        isatty    LARGS((int));
+#endif
+
+#ifdef    DEF_ERRNO
+    extern int    errno;
+#endif
+
+#undef    min
+#define   min(a,b)    ((a>b) ? b : a)
+
+#define    MAGIC_1        (char_type)'\037'/* First byte of compressed file                */
+#define    MAGIC_2        (char_type)'\235'/* Second byte of compressed file                */
+#define BIT_MASK    0x1f            /* Mask for 'number of compresssion bits'        */
+                                    /* Masks 0x20 and 0x40 are free.                  */
+                                    /* I think 0x20 should mean that there is        */
+                                    /* a fourth header byte (for expansion).        */
+#define BLOCK_MODE    0x80          /* Block compresssion if table is full and        */
+                                    /* compression rate is dropping flush tables    */
+
+            /* the next two codes should not be changed lightly, as they must not   */
+            /* lie within the contiguous general code space.                        */
+#define FIRST    257                    /* first free entry                             */
+#define CLEAR    256                    /* table clear output code                         */
+
+#define INIT_BITS 9            /* initial number of bits/code */
+
+#ifndef    BYTEORDER
+#    define    BYTEORDER    0000
+#endif
+
+#ifndef    NOALLIGN
+#    define    NOALLIGN    0
+#endif
+
+/*
+ * machine variants which require cc -Dmachine:  pdp11, z8000, DOS
+ */
+
+#ifdef interdata    /* Perkin-Elmer                                                    */
+#    define SIGNED_COMPARE_SLOW    /* signed compare is slower than unsigned             */
+#endif
+
+#ifdef MSDOS            /* PC/XT/AT (8088) processor                                    */
+#    undef    BYTEORDER
+#    define    BYTEORDER     4321
+#    undef    NOALLIGN
+#    define    NOALLIGN    1
+#endif /* DOS */
+
+#ifndef    O_BINARY
+#    define    O_BINARY    0    /* System has no binary mode                            */
+#endif
+
+typedef long int code_int;
+
+#ifdef SIGNED_COMPARE_SLOW
+    typedef unsigned short int   count_short;
+    typedef unsigned long int    cmp_code_int;    /* Cast to make compare faster    */
+#else
+    typedef long int             cmp_code_int;
+#endif
+
+typedef    unsigned char    char_type;
+
+#define MAXCODE(n)    (1L << (n))
+
+#ifndef    REGISTERS
+#    define    REGISTERS    20
+#endif
+#define    REG1
+#define    REG2
+#define    REG3
+#define    REG4
+#define    REG5
+#define    REG6
+#define    REG7
+#define    REG8
+#define    REG9
+#define    REG10
+#define    REG11
+#define    REG12
+#define    REG13
+#define    REG14
+#define    REG15
+#define    REG16
+#if REGISTERS >= 1
+#    undef    REG1
+#    define    REG1    register
+#endif
+#if REGISTERS >= 2
+#    undef    REG2
+#    define    REG2    register
+#endif
+#if REGISTERS >= 3
+#    undef    REG3
+#    define    REG3    register
+#endif
+#if REGISTERS >= 4
+#    undef    REG4
+#    define    REG4    register
+#endif
+#if REGISTERS >= 5
+#    undef    REG5
+#    define    REG5    register
+#endif
+#if REGISTERS >= 6
+#    undef    REG6
+#    define    REG6    register
+#endif
+#if REGISTERS >= 7
+#    undef    REG7
+#    define    REG7    register
+#endif
+#if REGISTERS >= 8
+#    undef    REG8
+#    define    REG8    register
+#endif
+#if REGISTERS >= 9
+#    undef    REG9
+#    define    REG9    register
+#endif
+#if REGISTERS >= 10
+#    undef    REG10
+#    define    REG10    register
+#endif
+#if REGISTERS >= 11
+#    undef    REG11
+#    define    REG11    register
+#endif
+#if REGISTERS >= 12
+#    undef    REG12
+#    define    REG12    register
+#endif
+#if REGISTERS >= 13
+#    undef    REG13
+#    define    REG13    register
+#endif
+#if REGISTERS >= 14
+#    undef    REG14
+#    define    REG14    register
+#endif
+#if REGISTERS >= 15
+#    undef    REG15
+#    define    REG15    register
+#endif
+#if REGISTERS >= 16
+#    undef    REG16
+#    define    REG16    register
+#endif
+
+#if BYTEORDER == 4321 && NOALLIGN == 1
+#define    input(b,o,c,n,m){                                                 \
+                            (c) = (*(long *)(&(b)[(o)>>3])>>((o)&0x7))&(m);  \
+                            (o) += (n);                                      \
+                        }
+#else
+#define    input(b,o,c,n,m){    REG1 char_type         *p = &(b)[(o)>>3];    \
+                            (c) = ((((long)(p[0]))|((long)(p[1])<<8)|        \
+                                     ((long)(p[2])<<16))>>((o)&0x7))&(m);    \
+                            (o) += (n);                                      \
+                        }
+#endif
+
+/*
+ * 8086 & 80286 Has a problem with array bigger than 64K so fake the array
+ * For processors with a limited address space and segments.
+ */
+/*
+ * To save much memory, we overlay the table used by compress() with those
+ * used by lz_decompress().  The tab_prefix table is the same size and type
+ * as the codetab.  The tab_suffix table needs 2**BITS characters.  We
+ * get this from the beginning of htab.  The output stack uses the rest
+ * of htab, and contains characters.  There is plenty of room for any
+ * possible stack (stack used to be 8000 characters).
+ */
+#ifdef MAXSEG_64K
+ #error removed MAXSEG_64K
+#else    /* Normal machine */
+#    define HSIZE (1<<16) /* (1<<15) is few, (1<<16) seems to be OK, (1<<17) is proven safe OK */
+#if 0
+    char_type lz_htab[2*HSIZE]; /* Dat: HSIZE for the codes and HSIZE for de_stack */
+    unsigned short lz_codetab[HSIZE];
+#endif
+#    define    tab_prefixof(i)         codetab[i]
+#    define    tab_suffixof(i)         htab[i]
+#    define    de_stack                (htab+(sizeof(htab[0])*(2*HSIZE-1)))
+#    define    clear_tab_prefixof()    memset(codetab, 0, 256*sizeof(codetab[0]));
+#endif    /* MAXSEG_64K */
+
+typedef struct lz_reader_t {
+  /* constants (don't change during decompression) */
+  fx_type fdin;
+  char_type* inbuf; /* [IBUFSIZ+64];  Input buffer */
+  char_type* htab; /* [2*HSIZE];  Dat: HSIZE for the codes and HSIZE for de_stack */
+  unsigned short* codetab; /* [HSIZE]; */
+  int blkmode;
+  code_int maycode;
+
+  /* variables that have to be saved */
+  char_type        *stackp;
+  code_int         code;
+  int              finchar;
+  code_int         oldcode;
+  code_int         incode;
+  int              inbits;
+  int              posbits;
+  int              insize;
+  int              bitmask;
+  code_int         freeent;
+  code_int         maxcode;
+  int              n_bits;
+  int              rsize;
+  int              maxbits;
+} lz_reader_t;
+
+static struct lz_reader_t* lz_read_new(FILE *inf) {
+  lz_reader_t* reader=(lz_reader_t*)malloc(sizeof(lz_reader_t));
+  reader->fdin=NULL;
+  if (reader!=NULL) {
+    if (lz_read_init(reader, inf)!=0) {
+      lz_close(reader);
+      free(reader); reader=NULL;
+    }
+  }
+  return reader;
+}
+static int lz_close(struct lz_reader_t* reader) {
+  FILE *fin=reader->fdin;
+  reader->rsize=-1;
+  if (reader->inbuf!=NULL)   { free(reader->inbuf  ); reader->inbuf  =NULL; }
+  if (reader->htab!=NULL)    { free(reader->htab   ); reader->htab   =NULL; }
+  if (reader->codetab!=NULL) { free(reader->codetab); reader->codetab=NULL; }
+  if (fin==NULL) return 0;
+  reader->fdin=NULL;
+  return fclose(fin);
+}
+/** @param Zreader uninitialized
+ * @return 0 on success
+ */
+static int lz_read_init(struct lz_reader_t* reader, FILE *inf) {
+  char_type* htab;
+  unsigned short* codetab;
+  code_int codex;
+  reader->fdin=inf;
+  if (NULL==(reader->inbuf=malloc(IBUFSIZ+67))) return 1;
+  if (NULL==(htab=reader->htab=malloc(2*HSIZE))) return 1; /* Dat: HSIZE for the codes and HSIZE for de_stack */
+  if (NULL==(codetab=reader->codetab=malloc(sizeof(reader->codetab[0])*HSIZE))) return 1;
+  reader->insize=0;
+  reader->rsize=0;
+  while (reader->insize < 3 && (reader->rsize = fx_read(reader->fdin, reader->inbuf+reader->insize, IBUFSIZ)) > 0)
+      reader->insize += reader->rsize;
+
+  if (reader->insize < 3
+   || reader->inbuf[0] != (char_type)'\037' /* First byte of compressed file */
+   || reader->inbuf[1] != (char_type)'\235' /* Second byte of compressed file */
+  ) return reader->insize >= 0 ? 2 : 3;
+
+  reader->maxbits = reader->inbuf[2] & BIT_MASK;
+  reader->blkmode = reader->inbuf[2] & BLOCK_MODE;
+  reader->maycode = MAXCODE(reader->maxbits);
+
+  if (reader->maxbits > BITS) return 4;
+#if 0
+      fprintf(stderr,
+              "%s: compressed with %d bits, can only handle %d bits\n",
+              ("stdin"), maxbits, BITS);
+      return 4;
+#endif
+
+  reader->maxcode = MAXCODE(reader->n_bits = INIT_BITS)-1;
+  reader->bitmask = (1<<reader->n_bits)-1;
+  reader->oldcode = -1;
+  reader->finchar = 0;
+  reader->posbits = 3<<3;
+  reader->stackp  = NULL;
+  reader->code    = -1;
+  reader->incode  = -1; /* fake */
+  reader->inbits  = 0;  /* fake */
+
+  reader->freeent = ((reader->blkmode) ? FIRST : 256);
+
+  clear_tab_prefixof();    /* As above, initialize the first 256 entries in the table. */
+
+  for (codex = 255 ; codex >= 0 ; --codex)
+      tab_suffixof(codex) = (char_type)codex;
+  return 0; /* success */
+}
+
+/*
+ * Decompress stdin to stdout.  This routine adapts to the codes in the
+ * file building the "string" table on-the-fly; requiring no table to
+ * be stored in the compressed file.  The tables used herein are shared
+ * with those of the compress() routine.  See the definitions above.
+ */
+static unsigned lz_read(struct lz_reader_t* reader, char* outbuf, unsigned obufsize) {
+/* static int lz_decompress(fx_type fdin, fx_type fdout) */
+  REG2    char_type        *stackp;
+  REG3    code_int         code;
+  REG4    int              finchar;
+  REG5    code_int         oldcode;
+  REG6    code_int         incode;
+  REG7    int              inbits;
+  REG8    int              posbits;
+  REG10   int              insize;
+  REG11   int              bitmask;
+  REG12   code_int         freeent;
+  REG13   code_int         maxcode;
+  REG14   code_int         maycode;
+  REG15   int              n_bits;
+  REG16   int              rsize;
+          int              blkmode;
+          int              maxbits;
+          char_type* inbuf;
+          char_type* htab;
+          unsigned short* codetab;
+          fx_type fdin;
+  REG9    unsigned outpos=0; /* not restored */
+
+#if 0
+  fprintf(stderr, ":: call rsize=%d oldcode=%d\n", reader->rsize, (int)reader->oldcode);
+#endif
+  if (reader->rsize<1) return reader->rsize; /* already EOF or error */
+
+  stackp =reader->stackp;
+  code   =reader->code;
+  finchar=reader->finchar;
+  oldcode=reader->oldcode;
+  incode =reader->incode;
+  inbits =reader->inbits;
+  posbits=reader->posbits;
+  insize =reader->insize;
+  bitmask=reader->bitmask;
+  freeent=reader->freeent;
+  maxcode=reader->maxcode;
+  maycode=reader->maycode;
+  n_bits =reader->n_bits;
+  rsize  =reader->rsize;
+  blkmode=reader->blkmode;
+  maxbits=reader->maxbits;
+  htab   =reader->htab;
+  codetab=reader->codetab;
+  fdin   =reader->fdin;
+  inbuf  =reader->inbuf;
+  if (oldcode!=-1) goto try_fit; /* lz_read() called again */
+
+  do {
+    resetbuf: ;
+    {
+      REG1     int    i;
+      int                e;
+      int                o;
+
+      e = insize-(o = (posbits>>3));
+
+      for (i = 0 ; i < e ; ++i)
+          inbuf[i] = inbuf[i+o];
+
+      insize = e;
+      posbits = 0;
+    }
+
+    if ((unsigned)insize < /*sizeof(inbuf)-IBUFSIZ*/ 64) {
+#if 0
+      fprintf(stderr, ":: try read insize=%d\n", insize);
+#endif
+      if ((rsize = fx_read(fdin, inbuf+insize, IBUFSIZ)) < 0 || ferror(fdin)) return reader->rsize=-1;
+#if 0
+      fprintf(stderr, ":: got rsize=%d\n", rsize);
+#endif
+      insize += rsize;
+      inbuf[insize]=inbuf[insize+1]=inbuf[insize+2]=0;
+      /* ^^^ sentinel, so input() won't produce ``read uninitialized byte(s) in a block.'' */
+    }
+
+    inbits = ((rsize > 0) ? (insize - insize%n_bits)<<3 :
+                            (insize<<3)-(n_bits-1));
+
+    while (inbits > posbits) {
+      if (freeent > maxcode) {
+        posbits = ((posbits-1) + ((n_bits<<3) -
+                         (posbits-1+(n_bits<<3))%(n_bits<<3)));
+        ++n_bits;
+        if (n_bits == maxbits)
+            maxcode = maycode;
+        else
+            maxcode = MAXCODE(n_bits)-1;
+
+        bitmask = (1<<n_bits)-1;
+        goto resetbuf;
+      }
+
+#if 0
+      fputc('#',stderr);
+#endif
+      input(inbuf,posbits,code,n_bits,bitmask);
+
+      if (oldcode == -1) {
+        outbuf[outpos++] = (char_type)(finchar = (int)(oldcode = code));
+        continue;
+      }
+      /* Dat: oldcode will never be -1 again */
+
+      if (code == CLEAR && blkmode) {
+        clear_tab_prefixof();
+        freeent = FIRST - 1;
+        posbits = ((posbits-1) + ((n_bits<<3) -
+                    (posbits-1+(n_bits<<3))%(n_bits<<3)));
+        maxcode = MAXCODE(n_bits = INIT_BITS)-1;
+        bitmask = (1<<n_bits)-1;
+        goto resetbuf;
+      }
+
+      incode = code;
+      stackp = de_stack;
+
+      if (code >= freeent) {    /* Special case for KwKwK string.    */
+        if (code > freeent) {
+            REG1 char_type         *p;
+
+            posbits -= n_bits;
+            p = &inbuf[posbits>>3];
+
+#if 0
+            fprintf(stderr, "uncompress: insize:%d posbits:%d inbuf:%02X %02X %02X %02X %02X (%d)\n", insize, posbits,
+                    p[-1],p[0],p[1],p[2],p[3], (posbits&07));
+            fprintf(stderr, "uncompress: corrupt input\n");
+            abort();
+#else
+            return reader->rsize=-1;
+#endif
+        }
+
+        *--stackp = (char_type)finchar;
+        code = oldcode;
+      }
+
+      while ((cmp_code_int)code >= (cmp_code_int)256) {
+        /* Generate output characters in reverse order */
+        *--stackp = tab_suffixof(code);
+        code = tab_prefixof(code);
+      }
+#if 0
+      fprintf(stderr, ":: to stack code=%d\n", (int)code);
+#endif
+      *--stackp =    (char_type)(finchar = tab_suffixof(code));
+      ASSERT(outpos<=obufsize);
+
+      /* And put them out in forward order */
+      {
+        REG1 int    i;
+
+        try_fit: if (outpos+(i = (de_stack-stackp)) >= obufsize) {
+          /* The entire stack doesn't fit into the outbuf */
+          i=obufsize-outpos;
+          memcpy(outbuf+outpos, stackp, i);
+          stackp+=i;
+          /* vvv Dat: blkmode, maycode, inbuf, htab, codetab, fdin need not be saved */
+          reader->stackp =stackp;
+          reader->code   =code;
+          reader->finchar=finchar;
+          reader->oldcode=oldcode;
+          reader->incode =incode;
+          reader->inbits =inbits;
+          reader->posbits=posbits;
+          reader->insize =insize;
+          reader->bitmask=bitmask;
+          reader->freeent=freeent;
+          reader->maxcode=maxcode;
+          reader->maycode=maycode;
+          reader->n_bits =n_bits;
+          reader->rsize  =rsize;
+          reader->blkmode=blkmode;
+          reader->maxbits=maxbits;
+#if 0
+          fprintf(stderr, ":: return obufsize=%d oldcode=%d\n", obufsize, (int)oldcode);
+#endif
+          return obufsize;
+          /* Dat: co-routine return back to try_fit, with outpos==0, outbuf=... obufsize=... */
+        } else {
+          memcpy(outbuf+outpos, stackp, i);
+          outpos += i;
+        }
+      }
+      /* Dat: ignore stackp from now */
+
+      if ((code = freeent) < maycode) { /* Generate the new entry. */
+#if 0
+        fprintf(stderr, ":: new entry code=(%d)\n", (int)code);
+#endif
+        tab_prefixof(code) = (unsigned short)oldcode;
+        tab_suffixof(code) = (char_type)finchar;
+        freeent = code+1;
+      }
+      oldcode = incode;    /* Remember previous code.    */
+    }
+  } while (rsize > 0);
+  reader->rsize=0;
+  return outpos;
+}
+
+/* --- */
+
+/* Values used in typeflag field.  */
+
+#define REGTYPE         '0'            /* regular file */
+#define AREGTYPE '\0'          /* regular file */
+#define LNKTYPE  '1'           /* link */
+#define SYMTYPE  '2'           /* reserved */
+#define CHRTYPE  '3'           /* character special */
+#define BLKTYPE  '4'           /* block special */
+#define DIRTYPE  '5'           /* directory */
+#define FIFOTYPE '6'           /* FIFO special */
+#define CONTTYPE '7'           /* reserved */
+
+#define BLOCKSIZE 512
+
+struct tar_header
+{                              /* byte offset */
+  char name[100];              /*   0 */
+  char mode[8];                        /* 100 */
+  char uid[8];                 /* 108 */
+  char gid[8];                 /* 116 */
+  char size[12];               /* 124 */
+  char mtime[12];              /* 136 */
+  char chksum[8];              /* 148 */
+  char typeflag;               /* 156 */
+  char linkname[100];          /* 157 */
+  char magic[6];               /* 257 */
+  char version[2];             /* 263 */
+  char uname[32];              /* 265 */
+  char gname[32];              /* 297 */
+  char devmajor[8];            /* 329 */
+  char devminor[8];            /* 337 */
+  char prefix[155];            /* 345 */
+                               /* 500 */
+};
+
+union tar_buffer {
+  char               buffer[BLOCKSIZE];
+  struct tar_header  header;
+};
+
+enum { TGZ_EXTRACT = 0, TGZ_LIST };
+
+#if 0
+static char *TGZfname  OF((const char *));
+void TGZnotfound       OF((const char *));
+
+int getoct             OF((char *, int));
+char *strtime          OF((time_t *));
+int ExprMatch          OF((char *,char *));
+
+int makedir            OF((char *));
+int matchname          OF((int,int,char **,char *));
+
+void error             OF((const char *));
+int  tar               OF((gzFile, int, int, int, char **));
+
+void help              OF((int));
+int main               OF((int, char **));
+#endif
+
+static char *prog;
+
+static void error(const char *msg) {
+  fprintf(stderr, "%s: %s\n", prog, msg);
+  exit(1);
+}
+
+/* This will give a benign warning */
+
+static char *TGZprefix[] = { "\0", ".tgz", ".tar.gz", ".tar.bz2", ".tar.Z", ".tar", NULL };
+
+/* Return the real name of the TGZ archive */
+/* or NULL if it does not exist. */
+
+static char *TGZfname OF((const char *fname))
+{
+  static char buffer[1024];
+  int origlen,i;
+
+  strcpy(buffer,fname);
+  origlen = strlen(buffer);
+
+  for (i=0; TGZprefix[i]; i++)
+    {
+       strcpy(buffer+origlen,TGZprefix[i]);
+       if (access(buffer,F_OK) == 0)
+         return buffer;
+    }
+  return NULL;
+}
+
+/* error message for the filename */
+
+static void TGZnotfound OF((const char *fname))
+{
+  int i;
+
+  fprintf(stderr,"%s : couldn't find ",prog);
+  for (i=0;TGZprefix[i];i++)
+    fprintf(stderr,(TGZprefix[i+1]) ? "%s%s, " : "or %s%s\n",
+            fname,
+            TGZprefix[i]);
+  exit(1);
+}
+
+
+/* help functions */
+
+static int getoct(char *p,int width)
+{
+  int result = 0;
+  char c;
+
+  while (width --)
+    {
+      c = *p++;
+      if (c == ' ')
+       continue;
+      if (c == 0)
+       break;
+      result = result * 8 + (c - '0');
+    }
+  return result;
+}
+
+static char *strtime (time_t *t)
+{
+  struct tm   *local;
+  static char result[32];
+
+  local = localtime(t);
+  sprintf(result,"%2d/%02d/%4d %02d:%02d:%02d",
+         local->tm_mday, local->tm_mon+1, local->tm_year+1900,
+         local->tm_hour, local->tm_min,   local->tm_sec);
+  return result;
+}
+
+
+/* regular expression matching */
+
+#define ISSPECIAL(c) (((c) == '*') || ((c) == '/'))
+
+static int ExprMatch(char *string,char *expr)
+{
+  while (1)
+    {
+      if (ISSPECIAL(*expr))
+       {
+         if (*expr == '/')
+           {
+             if (*string != '\\' && *string != '/')
+               return 0;
+             string ++; expr++;
+           }
+         else if (*expr == '*')
+           {
+             if (*expr ++ == 0)
+               return 1;
+             while (*++string != *expr)
+               if (*string == 0)
+                 return 0;
+           }
+       }
+      else
+       {
+         if (*string != *expr)
+           return 0;
+         if (*expr++ == 0)
+           return 1;
+         string++;
+       }
+    }
+}
+
+/* recursive make directory */
+/* abort if you get an ENOENT errno somewhere in the middle */
+/* e.g. ignore error "mkdir on existing directory" */
+/* */
+/* return 1 if OK */
+/*        0 on error */
+
+static int makedir (char *newdir) {
+  /* avoid calling strdup, since it's not ansi C */
+  int  len = strlen(newdir);
+  char *p, *buffer = malloc(len+1);
+  if (buffer==NULL) error("out of memory");
+  memcpy(buffer,newdir,len+1);
+
+  if (len <= 0) {
+    free(buffer);
+    return 0;
+  }
+  if (buffer[len-1] == '/') {
+    buffer[len-1] = '\0';
+  }
+  if (mkdir(buffer, 0775) == 0)
+    {
+      free(buffer);
+      return 1;
+    }
+
+  p = buffer+1;
+  while (1)
+    {
+      char hold;
+
+      while(*p && *p != '\\' && *p != '/')
+       p++;
+      hold = *p;
+      *p = 0;
+      if ((mkdir(buffer, 0775) == -1) && (errno == ENOENT))
+       {
+         fprintf(stderr,"%s: couldn't create directory %s\n",prog,buffer);
+         free(buffer);
+         return 0;
+       }
+      if (hold == 0)
+       break;
+      *p++ = hold;
+    }
+  free(buffer);
+  return 1;
+}
+
+static int matchname (int arg,int argc,char **argv,char *fname)
+{
+  if (arg == argc)             /* no arguments given (untgz tgzarchive) */
+    return 1;
+
+  while (arg < argc)
+    if (ExprMatch(fname,argv[arg++]))
+      return 1;
+
+  return 0; /* ignore this for the moment being */
+}
+
+
+/* Tar file list or extract */
+
+static int tar (Readable* rin,int action,int arg,int argc,char **argv, char const* TGZfile, int verbose, void (*step)(void)) {
+  union  tar_buffer buffer;
+  int    is_tar_ok=0;
+  int    len;
+  int    err;
+  int    getheader = 1;
+  int    remaining = 0;
+  FILE   *outfile = NULL;
+  char   fname[BLOCKSIZE];
+  time_t tartime;
+
+#if 0
+  while (0<(len=rin->xRead(rin, &buffer, BLOCKSIZE))) {
+    fwrite(buffer.buffer, 1, len, stdout);
+  }
+  exit(0);
+#endif
+
+  if (action == TGZ_LIST)
+    printf("     day      time     size                       file\n"
+          " ---------- -------- --------- -------------------------------------\n");
+  while (1) {
+      len = rin->xRead(rin, &buffer, BLOCKSIZE);
+      if (len+1 == 0)
+       error (rin->xError(rin, &err));
+      if (!is_tar_ok && !(is_tar_ok=is_tar(buffer.buffer, len))) {
+        fprintf(stderr, "%s: compressed file not tared: %s\n", prog, TGZfile);
+        if (action == TGZ_EXTRACT) {
+          FILE *of;
+          unsigned len0=strlen(TGZfile), len1=len0;
+          char *ofn=malloc(len1+5);
+          if (ofn==NULL) return 1;
+          memcpy(ofn, TGZfile, len1+1);
+          while (len1>0 && ofn[len1]!='/' && ofn[len1]!='\\' && ofn[len1]!='.') len1--;
+          if (ofn[len1]=='.') ofn[len1]='\0'; else strcpy(ofn+len0, ".unc");
+          /* ^^^ remove last extension, or add `.unc' */
+          fprintf(stderr, "%s: extracting as: %s\n", prog, ofn);
+          if (NULL==(of=fopen(ofn, "wb"))) error("fopen write error");
+          do {
+            fwrite(buffer.buffer, 1, len, of);
+            if (ferror(of)) error("write error");
+          } while (0<(len=rin->xRead(rin, &buffer, BLOCKSIZE))); /* Imp: larger blocks */
+          len=ferror(of);
+          if (0!=(len|fclose(of))) error("fclose write error");
+          free(ofn);
+          return 0;
+        }
+        return 1;
+        /* !! */
+      }
+      /*
+       * Always expect complete blocks to process
+       * the tar information.
+       */
+      if (len != BLOCKSIZE)
+       error("read: incomplete block read");
+
+      /*
+       * If we have to get a tar header
+       */
+      if (getheader == 1)
+       {
+         /*
+          * if we met the end of the tar
+          * or the end-of-tar block,
+          * we are done
+          */
+         if ((len == 0)  || (buffer.header.name[0]== 0)) break;
+
+         tartime = (time_t)getoct(buffer.header.mtime,12);
+         strcpy(fname,buffer.header.name);
+
+         switch (buffer.header.typeflag)
+           {
+           case DIRTYPE:
+             if (action == TGZ_LIST)
+               printf(" %s     <dir> %s\n",strtime(&tartime),fname);
+             if (action == TGZ_EXTRACT)
+               makedir(fname);
+             break;
+           case REGTYPE:
+           case AREGTYPE:
+             remaining = getoct(buffer.header.size,12);
+             if (action == TGZ_LIST)
+               printf(" %s %9d %s\n",strtime(&tartime),remaining,fname);
+             if (action == TGZ_EXTRACT)
+               {
+                 if ((remaining) && (matchname(arg,argc,argv,fname)))
+                   {
+                     outfile = fopen(fname,"wb");
+                     if (outfile == NULL) {
+                       /* try creating directory */
+                       char *p = strrchr(fname, '/');
+                       if (p != NULL) {
+                         *p = '\0';
+                         makedir(fname);
+                         *p = '/';
+                         outfile = fopen(fname,"wb");
+                       }
+                     }
+                      if (verbose)
+                       fprintf(stderr,
+                               "%s %s\n",
+                               (outfile) ? "Extracting" : "Couldn't create",
+                               fname);
+                   }
+                 else
+                   outfile = NULL;
+               }
+             /*
+              * could have no contents
+              */
+             getheader = (remaining) ? 0 : 1;
+             break;
+           default:
+             if (action == TGZ_LIST)
+               printf(" %s     <---> %s\n",strtime(&tartime),fname);
+             break;
+           }
+       }
+      else
+       {
+         unsigned int bytes = (remaining > BLOCKSIZE) ? BLOCKSIZE : remaining;
+
+         if ((action == TGZ_EXTRACT) && (outfile != NULL))
+           {
+             if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes)
+               {
+                 fprintf(stderr,"%s : error writing %s skipping...\n",prog,fname);
+                 fclose(outfile);
+                 unlink(fname);
+               }
+           }
+         remaining -= bytes;
+         if (remaining == 0)
+           {
+             getheader = 1;
+             if ((action == TGZ_EXTRACT) && (outfile != NULL))
+               {
+#ifdef WIN32
+                 HANDLE hFile;
+                 FILETIME ftm,ftLocal;
+                 SYSTEMTIME st;
+                 struct tm localt;
+
+                 fclose(outfile);
+
+                 localt = *localtime(&tartime);
+
+                 hFile = CreateFile(fname, GENERIC_READ | GENERIC_WRITE,
+                                    0, NULL, OPEN_EXISTING, 0, NULL);
+
+                 st.wYear = (WORD)localt.tm_year+1900;
+                 st.wMonth = (WORD)localt.tm_mon;
+                 st.wDayOfWeek = (WORD)localt.tm_wday;
+                 st.wDay = (WORD)localt.tm_mday;
+                 st.wHour = (WORD)localt.tm_hour;
+                 st.wMinute = (WORD)localt.tm_min;
+                 st.wSecond = (WORD)localt.tm_sec;
+                 st.wMilliseconds = 0;
+                 SystemTimeToFileTime(&st,&ftLocal);
+                 LocalFileTimeToFileTime(&ftLocal,&ftm);
+                 SetFileTime(hFile,&ftm,NULL,&ftm);
+                 CloseHandle(hFile);
+
+                 outfile = NULL;
+#else
+                 struct utimbuf settime;
+
+                 settime.actime = settime.modtime = tartime;
+
+                 fclose(outfile);
+                 outfile = NULL;
+                 utime(fname,&settime);
+#endif
+                  if (step) step();
+               }
+           }
+       }
+    }
+
+  if (rin->xClose(rin))
+    error("failed gzclose");
+
+  return 0;
+}
+
+
+/* =========================================================== */
+
+static void help(int exitval)
+{
+  fprintf(stderr,
+         "untarka v0.34: super untar + untar.Z"
+#ifdef HAVE_ZLIB
+          " + untar.gz"
+#endif
+#ifdef HAVE_BZ2LIB
+          " + untar.bz2"
+#endif
+         "\ncontains code (C) by pts@fazekas.hu since 2003.01.28\n"
+         "This program is under GPL >=2.0. There is NO WARRANTY. Use at your own risk!\n\n"
+          "Usage: untarka [-x] tarfile          to extract all files\n"
+          "       untarka -x tarfile fname ...  to extract selected files\n"
+          "       untarka -l tarfile            to list archive contents\n"
+          "       untarka -h                    to display this help\n");
+  exit(exitval);
+}
+
+/* ====================================================================== */
+
+#ifdef DOSISH
+extern int _CRT_glob;
+int _CRT_glob = 0;     /* disable globbing of the arguments */
+#endif
+#ifdef COMPILE_MAIN
+int main(int argc,char **argv) {
+    int        action = TGZ_EXTRACT;
+    int        arg = 1;
+    char       *TGZfile;
+    Readable    r;
+
+#if DOSISH
+    setmode(0, O_BINARY);
+#endif
+    prog = strrchr(argv[0],'\\');
+    if (prog == NULL)
+      {
+       prog = strrchr(argv[0],'/');
+       if (prog == NULL)
+         {
+           prog = strrchr(argv[0],':');
+           if (prog == NULL)
+             prog = argv[0];
+           else
+             prog++;
+         }
+       else
+         prog++;
+      }
+    else
+      prog++;
+
+    if (argc == 1)
+      help(0);
+
+    if (strcmp(argv[arg],"-l") == 0 || strcmp(argv[arg],"-v") == 0) {
+      action = TGZ_LIST;
+      if (argc == ++arg) help(0);
+    } else if (strcmp(argv[arg],"-x") == 0) {
+      action = TGZ_EXTRACT;
+      if (argc == ++arg) help(0);
+    } else if (strcmp(argv[arg],"-h") == 0) help(0);
+
+    if ((TGZfile = TGZfname(argv[arg])) == NULL)
+      TGZnotfound(argv[arg]);
+
+    ++arg;
+    if ((action == TGZ_LIST) && (arg != argc))
+      help(1);
+
+    /*
+     *  Process the TGZ file
+     */
+    switch (action) {
+     case TGZ_LIST:
+     case TGZ_EXTRACT:
+      switch (xOpen4Read(&r,TGZfile)) {
+       case 0: break;
+       case 1: fprintf(stderr, "%s: cannot decode compressed tar file: %s\n", prog, TGZfile); return 1;
+       case 2: fprintf(stderr, "%s: tar file too short: %s\n", prog, TGZfile); return 1;
+       case 3: fprintf(stderr, "%s: not a tar file: %s\n", prog, TGZfile); return 1;
+       case 4: fprintf(stderr, "%s: cannot open tar file: %s\n", prog, TGZfile); return 1;
+      }
+      return tar(&r, action, arg, argc, argv, TGZfile, 1, 0);
+      default: error("Unknown option!");
+    }
+    return 0;
+}
+#endif
+
+void
+tarextract(char *TGZfile,char *dest,int verbose, void (*step)(void))
+{
+   Readable    r;
+   if (xOpen4Read(&r,TGZfile) == 0)
+      {
+      int arg = 2,
+          argc = 2;
+      char *argv[2];
+      chdir( dest );
+      argv[0] = "fgadmin";
+      argv[1] = TGZfile;
+      tar(&r, TGZ_EXTRACT, arg, argc, argv, TGZfile, 0, step);
+      }
+}
diff --git a/utils/fgadmin/src/untarka.h b/utils/fgadmin/src/untarka.h
new file mode 100644 (file)
index 0000000..f1ee99b
--- /dev/null
@@ -0,0 +1,10 @@
+#include <string>
+
+using std::string;
+
+// list the contents of the specified tar file
+// bool tarlist( char *tarfile, char *destdir, bool verbose );
+
+// extract the specified tar file into the specified destination
+// directory
+extern "C" void tarextract( char *tarfile, char *destdir, int verbose, void (*step)(void) );
diff --git a/utils/fgadmin/visualc/fgadmin.sln b/utils/fgadmin/visualc/fgadmin.sln
new file mode 100644 (file)
index 0000000..6bcdb0c
--- /dev/null
@@ -0,0 +1,27 @@
+Microsoft Visual Studio Solution File, Format Version 7.00\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fgadmin", "fgadmin\fgadmin.vcproj", "{7004E589-7EA0-4AFD-B432-3D5E00B55049}"\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "untarka", "untarka\untarka.vcproj", "{9FC55559-6801-4537-BAA3-D145B1B5A2F8}"\r
+EndProject\r
+Global\r
+       GlobalSection(SolutionConfiguration) = preSolution\r
+               ConfigName.0 = Debug\r
+               ConfigName.1 = Release\r
+       EndGlobalSection\r
+       GlobalSection(ProjectDependencies) = postSolution\r
+       EndGlobalSection\r
+       GlobalSection(ProjectConfiguration) = postSolution\r
+               {7004E589-7EA0-4AFD-B432-3D5E00B55049}.Debug.ActiveCfg = Debug|Win32\r
+               {7004E589-7EA0-4AFD-B432-3D5E00B55049}.Debug.Build.0 = Debug|Win32\r
+               {7004E589-7EA0-4AFD-B432-3D5E00B55049}.Release.ActiveCfg = Release|Win32\r
+               {7004E589-7EA0-4AFD-B432-3D5E00B55049}.Release.Build.0 = Release|Win32\r
+               {9FC55559-6801-4537-BAA3-D145B1B5A2F8}.Debug.ActiveCfg = Debug|Win32\r
+               {9FC55559-6801-4537-BAA3-D145B1B5A2F8}.Debug.Build.0 = Debug|Win32\r
+               {9FC55559-6801-4537-BAA3-D145B1B5A2F8}.Release.ActiveCfg = Release|Win32\r
+               {9FC55559-6801-4537-BAA3-D145B1B5A2F8}.Release.Build.0 = Release|Win32\r
+       EndGlobalSection\r
+       GlobalSection(ExtensibilityGlobals) = postSolution\r
+       EndGlobalSection\r
+       GlobalSection(ExtensibilityAddIns) = postSolution\r
+       EndGlobalSection\r
+EndGlobal\r
diff --git a/utils/fgadmin/visualc/fgadmin/fgadmin.vcproj b/utils/fgadmin/visualc/fgadmin/fgadmin.vcproj
new file mode 100644 (file)
index 0000000..8c6a3f3
--- /dev/null
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding = "Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="7.00"\r
+       Name="fgadmin"\r
+       ProjectGUID="{7004E589-7EA0-4AFD-B432-3D5E00B55049}"\r
+       Keyword="Win32Proj">\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"/>\r
+       </Platforms>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="Debug"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="..\..\..\..\fltk-1.1.4"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;HAVE_ZLIB"\r
+                               MinimalRebuild="TRUE"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="3"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="4"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="fltkd.lib Simgear_d.lib ul_d.lib comctl32.lib wsock32.lib zlib.lib"\r
+                               OutputFile="$(OutDir)/fgadmin.exe"\r
+                               LinkIncremental="2"\r
+                               AdditionalLibraryDirectories="&quot;..\..\..\..\fltk-1.1.4\lib&quot;"\r
+                               GenerateDebugInformation="TRUE"\r
+                               ProgramDatabaseFile="$(OutDir)/fgadmin.pdb"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="2"\r
+                               InlineFunctionExpansion="1"\r
+                               OmitFramePointers="TRUE"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"\r
+                               StringPooling="TRUE"\r
+                               RuntimeLibrary="4"\r
+                               EnableFunctionLevelLinking="TRUE"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="3"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="$(OutDir)/fgadmin.exe"\r
+                               LinkIncremental="1"\r
+                               GenerateDebugInformation="TRUE"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+               </Configuration>\r
+       </Configurations>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm">\r
+                       <File\r
+                               RelativePath="..\..\..\src\fgadmin.cxx">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\fgadmin_funcs.cxx">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\main.cxx">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\untarka.c">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc">\r
+                       <File\r
+                               RelativePath="..\..\..\src\fgadmin.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\src\tar_utils.hxx">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r