+++ /dev/null
-// fgadmin_funcs.cxx -- FG Admin UI functions.
-//
-// Written by Curtis Olson, started February 2004.
-//
-// Copyright (c) 2004 Curtis L. Olson - http://www.flightgear.org/~curt
-//
-// 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 2 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, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//
-// $Id$
-
-
-#include <iostream>
-#include <string>
-#include <set>
-#include <sys/stat.h>
-
-#ifdef _WIN32
-# include <direct.h>
-# include <io.h>
-#define unlink _unlink
-#define mkdir _mkdir
-#else // !_WIN32
-#include <unistd.h>
-#endif
-
-#include <FL/Fl_File_Chooser.H>
-
-#include <simgear/misc/sg_path.hxx>
-
-#include "fgadmin.h"
-#include "untarka.h"
-
-using std::cout;
-using std::endl;
-using std::set;
-using std::string;
-
-extern string def_install_source;
-extern string def_scenery_dest;
-
-static const float min_progress = 0.0;
-static const float max_progress = 5000.0;
-
-// FIXME: Ugly hack to detect the situation below
-#ifdef FL_Volume_Down
-//#if (FL_MAJOR_VERSION > 1)||((FL_MAJOR_VERSION == 1)&&(FL_MINOR_VERSION >= 3))
- // Fltk 1.3 or newer, need to use "fl_filename_free_list"
- #define FL_FREE_DIR_ENTRY(e) // do nothing, since "fl_filename_free_list" frees entire list
- #define FL_FREE_DIR_LIST(list,count) fl_filename_free_list(&list, count)
- #define FL_STAT(file,info) fl_stat( file.str().c_str(), info )
-#else
- // Fltk < 1.3, "fl_filename_free_list", "fl_stat" not available
- #define FL_FREE_DIR_ENTRY(e) free(e)
- #define FL_FREE_DIR_LIST(list,count) free(list)
- #define FL_STAT(file,info) stat( file.str().c_str(), info );
-#endif
-
-/** Strip a single trailing '/' or '\\' */
-static char* stripSlash(char* str)
-{
- int l = strlen(str);
- if ((l>0)&&
- ((str[l-1]=='/')||(str[l-1]=='\\')))
- {
- str[l-1] = 0;
- }
- return str;
-}
-
-// destructor
-FGAdminUI::~FGAdminUI() {
- delete prefs;
-}
-
-
-// initialize additional class elements
-void FGAdminUI::init() {
- prefs = new Fl_Preferences( Fl_Preferences::USER,
- "flightgear.org",
- "fgadmin" );
- char buf[FL_PATH_MAX];
- prefs->get( "install-source", buf, def_install_source.c_str(), FL_PATH_MAX );
- source_text->value( buf );
- source = buf;
-
- prefs->get( "scenery-dest", buf, def_scenery_dest.c_str(), FL_PATH_MAX );
- dest_text->value( buf );
- dest = buf;
-
- refresh_lists();
-
- progress->minimum( min_progress );
- progress->maximum( max_progress );
-
- main_window->size_range( 465, 435 );
-}
-
-// show our UI
-void FGAdminUI::show() {
- main_window->show();
-}
-
-
-// refresh the check box lists
-void FGAdminUI::refresh_lists() {
- update_install_box();
- update_remove_box();
-}
-
-
-// scan the source directory and update the install_box contents
-// quit
-void FGAdminUI::quit() {
- main_window->hide();
-}
-
-
-// select the install source
-void FGAdminUI::select_install_source() {
- char* p = fl_dir_chooser( "Select Scenery Source Directory",
- source.c_str(),
- 0 );
- if ( p != 0 ) {
- source = p;
- source_text->value( p );
- prefs->set( "install-source", p );
- prefs->flush();
- }
-}
-
-
-// select the install source
-void FGAdminUI::select_install_dest() {
- char* p = fl_dir_chooser( "Select Scenery Install Directory",
- dest.c_str(),
- 0 );
- if ( p != 0 ) {
- dest = p;
- dest_text->value( p );
- prefs->set( "scenery-dest", p );
- prefs->flush();
- }
-}
-
-#if 0
-// Like strcmp, but for strings
-static int stringCompare(const void *string1, const void *string2)
-{
- const string *s1 = (const string *)string1;
- const string *s2 = (const string *)string2;
-
- // Compare name first, and then index.
- return strcmp(s1->c_str(), s2->c_str());
-}
-#endif
-
-void FGAdminUI::update_install_box() {
- set<string> file_list;
-
- install_box->clear();
-
- if ( source.length() ) {
- struct dirent **list;
- int nb = fl_filename_list( source.c_str(), &list );
- for ( int i = 0; i < nb; ++i ) {
- // find base name of archive file
- char base[FL_PATH_MAX];
- dirent *ent = list[i];
- stripSlash(ent->d_name);
- strncpy( base, ent->d_name, FL_PATH_MAX );
- const char *p = fl_filename_ext( base );
- int offset;
- string::size_type expected_length = 0;
- if ( strcmp( p, ".gz" ) == 0 ) {
- offset = p - base;
- base[offset] = '\0';
- p = fl_filename_ext( base );
- if ( strcmp( p, ".tar" ) == 0 ) {
- offset = p - base;
- base[offset] = '\0';
- expected_length = 14;
- }
- } else if ( strcmp( p, ".tgz" ) == 0 ) {
- offset = p - base;
- base[offset] = '\0';
- expected_length = 11;
- } else if ( strcmp( p, ".zip" ) == 0 ) {
- offset = p - base;
- base[offset] = '\0';
- expected_length = 11;
- }
-
- if ( strlen(ent->d_name) != expected_length ) {
- // simple heuristic to ignore non-scenery files
- } else if ( ent->d_name[0] != 'e' && ent->d_name[0] != 'w' ) {
- // further sanity checks on name
- } else if ( ent->d_name[4] != 'n' && ent->d_name[4] != 's' ) {
- // further sanity checks on name
- } else {
- // add to list if not installed
- SGPath install( dest );
- install.append( base );
- if ( ! fl_filename_isdir( install.c_str() ) ) {
- // cout << install.str() << " install candidate." << endl;
- file_list.insert( ent->d_name );
- } else {
- // cout << install.str() << " exists." << endl;
- }
- }
- FL_FREE_DIR_ENTRY(ent);
- }
- FL_FREE_DIR_LIST(list, nb);
-
- for ( set<string>::iterator it = file_list.begin(); it != file_list.end(); ++it ) {
- install_box->add( it->c_str() );
- }
-
- install_box->redraw();
- }
-}
-
-
-// scan the source directory and update the install_box contents
-void FGAdminUI::update_remove_box() {
-
- remove_box->clear();
-
- if ( dest.length() ) {
- string path[2];
- path[0] = dest + "/Terrain";
- path[1] = dest + "/Objects";
- if ( !fl_filename_isdir( path[0].c_str() ) ) {
- path[0] = dest;
- path[1] = "";
- } else if ( !fl_filename_isdir( path[1].c_str() ) ) {
- path[1] = "";
- }
-
- set<string> dir_list;
- for ( int i = 0; i < 2; i++ ) {
- if ( !path[i].empty() ) {
- dirent **list;
- int nb = fl_filename_list( path[i].c_str(), &list );
- for ( int i = 0; i < nb; ++i ) {
- dirent *ent = list[i];
- stripSlash(ent->d_name);
- if ( strlen(ent->d_name) == 7 &&
- ( ent->d_name[0] == 'e' || ent->d_name[0] == 'w' ) &&
- ( ent->d_name[4] == 'n' || ent->d_name[4] == 's' ) ) {
- dir_list.insert( ent->d_name );
- }
- FL_FREE_DIR_ENTRY(ent);
- }
- FL_FREE_DIR_LIST(list, nb);
- }
- }
-
- for ( set<string>::iterator it = dir_list.begin(); it != dir_list.end(); ++it ) {
- remove_box->add( it->c_str() );
- }
-
- remove_box->redraw();
- }
-}
-
-
-// install selected files
-void FGAdminUI::install_selected() {
- char *f;
-
- install_b->deactivate();
- remove_b->deactivate();
- quit_b->deactivate();
-
- // traverse install box and install each item
- 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 );
- struct ::stat info;
- FL_STAT( file, &info );
- float old_max = progress->maximum();
- progress->maximum( info.st_size );
- progress_label = "Installing ";
- progress_label += f;
- progress->label( progress_label.c_str() );
- progress->value( min_progress );
- main_window->cursor( FL_CURSOR_WAIT );
- tarextract( (char *)file.c_str(), (char *)dest.c_str(), true, &FGAdminUI::step, this );
- progress->value( min_progress );
- main_window->cursor( FL_CURSOR_DEFAULT );
- progress->label( "" );
- progress->maximum( old_max );
- }
- }
- quit_b->activate();
- install_b->activate();
- remove_b->activate();
-
- refresh_lists();
-}
-
-
-static unsigned long count_dir( const char *dir_name, bool top = true ) {
- unsigned long cnt = 0L;
- dirent **list;
- int nb = fl_filename_list( dir_name, &list );
- if ( nb != 0 ) {
- for ( int i = 0; i < nb; ++i ) {
- dirent *ent = list[i];
- stripSlash(ent->d_name);
- if ( strcmp( ent->d_name, "." ) == 0 ) {
- // ignore "."
- } else if ( strcmp( ent->d_name, ".." ) == 0 ) {
- // ignore ".."
- } else if ( fl_filename_isdir( ent->d_name ) ) {
- SGPath child( dir_name );
- child.append( ent->d_name );
- cnt += count_dir( child.c_str(), false );
- } else {
- cnt += 1;
- }
- FL_FREE_DIR_ENTRY(ent);
- }
- FL_FREE_DIR_LIST(list, nb);
- } else if ( top ) {
- string base = dir_name;
- size_t pos = base.rfind('/');
- string file = base.substr( pos );
- base.erase( pos );
- string path = base + "/Terrain" + file;
- cnt = count_dir( path.c_str(), false );
- path = base + "/Objects" + file;
- cnt += count_dir( path.c_str(), false );
- }
- return cnt;
-}
-
-static void remove_dir( const char *dir_name, void (*step)(void*,int), void *data, bool top = true ) {
- dirent **list;
- int nb = fl_filename_list( dir_name, &list );
- if ( nb > 0 ) {
- for ( int i = 0; i < nb; ++i ) {
- dirent *ent = list[i];
- SGPath child( dir_name );
- child.append( ent->d_name );
- stripSlash(ent->d_name);
- if ( strcmp( ent->d_name, "." ) == 0 ) {
- // ignore "."
- } else if ( strcmp( ent->d_name, ".." ) == 0 ) {
- // ignore ".."
- } else if ( child.isDir() ) {
- remove_dir( child.c_str(), step, data, false );
- } else {
- unlink( child.c_str() );
- if (step) step( data, 1 );
- }
- FL_FREE_DIR_ENTRY(ent);
- }
- FL_FREE_DIR_LIST(list, nb);
- rmdir( dir_name );
- } else if ( top ) {
- string base = dir_name;
- size_t pos = base.rfind('/');
- string file = base.substr( pos );
- base.erase( pos );
- string path = base + "/Terrain" + file;
- remove_dir( path.c_str(), step, data, false );
- path = base + "/Objects" + file;
- remove_dir( path.c_str(), step, data, false );
- }
-}
-
-
-// remove selected files
-void FGAdminUI::remove_selected() {
- char *f;
-
- install_b->deactivate();
- remove_b->deactivate();
- quit_b->deactivate();
- // traverse remove box and recursively remove each item
- for ( int i = 0; i <= remove_box->nitems(); ++i ) {
- if ( remove_box->checked( i ) ) {
- f = remove_box->text( i );
- SGPath dir( dest );
- dir.append( f );
- float old_max = progress->maximum();
- progress_label = "Removing ";
- progress_label += f;
- progress->label( progress_label.c_str() );
- progress->value( min_progress );
- main_window->cursor( FL_CURSOR_WAIT );
- progress->maximum( count_dir( dir.c_str() ) );
- remove_dir( dir.c_str(), &FGAdminUI::step, this );
- progress->value( min_progress );
- main_window->cursor( FL_CURSOR_DEFAULT );
- progress->label( "" );
- progress->maximum( old_max );
- }
- }
- quit_b->activate();
- install_b->activate();
- remove_b->activate();
-
- refresh_lists();
-
-}
-
-void FGAdminUI::step(void *data)
-{
- Fl_Progress *p = ((FGAdminUI*)data)->progress;
-
- // we don't actually know the total work in advanced due to the
- // nature of tar archives, and it would be inefficient to prescan
- // the files, so just cycle the progress bar until we are done.
- float tmp = p->value() + 1;
- if ( tmp > max_progress ) {
- tmp = 0.0;
- }
- p->value( tmp );
-
- Fl::check();
-}
-
-void FGAdminUI::step(void *data, int n)
-{
- Fl_Progress *p = ((FGAdminUI*)data)->progress;
-
- float tmp = p->value() + n;
- p->value( tmp );
-
- Fl::check();
-}
+++ /dev/null
-#ifdef HAVE_CONFIG_H
-#include "config_fgadmin.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
-#ifdef WIN32
-# 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
-
-#include "untarka.h"
-
-static void error OF((const char *msg));
-
-static unsigned long total_read;
-
-/* #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) { total_read=0; 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);
- total_read+=got;
- 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";
-}
-
-#ifdef HAVE_ZLIB
-#include "zlib.h"
-/* #define xFILE gzFile */
-static int xGZ_Open4Read(struct Readable* self, char const* filename) { total_read=0; 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) { unsigned l=gzread((gzFile)self->f,buf,len); total_read=((z_streamp)self->f)->total_in; return l; }
-static char const* xGZ_Error(struct Readable* self, int *errnum_ret) { return gzerror((gzFile)self->f, errnum_ret); }
-#endif
-
-#ifdef 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) {
-#ifdef 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) {
-#ifdef 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) {
- posbits -= n_bits;
-#if 0
- {
- REG1 char_type *p;
- p = &inbuf[posbits>>3];
-
- 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);
-}
-
-#ifdef DOSISH
-/* 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);
-}
-#endif
-
-
-/* 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 *,int), void *data) {
- 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 = 0;
- unsigned long last_read;
-
-#if 0
- while (0<(len=rin->xRead(rin, &buffer, BLOCKSIZE))) {
- fwrite(buffer.buffer, 1, len, stdout);
- }
- exit(0);
-#endif
-
- last_read = 0;
- 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 (step) { step(data,total_read - last_read); last_read = total_read; }
- 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 (rin->xClose(rin))
- error("failed gzclose");
-
- return 0;
-}
-
-
-#ifdef DOSISH
-/* =========================================================== */
-
-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);
-}
-
-/* ====================================================================== */
-
-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, 0);
- default: error("Unknown option!");
- }
- return 0;
-}
-#endif
-
-void
-tarextract(char *TGZfile,char *dest,int verbose, void (*step)(void *,int), void *data)
-{
- 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, data);
- }
-}