which included commits to RCS files with non-trunk default branches. git-svn-id: svn://10.65.10.50/trunk@5403 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			1806 lines
		
	
	
		
			62 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1806 lines
		
	
	
		
			62 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/*---------------------------------------------------------------------------
 | 
						|
 | 
						|
  msdos.c
 | 
						|
 | 
						|
  MSDOS-specific routines for use with Info-ZIP's UnZip 5.3 and later.
 | 
						|
 | 
						|
  Contains:  Opendir()                      (from zip)
 | 
						|
             Readdir()                      (from zip)
 | 
						|
             do_wild()
 | 
						|
             mapattr()
 | 
						|
             mapname()
 | 
						|
             map2fat()
 | 
						|
             checkdir()
 | 
						|
             isfloppy()
 | 
						|
             volumelabel()                  (non-djgpp, non-emx)
 | 
						|
             close_outfile()
 | 
						|
             dateformat()
 | 
						|
             version()
 | 
						|
             _dos_getcountryinfo()          (djgpp, emx)
 | 
						|
            [_dos_getftime()                (djgpp, emx)   to be added]
 | 
						|
             _dos_setftime()                (djgpp, emx)
 | 
						|
             _dos_setfileattr()             (djgpp, emx)
 | 
						|
             _dos_getdrive()                (djgpp, emx)
 | 
						|
             _dos_creat()                   (djgpp, emx)
 | 
						|
             _dos_close()                   (djgpp, emx)
 | 
						|
             volumelabel()                  (djgpp, emx)
 | 
						|
             __crt0_glob_function()         (djgpp 2.x)
 | 
						|
             __crt_load_environment_file()  (djgpp 2.x)
 | 
						|
             int86x_realmode()              (Watcom 32-bit)
 | 
						|
             stat_bandaid()                 (Watcom)
 | 
						|
 | 
						|
  ---------------------------------------------------------------------------*/
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#define UNZIP_INTERNAL
 | 
						|
#include "unzip.h"
 | 
						|
 | 
						|
#ifdef MAYBE_PLAIN_FAT
 | 
						|
   static void map2fat OF((char *pathcomp, char *last_dot));
 | 
						|
#endif
 | 
						|
static int isfloppy OF((int nDrive));
 | 
						|
static int volumelabel OF((char *newlabel));
 | 
						|
 | 
						|
static int created_dir;        /* used by mapname(), checkdir() */
 | 
						|
static int renamed_fullpath;   /* ditto */
 | 
						|
static unsigned nLabelDrive;   /* ditto, plus volumelabel() */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/*****************************/
 | 
						|
/*  Strings used in msdos.c  */
 | 
						|
/*****************************/
 | 
						|
 | 
						|
#ifndef SFX
 | 
						|
  static char Far CantAllocateWildcard[] =
 | 
						|
    "warning:  can't allocate wildcard buffers\n";
 | 
						|
#endif
 | 
						|
static char Far Creating[] = "   creating: %s\n";
 | 
						|
static char Far ConversionFailed[] = "mapname:  conversion of %s failed\n";
 | 
						|
static char Far Labelling[] = "labelling %c: %-22s\n";
 | 
						|
static char Far ErrSetVolLabel[] = "mapname:  error setting volume label\n";
 | 
						|
static char Far PathTooLong[] = "checkdir error:  path too long: %s\n";
 | 
						|
static char Far CantCreateDir[] = "checkdir error:  can't create %s\n\
 | 
						|
                 unable to process %s.\n";
 | 
						|
static char Far DirIsntDirectory[] =
 | 
						|
  "checkdir error:  %s exists but is not directory\n\
 | 
						|
                 unable to process %s.\n";
 | 
						|
static char Far PathTooLongTrunc[] =
 | 
						|
  "checkdir warning:  path too long; truncating\n                   %s\n\
 | 
						|
                -> %s\n";
 | 
						|
#if (!defined(SFX) || defined(SFX_EXDIR))
 | 
						|
   static char Far CantCreateExtractDir[] =
 | 
						|
     "checkdir:  can't create extraction directory: %s\n";
 | 
						|
#endif
 | 
						|
#ifdef __TURBOC__
 | 
						|
   static char Far AttribsMayBeWrong[] =
 | 
						|
     "\nwarning:  file attributes may not be correct\n";
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/****************************/
 | 
						|
/*  Macros used in msdos.c  */
 | 
						|
/****************************/
 | 
						|
 | 
						|
#ifdef WATCOMC_386
 | 
						|
#  define WREGS(v,r) (v##.w.##r)
 | 
						|
#  define int86x int386x
 | 
						|
   static int int86x_realmode(int inter_no, union REGS *in,
 | 
						|
                              union REGS *out, struct SREGS *seg);
 | 
						|
#  define F_intdosx(ir,or,sr) int86x_realmode(0x21, ir, or, sr)
 | 
						|
#  define XXX__MK_FP_IS_BROKEN
 | 
						|
#else
 | 
						|
#  define WREGS(v,r) (v##.x.##r)
 | 
						|
#  define F_intdosx(ir,or,sr) intdosx(ir, or, sr)
 | 
						|
#endif
 | 
						|
 | 
						|
#if (defined(__GO32__) || defined(__EMX__))
 | 
						|
#  include <dirent.h>        /* use readdir() */
 | 
						|
#  define MKDIR(path,mode)   mkdir(path,mode)
 | 
						|
#  define Opendir  opendir
 | 
						|
#  define Readdir  readdir
 | 
						|
#  define Closedir closedir
 | 
						|
#  define zdirent  dirent
 | 
						|
#  define zDIR     DIR
 | 
						|
#  ifdef __EMX__
 | 
						|
#    include <dos.h>
 | 
						|
#    define GETDRIVE(d)      d = _getdrive()
 | 
						|
#    define FA_LABEL         A_LABEL
 | 
						|
#  else
 | 
						|
#    define GETDRIVE(d)      _dos_getdrive(&d)
 | 
						|
#  endif
 | 
						|
#else /* !(__GO32__ || __EMX__) */
 | 
						|
#  define MKDIR(path,mode)   mkdir(path)
 | 
						|
#  ifdef __TURBOC__
 | 
						|
#    define FATTR            FA_HIDDEN+FA_SYSTEM+FA_DIREC
 | 
						|
#    define FVOLID           FA_VOLID
 | 
						|
#    define FFIRST(n,d,a)    findfirst(n,(struct ffblk *)d,a)
 | 
						|
#    define FNEXT(d)         findnext((struct ffblk *)d)
 | 
						|
#    define GETDRIVE(d)      d=getdisk()+1
 | 
						|
#    include <dir.h>
 | 
						|
#  else /* !__TURBOC__ */
 | 
						|
#    define FATTR            _A_HIDDEN+_A_SYSTEM+_A_SUBDIR
 | 
						|
#    define FVOLID           _A_VOLID
 | 
						|
#    define FFIRST(n,d,a)    _dos_findfirst(n,a,(struct find_t *)d)
 | 
						|
#    define FNEXT(d)         _dos_findnext((struct find_t *)d)
 | 
						|
#    define GETDRIVE(d)      _dos_getdrive(&d)
 | 
						|
#    include <direct.h>
 | 
						|
#  endif /* ?__TURBOC__ */
 | 
						|
   typedef struct zdirent {
 | 
						|
       char d_reserved[30];
 | 
						|
       char d_name[13];
 | 
						|
       int d_first;
 | 
						|
   } zDIR;
 | 
						|
   zDIR *Opendir OF((const char *));
 | 
						|
   struct zdirent *Readdir OF((zDIR *));
 | 
						|
#  define Closedir free
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#ifndef SFX
 | 
						|
 | 
						|
/**********************/   /* Borland C++ 3.x has its own opendir/readdir */
 | 
						|
/* Function Opendir() */   /*  library routines, but earlier versions don't, */
 | 
						|
/**********************/   /*  so use ours regardless */
 | 
						|
 | 
						|
zDIR *Opendir(name)
 | 
						|
    const char *name;        /* name of directory to open */
 | 
						|
{
 | 
						|
    zDIR *dirp;              /* malloc'd return value */
 | 
						|
    char *nbuf;              /* malloc'd temporary string */
 | 
						|
    int len = strlen(name);  /* path length to avoid strlens and strcats */
 | 
						|
 | 
						|
 | 
						|
    if ((dirp = (zDIR *)malloc(sizeof(zDIR))) == (zDIR *)NULL)
 | 
						|
        return (zDIR *)NULL;
 | 
						|
    if ((nbuf = malloc(len + 5)) == (char *)NULL) {
 | 
						|
        free(dirp);
 | 
						|
        return (zDIR *)NULL;
 | 
						|
    }
 | 
						|
    strcpy(nbuf, name);
 | 
						|
    if (nbuf[len-1] == ':') {
 | 
						|
        nbuf[len++] = '.';
 | 
						|
    } else if (nbuf[len-1] == '/' || nbuf[len-1] == '\\')
 | 
						|
        --len;
 | 
						|
    strcpy(nbuf+len, "/*.*");
 | 
						|
    Trace((stderr, "Opendir:  nbuf = [%s]\n", nbuf));
 | 
						|
 | 
						|
    if (FFIRST(nbuf, dirp, FATTR)) {
 | 
						|
        free((zvoid *)nbuf);
 | 
						|
        return (zDIR *)NULL;
 | 
						|
    }
 | 
						|
    free((zvoid *)nbuf);
 | 
						|
    dirp->d_first = 1;
 | 
						|
    return dirp;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/**********************/
 | 
						|
/* Function Readdir() */
 | 
						|
/**********************/
 | 
						|
 | 
						|
struct zdirent *Readdir(d)
 | 
						|
    zDIR *d;        /* directory stream from which to read */
 | 
						|
{
 | 
						|
    /* Return pointer to first or next directory entry, or NULL if end. */
 | 
						|
 | 
						|
    if (d->d_first)
 | 
						|
        d->d_first = 0;
 | 
						|
    else
 | 
						|
        if (FNEXT(d))
 | 
						|
            return (struct zdirent *)NULL;
 | 
						|
    return (struct zdirent *)d;
 | 
						|
}
 | 
						|
 | 
						|
#endif /* !SFX */
 | 
						|
#endif /* ?(__GO32__ || __EMX__) */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#ifndef SFX
 | 
						|
 | 
						|
/************************/
 | 
						|
/*  Function do_wild()  */   /* identical to OS/2 version */
 | 
						|
/************************/
 | 
						|
 | 
						|
char *do_wild(__G__ wildspec)
 | 
						|
    __GDEF
 | 
						|
    char *wildspec;          /* only used first time on a given dir */
 | 
						|
{
 | 
						|
    static zDIR *dir = (zDIR *)NULL;
 | 
						|
    static char *dirname, *wildname, matchname[FILNAMSIZ];
 | 
						|
    static int firstcall=TRUE, have_dirname, dirnamelen;
 | 
						|
    struct zdirent *file;
 | 
						|
 | 
						|
 | 
						|
    /* Even when we're just returning wildspec, we *always* do so in
 | 
						|
     * matchname[]--calling routine is allowed to append four characters
 | 
						|
     * to the returned string, and wildspec may be a pointer to argv[].
 | 
						|
     */
 | 
						|
    if (firstcall) {        /* first call:  must initialize everything */
 | 
						|
        firstcall = FALSE;
 | 
						|
 | 
						|
        if (!iswild(wildspec)) {
 | 
						|
            strcpy(matchname, wildspec);
 | 
						|
            have_dirname = FALSE;
 | 
						|
            dir = NULL;
 | 
						|
            return matchname;
 | 
						|
        }
 | 
						|
 | 
						|
        /* break the wildspec into a directory part and a wildcard filename */
 | 
						|
        if ((wildname = strrchr(wildspec, '/')) == (char *)NULL &&
 | 
						|
            (wildname = strrchr(wildspec, ':')) == (char *)NULL) {
 | 
						|
            dirname = ".";
 | 
						|
            dirnamelen = 1;
 | 
						|
            have_dirname = FALSE;
 | 
						|
            wildname = wildspec;
 | 
						|
        } else {
 | 
						|
            ++wildname;     /* point at character after '/' or ':' */
 | 
						|
            dirnamelen = (int)(wildname - wildspec);
 | 
						|
            if ((dirname = (char *)malloc(dirnamelen+1)) == (char *)NULL) {
 | 
						|
                Info(slide, 1, ((char *)slide,
 | 
						|
                  LoadFarString(CantAllocateWildcard)));
 | 
						|
                strcpy(matchname, wildspec);
 | 
						|
                return matchname;   /* but maybe filespec was not a wildcard */
 | 
						|
            }
 | 
						|
/* GRR:  can't strip trailing char for opendir since might be "d:/" or "d:"
 | 
						|
 *       (would have to check for "./" at end--let opendir handle it instead) */
 | 
						|
            strncpy(dirname, wildspec, dirnamelen);
 | 
						|
            dirname[dirnamelen] = '\0';       /* terminate for strcpy below */
 | 
						|
            have_dirname = TRUE;
 | 
						|
        }
 | 
						|
        Trace((stderr, "do_wild:  dirname = [%s]\n", dirname));
 | 
						|
 | 
						|
        if ((dir = Opendir(dirname)) != (zDIR *)NULL) {
 | 
						|
            while ((file = Readdir(dir)) != (struct zdirent *)NULL) {
 | 
						|
                Trace((stderr, "do_wild:  readdir returns %s\n", file->d_name));
 | 
						|
                if (match(file->d_name, wildname, 1)) {  /* 1 == ignore case */
 | 
						|
                    Trace((stderr, "do_wild:  match() succeeds\n"));
 | 
						|
                    if (have_dirname) {
 | 
						|
                        strcpy(matchname, dirname);
 | 
						|
                        strcpy(matchname+dirnamelen, file->d_name);
 | 
						|
                    } else
 | 
						|
                        strcpy(matchname, file->d_name);
 | 
						|
                    return matchname;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            /* if we get to here directory is exhausted, so close it */
 | 
						|
            Closedir(dir);
 | 
						|
            dir = (zDIR *)NULL;
 | 
						|
        }
 | 
						|
        Trace((stderr, "do_wild:  Opendir(%s) returns NULL\n", dirname));
 | 
						|
 | 
						|
        /* return the raw wildspec in case that works (e.g., directory not
 | 
						|
         * searchable, but filespec was not wild and file is readable) */
 | 
						|
        strcpy(matchname, wildspec);
 | 
						|
        return matchname;
 | 
						|
    }
 | 
						|
 | 
						|
    /* last time through, might have failed opendir but returned raw wildspec */
 | 
						|
    if (dir == (zDIR *)NULL) {
 | 
						|
        firstcall = TRUE;  /* nothing left to try--reset for new wildspec */
 | 
						|
        if (have_dirname)
 | 
						|
            free(dirname);
 | 
						|
        return (char *)NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    /* If we've gotten this far, we've read and matched at least one entry
 | 
						|
     * successfully (in a previous call), so dirname has been copied into
 | 
						|
     * matchname already.
 | 
						|
     */
 | 
						|
    while ((file = Readdir(dir)) != (struct zdirent *)NULL)
 | 
						|
        if (match(file->d_name, wildname, 1)) {   /* 1 == ignore case */
 | 
						|
            if (have_dirname) {
 | 
						|
                /* strcpy(matchname, dirname); */
 | 
						|
                strcpy(matchname+dirnamelen, file->d_name);
 | 
						|
            } else
 | 
						|
                strcpy(matchname, file->d_name);
 | 
						|
            return matchname;
 | 
						|
        }
 | 
						|
 | 
						|
    Closedir(dir);     /* have read at least one dir entry; nothing left */
 | 
						|
    dir = (zDIR *)NULL;
 | 
						|
    firstcall = TRUE;  /* reset for new wildspec */
 | 
						|
    if (have_dirname)
 | 
						|
        free(dirname);
 | 
						|
    return (char *)NULL;
 | 
						|
 | 
						|
} /* end function do_wild() */
 | 
						|
 | 
						|
#endif /* !SFX */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/**********************/
 | 
						|
/* Function mapattr() */
 | 
						|
/**********************/
 | 
						|
 | 
						|
int mapattr(__G)
 | 
						|
    __GDEF
 | 
						|
{
 | 
						|
    /* set archive bit (file is not backed up): */
 | 
						|
    G.pInfo->file_attr = (unsigned)(G.crec.external_file_attributes | 32) &
 | 
						|
      0xff;
 | 
						|
    return 0;
 | 
						|
 | 
						|
} /* end function mapattr() */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/************************/
 | 
						|
/*  Function mapname()  */
 | 
						|
/************************/
 | 
						|
                             /* return 0 if no error, 1 if caution (filename */
 | 
						|
int mapname(__G__ renamed)   /*  truncated), 2 if warning (skip file because */
 | 
						|
    __GDEF                   /*  dir doesn't exist), 3 if error (skip file), */
 | 
						|
    int renamed;             /*  or 10 if out of memory (skip file) */
 | 
						|
{                            /*  [also IZ_VOL_LABEL, IZ_CREATED_DIR] */
 | 
						|
    char pathcomp[FILNAMSIZ];      /* path-component buffer */
 | 
						|
    char *pp, *cp=(char *)NULL;    /* character pointers */
 | 
						|
    char *lastsemi=(char *)NULL;   /* pointer to last semi-colon in pathcomp */
 | 
						|
#ifdef MAYBE_PLAIN_FAT
 | 
						|
    char *last_dot=(char *)NULL;   /* last dot not converted to underscore */
 | 
						|
    int dotname = FALSE;           /* path component begins with dot? */
 | 
						|
# ifdef USE_LFN
 | 
						|
    int use_lfn = USE_LFN;         /* file system supports long filenames? */
 | 
						|
# endif
 | 
						|
#endif
 | 
						|
    int error = 0;
 | 
						|
    register unsigned workch;      /* hold the character being tested */
 | 
						|
 | 
						|
 | 
						|
/*---------------------------------------------------------------------------
 | 
						|
    Initialize various pointers and counters and stuff.
 | 
						|
  ---------------------------------------------------------------------------*/
 | 
						|
 | 
						|
    /* can create path as long as not just freshening, or if user told us */
 | 
						|
    G.create_dirs = (!G.fflag || renamed);
 | 
						|
 | 
						|
    created_dir = FALSE;        /* not yet */
 | 
						|
    renamed_fullpath = FALSE;
 | 
						|
 | 
						|
    if (renamed) {
 | 
						|
        cp = G.filename - 1;    /* point to beginning of renamed name... */
 | 
						|
        while (*++cp)
 | 
						|
            if (*cp == '\\')    /* convert backslashes to forward */
 | 
						|
                *cp = '/';
 | 
						|
        cp = G.filename;
 | 
						|
        /* use temporary rootpath if user gave full pathname */
 | 
						|
        if (G.filename[0] == '/') {
 | 
						|
            renamed_fullpath = TRUE;
 | 
						|
            pathcomp[0] = '/';  /* copy the '/' and terminate */
 | 
						|
            pathcomp[1] = '\0';
 | 
						|
            ++cp;
 | 
						|
        } else if (isalpha(G.filename[0]) && G.filename[1] == ':') {
 | 
						|
            renamed_fullpath = TRUE;
 | 
						|
            pp = pathcomp;
 | 
						|
            *pp++ = *cp++;      /* copy the "d:" (+ '/', possibly) */
 | 
						|
            *pp++ = *cp++;
 | 
						|
            if (*cp == '/')
 | 
						|
                *pp++ = *cp++;  /* otherwise add "./"? */
 | 
						|
            *pp = '\0';
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /* pathcomp is ignored unless renamed_fullpath is TRUE: */
 | 
						|
    if ((error = checkdir(__G__ pathcomp, INIT)) != 0) /* initialize path buf */
 | 
						|
        return error;           /* ...unless no mem or vol label on hard disk */
 | 
						|
 | 
						|
    *pathcomp = '\0';           /* initialize translation buffer */
 | 
						|
    pp = pathcomp;              /* point to translation buffer */
 | 
						|
    if (!renamed) {             /* cp already set if renamed */
 | 
						|
        if (G.jflag)            /* junking directories */
 | 
						|
            cp = (char *)strrchr(G.filename, '/');
 | 
						|
        if (cp == (char *)NULL) /* no '/' or not junking dirs */
 | 
						|
            cp = G.filename;    /* point to internal zipfile-member pathname */
 | 
						|
        else
 | 
						|
            ++cp;               /* point to start of last component of path */
 | 
						|
    }
 | 
						|
 | 
						|
/*---------------------------------------------------------------------------
 | 
						|
    Begin main loop through characters in filename.
 | 
						|
  ---------------------------------------------------------------------------*/
 | 
						|
 | 
						|
    while ((workch = (uch)*cp++) != 0) {
 | 
						|
 | 
						|
        switch (workch) {
 | 
						|
            case '/':             /* can assume -j flag not given */
 | 
						|
                *pp = '\0';
 | 
						|
#ifdef MAYBE_PLAIN_FAT
 | 
						|
# ifdef USE_LFN
 | 
						|
                if (!use_lfn)
 | 
						|
# endif
 | 
						|
                {
 | 
						|
                    map2fat(pathcomp, last_dot);   /* 8.3 trunc. (in place) */
 | 
						|
                    last_dot = (char *)NULL;
 | 
						|
                }
 | 
						|
#endif
 | 
						|
                if ((error = checkdir(__G__ pathcomp, APPEND_DIR)) > 1)
 | 
						|
                    return error;
 | 
						|
                pp = pathcomp;    /* reset conversion buffer for next piece */
 | 
						|
                lastsemi = (char *)NULL; /* leave directory semi-colons alone */
 | 
						|
                break;
 | 
						|
 | 
						|
            /* drive names are not stored in zipfile, so no colons allowed;
 | 
						|
             *  no brackets or most other punctuation either (all of which
 | 
						|
             *  can appear in Unix-created archives; backslash is particularly
 | 
						|
             *  bad unless all necessary directories exist) */
 | 
						|
#ifdef MAYBE_PLAIN_FAT
 | 
						|
            case '[':          /* these punctuation characters forbidden */
 | 
						|
            case ']':          /*  only on plain FAT file systems */
 | 
						|
            case '+':
 | 
						|
            case ',':
 | 
						|
            case '=':
 | 
						|
# ifdef USE_LFN
 | 
						|
                if (use_lfn)
 | 
						|
                    *pp++ = (char)workch;
 | 
						|
                else
 | 
						|
                    *pp++ = '_';
 | 
						|
                break;
 | 
						|
# endif
 | 
						|
#endif
 | 
						|
            case ':':           /* special shell characters of command.com */
 | 
						|
            case '\\':          /*  (device and directory limiters, wildcard */
 | 
						|
            case '"':           /*  characters, stdin/stdout redirection and */
 | 
						|
            case '<':           /*  pipe indicators and the quote sign) are */
 | 
						|
            case '>':           /*  never allowed in filenames on (V)FAT */
 | 
						|
            case '|':
 | 
						|
            case '*':
 | 
						|
            case '?':
 | 
						|
                *pp++ = '_';
 | 
						|
                break;
 | 
						|
 | 
						|
#ifdef MAYBE_PLAIN_FAT
 | 
						|
            case '.':
 | 
						|
# ifdef USE_LFN
 | 
						|
                if (use_lfn) {
 | 
						|
                    *pp++ = (char)workch;
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
# endif
 | 
						|
                if (pp == pathcomp) {     /* nothing appended yet... */
 | 
						|
                    if (*cp == '/') {     /* don't bother appending a "./" */
 | 
						|
                        ++cp;             /*  component to the path:  skip */
 | 
						|
                        break;            /*  to next char after the '/' */
 | 
						|
                    } else if (*cp == '.' && cp[1] == '/') {   /* "../" */
 | 
						|
                        *pp++ = '.';      /* add first dot, unchanged... */
 | 
						|
                        ++cp;             /* skip second dot, since it will */
 | 
						|
                    } else {              /*  be "added" at end of if-block */
 | 
						|
                        *pp++ = '_';      /* FAT doesn't allow null filename */
 | 
						|
                        dotname = TRUE;   /*  bodies, so map .exrc -> _.exrc */
 | 
						|
                    }                     /*  (extra '_' now, "dot" below) */
 | 
						|
                } else if (dotname) {     /* found a second dot, but still */
 | 
						|
                    dotname = FALSE;      /*  have extra leading underscore: */
 | 
						|
                    *pp = '\0';           /*  remove it by shifting chars */
 | 
						|
                    pp = pathcomp + 1;    /*  left one space (e.g., .p1.p2: */
 | 
						|
                    while (pp[1]) {       /*  __p1 -> _p1_p2 -> _p1.p2 when */
 | 
						|
                        *pp = pp[1];      /*  finished) [opt.:  since first */
 | 
						|
                        ++pp;             /*  two chars are same, can start */
 | 
						|
                    }                     /*  shifting at second position] */
 | 
						|
                }
 | 
						|
                last_dot = pp;    /* point at last dot so far... */
 | 
						|
                *pp++ = '_';      /* convert dot to underscore for now */
 | 
						|
                break;
 | 
						|
#endif /* MAYBE_PLAIN_FAT */
 | 
						|
 | 
						|
            case ';':             /* start of VMS version? */
 | 
						|
                lastsemi = pp;
 | 
						|
#ifdef MAYBE_PLAIN_FAT
 | 
						|
# ifdef USE_LFN
 | 
						|
                if (use_lfn)
 | 
						|
                    *pp++ = ';';  /* keep for now; remove VMS ";##" later */
 | 
						|
# endif
 | 
						|
#else
 | 
						|
                *pp++ = ';';      /* keep for now; remove VMS ";##" later */
 | 
						|
#endif
 | 
						|
                break;
 | 
						|
 | 
						|
#ifdef MAYBE_PLAIN_FAT
 | 
						|
            case ' ':                      /* change spaces to underscores */
 | 
						|
# ifdef USE_LFN
 | 
						|
                if (!use_lfn && G.sflag)   /*  only if requested and NO lfn! */
 | 
						|
# else
 | 
						|
                if (G.sflag)               /*  only if requested */
 | 
						|
# endif
 | 
						|
                    *pp++ = '_';
 | 
						|
                else
 | 
						|
                    *pp++ = (char)workch;
 | 
						|
                break;
 | 
						|
#endif /* MAYBE_PLAIN_FAT */
 | 
						|
 | 
						|
            default:
 | 
						|
                /* allow ASCII 255 and European characters in filenames: */
 | 
						|
                if (isprint(workch) || workch >= 127)
 | 
						|
                    *pp++ = (char)workch;
 | 
						|
 | 
						|
        } /* end switch */
 | 
						|
    } /* end while loop */
 | 
						|
 | 
						|
    *pp = '\0';                   /* done with pathcomp:  terminate it */
 | 
						|
 | 
						|
    /* if not saving them, remove VMS version numbers (appended ";###") */
 | 
						|
    if (!G.V_flag && lastsemi) {
 | 
						|
#ifndef MAYBE_PLAIN_FAT
 | 
						|
        pp = lastsemi + 1;
 | 
						|
#else
 | 
						|
# ifdef USE_LFN
 | 
						|
        if (use_lfn)
 | 
						|
            pp = lastsemi + 1;
 | 
						|
        else
 | 
						|
            pp = lastsemi;        /* semi-colon was omitted:  expect all #'s */
 | 
						|
# else
 | 
						|
        pp = lastsemi;            /* semi-colon was omitted:  expect all #'s */
 | 
						|
# endif
 | 
						|
#endif
 | 
						|
        while (isdigit((uch)(*pp)))
 | 
						|
            ++pp;
 | 
						|
        if (*pp == '\0')          /* only digits between ';' and end:  nuke */
 | 
						|
            *lastsemi = '\0';
 | 
						|
    }
 | 
						|
 | 
						|
    if (G.pInfo->vollabel) {
 | 
						|
        if (strlen(pathcomp) > 11)
 | 
						|
            pathcomp[11] = '\0';
 | 
						|
    }
 | 
						|
 | 
						|
#ifdef MAYBE_PLAIN_FAT
 | 
						|
# ifdef USE_LFN
 | 
						|
    if (!use_lfn)
 | 
						|
        map2fat(pathcomp, last_dot);  /* 8.3 truncation (in place) */
 | 
						|
# else
 | 
						|
    map2fat(pathcomp, last_dot);  /* 8.3 truncation (in place) */
 | 
						|
# endif
 | 
						|
#endif
 | 
						|
 | 
						|
/*---------------------------------------------------------------------------
 | 
						|
    Report if directory was created (and no file to create:  filename ended
 | 
						|
    in '/'), check name to be sure it exists, and combine path and name be-
 | 
						|
    fore exiting.
 | 
						|
  ---------------------------------------------------------------------------*/
 | 
						|
 | 
						|
    if (G.filename[strlen(G.filename) - 1] == '/') {
 | 
						|
        checkdir(__G__ G.filename, GETPATH);
 | 
						|
        if (created_dir) {
 | 
						|
            if (QCOND2) {
 | 
						|
                Info(slide, 0, ((char *)slide, LoadFarString(Creating),
 | 
						|
                  FnFilter1(G.filename)));
 | 
						|
            }
 | 
						|
            return IZ_CREATED_DIR;   /* set dir time (note trailing '/') */
 | 
						|
        }
 | 
						|
        return 2;   /* dir existed already; don't look for data to extract */
 | 
						|
    }
 | 
						|
 | 
						|
    if (*pathcomp == '\0') {
 | 
						|
        Info(slide, 1, ((char *)slide, LoadFarString(ConversionFailed),
 | 
						|
          FnFilter1(G.filename)));
 | 
						|
        return 3;
 | 
						|
    }
 | 
						|
 | 
						|
    checkdir(__G__ pathcomp, APPEND_NAME);  /* returns 1 if truncated: care? */
 | 
						|
    checkdir(__G__ G.filename, GETPATH);
 | 
						|
 | 
						|
    if (G.pInfo->vollabel) {    /* set the volume label now */
 | 
						|
        if (QCOND2)
 | 
						|
            Info(slide, 0, ((char *)slide, LoadFarString(Labelling),
 | 
						|
              (nLabelDrive + 'a' - 1),
 | 
						|
              FnFilter1(G.filename)));
 | 
						|
        if (volumelabel(G.filename)) {
 | 
						|
            Info(slide, 1, ((char *)slide, LoadFarString(ErrSetVolLabel)));
 | 
						|
            return 3;
 | 
						|
        }
 | 
						|
        return 2;   /* success:  skip the "extraction" quietly */
 | 
						|
    }
 | 
						|
 | 
						|
    return error;
 | 
						|
 | 
						|
} /* end function mapname() */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#ifdef MAYBE_PLAIN_FAT
 | 
						|
 | 
						|
/**********************/
 | 
						|
/* Function map2fat() */
 | 
						|
/**********************/
 | 
						|
 | 
						|
static void map2fat(pathcomp, last_dot)
 | 
						|
    char *pathcomp, *last_dot;
 | 
						|
{
 | 
						|
    char *pEnd = pathcomp + strlen(pathcomp);
 | 
						|
 | 
						|
/*---------------------------------------------------------------------------
 | 
						|
    Case 1:  filename has no dot, so figure out if we should add one.  Note
 | 
						|
    that the algorithm does not try to get too fancy:  if there are no dots
 | 
						|
    already, the name either gets truncated at 8 characters or the last un-
 | 
						|
    derscore is converted to a dot (only if more characters are saved that
 | 
						|
    way).  In no case is a dot inserted between existing characters.
 | 
						|
 | 
						|
              GRR:  have problem if filename is volume label??
 | 
						|
 | 
						|
  ---------------------------------------------------------------------------*/
 | 
						|
 | 
						|
    /* pEnd = pathcomp + strlen(pathcomp); */
 | 
						|
    if (last_dot == (char *)NULL) {   /* no dots:  check for underscores... */
 | 
						|
        char *plu = strrchr(pathcomp, '_');   /* pointer to last underscore */
 | 
						|
 | 
						|
        if (plu == (char *)NULL) {  /* no dots, no underscores:  truncate at */
 | 
						|
            if (pEnd > pathcomp+8)  /* 8 chars (could insert '.' and keep 11) */
 | 
						|
                *(pEnd = pathcomp+8) = '\0';
 | 
						|
        } else if (MIN(plu - pathcomp, 8) + MIN(pEnd - plu - 1, 3) > 8) {
 | 
						|
            last_dot = plu;       /* be lazy:  drop through to next if-block */
 | 
						|
        } else if ((pEnd - pathcomp) > 8)    /* more fits into just basename */
 | 
						|
            pathcomp[8] = '\0';    /* than if convert last underscore to dot */
 | 
						|
        /* else whole thing fits into 8 chars or less:  no change */
 | 
						|
    }
 | 
						|
 | 
						|
/*---------------------------------------------------------------------------
 | 
						|
    Case 2:  filename has dot in it, so truncate first half at 8 chars (shift
 | 
						|
    extension if necessary) and second half at three.
 | 
						|
  ---------------------------------------------------------------------------*/
 | 
						|
 | 
						|
    if (last_dot != (char *)NULL) {   /* one dot (or two, in the case of */
 | 
						|
        *last_dot = '.';              /*  "..") is OK:  put it back in */
 | 
						|
 | 
						|
        if ((last_dot - pathcomp) > 8) {
 | 
						|
            char *p=last_dot, *q=pathcomp+8;
 | 
						|
            int i;
 | 
						|
 | 
						|
            for (i = 0;  (i < 4) && *p;  ++i)  /* too many chars in basename: */
 | 
						|
                *q++ = *p++;                   /*  shift extension left and */
 | 
						|
            *q = '\0';                         /*  truncate/terminate it */
 | 
						|
        } else if ((pEnd - last_dot) > 4)
 | 
						|
            last_dot[4] = '\0';                /* too many chars in extension */
 | 
						|
        /* else filename is fine as is:  no change */
 | 
						|
    }
 | 
						|
} /* end function map2fat() */
 | 
						|
 | 
						|
#endif /* MAYBE_PLAIN_FAT */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/***********************/
 | 
						|
/* Function checkdir() */
 | 
						|
/***********************/
 | 
						|
 | 
						|
int checkdir(__G__ pathcomp, flag)
 | 
						|
    __GDEF
 | 
						|
    char *pathcomp;
 | 
						|
    int flag;
 | 
						|
/*
 | 
						|
 * returns:  1 - (on APPEND_NAME) truncated filename
 | 
						|
 *           2 - path doesn't exist, not allowed to create
 | 
						|
 *           3 - path doesn't exist, tried to create and failed; or
 | 
						|
 *               path exists and is not a directory, but is supposed to be
 | 
						|
 *           4 - path is too long
 | 
						|
 *          10 - can't allocate memory for filename buffers
 | 
						|
 */
 | 
						|
{
 | 
						|
    static int rootlen = 0;   /* length of rootpath */
 | 
						|
    static char *rootpath;    /* user's "extract-to" directory */
 | 
						|
    static char *buildpath;   /* full path (so far) to extracted file */
 | 
						|
    static char *end;         /* pointer to end of buildpath ('\0') */
 | 
						|
#ifdef MSC
 | 
						|
    int attrs;                /* work around MSC stat() bug */
 | 
						|
#endif
 | 
						|
 | 
						|
#   define FN_MASK   7
 | 
						|
#   define FUNCTION  (flag & FN_MASK)
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/*---------------------------------------------------------------------------
 | 
						|
    APPEND_DIR:  append the path component to the path being built and check
 | 
						|
    for its existence.  If doesn't exist and we are creating directories, do
 | 
						|
    so for this one; else signal success or error as appropriate.
 | 
						|
  ---------------------------------------------------------------------------*/
 | 
						|
 | 
						|
    if (FUNCTION == APPEND_DIR) {
 | 
						|
        int too_long = FALSE;
 | 
						|
 | 
						|
        Trace((stderr, "appending dir segment [%s]\n", pathcomp));
 | 
						|
        while ((*end = *pathcomp++) != '\0')
 | 
						|
            ++end;
 | 
						|
 | 
						|
        /* GRR:  could do better check, see if overrunning buffer as we go:
 | 
						|
         * check end-buildpath after each append, set warning variable if
 | 
						|
         * within 20 of FILNAMSIZ; then if var set, do careful check when
 | 
						|
         * appending.  Clear variable when begin new path. */
 | 
						|
 | 
						|
        if ((end-buildpath) > FILNAMSIZ-3)  /* need '/', one-char name, '\0' */
 | 
						|
            too_long = TRUE;                /* check if extracting directory? */
 | 
						|
#ifdef MSC /* MSC 6.00 bug:  stat(non-existent-dir) == 0 [exists!] */
 | 
						|
        if (_dos_getfileattr(buildpath, &attrs) || stat(buildpath, &G.statbuf))
 | 
						|
#else
 | 
						|
        if (SSTAT(buildpath, &G.statbuf))    /* path doesn't exist */
 | 
						|
#endif
 | 
						|
        {
 | 
						|
            if (!G.create_dirs) { /* told not to create (freshening) */
 | 
						|
                free(buildpath);
 | 
						|
                return 2;         /* path doesn't exist:  nothing to do */
 | 
						|
            }
 | 
						|
            if (too_long) {
 | 
						|
                Info(slide, 1, ((char *)slide, LoadFarString(PathTooLong),
 | 
						|
                  FnFilter1(buildpath)));
 | 
						|
                free(buildpath);
 | 
						|
                return 4;         /* no room for filenames:  fatal */
 | 
						|
            }
 | 
						|
            if (MKDIR(buildpath, 0777) == -1) {   /* create the directory */
 | 
						|
                Info(slide, 1, ((char *)slide, LoadFarString(CantCreateDir),
 | 
						|
                  FnFilter2(buildpath), FnFilter1(G.filename)));
 | 
						|
                free(buildpath);
 | 
						|
                return 3;      /* path didn't exist, tried to create, failed */
 | 
						|
            }
 | 
						|
            created_dir = TRUE;
 | 
						|
        } else if (!S_ISDIR(G.statbuf.st_mode)) {
 | 
						|
            Info(slide, 1, ((char *)slide, LoadFarString(DirIsntDirectory),
 | 
						|
              FnFilter2(buildpath), FnFilter1(G.filename)));
 | 
						|
            free(buildpath);
 | 
						|
            return 3;          /* path existed but wasn't dir */
 | 
						|
        }
 | 
						|
        if (too_long) {
 | 
						|
            Info(slide, 1, ((char *)slide, LoadFarString(PathTooLong),
 | 
						|
              FnFilter1(buildpath)));
 | 
						|
            free(buildpath);
 | 
						|
            return 4;         /* no room for filenames:  fatal */
 | 
						|
        }
 | 
						|
        *end++ = '/';
 | 
						|
        *end = '\0';
 | 
						|
        Trace((stderr, "buildpath now = [%s]\n", FnFilter1(buildpath)));
 | 
						|
        return 0;
 | 
						|
 | 
						|
    } /* end if (FUNCTION == APPEND_DIR) */
 | 
						|
 | 
						|
/*---------------------------------------------------------------------------
 | 
						|
    GETPATH:  copy full path to the string pointed at by pathcomp, and free
 | 
						|
    buildpath.
 | 
						|
  ---------------------------------------------------------------------------*/
 | 
						|
 | 
						|
    if (FUNCTION == GETPATH) {
 | 
						|
        strcpy(pathcomp, buildpath);
 | 
						|
        Trace((stderr, "getting and freeing path [%s]\n",
 | 
						|
          FnFilter1(pathcomp)));
 | 
						|
        free(buildpath);
 | 
						|
        buildpath = end = (char *)NULL;
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
/*---------------------------------------------------------------------------
 | 
						|
    APPEND_NAME:  assume the path component is the filename; append it and
 | 
						|
    return without checking for existence.
 | 
						|
  ---------------------------------------------------------------------------*/
 | 
						|
 | 
						|
    if (FUNCTION == APPEND_NAME) {
 | 
						|
#ifdef NOVELL_BUG_WORKAROUND
 | 
						|
        if (end == buildpath && !G.pInfo->vollabel) {
 | 
						|
            /* work-around for Novell's "overwriting executables" bug:
 | 
						|
               prepend "./" to name when no path component is specified */
 | 
						|
            *end++ = '.';
 | 
						|
            *end++ = '/';
 | 
						|
        }
 | 
						|
#endif /* NOVELL_BUG_WORKAROUND */
 | 
						|
        Trace((stderr, "appending filename [%s]\n", FnFilter1(pathcomp)));
 | 
						|
        while ((*end = *pathcomp++) != '\0') {
 | 
						|
            ++end;
 | 
						|
            if ((end-buildpath) >= FILNAMSIZ) {
 | 
						|
                *--end = '\0';
 | 
						|
                Info(slide, 1, ((char *)slide, LoadFarString(PathTooLongTrunc),
 | 
						|
                  FnFilter1(G.filename), FnFilter2(buildpath)));
 | 
						|
                return 1;   /* filename truncated */
 | 
						|
            }
 | 
						|
        }
 | 
						|
        Trace((stderr, "buildpath now = [%s]\n", FnFilter1(buildpath)));
 | 
						|
        return 0;  /* could check for existence here, prompt for new name... */
 | 
						|
    }
 | 
						|
 | 
						|
/*---------------------------------------------------------------------------
 | 
						|
    INIT:  allocate and initialize buffer space for the file currently being
 | 
						|
    extracted.  If file was renamed with an absolute path, don't prepend the
 | 
						|
    extract-to path.
 | 
						|
  ---------------------------------------------------------------------------*/
 | 
						|
 | 
						|
    if (FUNCTION == INIT) {
 | 
						|
        Trace((stderr, "initializing buildpath to "));
 | 
						|
        /* allocate space for full filename, root path, and maybe "./" */
 | 
						|
        if ((buildpath = (char *)malloc(strlen(G.filename)+rootlen+3)) ==
 | 
						|
            (char *)NULL)
 | 
						|
            return 10;
 | 
						|
        if (G.pInfo->vollabel) {
 | 
						|
/* GRR:  for network drives, do strchr() and return IZ_VOL_LABEL if not [1] */
 | 
						|
            if (renamed_fullpath && pathcomp[1] == ':')
 | 
						|
                *buildpath = (char)ToLower(*pathcomp);
 | 
						|
            else if (!renamed_fullpath && rootlen > 1 && rootpath[1] == ':')
 | 
						|
                *buildpath = (char)ToLower(*rootpath);
 | 
						|
            else {
 | 
						|
                GETDRIVE(nLabelDrive);   /* assumed that a == 1, b == 2, etc. */
 | 
						|
                *buildpath = (char)(nLabelDrive - 1 + 'a');
 | 
						|
            }
 | 
						|
            nLabelDrive = *buildpath - 'a' + 1;        /* save for mapname() */
 | 
						|
            if (G.volflag == 0 || *buildpath < 'a' ||  /* no label/bogus disk */
 | 
						|
               (G.volflag == 1 && !isfloppy(nLabelDrive)))  /* -$:  no fixed */
 | 
						|
            {
 | 
						|
                free(buildpath);
 | 
						|
                return IZ_VOL_LABEL;     /* skipping with message */
 | 
						|
            }
 | 
						|
            *buildpath = '\0';
 | 
						|
            end = buildpath;
 | 
						|
        } else if (renamed_fullpath) {   /* pathcomp = valid data */
 | 
						|
            end = buildpath;
 | 
						|
            while ((*end = *pathcomp++) != '\0')
 | 
						|
                ++end;
 | 
						|
        } else if (rootlen > 0) {
 | 
						|
            strcpy(buildpath, rootpath);
 | 
						|
            end = buildpath + rootlen;
 | 
						|
        } else {
 | 
						|
            *buildpath = '\0';
 | 
						|
            end = buildpath;
 | 
						|
        }
 | 
						|
        Trace((stderr, "[%s]\n", FnFilter1(buildpath)));
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
/*---------------------------------------------------------------------------
 | 
						|
    ROOT:  if appropriate, store the path in rootpath and create it if neces-
 | 
						|
    sary; else assume it's a zipfile member and return.  This path segment
 | 
						|
    gets used in extracting all members from every zipfile specified on the
 | 
						|
    command line.  Note that under OS/2 and MS-DOS, if a candidate extract-to
 | 
						|
    directory specification includes a drive letter (leading "x:"), it is
 | 
						|
    treated just as if it had a trailing '/'--that is, one directory level
 | 
						|
    will be created if the path doesn't exist, unless this is otherwise pro-
 | 
						|
    hibited (e.g., freshening).
 | 
						|
  ---------------------------------------------------------------------------*/
 | 
						|
 | 
						|
#if (!defined(SFX) || defined(SFX_EXDIR))
 | 
						|
    if (FUNCTION == ROOT) {
 | 
						|
        Trace((stderr, "initializing root path to [%s]\n",
 | 
						|
          FnFilter1(pathcomp)));
 | 
						|
        if (pathcomp == (char *)NULL) {
 | 
						|
            rootlen = 0;
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
        if ((rootlen = strlen(pathcomp)) > 0) {
 | 
						|
            int had_trailing_pathsep=FALSE, has_drive=FALSE, xtra=2;
 | 
						|
 | 
						|
            if (isalpha(pathcomp[0]) && pathcomp[1] == ':')
 | 
						|
                has_drive = TRUE;   /* drive designator */
 | 
						|
            if (pathcomp[rootlen-1] == '/' || pathcomp[rootlen-1] == '\\') {
 | 
						|
                pathcomp[--rootlen] = '\0';
 | 
						|
                had_trailing_pathsep = TRUE;
 | 
						|
            }
 | 
						|
            if (has_drive && (rootlen == 2)) {
 | 
						|
                if (!had_trailing_pathsep)   /* i.e., original wasn't "x:/" */
 | 
						|
                    xtra = 3;      /* room for '.' + '/' + 0 at end of "x:" */
 | 
						|
            } else if (rootlen > 0) {     /* need not check "x:." and "x:/" */
 | 
						|
#ifdef MSC
 | 
						|
                /* MSC 6.00 bug:  stat(non-existent-dir) == 0 [exists!] */
 | 
						|
                if (_dos_getfileattr(pathcomp, &attrs) ||
 | 
						|
                    SSTAT(pathcomp,&G.statbuf) || !S_ISDIR(G.statbuf.st_mode))
 | 
						|
#else
 | 
						|
                if (SSTAT(pathcomp,&G.statbuf) || !S_ISDIR(G.statbuf.st_mode))
 | 
						|
#endif
 | 
						|
                {
 | 
						|
                    /* path does not exist */
 | 
						|
                    if (!G.create_dirs /* || iswild(pathcomp) */ ) {
 | 
						|
                        rootlen = 0;
 | 
						|
                        return 2;   /* treat as stored file */
 | 
						|
                    }
 | 
						|
/* GRR:  scan for wildcard characters?  OS-dependent...  if find any, return 2:
 | 
						|
 * treat as stored file(s) */
 | 
						|
                    /* create directory (could add loop here to scan pathcomp
 | 
						|
                     * and create more than one level, but really necessary?) */
 | 
						|
                    if (MKDIR(pathcomp, 0777) == -1) {
 | 
						|
                        Info(slide, 1, ((char *)slide,
 | 
						|
                          LoadFarString(CantCreateExtractDir),
 | 
						|
                          FnFilter1(pathcomp)));
 | 
						|
                        rootlen = 0;   /* path didn't exist, tried to create, */
 | 
						|
                        return 3;  /* failed:  file exists, or need 2+ levels */
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
            if ((rootpath = (char *)malloc(rootlen+xtra)) == (char *)NULL) {
 | 
						|
                rootlen = 0;
 | 
						|
                return 10;
 | 
						|
            }
 | 
						|
            strcpy(rootpath, pathcomp);
 | 
						|
            if (xtra == 3)                  /* had just "x:", make "x:." */
 | 
						|
                rootpath[rootlen++] = '.';
 | 
						|
            rootpath[rootlen++] = '/';
 | 
						|
            rootpath[rootlen] = '\0';
 | 
						|
            Trace((stderr, "rootpath now = [%s]\n", FnFilter1(rootpath)));
 | 
						|
        }
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
#endif /* !SFX || SFX_EXDIR */
 | 
						|
 | 
						|
/*---------------------------------------------------------------------------
 | 
						|
    END:  free rootpath, immediately prior to program exit.
 | 
						|
  ---------------------------------------------------------------------------*/
 | 
						|
 | 
						|
    if (FUNCTION == END) {
 | 
						|
        Trace((stderr, "freeing rootpath\n"));
 | 
						|
        if (rootlen > 0)
 | 
						|
            free(rootpath);
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    return 99;  /* should never reach */
 | 
						|
 | 
						|
} /* end function checkdir() */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/***********************/
 | 
						|
/* Function isfloppy() */
 | 
						|
/***********************/
 | 
						|
 | 
						|
static int isfloppy(nDrive)  /* more precisely, is it removable? */
 | 
						|
    int nDrive;
 | 
						|
{
 | 
						|
    union REGS regs;
 | 
						|
 | 
						|
    regs.h.ah = 0x44;
 | 
						|
    regs.h.al = 0x08;
 | 
						|
    regs.h.bl = (uch)nDrive;
 | 
						|
#ifdef __EMX__
 | 
						|
    _int86(0x21, ®s, ®s);
 | 
						|
    if (WREGS(regs,flags) & 1)
 | 
						|
#else
 | 
						|
    intdos(®s, ®s);
 | 
						|
    if (WREGS(regs,cflag))        /* error:  do default a/b check instead */
 | 
						|
#endif
 | 
						|
    {
 | 
						|
        Trace((stderr,
 | 
						|
          "error in DOS function 0x44 (AX = 0x%04x):  guessing instead...\n",
 | 
						|
          WREGS(regs,ax)));
 | 
						|
        return (nDrive == 1 || nDrive == 2)? TRUE : FALSE;
 | 
						|
    } else
 | 
						|
        return WREGS(regs,ax)? FALSE : TRUE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#if (!defined(__GO32__) && !defined(__EMX__))
 | 
						|
 | 
						|
typedef struct dosfcb {
 | 
						|
    uch  flag;        /* ff to indicate extended FCB */
 | 
						|
    char res[5];      /* reserved */
 | 
						|
    uch  vattr;       /* attribute */
 | 
						|
    uch  drive;       /* drive (1=A, 2=B, ...) */
 | 
						|
    uch  vn[11];      /* file or volume name */
 | 
						|
    char dmmy[5];
 | 
						|
    uch  nn[11];      /* holds new name if renaming (else reserved) */
 | 
						|
    char dmmy2[9];
 | 
						|
} dos_fcb;
 | 
						|
 | 
						|
/**************************/
 | 
						|
/* Function volumelabel() */
 | 
						|
/**************************/
 | 
						|
 | 
						|
static int volumelabel(newlabel)
 | 
						|
    char *newlabel;
 | 
						|
{
 | 
						|
#ifdef DEBUG
 | 
						|
    char *p;
 | 
						|
#endif
 | 
						|
    int len = strlen(newlabel);
 | 
						|
    int fcbseg, dtaseg, fcboff, dtaoff, retv;
 | 
						|
    dos_fcb  fcb, dta, far *pfcb=&fcb, far *pdta=&dta;
 | 
						|
    struct SREGS sregs;
 | 
						|
    union REGS regs;
 | 
						|
 | 
						|
 | 
						|
/*---------------------------------------------------------------------------
 | 
						|
    Label the diskette specified by nLabelDrive using FCB calls.  (Old ver-
 | 
						|
    sions of MS-DOS and OS/2 DOS boxes can't use DOS function 3Ch to create
 | 
						|
    labels.)  Must use far pointers for MSC FP_* macros to work; must pad
 | 
						|
    FCB filenames with spaces; and cannot include dot in 8th position.  May
 | 
						|
    or may not need to zero out FCBs before using; do so just in case.
 | 
						|
  ---------------------------------------------------------------------------*/
 | 
						|
 | 
						|
#ifdef WATCOMC_386
 | 
						|
    int truseg;
 | 
						|
 | 
						|
    memset(&sregs, 0, sizeof(sregs));
 | 
						|
    memset(®s, 0, sizeof(regs));
 | 
						|
    /* PMODE/W does not support extended versions of any dos FCB functions, */
 | 
						|
    /* so we have to use brute force, allocating real mode memory for them. */
 | 
						|
    regs.w.ax = 0x0100;
 | 
						|
    regs.w.bx = (2 * sizeof(dos_fcb) + 15) >> 4;   /* size in paragraphs */
 | 
						|
    int386(0x31, ®s, ®s);            /* DPMI allocate DOS memory */
 | 
						|
    if (regs.w.cflag)
 | 
						|
        return DF_MDY;                     /* no memory, return default */
 | 
						|
    truseg = regs.w.dx;                    /* protected mode selector */
 | 
						|
    dtaseg = regs.w.ax;                    /* real mode paragraph */
 | 
						|
    fcboff = 0;
 | 
						|
    dtaoff = sizeof(dos_fcb);
 | 
						|
#ifdef XXX__MK_FP_IS_BROKEN
 | 
						|
    /* XXX  This code may not be trustworthy in general, though it is   */
 | 
						|
    /* valid with DOS/4GW and PMODE/w, which is all we support for now. */
 | 
						|
    regs.w.ax = 6;
 | 
						|
    regs.w.bx = truseg;
 | 
						|
    int386(0x31, ®s, ®s);            /* convert seg to linear address */
 | 
						|
    pfcb = (dos_fcb far *) (((ulg) regs.w.cx << 16) | regs.w.dx);
 | 
						|
    /* pfcb = (dos_fcb far *) ((ulg) dtaseg << 4); */
 | 
						|
    pdta = pfcb + 1;
 | 
						|
#else
 | 
						|
    pfcb = MK_FP(truseg, fcboff);
 | 
						|
    pdta = MK_FP(truseg, dtaoff);
 | 
						|
#endif
 | 
						|
    _fmemset((char far *)pfcb, 0, 2 * sizeof(dos_fcb));
 | 
						|
    /* we pass the REAL MODE paragraph to the dos interrupts: */
 | 
						|
    fcbseg = dtaseg;
 | 
						|
 | 
						|
#else /* !WATCOMC_386 */
 | 
						|
 | 
						|
    memset((char *)&dta, 0, sizeof(dos_fcb));
 | 
						|
    memset((char *)&fcb, 0, sizeof(dos_fcb));
 | 
						|
    fcbseg = FP_SEG(pfcb);
 | 
						|
    fcboff = FP_OFF(pfcb);
 | 
						|
    dtaseg = FP_SEG(pdta);
 | 
						|
    dtaoff = FP_OFF(pdta);
 | 
						|
#endif /* ?WATCOMC_386 */
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
    for (p = (char *)&dta; (p - (char *)&dta) < sizeof(dos_fcb); ++p)
 | 
						|
        if (*p)
 | 
						|
            fprintf(stderr, "error:  dta[%d] = %x\n", (p - (char *)&dta), *p);
 | 
						|
    for (p = (char *)&fcb; (p - (char *)&fcb) < sizeof(dos_fcb); ++p)
 | 
						|
        if (*p)
 | 
						|
            fprintf(stderr, "error:  fcb[%d] = %x\n", (p - (char *)&fcb), *p);
 | 
						|
    printf("testing pointer macros:\n");
 | 
						|
    segread(&sregs);
 | 
						|
    printf("cs = %x, ds = %x, es = %x, ss = %x\n", sregs.cs, sregs.ds, sregs.es,
 | 
						|
      sregs.ss);
 | 
						|
#endif /* DEBUG */
 | 
						|
 | 
						|
#if 0
 | 
						|
#ifdef __TURBOC__
 | 
						|
    bdosptr(0x1a, dta, DO_NOT_CARE);
 | 
						|
#else
 | 
						|
    (intdosx method below)
 | 
						|
#endif
 | 
						|
#endif /* 0 */
 | 
						|
 | 
						|
    /* set the disk transfer address for subsequent FCB calls */
 | 
						|
    sregs.ds = dtaseg;
 | 
						|
    WREGS(regs,dx) = dtaoff;
 | 
						|
    Trace((stderr, "segment:offset of pdta = %x:%x\n", dtaseg, dtaoff));
 | 
						|
    Trace((stderr, "&dta = %lx, pdta = %lx\n", (ulg)&dta, (ulg)pdta));
 | 
						|
    regs.h.ah = 0x1a;
 | 
						|
    F_intdosx(®s, ®s, &sregs);
 | 
						|
 | 
						|
    /* fill in the FCB */
 | 
						|
    sregs.ds = fcbseg;
 | 
						|
    WREGS(regs,dx) = fcboff;
 | 
						|
    pfcb->flag = 0xff;          /* extended FCB */
 | 
						|
    pfcb->vattr = 0x08;         /* attribute:  disk volume label */
 | 
						|
    pfcb->drive = (uch)nLabelDrive;
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
    Trace((stderr, "segment:offset of pfcb = %x:%x\n", sregs.ds, WREGS(regs,dx)));
 | 
						|
    Trace((stderr, "&fcb = %lx, pfcb = %lx\n", (ulg)&fcb, (ulg)pfcb));
 | 
						|
    Trace((stderr, "(2nd check:  labelling drive %c:)\n", pfcb->drive-1+'A'));
 | 
						|
    if (pfcb->flag != fcb.flag)
 | 
						|
        fprintf(stderr, "error:  pfcb->flag = %d, fcb.flag = %d\n",
 | 
						|
          pfcb->flag, fcb.flag);
 | 
						|
    if (pfcb->drive != fcb.drive)
 | 
						|
        fprintf(stderr, "error:  pfcb->drive = %d, fcb.drive = %d\n",
 | 
						|
          pfcb->drive, fcb.drive);
 | 
						|
    if (pfcb->vattr != fcb.vattr)
 | 
						|
        fprintf(stderr, "error:  pfcb->vattr = %d, fcb.vattr = %d\n",
 | 
						|
          pfcb->vattr, fcb.vattr);
 | 
						|
#endif /* DEBUG */
 | 
						|
 | 
						|
    /* check for existing label */
 | 
						|
    Trace((stderr, "searching for existing label via FCBs\n"));
 | 
						|
    regs.h.ah = 0x11;      /* FCB find first */
 | 
						|
#ifdef WATCOMC_386
 | 
						|
    _fstrncpy((char far *)&pfcb->vn, "???????????", 11);
 | 
						|
#else
 | 
						|
# if 0  /* THIS STRNCPY FAILS (MSC bug?): */
 | 
						|
    strncpy(pfcb->vn, "???????????", 11);   /* i.e., "*.*" */
 | 
						|
    Trace((stderr, "pfcb->vn = %lx\n", (ulg)pfcb->vn));
 | 
						|
    Trace((stderr, "flag = %x, drive = %d, vattr = %x, vn = %s = %s.\n",
 | 
						|
      fcb.flag, fcb.drive, fcb.vattr, fcb.vn, pfcb->vn));
 | 
						|
# endif
 | 
						|
    strncpy((char *)fcb.vn, "???????????", 11);   /* i.e., "*.*" */
 | 
						|
#endif /* ?WATCOMC_386 */
 | 
						|
    Trace((stderr, "fcb.vn = %lx\n", (ulg)fcb.vn));
 | 
						|
    Trace((stderr, "regs.h.ah = %x, regs.x.dx = %04x, sregs.ds = %04x\n",
 | 
						|
      regs.h.ah, WREGS(regs,dx), sregs.ds));
 | 
						|
    Trace((stderr, "flag = %x, drive = %d, vattr = %x, vn = %s = %s.\n",
 | 
						|
      fcb.flag, fcb.drive, fcb.vattr, fcb.vn, pfcb->vn));
 | 
						|
    F_intdosx(®s, ®s, &sregs);
 | 
						|
 | 
						|
/*---------------------------------------------------------------------------
 | 
						|
    If not previously labelled, write a new label.  Otherwise just rename,
 | 
						|
    since MS-DOS 2.x has a bug that damages the FAT when the old label is
 | 
						|
    deleted.
 | 
						|
  ---------------------------------------------------------------------------*/
 | 
						|
 | 
						|
    if (regs.h.al) {
 | 
						|
        Trace((stderr, "no label found\n\n"));
 | 
						|
        regs.h.ah = 0x16;                 /* FCB create file */
 | 
						|
#ifdef WATCOMC_386
 | 
						|
        _fstrncpy((char far *)pfcb->vn, newlabel, len);
 | 
						|
        if (len < 11)
 | 
						|
            _fstrncpy((char far *)(pfcb->vn+len), "           ", 11-len);
 | 
						|
#else
 | 
						|
        strncpy((char *)fcb.vn, newlabel, len);
 | 
						|
        if (len < 11)   /* fill with spaces */
 | 
						|
            strncpy((char *)(fcb.vn+len), "           ", 11-len);
 | 
						|
#endif
 | 
						|
        Trace((stderr, "fcb.vn = %lx  pfcb->vn = %lx\n", (ulg)fcb.vn,
 | 
						|
          (ulg)pfcb->vn));
 | 
						|
        Trace((stderr, "flag = %x, drive = %d, vattr = %x\n", fcb.flag,
 | 
						|
          fcb.drive, fcb.vattr));
 | 
						|
        Trace((stderr, "vn = %s = %s.\n", fcb.vn, pfcb->vn));
 | 
						|
        F_intdosx(®s, ®s, &sregs);
 | 
						|
        regs.h.ah = 0x10;                 /* FCB close file */
 | 
						|
        if (regs.h.al) {
 | 
						|
            Trace((stderr, "unable to write volume name (AL = %x)\n",
 | 
						|
              regs.h.al));
 | 
						|
            F_intdosx(®s, ®s, &sregs);
 | 
						|
            retv = 1;
 | 
						|
        } else {
 | 
						|
            F_intdosx(®s, ®s, &sregs);
 | 
						|
            Trace((stderr, "new volume label [%s] written\n", newlabel));
 | 
						|
            retv = 0;
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        Trace((stderr, "found old label [%s]\n\n", dta.vn));  /* not term. */
 | 
						|
        regs.h.ah = 0x17;                 /* FCB rename */
 | 
						|
#ifdef WATCOMC_386
 | 
						|
        _fstrncpy((char far *)pfcb->vn, (char far *)pdta->vn, 11);
 | 
						|
        _fstrncpy((char far *)pfcb->nn, newlabel, len);
 | 
						|
        if (len < 11)
 | 
						|
            _fstrncpy((char far *)(pfcb->nn+len), "           ", 11-len);
 | 
						|
#else
 | 
						|
        strncpy((char *)fcb.vn, (char *)dta.vn, 11);
 | 
						|
        strncpy((char *)fcb.nn, newlabel, len);
 | 
						|
        if (len < 11)                     /* fill with spaces */
 | 
						|
            strncpy((char *)(fcb.nn+len), "           ", 11-len);
 | 
						|
#endif
 | 
						|
        Trace((stderr, "fcb.vn = %lx  pfcb->vn = %lx\n", (ulg)fcb.vn,
 | 
						|
          (ulg)pfcb->vn));
 | 
						|
        Trace((stderr, "fcb.nn = %lx  pfcb->nn = %lx\n", (ulg)fcb.nn,
 | 
						|
          (ulg)pfcb->nn));
 | 
						|
        Trace((stderr, "flag = %x, drive = %d, vattr = %x\n", fcb.flag,
 | 
						|
          fcb.drive, fcb.vattr));
 | 
						|
        Trace((stderr, "vn = %s = %s.\n", fcb.vn, pfcb->vn));
 | 
						|
        Trace((stderr, "nn = %s = %s.\n", fcb.nn, pfcb->nn));
 | 
						|
        F_intdosx(®s, ®s, &sregs);
 | 
						|
        if (regs.h.al) {
 | 
						|
            Trace((stderr, "Unable to change volume name (AL = %x)\n",
 | 
						|
              regs.h.al));
 | 
						|
            retv = 1;
 | 
						|
        } else {
 | 
						|
            Trace((stderr, "volume label changed to [%s]\n", newlabel));
 | 
						|
            retv = 0;
 | 
						|
        }
 | 
						|
    }
 | 
						|
#ifdef WATCOMC_386
 | 
						|
    regs.w.ax = 0x0101;                    /* free dos memory */
 | 
						|
    regs.w.dx = truseg;
 | 
						|
    int386(0x31, ®s, ®s);
 | 
						|
#endif
 | 
						|
    return retv;
 | 
						|
 | 
						|
} /* end function volumelabel() */
 | 
						|
 | 
						|
#endif /* !__GO32__ && !__EMX__ */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/****************************/
 | 
						|
/* Function close_outfile() */
 | 
						|
/****************************/
 | 
						|
 | 
						|
void close_outfile(__G)
 | 
						|
    __GDEF
 | 
						|
 /*
 | 
						|
  * MS-DOS VERSION
 | 
						|
  *
 | 
						|
  * Set the output file date/time stamp according to information from the
 | 
						|
  * zipfile directory record for this member, then close the file and set
 | 
						|
  * its permissions (archive, hidden, read-only, system).  Aside from closing
 | 
						|
  * the file, this routine is optional (but most compilers support it).
 | 
						|
  */
 | 
						|
{
 | 
						|
#ifdef USE_EF_UT_TIME
 | 
						|
    iztimes z_utime;
 | 
						|
 | 
						|
    /* The following DOS date/time structure is machine-dependent as it
 | 
						|
     * assumes "little endian" byte order.  For MSDOS specific code, which
 | 
						|
     * is run on x86 CPUs (or emulators), this assumption is valid; but
 | 
						|
     * care should be taken when using this code as template for other ports.
 | 
						|
     */
 | 
						|
    union {
 | 
						|
        ulg z_dostime;
 | 
						|
# ifdef __TURBOC__
 | 
						|
        struct ftime ft;        /* system file time record */
 | 
						|
# endif
 | 
						|
        struct {                /* date and time words */
 | 
						|
            union {             /* DOS file modification time word */
 | 
						|
                ush ztime;
 | 
						|
                struct {
 | 
						|
                    unsigned zt_se : 5;
 | 
						|
                    unsigned zt_mi : 6;
 | 
						|
                    unsigned zt_hr : 5;
 | 
						|
                } _tf;
 | 
						|
            } _t;
 | 
						|
            union {             /* DOS file modification date word */
 | 
						|
                ush zdate;
 | 
						|
                struct {
 | 
						|
                    unsigned zd_dy : 5;
 | 
						|
                    unsigned zd_mo : 4;
 | 
						|
                    unsigned zd_yr : 7;
 | 
						|
                } _df;
 | 
						|
            } _d;
 | 
						|
        } zt;
 | 
						|
    } dos_dt;
 | 
						|
#else /* !USE_EF_UT_TIME */
 | 
						|
# ifdef __TURBOC__
 | 
						|
    union {
 | 
						|
        struct ftime ft;        /* system file time record */
 | 
						|
        struct {
 | 
						|
            ush ztime;          /* date and time words */
 | 
						|
            ush zdate;          /* .. same format as in .ZIP file */
 | 
						|
        } zt;
 | 
						|
    } dos_dt;
 | 
						|
# endif
 | 
						|
#endif /* ?USE_EF_UT_TIME */
 | 
						|
 | 
						|
 | 
						|
/*---------------------------------------------------------------------------
 | 
						|
    Copy and/or convert time and date variables, if necessary; then set the
 | 
						|
    file time/date.  WEIRD BORLAND "BUG":  if output is buffered, and if run
 | 
						|
    under at least some versions of DOS (e.g., 6.0), and if files are smaller
 | 
						|
    than DOS physical block size (i.e., 512 bytes) (?), then files MAY NOT
 | 
						|
    get timestamped correctly--apparently setftime() occurs before any data
 | 
						|
    are written to the file, and when file is closed and buffers are flushed,
 | 
						|
    timestamp is overwritten with current time.  Even with a 32K buffer, this
 | 
						|
    does not seem to occur with larger files.  UnZip output is now unbuffered,
 | 
						|
    but if it were not, could still avoid problem by adding "fflush(outfile)"
 | 
						|
    just before setftime() call.  Weird, huh?
 | 
						|
  ---------------------------------------------------------------------------*/
 | 
						|
 | 
						|
#ifdef USE_EF_UT_TIME
 | 
						|
    if (G.extra_field && (ef_scan_for_izux(G.extra_field,
 | 
						|
        G.lrec.extra_field_length, 0, &z_utime, NULL) & EB_UT_FL_MTIME))
 | 
						|
    {
 | 
						|
        struct tm *t;
 | 
						|
 | 
						|
        TTrace((stderr, "close_outfile:  Unix e.f. modif. time = %ld\n",
 | 
						|
          z_utime.mtime));
 | 
						|
        /* round up to even seconds */
 | 
						|
        z_utime.mtime = (z_utime.mtime + 1) & (~1);
 | 
						|
        TIMET_TO_NATIVE(z_utime.mtime)   /* NOP unless MSC 7.0 or Macintosh */
 | 
						|
        t = localtime(&(z_utime.mtime));
 | 
						|
        if (t->tm_year < 80) {
 | 
						|
            dos_dt.zt._t._tf.zt_se = 0;
 | 
						|
            dos_dt.zt._t._tf.zt_mi = 0;
 | 
						|
            dos_dt.zt._t._tf.zt_hr = 0;
 | 
						|
            dos_dt.zt._d._df.zd_dy = 1;
 | 
						|
            dos_dt.zt._d._df.zd_mo = 1;
 | 
						|
            dos_dt.zt._d._df.zd_yr = 0;
 | 
						|
        } else {
 | 
						|
            dos_dt.zt._t._tf.zt_se = t->tm_sec >> 1;
 | 
						|
            dos_dt.zt._t._tf.zt_mi = t->tm_min;
 | 
						|
            dos_dt.zt._t._tf.zt_hr = t->tm_hour;
 | 
						|
            dos_dt.zt._d._df.zd_dy = t->tm_mday;
 | 
						|
            dos_dt.zt._d._df.zd_mo = t->tm_mon + 1;
 | 
						|
            dos_dt.zt._d._df.zd_yr = t->tm_year - 80;
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        dos_dt.zt._t.ztime = G.lrec.last_mod_file_time;
 | 
						|
        dos_dt.zt._d.zdate = G.lrec.last_mod_file_date;
 | 
						|
    }
 | 
						|
# ifdef __TURBOC__
 | 
						|
    setftime(fileno(G.outfile), &dos_dt.ft);
 | 
						|
# else
 | 
						|
    _dos_setftime(fileno(G.outfile), dos_dt.zt._d.zdate, dos_dt.zt._t.ztime);
 | 
						|
# endif
 | 
						|
#else /* !USE_EF_UT_TIME */
 | 
						|
# ifdef __TURBOC__
 | 
						|
    dos_dt.zt.ztime = G.lrec.last_mod_file_time;
 | 
						|
    dos_dt.zt.zdate = G.lrec.last_mod_file_date;
 | 
						|
    setftime(fileno(G.outfile), &dos_dt.ft);
 | 
						|
# else
 | 
						|
    _dos_setftime(fileno(G.outfile), G.lrec.last_mod_file_date,
 | 
						|
                                     G.lrec.last_mod_file_time);
 | 
						|
# endif
 | 
						|
#endif /* ?USE_EF_UT_TIME */
 | 
						|
 | 
						|
/*---------------------------------------------------------------------------
 | 
						|
    And finally we can close the file...at least everybody agrees on how to
 | 
						|
    do *this*.  I think...  Also change the mode according to the stored file
 | 
						|
    attributes, since we didn't do that when we opened the dude.
 | 
						|
  ---------------------------------------------------------------------------*/
 | 
						|
 | 
						|
    fclose(G.outfile);
 | 
						|
 | 
						|
#ifdef __TURBOC__
 | 
						|
#   if (defined(__BORLANDC__) && (__BORLANDC__ >= 0x0452))
 | 
						|
#     define Chmod  _rtl_chmod
 | 
						|
#   else
 | 
						|
#     define Chmod  _chmod
 | 
						|
#   endif
 | 
						|
    if (Chmod(G.filename, 1, G.pInfo->file_attr) != G.pInfo->file_attr)
 | 
						|
        Info(slide, 1, ((char *)slide, LoadFarString(AttribsMayBeWrong)));
 | 
						|
#else /* !__TURBOC__ */
 | 
						|
    _dos_setfileattr(G.filename, G.pInfo->file_attr);
 | 
						|
#endif /* ?__TURBOC__ */
 | 
						|
 | 
						|
} /* end function close_outfile() */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#ifndef SFX
 | 
						|
 | 
						|
/*************************/
 | 
						|
/* Function dateformat() */
 | 
						|
/*************************/
 | 
						|
 | 
						|
int dateformat()
 | 
						|
{
 | 
						|
 | 
						|
/*---------------------------------------------------------------------------
 | 
						|
    For those operating systems that support it, this function returns a
 | 
						|
    value that tells how national convention says that numeric dates are
 | 
						|
    displayed.  Return values are DF_YMD, DF_DMY and DF_MDY (the meanings
 | 
						|
    should be fairly obvious).
 | 
						|
  ---------------------------------------------------------------------------*/
 | 
						|
 | 
						|
#ifndef WINDLL
 | 
						|
    ush CountryInfo[18];
 | 
						|
#if (!defined(__GO32__) && !defined(__EMX__))
 | 
						|
    ush far *_CountryInfo = CountryInfo;
 | 
						|
    struct SREGS sregs;
 | 
						|
    union REGS regs;
 | 
						|
#ifdef WATCOMC_386
 | 
						|
    ush seg, para;
 | 
						|
 | 
						|
    memset(&sregs, 0, sizeof(sregs));
 | 
						|
    memset(®s, 0, sizeof(regs));
 | 
						|
    /* PMODE/W does not support an extended version of dos function 38,   */
 | 
						|
    /* so we have to use brute force, allocating real mode memory for it. */
 | 
						|
    regs.w.ax = 0x0100;
 | 
						|
    regs.w.bx = 3;                         /* 36 bytes rounds up to 48 */
 | 
						|
    int386(0x31, ®s, ®s);            /* DPMI allocate DOS memory */
 | 
						|
    if (regs.w.cflag)
 | 
						|
        return DF_MDY;                     /* no memory, return default */
 | 
						|
    seg = regs.w.dx;
 | 
						|
    para = regs.w.ax;
 | 
						|
 | 
						|
#ifdef XXX__MK_FP_IS_BROKEN
 | 
						|
    /* XXX  This code may not be trustworthy in general, though it is
 | 
						|
     * valid with DOS/4GW and PMODE/w, which is all we support for now. */
 | 
						|
 /* _CountryInfo = (ush far *) (para << 4); */ /* works for some extenders */
 | 
						|
    regs.w.ax = 6;
 | 
						|
    regs.w.bx = seg;
 | 
						|
    int386(0x31, ®s, ®s);            /* convert seg to linear address */
 | 
						|
    _CountryInfo = (ush far *) (((ulg) regs.w.cx << 16) | regs.w.dx);
 | 
						|
#else
 | 
						|
    _CountryInfo = (ush far *) MK_FP(seg, 0);
 | 
						|
#endif
 | 
						|
 | 
						|
    sregs.ds = para;                       /* real mode paragraph */
 | 
						|
    regs.w.dx = 0;                         /* no offset from segment */
 | 
						|
    regs.w.ax = 0x3800;
 | 
						|
    int86x_realmode(0x21, ®s, ®s, &sregs);
 | 
						|
    CountryInfo[0] = regs.w.cflag ? 0 : _CountryInfo[0];
 | 
						|
    regs.w.ax = 0x0101;
 | 
						|
    regs.w.dx = seg;
 | 
						|
    int386(0x31, ®s, ®s);              /* DPMI free DOS memory */
 | 
						|
 | 
						|
#else /* !WATCOMC_386 */
 | 
						|
 | 
						|
    sregs.ds  = FP_SEG(_CountryInfo);
 | 
						|
    regs.x.dx = FP_OFF(_CountryInfo);
 | 
						|
    regs.x.ax = 0x3800;
 | 
						|
    intdosx(®s, ®s, &sregs);
 | 
						|
#endif /* ?WATCOMC_386 */
 | 
						|
 | 
						|
#else /* __GO32__ || __EMX__ */
 | 
						|
    _dos_getcountryinfo(CountryInfo);
 | 
						|
#endif /* ?(__GO32__ || __EMX__) */
 | 
						|
 | 
						|
    switch(CountryInfo[0]) {
 | 
						|
        case 0:
 | 
						|
            return DF_MDY;
 | 
						|
        case 1:
 | 
						|
            return DF_DMY;
 | 
						|
        case 2:
 | 
						|
            return DF_YMD;
 | 
						|
    }
 | 
						|
#endif /* !WINDLL && !WATCOMC_386 */
 | 
						|
 | 
						|
    return DF_MDY;   /* default for systems without locale info */
 | 
						|
 | 
						|
} /* end function dateformat() */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#ifndef WINDLL
 | 
						|
 | 
						|
/************************/
 | 
						|
/*  Function version()  */
 | 
						|
/************************/
 | 
						|
 | 
						|
void version(__G)
 | 
						|
    __GDEF
 | 
						|
{
 | 
						|
    int len;
 | 
						|
#if defined(__DJGPP__) || defined(__WATCOMC__) || \
 | 
						|
    (defined(_MSC_VER) && (_MSC_VER != 800))
 | 
						|
    char buf[80];
 | 
						|
#endif
 | 
						|
 | 
						|
    len = sprintf((char *)slide, LoadFarString(CompiledWith),
 | 
						|
 | 
						|
#ifdef __GNUC__
 | 
						|
#  ifdef __DJGPP__
 | 
						|
      (sprintf(buf, "djgpp v%d.%02d / gcc ", __DJGPP__, __DJGPP_MINOR__), buf),
 | 
						|
#  elif __GO32__                  /* __GO32__ is defined as "1" only (sigh) */
 | 
						|
      "djgpp v1.x / gcc ",
 | 
						|
#  elif defined(__EMX__)          /* ...so is __EMX__ (double sigh) */
 | 
						|
      "emx+gcc ",
 | 
						|
#  else
 | 
						|
      "gcc ",
 | 
						|
#  endif
 | 
						|
      __VERSION__,
 | 
						|
#elif defined(__WATCOMC__)
 | 
						|
#  if (__WATCOMC__ % 10 != 0)
 | 
						|
      "Watcom C/C++", (sprintf(buf, " %d.%02d", __WATCOMC__ / 100,
 | 
						|
                               __WATCOMC__ % 100), buf),
 | 
						|
#  else
 | 
						|
      "Watcom C/C++", (sprintf(buf, " %d.%d", __WATCOMC__ / 100,
 | 
						|
                               (__WATCOMC__ % 100) / 10), buf),
 | 
						|
#  endif
 | 
						|
#elif defined(__TURBOC__)
 | 
						|
#  ifdef __BORLANDC__
 | 
						|
      "Borland C++",
 | 
						|
#    if (__BORLANDC__ < 0x0200)
 | 
						|
        " 1.0",
 | 
						|
#    elif (__BORLANDC__ == 0x0200)   /* James:  __TURBOC__ = 0x0297 */
 | 
						|
        " 2.0",
 | 
						|
#    elif (__BORLANDC__ == 0x0400)
 | 
						|
        " 3.0",
 | 
						|
#    elif (__BORLANDC__ == 0x0410)   /* __BCPLUSPLUS__ = 0x0310 */
 | 
						|
        " 3.1",
 | 
						|
#    elif (__BORLANDC__ == 0x0452)   /* __BCPLUSPLUS__ = 0x0320 */
 | 
						|
        " 4.0 or 4.02",
 | 
						|
#    elif (__BORLANDC__ == 0x0460)   /* __BCPLUSPLUS__ = 0x0340 */
 | 
						|
        " 4.5",
 | 
						|
#    elif (__BORLANDC__ == 0x0500)
 | 
						|
        " 5.0",
 | 
						|
#    else
 | 
						|
        " later than 5.0",
 | 
						|
#    endif
 | 
						|
#  else
 | 
						|
      "Turbo C",
 | 
						|
#    if (__TURBOC__ > 0x0500)
 | 
						|
        "++ later than 5.0",
 | 
						|
#    elif (__TURBOC__ == 0x0500)     /* Mike W:  5.0 -> 0x0500 */
 | 
						|
        "++ 5.0",
 | 
						|
#    elif (__TURBOC__ >= 0x0400)     /* Kevin:  3.0 -> 0x0401 */
 | 
						|
        "++ 3.0 or 4.x",
 | 
						|
#    elif (__TURBOC__ == 0x0295)     /* [661] vfy'd by Kevin */
 | 
						|
        "++ 1.0",
 | 
						|
#    elif ((__TURBOC__ >= 0x018d) && (__TURBOC__ <= 0x0200)) /* James: 0x0200 */
 | 
						|
        " 2.0",
 | 
						|
#    elif (__TURBOC__ > 0x0100)
 | 
						|
        " 1.5",                      /* James:  0x0105? */
 | 
						|
#    else
 | 
						|
        " 1.0",                      /* James:  0x0100 */
 | 
						|
#    endif
 | 
						|
#  endif
 | 
						|
#elif defined(MSC)
 | 
						|
      "Microsoft C ",
 | 
						|
#  ifdef _MSC_VER
 | 
						|
#    if (_MSC_VER == 800)
 | 
						|
        "8.0/8.0c (Visual C++ 1.0/1.5)",
 | 
						|
#    else
 | 
						|
        (sprintf(buf, "%d.%02d", _MSC_VER/100, _MSC_VER%100), buf),
 | 
						|
#    endif
 | 
						|
#  else
 | 
						|
      "5.1 or earlier",
 | 
						|
#  endif
 | 
						|
#else
 | 
						|
      "unknown compiler", "",
 | 
						|
#endif /* ?compilers */
 | 
						|
 | 
						|
      "MS-DOS",
 | 
						|
 | 
						|
#if (defined(__GNUC__) || defined(WATCOMC_386))
 | 
						|
      " (32-bit)",
 | 
						|
#else
 | 
						|
#  if defined(M_I86HM) || defined(__HUGE__)
 | 
						|
      " (16-bit, huge)",
 | 
						|
#  elif defined(M_I86LM) || defined(__LARGE__)
 | 
						|
      " (16-bit, large)",
 | 
						|
#  elif defined(M_I86MM) || defined(__MEDIUM__)
 | 
						|
      " (16-bit, medium)",
 | 
						|
#  elif defined(M_I86CM) || defined(__COMPACT__)
 | 
						|
      " (16-bit, compact)",
 | 
						|
#  elif defined(M_I86SM) || defined(__SMALL__)
 | 
						|
      " (16-bit, small)",
 | 
						|
#  elif defined(M_I86TM) || defined(__TINY__)
 | 
						|
      " (16-bit, tiny)",
 | 
						|
#  else
 | 
						|
      " (16-bit)",
 | 
						|
#  endif
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef __DATE__
 | 
						|
      " on ", __DATE__
 | 
						|
#else
 | 
						|
      "", ""
 | 
						|
#endif
 | 
						|
    );
 | 
						|
 | 
						|
    (*G.message)((zvoid *)&G, slide, (ulg)len, 0);
 | 
						|
                                /* MSC can't handle huge macro expansion */
 | 
						|
 | 
						|
    /* temporary debugging code for Borland compilers only */
 | 
						|
#if (defined(__TURBOC__) && defined(DEBUG))
 | 
						|
    Info(slide, 0, ((char *)slide, "\tdebug(__TURBOC__ = 0x%04x = %d)\n",
 | 
						|
      __TURBOC__, __TURBOC__));
 | 
						|
#ifdef __BORLANDC__
 | 
						|
    Info(slide, 0, ((char *)slide, "\tdebug(__BORLANDC__ = 0x%04x)\n",
 | 
						|
      __BORLANDC__));
 | 
						|
#else
 | 
						|
    Info(slide, 0, ((char *)slide, "\tdebug(__BORLANDC__ not defined)\n"));
 | 
						|
#endif
 | 
						|
#ifdef __TCPLUSPLUS__
 | 
						|
    Info(slide, 0, ((char *)slide, "\tdebug(__TCPLUSPLUS__ = 0x%04x)\n",
 | 
						|
      __TCPLUSPLUS__));
 | 
						|
#else
 | 
						|
    Info(slide, 0, ((char *)slide, "\tdebug(__TCPLUSPLUS__ not defined)\n"));
 | 
						|
#endif
 | 
						|
#ifdef __BCPLUSPLUS__
 | 
						|
    Info(slide, 0, ((char *)slide, "\tdebug(__BCPLUSPLUS__ = 0x%04x)\n\n",
 | 
						|
      __BCPLUSPLUS__));
 | 
						|
#else
 | 
						|
    Info(slide, 0, ((char *)slide, "\tdebug(__BCPLUSPLUS__ not defined)\n\n"));
 | 
						|
#endif
 | 
						|
#endif /* __TURBOC__ && DEBUG */
 | 
						|
 | 
						|
} /* end function version() */
 | 
						|
 | 
						|
#endif /* !WINDLL */
 | 
						|
#endif /* !SFX */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#if (defined(__GO32__) || defined(__EMX__))
 | 
						|
 | 
						|
int volatile _doserrno;
 | 
						|
 | 
						|
unsigned _dos_getcountryinfo(void *countrybuffer)
 | 
						|
{
 | 
						|
    asm("movl %0, %%edx": : "g" (countrybuffer));
 | 
						|
    asm("movl $0x3800, %eax");
 | 
						|
    asm("int $0x21": : : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi");
 | 
						|
    _doserrno = 0;
 | 
						|
    asm("jnc 1f");
 | 
						|
    asm("movl %%eax, %0": "=m" (_doserrno));
 | 
						|
    asm("1:");
 | 
						|
    return _doserrno;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if (!defined(__DJGPP__) || (__DJGPP__ < 2))
 | 
						|
 | 
						|
void _dos_setftime(int fd, ush dosdate, ush dostime)
 | 
						|
{
 | 
						|
    asm("movl %0, %%ebx": : "g" (fd));
 | 
						|
    asm("movl %0, %%ecx": : "g" (dostime));
 | 
						|
    asm("movl %0, %%edx": : "g" (dosdate));
 | 
						|
    asm("movl $0x5701, %eax");
 | 
						|
    asm("int $0x21": : : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi");
 | 
						|
}
 | 
						|
 | 
						|
void _dos_setfileattr(char *name, int attr)
 | 
						|
{
 | 
						|
    asm("movl %0, %%edx": : "g" (name));
 | 
						|
    asm("movl %0, %%ecx": : "g" (attr));
 | 
						|
    asm("movl $0x4301, %eax");
 | 
						|
    asm("int $0x21": : : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi");
 | 
						|
}
 | 
						|
 | 
						|
void _dos_getdrive(unsigned *d)
 | 
						|
{
 | 
						|
    asm("movl $0x1900, %eax");
 | 
						|
    asm("int $0x21": : : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi");
 | 
						|
    asm("xorb %ah, %ah");
 | 
						|
    asm("incb %al");
 | 
						|
    asm("movl %%eax, %0": "=a" (*d));
 | 
						|
}
 | 
						|
 | 
						|
unsigned _dos_creat(char *path, unsigned attr, int *fd)
 | 
						|
{
 | 
						|
    asm("movl $0x3c00, %eax");
 | 
						|
    asm("movl %0, %%edx": :"g" (path));
 | 
						|
    asm("movl %0, %%ecx": :"g" (attr));
 | 
						|
    asm("int $0x21": : : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi");
 | 
						|
    asm("movl %%eax, %0": "=a" (*fd));
 | 
						|
    _doserrno = 0;
 | 
						|
    asm("jnc 1f");
 | 
						|
    _doserrno = *fd;
 | 
						|
    switch (_doserrno) {
 | 
						|
    case 3:
 | 
						|
           errno = ENOENT;
 | 
						|
           break;
 | 
						|
    case 4:
 | 
						|
           errno = EMFILE;
 | 
						|
           break;
 | 
						|
    case 5:
 | 
						|
           errno = EACCES;
 | 
						|
           break;
 | 
						|
    }
 | 
						|
    asm("1:");
 | 
						|
    return _doserrno;
 | 
						|
}
 | 
						|
 | 
						|
unsigned _dos_close(int fd)
 | 
						|
{
 | 
						|
    asm("movl %0, %%ebx": : "g" (fd));
 | 
						|
    asm("movl $0x3e00, %eax");
 | 
						|
    asm("int $0x21": : : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi");
 | 
						|
    _doserrno = 0;
 | 
						|
    asm("jnc 1f");
 | 
						|
    asm ("movl %%eax, %0": "=m" (_doserrno));
 | 
						|
    if (_doserrno == 6) {
 | 
						|
          errno = EBADF;
 | 
						|
    }
 | 
						|
    asm("1:");
 | 
						|
    return _doserrno;
 | 
						|
}
 | 
						|
 | 
						|
#endif /* !__DJGPP__ || (__DJGPP__ < 2) */
 | 
						|
 | 
						|
 | 
						|
static int volumelabel(char *name)
 | 
						|
{
 | 
						|
    int fd;
 | 
						|
 | 
						|
    return _dos_creat(name, FA_LABEL, &fd) ? fd : _dos_close(fd);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if (defined(__DJGPP__) && (__DJGPP__ > 1))
 | 
						|
 | 
						|
/* Prevent globbing of filenames.  This gives the same functionality as
 | 
						|
 * "stubedit <program> globbing=no" did with DJGPP v1.
 | 
						|
 */
 | 
						|
int __crt0_glob_function(void)
 | 
						|
{
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* Reduce the size of the executable and remove the functionality to read
 | 
						|
 * the program's environment from whatever $DJGPP points to.
 | 
						|
 */
 | 
						|
void __crt_load_environment_file(void)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
#endif /* __DJGPP__ > 1 */
 | 
						|
#endif /* __GO32__ || __EMX__ */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#ifdef WATCOMC_386
 | 
						|
 | 
						|
static struct RMINFO {
 | 
						|
    ulg edi, esi, ebp;
 | 
						|
    ulg reserved;
 | 
						|
    ulg ebx, edx, ecx, eax;
 | 
						|
    ush flags;
 | 
						|
    ush es,ds,fs,gs;
 | 
						|
    ush ip_ignored,cs_ignored;
 | 
						|
    ush sp,ss;
 | 
						|
};
 | 
						|
 | 
						|
/* This function is used to call dos interrupts that may not be supported
 | 
						|
 * by some particular 32-bit DOS extender.  It uses DPMI function 300h to
 | 
						|
 * simulate a real mode call of the interrupt.  The caller is responsible
 | 
						|
 * for providing real mode addresses of any buffer areas used.  The docs
 | 
						|
 * for PMODE/W imply that this should not be necessary for calling the DOS
 | 
						|
 * interrupts that it doesn't extend, but it crashes when this isn't used. */
 | 
						|
 | 
						|
static int int86x_realmode(int inter_no, union REGS *in,
 | 
						|
                            union REGS *out, struct SREGS *seg)
 | 
						|
{
 | 
						|
    union REGS local;
 | 
						|
    struct SREGS localseg;
 | 
						|
    struct RMINFO rmi;
 | 
						|
    int r;
 | 
						|
 | 
						|
    rmi.eax = in->x.eax;
 | 
						|
    rmi.ebx = in->x.ebx;
 | 
						|
    rmi.ecx = in->x.ecx;
 | 
						|
    rmi.edx = in->x.edx;
 | 
						|
    rmi.edi = in->x.edi;
 | 
						|
    rmi.esi = in->x.esi;
 | 
						|
    rmi.ebp = rmi.reserved = 0L;
 | 
						|
    rmi.es = seg->es;
 | 
						|
    rmi.ds = seg->ds;
 | 
						|
    rmi.fs = seg->fs;
 | 
						|
    rmi.gs = seg->gs;
 | 
						|
    rmi.sp = rmi.ss = rmi.ip_ignored = rmi.cs_ignored = rmi.flags = 0;
 | 
						|
    memset(&local, 0, sizeof(local));
 | 
						|
    memset(&localseg, 0, sizeof(localseg));
 | 
						|
    local.w.ax = 0x0300;
 | 
						|
    local.h.bl = inter_no;
 | 
						|
    local.h.bh = 0;
 | 
						|
    local.w.cx = 0;
 | 
						|
    localseg.es = FP_SEG(&rmi);
 | 
						|
    local.x.edi = FP_OFF(&rmi);
 | 
						|
    r = int386x(0x31, &local, &local, &localseg);
 | 
						|
    out->x.eax = rmi.eax;
 | 
						|
    out->x.ebx = rmi.ebx;
 | 
						|
    out->x.ecx = rmi.ecx;
 | 
						|
    out->x.edx = rmi.edx;
 | 
						|
    out->x.edi = rmi.edi;
 | 
						|
    out->x.esi = rmi.esi;
 | 
						|
    out->x.cflag = rmi.flags & INTR_CF;
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
#endif /* WATCOMC_386 */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#ifdef __WATCOMC__
 | 
						|
 | 
						|
/* This papers over a bug in Watcom 10.6's standard library...sigh.
 | 
						|
 * Apparently it applies to both the DOS and Win32 stat()s. */
 | 
						|
 | 
						|
int stat_bandaid(const char *path, struct stat *buf)
 | 
						|
{
 | 
						|
    char newname[4];
 | 
						|
 | 
						|
    if (!stat(path, buf))
 | 
						|
        return 0;
 | 
						|
    else if (!strcmp(path, ".") || (path[0] && !strcmp(path + 1, ":."))) {
 | 
						|
        strcpy(newname, path);
 | 
						|
        newname[strlen(path) - 1] = '\\';   /* stat(".") fails for root! */
 | 
						|
        return stat(newname, buf);
 | 
						|
    } else
 | 
						|
        return -1;
 | 
						|
}
 | 
						|
 | 
						|
#endif /* __WATCOMC__ */
 |