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
		
			
				
	
	
		
			2949 lines
		
	
	
		
			84 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			2949 lines
		
	
	
		
			84 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/*---------------------------------------------------------------------------
 | 
						|
 | 
						|
  vms.c                                        Igor Mandrichenko and others
 | 
						|
 | 
						|
  This file contains routines to extract VMS file attributes from a zipfile
 | 
						|
  extra field and create a file with these attributes.  The code was almost
 | 
						|
  entirely written by Igor, with a couple of routines by CN and lots of
 | 
						|
  modifications by Christian Spieler.
 | 
						|
 | 
						|
  Contains:  check_format()
 | 
						|
             open_outfile()
 | 
						|
             find_vms_attrs()
 | 
						|
             flush()
 | 
						|
             close_outfile()
 | 
						|
             do_wild()
 | 
						|
             mapattr()
 | 
						|
             mapname()
 | 
						|
             checkdir()
 | 
						|
             check_for_newer()
 | 
						|
             return_VMS
 | 
						|
             screenlines()
 | 
						|
             version()
 | 
						|
 | 
						|
  ---------------------------------------------------------------------------
 | 
						|
 | 
						|
     Copyright (C) 1992-93 Igor Mandrichenko.
 | 
						|
     Permission is granted to any individual or institution to use, copy,
 | 
						|
     or redistribute this software so long as all of the original files
 | 
						|
     are included unmodified and that this copyright notice is retained.
 | 
						|
 | 
						|
  ---------------------------------------------------------------------------*/
 | 
						|
 | 
						|
#ifdef VMS                      /* VMS only! */
 | 
						|
 | 
						|
#define UNZIP_INTERNAL
 | 
						|
#include "unzip.h"
 | 
						|
#include "vms.h"
 | 
						|
#include "vmsdefs.h"
 | 
						|
#include <lib$routines.h>
 | 
						|
#include <unixlib.h>
 | 
						|
 | 
						|
#define BUFS512 8192*2          /* Must be a multiple of 512 */
 | 
						|
 | 
						|
#define OK(s)   ((s)&1)         /* VMS success or warning status */
 | 
						|
#define STRICMP(s1,s2)  STRNICMP(s1,s2,2147483647)
 | 
						|
 | 
						|
/*
 | 
						|
*   Local static storage
 | 
						|
*/
 | 
						|
static struct FAB       fileblk;
 | 
						|
static struct XABDAT    dattim;
 | 
						|
static struct XABRDT    rdt;
 | 
						|
static struct RAB       rab;
 | 
						|
static struct NAM       nam;
 | 
						|
 | 
						|
static struct FAB *outfab = NULL;
 | 
						|
static struct RAB *outrab = NULL;
 | 
						|
static struct XABFHC *xabfhc = NULL;
 | 
						|
static struct XABDAT *xabdat = NULL;
 | 
						|
static struct XABRDT *xabrdt = NULL;
 | 
						|
static struct XABPRO *xabpro = NULL;
 | 
						|
static struct XABKEY *xabkey = NULL;
 | 
						|
static struct XABALL *xaball = NULL;
 | 
						|
static struct XAB *first_xab = NULL, *last_xab = NULL;
 | 
						|
 | 
						|
static char query = 0;
 | 
						|
static int  text_output = 0,
 | 
						|
            bin_fixed = 0;
 | 
						|
#ifdef USE_ORIG_DOS
 | 
						|
static int  hostnum;
 | 
						|
#endif
 | 
						|
 | 
						|
static uch rfm;
 | 
						|
 | 
						|
static uch locbuf[BUFS512];
 | 
						|
static int loccnt = 0;
 | 
						|
static uch *locptr;
 | 
						|
static char got_eol = 0;
 | 
						|
 | 
						|
static int  _flush_blocks(__GPRO__ uch *rawbuf, unsigned size, int final_flag),
 | 
						|
            _flush_stream(__GPRO__ uch *rawbuf, unsigned size, int final_flag),
 | 
						|
            _flush_varlen(__GPRO__ uch *rawbuf, unsigned size, int final_flag),
 | 
						|
            _flush_qio(__GPRO__ uch *rawbuf, unsigned size, int final_flag),
 | 
						|
            _close_rms(__GPRO),
 | 
						|
            _close_qio(__GPRO),
 | 
						|
            WriteBuffer(__GPRO__ uch *buf, int len),
 | 
						|
            WriteRecord(__GPRO__ uch *rec, int len);
 | 
						|
 | 
						|
static int  (*_flush_routine)(__GPRO__ uch *rawbuf, unsigned size,
 | 
						|
                              int final_flag),
 | 
						|
            (*_close_routine)(__GPRO);
 | 
						|
 | 
						|
static void init_buf_ring(void);
 | 
						|
static void set_default_datetime_XABs(__GPRO);
 | 
						|
static int  create_default_output(__GPRO),
 | 
						|
            create_rms_output(__GPRO),
 | 
						|
            create_qio_output(__GPRO);
 | 
						|
static int  replace(__GPRO);
 | 
						|
static int  find_vms_attrs(__GPRO);
 | 
						|
static void free_up(void);
 | 
						|
#ifdef CHECK_VERSIONS
 | 
						|
static int  get_vms_version(char *verbuf, int len);
 | 
						|
#endif /* CHECK_VERSIONS */
 | 
						|
static uch  *extract_block(__GPRO__ struct IZ_block *p, int *retlen,
 | 
						|
                           uch *init, int needlen);
 | 
						|
static void decompress_bits(uch *outptr, int needlen, uch *bitptr);
 | 
						|
static int  find_eol(uch *p, int n, int *l);
 | 
						|
static void vms_msg(__GPRO__ char *string, int status);
 | 
						|
 | 
						|
struct bufdsc
 | 
						|
{
 | 
						|
    struct bufdsc *next;
 | 
						|
    uch *buf;
 | 
						|
    int bufcnt;
 | 
						|
};
 | 
						|
 | 
						|
static struct bufdsc b1, b2, *curbuf;
 | 
						|
static uch buf1[BUFS512];
 | 
						|
 | 
						|
int check_format(__G)
 | 
						|
    __GDEF
 | 
						|
{
 | 
						|
    int rtype;
 | 
						|
    struct FAB fab;
 | 
						|
 | 
						|
    fab = cc$rms_fab;
 | 
						|
    fab.fab$l_fna = G.zipfn;
 | 
						|
    fab.fab$b_fns = strlen(G.zipfn);
 | 
						|
 | 
						|
    if ((sys$open(&fab) & 1) == 0)
 | 
						|
    {
 | 
						|
        Info(slide, 1, ((char *)slide, "\n\
 | 
						|
     error:  cannot open zipfile [ %s ] (access denied?).\n\n",
 | 
						|
          G.zipfn));
 | 
						|
        return PK_ERR;
 | 
						|
    }
 | 
						|
    rtype = fab.fab$b_rfm;
 | 
						|
    sys$close(&fab);
 | 
						|
 | 
						|
    if (rtype == FAB$C_VAR || rtype == FAB$C_VFC)
 | 
						|
    {
 | 
						|
        Info(slide, 1, ((char *)slide, "\n\
 | 
						|
     Error:  zipfile is in variable-length record format.  Please\n\
 | 
						|
     run \"bilf l %s\" to convert the zipfile to stream-LF\n\
 | 
						|
     record format.  (BILF is available at various VMS archives.)\n\n",
 | 
						|
          G.zipfn));
 | 
						|
        return PK_ERR;
 | 
						|
    }
 | 
						|
 | 
						|
    return PK_COOL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#define PRINTABLE_FORMAT(x)      ( (x) == FAB$C_VAR     \
 | 
						|
                                || (x) == FAB$C_STMLF   \
 | 
						|
                                || (x) == FAB$C_STMCR   \
 | 
						|
                                || (x) == FAB$C_STM     )
 | 
						|
 | 
						|
/* VMS extra field types */
 | 
						|
#define VAT_NONE    0
 | 
						|
#define VAT_IZ      1   /* old Info-ZIP format */
 | 
						|
#define VAT_PK      2   /* PKWARE format */
 | 
						|
 | 
						|
static int  vet;
 | 
						|
 | 
						|
/*
 | 
						|
 *  open_outfile() assignments:
 | 
						|
 *
 | 
						|
 *  VMS attributes ?        create_xxx      _flush_xxx
 | 
						|
 *  ----------------        ----------      ----------
 | 
						|
 *  not found               'default'       text mode ?
 | 
						|
 *                                          yes -> 'stream'
 | 
						|
 *                                          no  -> 'block'
 | 
						|
 *
 | 
						|
 *  yes, in IZ format       'rms'           G.cflag ?
 | 
						|
 *                                          yes -> switch(fab.rfm)
 | 
						|
 *                                              VAR  -> 'varlen'
 | 
						|
 *                                              STM* -> 'stream'
 | 
						|
 *                                              default -> 'block'
 | 
						|
 *                                          no -> 'block'
 | 
						|
 *
 | 
						|
 *  yes, in PK format       'qio'           G.cflag ?
 | 
						|
 *                                          yes -> switch(pka_rattr)
 | 
						|
 *                                              VAR  -> 'varlen'
 | 
						|
 *                                              STM* -> 'stream'
 | 
						|
 *                                              default -> 'block'
 | 
						|
 *                                          no -> 'qio'
 | 
						|
 *
 | 
						|
 *  "text mode" == G.pInfo->textmode || G.cflag
 | 
						|
 */
 | 
						|
 | 
						|
int open_outfile(__G)           /* return 1 (PK_WARN) if fail */
 | 
						|
    __GDEF
 | 
						|
{
 | 
						|
    switch(vet = find_vms_attrs(__G))
 | 
						|
    {
 | 
						|
        case VAT_NONE:
 | 
						|
        default:
 | 
						|
            return  create_default_output(__G);
 | 
						|
        case VAT_IZ:
 | 
						|
            return  create_rms_output(__G);
 | 
						|
        case VAT_PK:
 | 
						|
            return  create_qio_output(__G);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void init_buf_ring()
 | 
						|
{
 | 
						|
    locptr = &locbuf[0];
 | 
						|
    loccnt = 0;
 | 
						|
 | 
						|
    b1.buf = &locbuf[0];
 | 
						|
    b1.bufcnt = 0;
 | 
						|
    b1.next = &b2;
 | 
						|
    b2.buf = &buf1[0];
 | 
						|
    b2.bufcnt = 0;
 | 
						|
    b2.next = &b1;
 | 
						|
    curbuf = &b1;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Static data storage for time conversion: */
 | 
						|
 | 
						|
/*   string constants for month names */
 | 
						|
static ZCONST char *month[] =
 | 
						|
            {"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
 | 
						|
             "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
 | 
						|
 | 
						|
/*   buffer for time string */
 | 
						|
static char timbuf[24];         /* length = first entry in "stupid" + 1 */
 | 
						|
 | 
						|
/*   fixed-length string descriptor for timbuf: */
 | 
						|
static ZCONST struct dsc$descriptor stupid =
 | 
						|
            {sizeof(timbuf)-1, DSC$K_DTYPE_T, DSC$K_CLASS_S, timbuf};
 | 
						|
 | 
						|
 | 
						|
static void set_default_datetime_XABs(__GPRO)
 | 
						|
{
 | 
						|
    unsigned yr, mo, dy, hh, mm, ss;
 | 
						|
#ifdef USE_EF_UT_TIME
 | 
						|
    iztimes z_utime;
 | 
						|
 | 
						|
    if (G.extra_field &&
 | 
						|
        (ef_scan_for_izux(G.extra_field, G.crec.extra_field_length, 0,
 | 
						|
                          &z_utime, NULL) & EB_UT_FL_MTIME))
 | 
						|
    {
 | 
						|
        struct tm *t = localtime(&(z_utime.mtime));
 | 
						|
 | 
						|
        yr = t->tm_year + 1900;
 | 
						|
        mo = t->tm_mon;
 | 
						|
        dy = t->tm_mday;
 | 
						|
        hh = t->tm_hour;
 | 
						|
        mm = t->tm_min;
 | 
						|
        ss = t->tm_sec;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        yr = ((G.lrec.last_mod_file_date >> 9) & 0x7f) + 1980;
 | 
						|
        mo = ((G.lrec.last_mod_file_date >> 5) & 0x0f) - 1;
 | 
						|
        dy = (G.lrec.last_mod_file_date & 0x1f);
 | 
						|
        hh = (G.lrec.last_mod_file_time >> 11) & 0x1f;
 | 
						|
        mm = (G.lrec.last_mod_file_time >> 5) & 0x3f;
 | 
						|
        ss = (G.lrec.last_mod_file_time & 0x1f) * 2;
 | 
						|
    }
 | 
						|
#else /* !USE_EF_UT_TIME */
 | 
						|
 | 
						|
    yr = ((G.lrec.last_mod_file_date >> 9) & 0x7f) + 1980;
 | 
						|
    mo = ((G.lrec.last_mod_file_date >> 5) & 0x0f) - 1;
 | 
						|
    dy = (G.lrec.last_mod_file_date & 0x1f);
 | 
						|
    hh = (G.lrec.last_mod_file_time >> 11) & 0x1f;
 | 
						|
    mm = (G.lrec.last_mod_file_time >> 5) & 0x3f;
 | 
						|
    ss = (G.lrec.last_mod_file_time & 0x1f) * 2;
 | 
						|
#endif /* ?USE_EF_UT_TIME */
 | 
						|
 | 
						|
    dattim = cc$rms_xabdat;     /* fill XABs with default values */
 | 
						|
    rdt = cc$rms_xabrdt;
 | 
						|
    sprintf(timbuf, "%02u-%3s-%04u %02u:%02u:%02u.00", dy, month[mo],
 | 
						|
            yr, hh, mm, ss);
 | 
						|
    sys$bintim(&stupid, &dattim.xab$q_cdt);
 | 
						|
    memcpy(&rdt.xab$q_rdt, &dattim.xab$q_cdt, sizeof(rdt.xab$q_rdt));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int create_default_output(__GPRO)        /* return 1 (PK_WARN) if fail */
 | 
						|
{
 | 
						|
    int ierr;
 | 
						|
 | 
						|
    text_output = G.pInfo->textmode ||
 | 
						|
                  G.cflag;      /* extract the file in text
 | 
						|
                                 * (variable-length) format */
 | 
						|
    bin_fixed = text_output || (G.bflag == 0)
 | 
						|
                ? 0
 | 
						|
                : ((G.bflag - 1) ? 1 : !G.pInfo->textfile);
 | 
						|
#ifdef USE_ORIG_DOS
 | 
						|
    hostnum = G.pInfo -> hostnum;
 | 
						|
#endif
 | 
						|
 | 
						|
    rfm = FAB$C_STMLF;  /* Default, stream-LF format from VMS or UNIX */
 | 
						|
 | 
						|
    if (!G.cflag)               /* Redirect output */
 | 
						|
    {
 | 
						|
        rab = cc$rms_rab;       /* fill RAB with default values */
 | 
						|
        fileblk = cc$rms_fab;   /* fill FAB with default values */
 | 
						|
 | 
						|
        outfab = &fileblk;
 | 
						|
        outfab->fab$l_xab = NULL;
 | 
						|
 | 
						|
        if (text_output)
 | 
						|
        {   /* Default format for output `real' text file */
 | 
						|
 | 
						|
            outfab->fab$b_rfm = FAB$C_VAR;      /* variable length records */
 | 
						|
            outfab->fab$b_rat = FAB$M_CR;       /* implied (CR) carriage ctrl */
 | 
						|
        }
 | 
						|
        else if (bin_fixed)
 | 
						|
        {   /* Default format for output `real' binary file */
 | 
						|
 | 
						|
            outfab->fab$b_rfm = FAB$C_FIX;      /* fixed length record format */
 | 
						|
            outfab->fab$w_mrs = 512;            /* record size 512 bytes */
 | 
						|
            outfab->fab$b_rat = 0;              /* no carriage ctrl */
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {   /* Default format for output misc (bin or text) file */
 | 
						|
 | 
						|
            outfab->fab$b_rfm = FAB$C_STMLF;    /* stream-LF record format */
 | 
						|
            outfab->fab$b_rat = FAB$M_CR;       /* implied (CR) carriage ctrl */
 | 
						|
        }
 | 
						|
 | 
						|
        outfab->fab$l_fna = G.filename;
 | 
						|
        outfab->fab$b_fns = strlen(outfab->fab$l_fna);
 | 
						|
 | 
						|
        {
 | 
						|
            set_default_datetime_XABs(__G);
 | 
						|
 | 
						|
            dattim.xab$l_nxt = outfab->fab$l_xab;
 | 
						|
            outfab->fab$l_xab = (void *) &dattim;
 | 
						|
        }
 | 
						|
 | 
						|
        outfab->fab$w_ifi = 0;  /* Clear IFI. It may be nonzero after ZIP */
 | 
						|
 | 
						|
        ierr = sys$create(outfab);
 | 
						|
        if (ierr == RMS$_FEX)
 | 
						|
            ierr = replace(__G);
 | 
						|
 | 
						|
        if (ierr == 0)          /* Canceled */
 | 
						|
            return (free_up(), PK_WARN);
 | 
						|
 | 
						|
        if (ERR(ierr))
 | 
						|
        {
 | 
						|
            char buf[256];
 | 
						|
 | 
						|
            sprintf(buf, "[ Cannot create output file %s ]\n", G.filename);
 | 
						|
            vms_msg(__G__ buf, ierr);
 | 
						|
            vms_msg(__G__ "", outfab->fab$l_stv);
 | 
						|
            free_up();
 | 
						|
            return PK_WARN;
 | 
						|
        }
 | 
						|
 | 
						|
        if (!text_output)    /* Do not reopen text files and stdout
 | 
						|
                              *  Just open them in right mode         */
 | 
						|
        {
 | 
						|
            /*
 | 
						|
             *      Reopen file for Block I/O with no XABs.
 | 
						|
             */
 | 
						|
            if ((ierr = sys$close(outfab)) != RMS$_NORMAL)
 | 
						|
            {
 | 
						|
#ifdef DEBUG
 | 
						|
                vms_msg(__G__ "[ create_default_output: sys$close failed ]\n",
 | 
						|
                        ierr);
 | 
						|
                vms_msg(__G__ "", outfab->fab$l_stv);
 | 
						|
#endif
 | 
						|
                Info(slide, 1, ((char *)slide,
 | 
						|
                     "Can't create output file:  %s\n", G.filename));
 | 
						|
                free_up();
 | 
						|
                return PK_WARN;
 | 
						|
            }
 | 
						|
 | 
						|
 | 
						|
            outfab->fab$b_fac = FAB$M_BIO | FAB$M_PUT;  /* Get ready for block
 | 
						|
                                                         * output */
 | 
						|
            outfab->fab$l_xab = NULL;   /* Unlink all XABs */
 | 
						|
 | 
						|
            if ((ierr = sys$open(outfab)) != RMS$_NORMAL)
 | 
						|
            {
 | 
						|
                char buf[256];
 | 
						|
 | 
						|
                sprintf(buf, "[ Cannot open output file %s ]\n", G.filename);
 | 
						|
                vms_msg(__G__ buf, ierr);
 | 
						|
                vms_msg(__G__ "", outfab->fab$l_stv);
 | 
						|
                free_up();
 | 
						|
                return PK_WARN;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        outrab = &rab;
 | 
						|
        rab.rab$l_fab = outfab;
 | 
						|
        if (!text_output)
 | 
						|
        {
 | 
						|
            rab.rab$l_rop |= (RAB$M_BIO | RAB$M_ASY);
 | 
						|
        }
 | 
						|
        rab.rab$b_rac = RAB$C_SEQ;
 | 
						|
 | 
						|
        if ((ierr = sys$connect(outrab)) != RMS$_NORMAL)
 | 
						|
        {
 | 
						|
#ifdef DEBUG
 | 
						|
            vms_msg(__G__ "create_default_output: sys$connect failed.\n", ierr);
 | 
						|
            vms_msg(__G__ "", outfab->fab$l_stv);
 | 
						|
#endif
 | 
						|
            Info(slide, 1, ((char *)slide,
 | 
						|
                 "Can't create output file:  %s\n", G.filename));
 | 
						|
            free_up();
 | 
						|
            return PK_WARN;
 | 
						|
        }
 | 
						|
    }                   /* end if (!G.cflag) */
 | 
						|
 | 
						|
    init_buf_ring();
 | 
						|
 | 
						|
    _flush_routine = text_output? got_eol=0,_flush_stream : _flush_blocks;
 | 
						|
    _close_routine = _close_rms;
 | 
						|
    return PK_COOL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static int create_rms_output(__GPRO)           /* return 1 (PK_WARN) if fail */
 | 
						|
{
 | 
						|
    int ierr;
 | 
						|
 | 
						|
    text_output = G.cflag;      /* extract the file in text
 | 
						|
                                 * (variable-length) format;
 | 
						|
                                 * we ignore "-a" when attributes saved */
 | 
						|
#ifdef USE_ORIG_DOS
 | 
						|
    hostnum = G.pInfo -> hostnum;
 | 
						|
#endif
 | 
						|
 | 
						|
    rfm = outfab->fab$b_rfm;    /* Use record format from VMS extra field */
 | 
						|
 | 
						|
    if (G.cflag)
 | 
						|
    {
 | 
						|
        if (!PRINTABLE_FORMAT(rfm))
 | 
						|
        {
 | 
						|
            Info(slide, 1, ((char *)slide,
 | 
						|
               "[ File %s has illegal record format to put to screen ]\n",
 | 
						|
               G.filename));
 | 
						|
            free_up();
 | 
						|
            return PK_WARN;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else                        /* Redirect output */
 | 
						|
    {
 | 
						|
        rab = cc$rms_rab;       /* fill RAB with default values */
 | 
						|
 | 
						|
        /* The output FAB has already been initialized with the values
 | 
						|
         * found in the Zip file's "VMS attributes" extra field */
 | 
						|
 | 
						|
        outfab->fab$l_fna = G.filename;
 | 
						|
        outfab->fab$b_fns = strlen(outfab->fab$l_fna);
 | 
						|
 | 
						|
        if (!(xabdat && xabrdt))        /* Use date/time info
 | 
						|
                                         *  from zipfile if
 | 
						|
                                         *  no attributes given
 | 
						|
                                         */
 | 
						|
        {
 | 
						|
            set_default_datetime_XABs(__G);
 | 
						|
 | 
						|
            if (xabdat == NULL)
 | 
						|
            {
 | 
						|
                dattim.xab$l_nxt = outfab->fab$l_xab;
 | 
						|
                outfab->fab$l_xab = (void *) &dattim;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        outfab->fab$w_ifi = 0;  /* Clear IFI. It may be nonzero after ZIP */
 | 
						|
 | 
						|
        ierr = sys$create(outfab);
 | 
						|
        if (ierr == RMS$_FEX)
 | 
						|
            ierr = replace(__G);
 | 
						|
 | 
						|
        if (ierr == 0)          /* Canceled */
 | 
						|
            return (free_up(), PK_WARN);
 | 
						|
 | 
						|
        if (ERR(ierr))
 | 
						|
        {
 | 
						|
            char buf[256];
 | 
						|
 | 
						|
            sprintf(buf, "[ Cannot create output file %s ]\n", G.filename);
 | 
						|
            vms_msg(__G__ buf, ierr);
 | 
						|
            vms_msg(__G__ "", outfab->fab$l_stv);
 | 
						|
            free_up();
 | 
						|
            return PK_WARN;
 | 
						|
        }
 | 
						|
 | 
						|
        if (!text_output)    /* Do not reopen text files and stdout
 | 
						|
                              *  Just open them in right mode         */
 | 
						|
        {
 | 
						|
            /*
 | 
						|
             *      Reopen file for Block I/O with no XABs.
 | 
						|
             */
 | 
						|
            if ((ierr = sys$close(outfab)) != RMS$_NORMAL)
 | 
						|
            {
 | 
						|
#ifdef DEBUG
 | 
						|
                vms_msg(__G__ "[ create_rms_output: sys$close failed ]\n",
 | 
						|
                        ierr);
 | 
						|
                vms_msg(__G__ "", outfab->fab$l_stv);
 | 
						|
#endif
 | 
						|
                Info(slide, 1, ((char *)slide,
 | 
						|
                     "Can't create output file:  %s\n", G.filename));
 | 
						|
                free_up();
 | 
						|
                return PK_WARN;
 | 
						|
            }
 | 
						|
 | 
						|
 | 
						|
            outfab->fab$b_fac = FAB$M_BIO | FAB$M_PUT;  /* Get ready for block
 | 
						|
                                                         * output */
 | 
						|
            outfab->fab$l_xab = NULL;   /* Unlink all XABs */
 | 
						|
 | 
						|
            if ((ierr = sys$open(outfab)) != RMS$_NORMAL)
 | 
						|
            {
 | 
						|
                char buf[256];
 | 
						|
 | 
						|
                sprintf(buf, "[ Cannot open output file %s ]\n", G.filename);
 | 
						|
                vms_msg(__G__ buf, ierr);
 | 
						|
                vms_msg(__G__ "", outfab->fab$l_stv);
 | 
						|
                free_up();
 | 
						|
                return PK_WARN;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        outrab = &rab;
 | 
						|
        rab.rab$l_fab = outfab;
 | 
						|
        if (!text_output)
 | 
						|
        {
 | 
						|
            rab.rab$l_rop |= (RAB$M_BIO | RAB$M_ASY);
 | 
						|
        }
 | 
						|
        rab.rab$b_rac = RAB$C_SEQ;
 | 
						|
 | 
						|
        if ((ierr = sys$connect(outrab)) != RMS$_NORMAL)
 | 
						|
        {
 | 
						|
#ifdef DEBUG
 | 
						|
            vms_msg(__G__ "create_rms_output: sys$connect failed.\n", ierr);
 | 
						|
            vms_msg(__G__ "", outfab->fab$l_stv);
 | 
						|
#endif
 | 
						|
            Info(slide, 1, ((char *)slide,
 | 
						|
                 "Can't create output file:  %s\n", G.filename));
 | 
						|
            free_up();
 | 
						|
            return PK_WARN;
 | 
						|
        }
 | 
						|
    }                   /* end if (!G.cflag) */
 | 
						|
 | 
						|
    init_buf_ring();
 | 
						|
 | 
						|
    if ( text_output )
 | 
						|
        switch(rfm)
 | 
						|
        {
 | 
						|
            case FAB$C_VAR:
 | 
						|
                _flush_routine = _flush_varlen;
 | 
						|
                break;
 | 
						|
            case FAB$C_STM:
 | 
						|
            case FAB$C_STMCR:
 | 
						|
            case FAB$C_STMLF:
 | 
						|
                _flush_routine = _flush_stream;
 | 
						|
                got_eol = 0;
 | 
						|
                break;
 | 
						|
            default:
 | 
						|
                _flush_routine = _flush_blocks;
 | 
						|
                break;
 | 
						|
        }
 | 
						|
    else
 | 
						|
        _flush_routine = _flush_blocks;
 | 
						|
    _close_routine = _close_rms;
 | 
						|
    return PK_COOL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static  int pka_devchn;
 | 
						|
static  int pka_vbn;
 | 
						|
 | 
						|
static struct
 | 
						|
{
 | 
						|
    short   status;
 | 
						|
    long    count;
 | 
						|
    short   dummy;
 | 
						|
} pka_io_sb;
 | 
						|
 | 
						|
static struct
 | 
						|
{
 | 
						|
    short   status;
 | 
						|
    short   dummy;
 | 
						|
    void    *addr;
 | 
						|
} pka_acp_sb;
 | 
						|
 | 
						|
static struct fibdef    pka_fib;
 | 
						|
static struct atrdef    pka_atr[VMS_MAX_ATRCNT];
 | 
						|
static int              pka_idx;
 | 
						|
static ulg              pka_uchar;
 | 
						|
static struct fatdef    pka_rattr;
 | 
						|
 | 
						|
static struct dsc$descriptor    pka_fibdsc =
 | 
						|
{   sizeof(pka_fib), DSC$K_DTYPE_Z, DSC$K_CLASS_S, (void *) &pka_fib  };
 | 
						|
 | 
						|
static struct dsc$descriptor_s  pka_devdsc =
 | 
						|
{   0, DSC$K_DTYPE_T, DSC$K_CLASS_S, &nam.nam$t_dvi[1]  };
 | 
						|
 | 
						|
static struct dsc$descriptor_s  pka_fnam =
 | 
						|
{   0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL  };
 | 
						|
 | 
						|
#define PK_PRINTABLE_RECTYP(x)   ( (x) == FAT$C_VARIABLE \
 | 
						|
                                || (x) == FAT$C_STREAMLF \
 | 
						|
                                || (x) == FAT$C_STREAMCR \
 | 
						|
                                || (x) == FAT$C_STREAM   )
 | 
						|
 | 
						|
 | 
						|
static int create_qio_output(__GPRO)            /* return 1 (PK_WARN) if fail */
 | 
						|
{
 | 
						|
    int status;
 | 
						|
    static char exp_nam[NAM$C_MAXRSS];
 | 
						|
    static char res_nam[NAM$C_MAXRSS];
 | 
						|
    int i;
 | 
						|
 | 
						|
    if ( G.cflag )
 | 
						|
    {
 | 
						|
        int rtype = pka_rattr.fat$v_rtype;
 | 
						|
        if (!PK_PRINTABLE_RECTYP(rtype))
 | 
						|
        {
 | 
						|
            Info(slide, 1, ((char *)slide,
 | 
						|
               "[ File %s has illegal record format to put to screen ]\n",
 | 
						|
               G.filename));
 | 
						|
            return PK_WARN;
 | 
						|
        }
 | 
						|
 | 
						|
        init_buf_ring();
 | 
						|
 | 
						|
        switch(rtype)
 | 
						|
        {
 | 
						|
            case FAT$C_VARIABLE:
 | 
						|
                _flush_routine = _flush_varlen;
 | 
						|
                break;
 | 
						|
            case FAT$C_STREAM:
 | 
						|
            case FAT$C_STREAMCR:
 | 
						|
            case FAT$C_STREAMLF:
 | 
						|
                _flush_routine = _flush_stream;
 | 
						|
                got_eol = 0;
 | 
						|
                break;
 | 
						|
            default:
 | 
						|
                _flush_routine = _flush_blocks;
 | 
						|
                break;
 | 
						|
        }
 | 
						|
        _close_routine = _close_rms;
 | 
						|
    }
 | 
						|
    else                        /* !(G.cflag) : redirect output */
 | 
						|
    {
 | 
						|
 | 
						|
        fileblk = cc$rms_fab;
 | 
						|
        fileblk.fab$l_fna = G.filename;
 | 
						|
        fileblk.fab$b_fns = strlen(G.filename);
 | 
						|
 | 
						|
        nam = cc$rms_nam;
 | 
						|
        fileblk.fab$l_nam = &nam;
 | 
						|
        nam.nam$l_esa = exp_nam;
 | 
						|
        nam.nam$b_ess = sizeof(exp_nam);
 | 
						|
        nam.nam$l_rsa = res_nam;
 | 
						|
        nam.nam$b_rss = sizeof(res_nam);
 | 
						|
 | 
						|
        if ( ERR(status = sys$parse(&fileblk)) )
 | 
						|
        {
 | 
						|
            vms_msg(__G__ "create_qio_output: sys$parse failed.\n", status);
 | 
						|
            return PK_WARN;
 | 
						|
        }
 | 
						|
 | 
						|
        pka_devdsc.dsc$w_length = (unsigned short)nam.nam$t_dvi[0];
 | 
						|
 | 
						|
        if ( ERR(status = sys$assign(&pka_devdsc,&pka_devchn,0,0)) )
 | 
						|
        {
 | 
						|
            vms_msg(__G__ "sys$assign failed.\n",status);
 | 
						|
            return PK_WARN;
 | 
						|
        }
 | 
						|
 | 
						|
        pka_fnam.dsc$a_pointer = nam.nam$l_name;
 | 
						|
        pka_fnam.dsc$w_length  = nam.nam$b_name + nam.nam$b_type;
 | 
						|
        if ( G.V_flag /* keep versions */ )
 | 
						|
            pka_fnam.dsc$w_length += nam.nam$b_ver;
 | 
						|
 | 
						|
        for (i=0;i<3;i++)
 | 
						|
        {
 | 
						|
            pka_fib.FIB$W_DID[i]=nam.nam$w_did[i];
 | 
						|
            pka_fib.FIB$W_FID[i]=0;
 | 
						|
        }
 | 
						|
 | 
						|
        pka_fib.FIB$L_ACCTL = FIB$M_WRITE;
 | 
						|
        /* Allocate space for the file */
 | 
						|
        pka_fib.FIB$W_EXCTL = FIB$M_EXTEND;
 | 
						|
        if ( pka_uchar & FCH$M_CONTIG )
 | 
						|
            pka_fib.FIB$W_EXCTL |= FIB$M_ALCON | FIB$M_FILCON;
 | 
						|
        if ( pka_uchar & FCH$M_CONTIGB )
 | 
						|
            pka_fib.FIB$W_EXCTL |= FIB$M_ALCONB;
 | 
						|
 | 
						|
#define SWAPW(x)        ( (((x)>>16)&0xFFFF) + ((x)<<16) )
 | 
						|
 | 
						|
        pka_fib.fib$l_exsz = SWAPW(pka_rattr.fat$l_hiblk);
 | 
						|
 | 
						|
        status = sys$qiow(0, pka_devchn, IO$_CREATE|IO$M_CREATE|IO$M_ACCESS,
 | 
						|
                          &pka_acp_sb, 0, 0,
 | 
						|
                          &pka_fibdsc, &pka_fnam, 0, 0, &pka_atr, 0);
 | 
						|
 | 
						|
        if ( !ERR(status) )
 | 
						|
            status = pka_acp_sb.status;
 | 
						|
 | 
						|
        if ( ERR(status) )
 | 
						|
        {
 | 
						|
            vms_msg(__G__ "[ Create file QIO failed.\n",status);
 | 
						|
            return PK_WARN;
 | 
						|
            sys$dassgn(pka_devchn);
 | 
						|
        }
 | 
						|
 | 
						|
        locptr = locbuf;
 | 
						|
        loccnt = 0;
 | 
						|
        pka_vbn = 1;
 | 
						|
        _flush_routine = _flush_qio;
 | 
						|
        _close_routine = _close_qio;
 | 
						|
    }                   /* end if (!G.cflag) */
 | 
						|
    return PK_COOL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static int replace(__GPRO)
 | 
						|
{                       /*
 | 
						|
                         *      File exists. Inquire user about further action.
 | 
						|
                         */
 | 
						|
    char answ[10];
 | 
						|
    struct NAM nam;
 | 
						|
    int ierr;
 | 
						|
 | 
						|
    if (query == 0)
 | 
						|
    {
 | 
						|
        do
 | 
						|
        {
 | 
						|
            Info(slide, 1, ((char *)slide,
 | 
						|
                 "%s exists:  [o]verwrite, new [v]ersion or [n]o extract?\n\
 | 
						|
  (uppercase response [O,V,N] = do same for all files): ",
 | 
						|
                 G.filename));
 | 
						|
            fflush(stderr);
 | 
						|
        } while (fgets(answ, 9, stderr) == NULL && !isalpha(answ[0])
 | 
						|
                 && tolower(answ[0]) != 'o'
 | 
						|
                 && tolower(answ[0]) != 'v'
 | 
						|
                 && tolower(answ[0]) != 'n');
 | 
						|
 | 
						|
        if (isupper(answ[0]))
 | 
						|
            query = answ[0] = tolower(answ[0]);
 | 
						|
    }
 | 
						|
    else
 | 
						|
        answ[0] = query;
 | 
						|
 | 
						|
    switch (answ[0])
 | 
						|
    {
 | 
						|
        case 'n':
 | 
						|
            ierr = 0;
 | 
						|
            break;
 | 
						|
        case 'v':
 | 
						|
            nam = cc$rms_nam;
 | 
						|
            nam.nam$l_rsa = G.filename;
 | 
						|
            nam.nam$b_rss = FILNAMSIZ - 1;
 | 
						|
 | 
						|
            outfab->fab$l_fop |= FAB$M_MXV;
 | 
						|
            outfab->fab$l_nam = &nam;
 | 
						|
 | 
						|
            ierr = sys$create(outfab);
 | 
						|
            if (!ERR(ierr))
 | 
						|
            {
 | 
						|
                outfab->fab$l_nam = NULL;
 | 
						|
                G.filename[outfab->fab$b_fns = nam.nam$b_rsl] = '\0';
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        case 'o':
 | 
						|
            outfab->fab$l_fop |= FAB$M_SUP;
 | 
						|
            ierr = sys$create(outfab);
 | 
						|
            break;
 | 
						|
    }
 | 
						|
    return ierr;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#define W(p)    (*(unsigned short*)(p))
 | 
						|
#define L(p)    (*(unsigned long*)(p))
 | 
						|
#define EQL_L(a,b)      ( L(a) == L(b) )
 | 
						|
#define EQL_W(a,b)      ( W(a) == W(b) )
 | 
						|
 | 
						|
/****************************************************************
 | 
						|
 * Function find_vms_attrs scans ZIP entry extra field if any   *
 | 
						|
 * and looks for VMS attribute records. Returns 0 if either no  *
 | 
						|
 * attributes found or no fab given.                            *
 | 
						|
 ****************************************************************/
 | 
						|
int find_vms_attrs(__G)
 | 
						|
    __GDEF
 | 
						|
{
 | 
						|
    uch *scan = G.extra_field;
 | 
						|
    struct  EB_header *hdr;
 | 
						|
    int len;
 | 
						|
    int type=VAT_NONE;
 | 
						|
 | 
						|
    outfab = NULL;
 | 
						|
    xabfhc = NULL;
 | 
						|
    xabdat = NULL;
 | 
						|
    xabrdt = NULL;
 | 
						|
    xabpro = NULL;
 | 
						|
    first_xab = last_xab = NULL;
 | 
						|
 | 
						|
    if (scan == NULL)
 | 
						|
        return VAT_NONE;
 | 
						|
    len = G.lrec.extra_field_length;
 | 
						|
 | 
						|
#define LINK(p) {/* Link xaballs and xabkeys into chain */      \
 | 
						|
                if ( first_xab == NULL )                \
 | 
						|
                        first_xab = (void *) p;         \
 | 
						|
                if ( last_xab != NULL )                 \
 | 
						|
                        last_xab -> xab$l_nxt = (void *) p;     \
 | 
						|
                last_xab = (void *) p;                  \
 | 
						|
                p -> xab$l_nxt = NULL;                  \
 | 
						|
        }
 | 
						|
    /* End of macro LINK */
 | 
						|
 | 
						|
    while (len > 0)
 | 
						|
    {
 | 
						|
        hdr = (struct EB_header *) scan;
 | 
						|
        if (EQL_W(&hdr->tag, IZ_SIGNATURE))
 | 
						|
        {
 | 
						|
            /*
 | 
						|
             *  Info-ZIP style extra block decoding
 | 
						|
             */
 | 
						|
            struct IZ_block *blk;
 | 
						|
            uch *block_id;
 | 
						|
 | 
						|
            type = VAT_IZ;
 | 
						|
 | 
						|
            blk = (struct IZ_block *)hdr;
 | 
						|
            block_id = (uch *) &blk->bid;
 | 
						|
            if (EQL_L(block_id, FABSIG))
 | 
						|
            {
 | 
						|
                outfab = (struct FAB *) extract_block(__G__ blk, 0,
 | 
						|
                                                (uch *)&cc$rms_fab, FABL);
 | 
						|
            }
 | 
						|
            else if (EQL_L(block_id, XALLSIG))
 | 
						|
            {
 | 
						|
                xaball = (struct XABALL *) extract_block(__G__ blk, 0,
 | 
						|
                                                (uch *)&cc$rms_xaball, XALLL);
 | 
						|
                LINK(xaball);
 | 
						|
            }
 | 
						|
            else if (EQL_L(block_id, XKEYSIG))
 | 
						|
            {
 | 
						|
                xabkey = (struct XABKEY *) extract_block(__G__ blk, 0,
 | 
						|
                                                (uch *)&cc$rms_xabkey, XKEYL);
 | 
						|
                LINK(xabkey);
 | 
						|
            }
 | 
						|
            else if (EQL_L(block_id, XFHCSIG))
 | 
						|
            {
 | 
						|
                xabfhc = (struct XABFHC *) extract_block(__G__ blk, 0,
 | 
						|
                                                (uch *)&cc$rms_xabfhc, XFHCL);
 | 
						|
            }
 | 
						|
            else if (EQL_L(block_id, XDATSIG))
 | 
						|
            {
 | 
						|
                xabdat = (struct XABDAT *) extract_block(__G__ blk, 0,
 | 
						|
                                                (uch *)&cc$rms_xabdat, XDATL);
 | 
						|
            }
 | 
						|
            else if (EQL_L(block_id, XRDTSIG))
 | 
						|
            {
 | 
						|
                xabrdt = (struct XABRDT *) extract_block(__G__ blk, 0,
 | 
						|
                                                (uch *)&cc$rms_xabrdt, XRDTL);
 | 
						|
            }
 | 
						|
            else if (EQL_L(block_id, XPROSIG))
 | 
						|
            {
 | 
						|
                xabpro = (struct XABPRO *) extract_block(__G__ blk, 0,
 | 
						|
                                                (uch *)&cc$rms_xabpro, XPROL);
 | 
						|
            }
 | 
						|
            else if (EQL_L(block_id, VERSIG))
 | 
						|
            {
 | 
						|
#ifdef CHECK_VERSIONS
 | 
						|
                char verbuf[80];
 | 
						|
                int verlen = 0;
 | 
						|
                uch *vers;
 | 
						|
                char *m;
 | 
						|
 | 
						|
                get_vms_version(verbuf, sizeof(verbuf));
 | 
						|
                vers = extract_block(__G__ blk, &verlen, 0, 0);
 | 
						|
                if ((m = strrchr((char *) vers, '-')) != NULL)
 | 
						|
                    *m = '\0';  /* Cut out release number */
 | 
						|
                if (strcmp(verbuf, (char *) vers) && G.qflag < 2)
 | 
						|
                {
 | 
						|
                    Info(slide, 0, ((char *)slide,
 | 
						|
                         "[ Warning: VMS version mismatch."));
 | 
						|
 | 
						|
                    Info(slide, 0, ((char *)slide,
 | 
						|
                         "   This version %s --", verbuf));
 | 
						|
                    strncpy(verbuf, (char *) vers, verlen);
 | 
						|
                    verbuf[verlen] = '\0';
 | 
						|
                    Info(slide, 0, ((char *)slide,
 | 
						|
                         " version made by %s ]\n", verbuf));
 | 
						|
                }
 | 
						|
                free(vers);
 | 
						|
#endif /* CHECK_VERSIONS */
 | 
						|
            }
 | 
						|
            else
 | 
						|
                Info(slide, 1, ((char *)slide,
 | 
						|
                     "[ Warning: Unknown block signature %s ]\n",
 | 
						|
                     block_id));
 | 
						|
        }
 | 
						|
        else if (hdr->tag == PK_SIGNATURE)
 | 
						|
        {
 | 
						|
            /*
 | 
						|
             *  PKWARE-style extra block decoding
 | 
						|
             */
 | 
						|
            struct  PK_header   *blk;
 | 
						|
            register byte   *scn;
 | 
						|
            register int    len;
 | 
						|
 | 
						|
            type = VAT_PK;
 | 
						|
 | 
						|
            blk = (struct PK_header *)hdr;
 | 
						|
            len = blk->size - (PK_HEADER_SIZE - EB_HEADSIZE);
 | 
						|
            scn = (byte *)(&blk->data);
 | 
						|
            pka_idx = 0;
 | 
						|
 | 
						|
            if (blk->crc32 != crc32(CRCVAL_INITIAL, scn, (extent)len))
 | 
						|
            {
 | 
						|
                Info(slide, 1, ((char *)slide,
 | 
						|
                  "[Warning: CRC error, discarding PKWARE extra field]\n"));
 | 
						|
                len = 0;
 | 
						|
                type = VAT_NONE;
 | 
						|
            }
 | 
						|
 | 
						|
            while (len > PK_FLDHDR_SIZE)
 | 
						|
            {
 | 
						|
                register struct  PK_field  *fld;
 | 
						|
                int skip=0;
 | 
						|
 | 
						|
                fld = (struct PK_field *)scn;
 | 
						|
                switch(fld->tag)
 | 
						|
                {
 | 
						|
                    case ATR$C_UCHAR:
 | 
						|
                        pka_uchar = L(&fld->value);
 | 
						|
                        break;
 | 
						|
                    case ATR$C_RECATTR:
 | 
						|
                        pka_rattr = *(struct fatdef *)(&fld->value);
 | 
						|
                        break;
 | 
						|
                    case ATR$C_UIC:
 | 
						|
                    case ATR$C_ADDACLENT:
 | 
						|
                        skip = !G.X_flag;
 | 
						|
                        break;
 | 
						|
                }
 | 
						|
 | 
						|
                if ( !skip )
 | 
						|
                {
 | 
						|
                    pka_atr[pka_idx].atr$w_size = fld->size;
 | 
						|
                    pka_atr[pka_idx].atr$w_type = fld->tag;
 | 
						|
                    pka_atr[pka_idx].atr$l_addr = &fld->value;
 | 
						|
                    ++pka_idx;
 | 
						|
                }
 | 
						|
                len -= fld->size + PK_FLDHDR_SIZE;
 | 
						|
                scn += fld->size + PK_FLDHDR_SIZE;
 | 
						|
            }
 | 
						|
            pka_atr[pka_idx].atr$w_size = 0;    /* End of list */
 | 
						|
            pka_atr[pka_idx].atr$w_type = 0;
 | 
						|
            pka_atr[pka_idx].atr$l_addr = 0; /* NULL when DECC VAX gets fixed */
 | 
						|
        }
 | 
						|
        len -= hdr->size + EB_HEADSIZE;
 | 
						|
        scan += hdr->size + EB_HEADSIZE;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    if ( type == VAT_IZ )
 | 
						|
    {
 | 
						|
        if (outfab != NULL)
 | 
						|
        {   /* Do not link XABPRO,XABRDT now. Leave them for sys$close() */
 | 
						|
 | 
						|
            outfab->fab$l_xab = NULL;
 | 
						|
            if (xabfhc != NULL)
 | 
						|
            {
 | 
						|
                xabfhc->xab$l_nxt = outfab->fab$l_xab;
 | 
						|
                outfab->fab$l_xab = (void *) xabfhc;
 | 
						|
            }
 | 
						|
            if (xabdat != NULL)
 | 
						|
            {
 | 
						|
                xabdat->xab$l_nxt = outfab->fab$l_xab;
 | 
						|
                outfab->fab$l_xab = (void *) xabdat;
 | 
						|
            }
 | 
						|
            if (first_xab != NULL)      /* Link xaball,xabkey subchain */
 | 
						|
            {
 | 
						|
                last_xab->xab$l_nxt = outfab->fab$l_xab;
 | 
						|
                outfab->fab$l_xab = (void *) first_xab;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else
 | 
						|
            type = VAT_NONE;
 | 
						|
    }
 | 
						|
    return type;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static void free_up()
 | 
						|
{
 | 
						|
    /*
 | 
						|
     * Free up all allocated xabs
 | 
						|
     */
 | 
						|
    if (xabdat != NULL) free(xabdat);
 | 
						|
    if (xabpro != NULL) free(xabpro);
 | 
						|
    if (xabrdt != NULL) free(xabrdt);
 | 
						|
    if (xabfhc != NULL) free(xabfhc);
 | 
						|
    while (first_xab != NULL)
 | 
						|
    {
 | 
						|
        struct XAB *x;
 | 
						|
 | 
						|
        x = (struct XAB *) first_xab->xab$l_nxt;
 | 
						|
        free(first_xab);
 | 
						|
        first_xab = x;
 | 
						|
    }
 | 
						|
    if (outfab != NULL && outfab != &fileblk)
 | 
						|
        free(outfab);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#ifdef CHECK_VERSIONS
 | 
						|
 | 
						|
static int get_vms_version(verbuf, len)
 | 
						|
    char *verbuf;
 | 
						|
    int len;
 | 
						|
{
 | 
						|
    int i = SYI$_VERSION;
 | 
						|
    int verlen = 0;
 | 
						|
    struct dsc$descriptor version;
 | 
						|
    char *m;
 | 
						|
 | 
						|
    version.dsc$a_pointer = verbuf;
 | 
						|
    version.dsc$w_length  = len - 1;
 | 
						|
    version.dsc$b_dtype   = DSC$K_DTYPE_B;
 | 
						|
    version.dsc$b_class   = DSC$K_CLASS_S;
 | 
						|
 | 
						|
    if (ERR(lib$getsyi(&i, 0, &version, &verlen, 0, 0)) || verlen == 0)
 | 
						|
        return 0;
 | 
						|
 | 
						|
    /* Cut out trailing spaces "V5.4-3   " -> "V5.4-3" */
 | 
						|
    for (m = verbuf + verlen, i = verlen - 1; i > 0 && verbuf[i] == ' '; --i)
 | 
						|
        --m;
 | 
						|
    *m = '\0';
 | 
						|
 | 
						|
    /* Cut out release number "V5.4-3" -> "V5.4" */
 | 
						|
    if ((m = strrchr(verbuf, '-')) != NULL)
 | 
						|
        *m = '\0';
 | 
						|
    return strlen(verbuf) + 1;  /* Transmit ending '\0' too */
 | 
						|
}
 | 
						|
 | 
						|
#endif /* CHECK_VERSIONS */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Extracts block from p. If resulting length is less then needed, fill
 | 
						|
 * extra space with corresponding bytes from 'init'.
 | 
						|
 * Currently understands 3 formats of block compression:
 | 
						|
 * - Simple storing
 | 
						|
 * - Compression of zero bytes to zero bits
 | 
						|
 * - Deflation (see memextract() in extract.c)
 | 
						|
 */
 | 
						|
static uch *extract_block(__G__ p, retlen, init, needlen)
 | 
						|
    __GDEF
 | 
						|
    struct IZ_block *p;
 | 
						|
    int *retlen;
 | 
						|
    uch *init;
 | 
						|
    int needlen;
 | 
						|
{
 | 
						|
    uch *block;         /* Pointer to block allocated */
 | 
						|
    int cmptype;
 | 
						|
    int usiz, csiz, max;
 | 
						|
 | 
						|
    cmptype = p->flags & BC_MASK;
 | 
						|
    csiz = p->size - EXTBSL - RESL;
 | 
						|
    usiz = (cmptype == BC_STORED ? csiz : p->length);
 | 
						|
 | 
						|
    if (needlen == 0)
 | 
						|
        needlen = usiz;
 | 
						|
 | 
						|
    if (retlen)
 | 
						|
        *retlen = usiz;
 | 
						|
 | 
						|
#ifndef MAX
 | 
						|
# define MAX(a,b)   ((a) > (b)? (a) : (b))
 | 
						|
#endif
 | 
						|
 | 
						|
    if ((block = (uch *) malloc(MAX(needlen, usiz))) == NULL)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    if (init && (usiz < needlen))
 | 
						|
        memcpy(block, init, needlen);
 | 
						|
 | 
						|
    switch (cmptype)
 | 
						|
    {
 | 
						|
        case BC_STORED: /* The simplest case */
 | 
						|
            memcpy(block, &(p->body[0]), usiz);
 | 
						|
            break;
 | 
						|
        case BC_00:
 | 
						|
            decompress_bits(block, usiz, &(p->body[0]));
 | 
						|
            break;
 | 
						|
        case BC_DEFL:
 | 
						|
            memextract(__G__ block, usiz, &(p->body[0]), csiz);
 | 
						|
            break;
 | 
						|
        default:
 | 
						|
            free(block);
 | 
						|
            block = NULL;
 | 
						|
    }
 | 
						|
    return block;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 *  Simple uncompression routine. The compression uses bit stream.
 | 
						|
 *  Compression scheme:
 | 
						|
 *
 | 
						|
 *  if (byte!=0)
 | 
						|
 *      putbit(1),putbyte(byte)
 | 
						|
 *  else
 | 
						|
 *      putbit(0)
 | 
						|
 */
 | 
						|
static void decompress_bits(outptr, needlen, bitptr)
 | 
						|
    uch *outptr;        /* Pointer into output block */
 | 
						|
    int needlen;        /* Size of uncompressed block */
 | 
						|
    uch *bitptr;        /* Pointer into compressed data */
 | 
						|
{
 | 
						|
    ulg bitbuf = 0;
 | 
						|
    int bitcnt = 0;
 | 
						|
 | 
						|
#define _FILL   if (bitcnt+8 <= 32)                     \
 | 
						|
                {       bitbuf |= (*bitptr++) << bitcnt;\
 | 
						|
                        bitcnt += 8;                    \
 | 
						|
                }
 | 
						|
 | 
						|
    while (needlen--)
 | 
						|
    {
 | 
						|
        if (bitcnt <= 0)
 | 
						|
            _FILL;
 | 
						|
 | 
						|
        if (bitbuf & 1)
 | 
						|
        {
 | 
						|
            bitbuf >>= 1;
 | 
						|
            if ((bitcnt -= 1) < 8)
 | 
						|
                _FILL;
 | 
						|
            *outptr++ = (uch) bitbuf;
 | 
						|
            bitcnt -= 8;
 | 
						|
            bitbuf >>= 8;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            *outptr++ = '\0';
 | 
						|
            bitcnt -= 1;
 | 
						|
            bitbuf >>= 1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/* flush contents of output buffer */
 | 
						|
int flush(__G__ rawbuf, size, unshrink)    /* return PK-type error code */
 | 
						|
    __GDEF
 | 
						|
    uch *rawbuf;
 | 
						|
    ulg size;
 | 
						|
    int unshrink;
 | 
						|
{
 | 
						|
    G.crc32val = crc32(G.crc32val, rawbuf, (extent)size);
 | 
						|
    if (G.tflag)
 | 
						|
        return PK_COOL; /* Do not output. Update CRC only */
 | 
						|
    else
 | 
						|
        return (*_flush_routine)(__G__ rawbuf, size, 0);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static int _flush_blocks(__G__ rawbuf, size, final_flag)
 | 
						|
                                                /* Asynchronous version */
 | 
						|
    __GDEF
 | 
						|
    uch *rawbuf;
 | 
						|
    unsigned size;
 | 
						|
    int final_flag;   /* 1 if this is the final flushout */
 | 
						|
{
 | 
						|
    int round;
 | 
						|
    int rest;
 | 
						|
    int off = 0;
 | 
						|
    int status;
 | 
						|
 | 
						|
    while (size > 0)
 | 
						|
    {
 | 
						|
        if (curbuf->bufcnt < BUFS512)
 | 
						|
        {
 | 
						|
            int ncpy;
 | 
						|
 | 
						|
            ncpy = size > (BUFS512 - curbuf->bufcnt) ?
 | 
						|
                            BUFS512 - curbuf->bufcnt :
 | 
						|
                            size;
 | 
						|
            memcpy(curbuf->buf + curbuf->bufcnt, rawbuf + off, ncpy);
 | 
						|
            size -= ncpy;
 | 
						|
            curbuf->bufcnt += ncpy;
 | 
						|
            off += ncpy;
 | 
						|
        }
 | 
						|
        if (curbuf->bufcnt == BUFS512)
 | 
						|
        {
 | 
						|
            status = WriteBuffer(__G__ curbuf->buf, curbuf->bufcnt);
 | 
						|
            if (status)
 | 
						|
                return status;
 | 
						|
            curbuf = curbuf->next;
 | 
						|
            curbuf->bufcnt = 0;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return (final_flag && (curbuf->bufcnt > 0)) ?
 | 
						|
        WriteBuffer(__G__ curbuf->buf, curbuf->bufcnt) :
 | 
						|
        PK_COOL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static int _flush_qio(__G__ rawbuf, size, final_flag)
 | 
						|
    __GDEF
 | 
						|
    uch *rawbuf;
 | 
						|
    unsigned size;
 | 
						|
    int final_flag;   /* 1 if this is the final flushout */
 | 
						|
{
 | 
						|
    int status;
 | 
						|
    uch *out_ptr=rawbuf;
 | 
						|
 | 
						|
    if ( final_flag )
 | 
						|
    {
 | 
						|
        if ( loccnt > 0 )
 | 
						|
        {
 | 
						|
            status = sys$qiow(0, pka_devchn, IO$_WRITEVBLK,
 | 
						|
                              &pka_io_sb, 0, 0,
 | 
						|
                              locbuf,
 | 
						|
                              (loccnt+1)&(~1), /* Round up to even byte count */
 | 
						|
                              pka_vbn,
 | 
						|
                              0, 0, 0);
 | 
						|
            if (!ERR(status))
 | 
						|
                status = pka_io_sb.status;
 | 
						|
            if (ERR(status))
 | 
						|
            {
 | 
						|
                vms_msg(__G__ "[ Write QIO failed ]\n",status);
 | 
						|
                return PK_DISK;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return PK_COOL;
 | 
						|
    }
 | 
						|
 | 
						|
    if ( loccnt > 0 )
 | 
						|
    {
 | 
						|
        /*
 | 
						|
         *   Fill local buffer upto 512 bytes then put it out
 | 
						|
         */
 | 
						|
        int ncpy;
 | 
						|
 | 
						|
        ncpy = 512-loccnt;
 | 
						|
        if ( ncpy > size )
 | 
						|
            ncpy = size;
 | 
						|
 | 
						|
        memcpy(locptr,rawbuf,ncpy);
 | 
						|
        locptr += ncpy;
 | 
						|
        loccnt += ncpy;
 | 
						|
        size -= ncpy;
 | 
						|
        out_ptr += ncpy;
 | 
						|
        if ( loccnt == 512 )
 | 
						|
        {
 | 
						|
            status = sys$qiow(0, pka_devchn, IO$_WRITEVBLK,
 | 
						|
                              &pka_io_sb, 0, 0,
 | 
						|
                              locbuf, loccnt, pka_vbn,
 | 
						|
                              0, 0, 0);
 | 
						|
            if (!ERR(status))
 | 
						|
                status = pka_io_sb.status;
 | 
						|
            if (ERR(status))
 | 
						|
            {
 | 
						|
                vms_msg(__G__ "[ Write QIO failed ]\n",status);
 | 
						|
                return PK_DISK;
 | 
						|
            }
 | 
						|
 | 
						|
            pka_vbn++;
 | 
						|
            loccnt = 0;
 | 
						|
            locptr = locbuf;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ( size >= 512 )
 | 
						|
    {
 | 
						|
        int nblk,put_cnt;
 | 
						|
 | 
						|
        /*
 | 
						|
         *   Put rest of buffer as a single VB
 | 
						|
         */
 | 
						|
        put_cnt = (nblk = size>>9)<<9;
 | 
						|
        status = sys$qiow(0, pka_devchn, IO$_WRITEVBLK,
 | 
						|
                          &pka_io_sb, 0, 0,
 | 
						|
                          out_ptr, put_cnt, pka_vbn,
 | 
						|
                          0, 0, 0);
 | 
						|
        if (!ERR(status))
 | 
						|
            status = pka_io_sb.status;
 | 
						|
        if (ERR(status))
 | 
						|
        {
 | 
						|
            vms_msg(__G__ "[ Write QIO failed ]\n",status);
 | 
						|
            return PK_DISK;
 | 
						|
        }
 | 
						|
 | 
						|
        pka_vbn += nblk;
 | 
						|
        out_ptr += put_cnt;
 | 
						|
        size -= put_cnt;
 | 
						|
    }
 | 
						|
 | 
						|
    if ( size > 0 )
 | 
						|
    {
 | 
						|
        memcpy(locptr,out_ptr,size);
 | 
						|
        loccnt += size;
 | 
						|
        locptr += size;
 | 
						|
    }
 | 
						|
 | 
						|
    return PK_COOL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static int _flush_varlen(__G__ rawbuf, size, final_flag)
 | 
						|
    __GDEF
 | 
						|
    uch *rawbuf;
 | 
						|
    unsigned size;
 | 
						|
    int final_flag;
 | 
						|
{
 | 
						|
    ush nneed;
 | 
						|
    ush reclen;
 | 
						|
    uch *inptr=rawbuf;
 | 
						|
 | 
						|
    /*
 | 
						|
     * Flush local buffer
 | 
						|
     */
 | 
						|
 | 
						|
    if ( loccnt > 0 )
 | 
						|
    {
 | 
						|
        reclen = *(ush*)locbuf;
 | 
						|
        if ( (nneed = reclen + 2 - loccnt) > 0 )
 | 
						|
        {
 | 
						|
            if ( nneed > size )
 | 
						|
            {
 | 
						|
                if ( size+loccnt > BUFS512 )
 | 
						|
                {
 | 
						|
                    char buf[80];
 | 
						|
                    Info(buf, 1, (buf,
 | 
						|
                         "[ Record too long (%d bytes) ]\n",reclen ));
 | 
						|
                    return PK_DISK;
 | 
						|
                }
 | 
						|
                memcpy(locbuf+loccnt,rawbuf,size);
 | 
						|
                loccnt += size;
 | 
						|
                size = 0;
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                memcpy(locbuf+loccnt,rawbuf,nneed);
 | 
						|
                loccnt += nneed;
 | 
						|
                size -= nneed;
 | 
						|
                inptr += nneed;
 | 
						|
                if ( reclen & 1 )
 | 
						|
                {
 | 
						|
                    size--;
 | 
						|
                    inptr++;
 | 
						|
                }
 | 
						|
                if ( WriteRecord(__G__ locbuf+2,reclen) )
 | 
						|
                    return PK_DISK;
 | 
						|
                loccnt = 0;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            if (WriteRecord(__G__ locbuf+2,reclen))
 | 
						|
                return PK_DISK;
 | 
						|
            loccnt -= reclen+2;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    /*
 | 
						|
     * Flush incoming records
 | 
						|
     */
 | 
						|
    while (size > 0)
 | 
						|
    {
 | 
						|
        reclen = *(ush*)inptr;
 | 
						|
        if ( reclen+2 <= size )
 | 
						|
        {
 | 
						|
            if (WriteRecord(__G__ inptr+2,reclen))
 | 
						|
                return PK_DISK;
 | 
						|
            size -= 2+reclen;
 | 
						|
            inptr += 2+reclen;
 | 
						|
            if ( reclen & 1)
 | 
						|
            {
 | 
						|
                --size;
 | 
						|
                ++inptr;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            memcpy(locbuf,inptr,size);
 | 
						|
            loccnt = size;
 | 
						|
            size = 0;
 | 
						|
        }
 | 
						|
 | 
						|
    }
 | 
						|
    /*
 | 
						|
     * Final flush rest of local buffer
 | 
						|
     */
 | 
						|
    if ( final_flag && loccnt > 0 )
 | 
						|
    {
 | 
						|
        char buf[80];
 | 
						|
 | 
						|
        Info(buf, 1, (buf,
 | 
						|
            "[ Warning, incomplete record of length %d ]\n",
 | 
						|
            *(ush*)locbuf));
 | 
						|
        if ( WriteRecord(__G__ locbuf+2,loccnt-2) )
 | 
						|
            return PK_DISK;
 | 
						|
    }
 | 
						|
    return PK_COOL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
*   Routine _flush_stream breaks decompressed stream into records
 | 
						|
*   depending on format of the stream (fab->rfm, G.pInfo->textmode, etc.)
 | 
						|
*   and puts out these records. It also handles CR LF sequences.
 | 
						|
*   Should be used when extracting *text* files.
 | 
						|
*/
 | 
						|
 | 
						|
#define VT      0x0B
 | 
						|
#define FF      0x0C
 | 
						|
 | 
						|
/* The file is from MSDOS/OS2/NT -> handle CRLF as record end, throw out ^Z */
 | 
						|
 | 
						|
/* GRR NOTES:  cannot depend on hostnum!  May have "flip'd" file or re-zipped
 | 
						|
 * a Unix file, etc. */
 | 
						|
 | 
						|
#ifdef USE_ORIG_DOS
 | 
						|
# define ORG_DOS   (hostnum==FS_FAT_ || hostnum==FS_HPFS_ || hostnum==FS_NTFS_)
 | 
						|
#else
 | 
						|
# define ORG_DOS    1
 | 
						|
#endif
 | 
						|
 | 
						|
/* Record delimiters */
 | 
						|
#ifdef undef
 | 
						|
#define RECORD_END(c,f)                                                 \
 | 
						|
(    ( ORG_DOS || G.pInfo->textmode ) && c==CTRLZ                      \
 | 
						|
  || ( f == FAB$C_STMLF && c==LF )                                      \
 | 
						|
  || ( f == FAB$C_STMCR || ORG_DOS || G.pInfo->textmode ) && c==CR     \
 | 
						|
  || ( f == FAB$C_STM && (c==CR || c==LF || c==FF || c==VT) )           \
 | 
						|
)
 | 
						|
#else
 | 
						|
#   define  RECORD_END(c,f)   ((c) == LF || (c) == (CR))
 | 
						|
#endif
 | 
						|
 | 
						|
static int  find_eol(p,n,l)
 | 
						|
/*
 | 
						|
 *  Find first CR,LF,CR-LF or LF-CR in string 'p' of length 'n'.
 | 
						|
 *  Return offset of the sequence found or 'n' if not found.
 | 
						|
 *  If found, return in '*l' length of the sequence (1 or 2) or
 | 
						|
 *  zero if sequence end not seen, i.e. CR or LF is last char
 | 
						|
 *  in the buffer.
 | 
						|
 */
 | 
						|
    uch *p;
 | 
						|
    int n;
 | 
						|
    int *l;
 | 
						|
{
 | 
						|
    int off = n;
 | 
						|
    uch *q;
 | 
						|
 | 
						|
    *l = 0;
 | 
						|
 | 
						|
    for (q=p ; n > 0 ; --n,++q)
 | 
						|
        if ( RECORD_END(*q,rfm) )
 | 
						|
        {
 | 
						|
            off = q-p;
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
    if ( n > 1 )
 | 
						|
    {
 | 
						|
        *l = 1;
 | 
						|
        if ( ( q[0] == CR && q[1] == LF ) || ( q[0] == LF && q[1] == CR ) )
 | 
						|
            *l = 2;
 | 
						|
    }
 | 
						|
 | 
						|
    return off;
 | 
						|
}
 | 
						|
 | 
						|
/* Record delimiters that must be put out */
 | 
						|
#define PRINT_SPEC(c)   ( (c)==FF || (c)==VT )
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static int _flush_stream(__G__ rawbuf, size, final_flag)
 | 
						|
    __GDEF
 | 
						|
    uch *rawbuf;
 | 
						|
    unsigned size;
 | 
						|
    int final_flag; /* 1 if this is the final flushout */
 | 
						|
{
 | 
						|
    int rest;
 | 
						|
    int end = 0, start = 0;
 | 
						|
    int off = 0;
 | 
						|
 | 
						|
    if (size == 0 && loccnt == 0)
 | 
						|
        return PK_COOL;         /* Nothing to do ... */
 | 
						|
 | 
						|
    if ( final_flag )
 | 
						|
    {
 | 
						|
        int recsize;
 | 
						|
 | 
						|
        /*
 | 
						|
         * This is flush only call. size must be zero now.
 | 
						|
         * Just eject everything we have in locbuf.
 | 
						|
         */
 | 
						|
        recsize = loccnt - (got_eol ? 1:0);
 | 
						|
        /*
 | 
						|
         *  If the last char of file was ^Z ( end-of-file in MSDOS ),
 | 
						|
         *  we will see it now.
 | 
						|
         */
 | 
						|
        if ( recsize==1 && locbuf[0] == CTRLZ )
 | 
						|
            return PK_COOL;
 | 
						|
 | 
						|
        return WriteRecord(__G__ locbuf, recsize) ? PK_DISK : PK_COOL;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    if ( loccnt > 0 )
 | 
						|
    {
 | 
						|
        /* Find end of record partially saved in locbuf */
 | 
						|
 | 
						|
        int recsize;
 | 
						|
        int complete=0;
 | 
						|
 | 
						|
        if ( got_eol )
 | 
						|
        {
 | 
						|
            recsize = loccnt - 1;
 | 
						|
            complete = 1;
 | 
						|
 | 
						|
            if ( (got_eol == CR && rawbuf[0] == LF) ||
 | 
						|
                 (got_eol == LF && rawbuf[0] == CR) )
 | 
						|
                end = 1;
 | 
						|
 | 
						|
            got_eol = 0;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            int eol_len;
 | 
						|
            int eol_off;
 | 
						|
 | 
						|
            eol_off = find_eol(rawbuf,size,&eol_len);
 | 
						|
 | 
						|
            if ( loccnt+eol_off > BUFS512 )
 | 
						|
            {
 | 
						|
                /*
 | 
						|
                 *  No room in locbuf. Dump it and clear
 | 
						|
                 */
 | 
						|
                char buf[80];           /* CANNOT use slide for Info() */
 | 
						|
 | 
						|
                recsize = loccnt;
 | 
						|
                start = 0;
 | 
						|
                Info(buf, 1, (buf,
 | 
						|
                     "[ Warning: Record too long (%d) ]\n", loccnt+eol_off));
 | 
						|
                complete = 1;
 | 
						|
                end = 0;
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                if ( eol_off >= size )
 | 
						|
                {
 | 
						|
                    end = size;
 | 
						|
                    complete = 0;
 | 
						|
                }
 | 
						|
                else if ( eol_len == 0 )
 | 
						|
                {
 | 
						|
                    got_eol = rawbuf[eol_off];
 | 
						|
                    end = size;
 | 
						|
                    complete = 0;
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    memcpy(locptr, rawbuf, eol_off);
 | 
						|
                    recsize = loccnt + eol_off;
 | 
						|
                    locptr += eol_off;
 | 
						|
                    loccnt += eol_off;
 | 
						|
                    end = eol_off + eol_len;
 | 
						|
                    complete = 1;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if ( complete )
 | 
						|
        {
 | 
						|
            if (WriteRecord(__G__ locbuf, recsize))
 | 
						|
                return PK_DISK;
 | 
						|
            loccnt = 0;
 | 
						|
            locptr = locbuf;
 | 
						|
        }
 | 
						|
    }                           /* end if ( loccnt ) */
 | 
						|
 | 
						|
    for (start = end; start < size && end < size; )
 | 
						|
    {
 | 
						|
        int eol_off,eol_len;
 | 
						|
 | 
						|
        got_eol = 0;
 | 
						|
 | 
						|
#ifdef undef
 | 
						|
        if (G.cflag)
 | 
						|
            /* skip CR's at the beginning of record */
 | 
						|
            while (start < size && rawbuf[start] == CR)
 | 
						|
                ++start;
 | 
						|
#endif
 | 
						|
 | 
						|
        if ( start >= size )
 | 
						|
            continue;
 | 
						|
 | 
						|
        /* Find record end */
 | 
						|
        end = start+(eol_off = find_eol(rawbuf+start, size-start, &eol_len));
 | 
						|
 | 
						|
        if ( end >= size )
 | 
						|
            continue;
 | 
						|
 | 
						|
        if ( eol_len > 0 )
 | 
						|
        {
 | 
						|
            if ( WriteRecord(__G__ rawbuf+start, end-start) )
 | 
						|
                return PK_DISK;
 | 
						|
            start = end + eol_len;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            got_eol = rawbuf[end];
 | 
						|
            end = size;
 | 
						|
            continue;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    rest = size - start;
 | 
						|
 | 
						|
    if (rest > 0)
 | 
						|
    {
 | 
						|
        if ( rest > BUFS512 )
 | 
						|
        {
 | 
						|
            int recsize;
 | 
						|
            char buf[80];               /* CANNOT use slide for Info() */
 | 
						|
 | 
						|
            recsize = rest - (got_eol ? 1:0 );
 | 
						|
            Info(buf, 1, (buf,
 | 
						|
                 "[ Warning: Record too long (%d) ]\n", recsize));
 | 
						|
            got_eol = 0;
 | 
						|
            return WriteRecord(__G__ rawbuf+start,recsize) ? PK_DISK : PK_COOL;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            memcpy(locptr, rawbuf + start, rest);
 | 
						|
            locptr += rest;
 | 
						|
            loccnt += rest;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return PK_COOL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static int WriteBuffer(__G__ buf, len)
 | 
						|
    __GDEF
 | 
						|
    uch *buf;
 | 
						|
    int len;
 | 
						|
{
 | 
						|
    int status;
 | 
						|
 | 
						|
    status = sys$wait(outrab);
 | 
						|
    if (ERR(status))
 | 
						|
    {
 | 
						|
        vms_msg(__G__ "[ WriteBuffer: sys$wait failed ]\n", status);
 | 
						|
        vms_msg(__G__ "", outrab->rab$l_stv);
 | 
						|
    }
 | 
						|
    outrab->rab$w_rsz = len;
 | 
						|
    outrab->rab$l_rbf = (char *) buf;
 | 
						|
 | 
						|
    if (ERR(status = sys$write(outrab)))
 | 
						|
    {
 | 
						|
        vms_msg(__G__ "[ WriteBuffer: sys$write failed ]\n", status);
 | 
						|
        vms_msg(__G__ "", outrab->rab$l_stv);
 | 
						|
        return PK_DISK;
 | 
						|
    }
 | 
						|
    return PK_COOL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static int WriteRecord(__G__ rec, len)
 | 
						|
    __GDEF
 | 
						|
    uch *rec;
 | 
						|
    int len;
 | 
						|
{
 | 
						|
    int status;
 | 
						|
 | 
						|
    if (G.cflag)
 | 
						|
    {
 | 
						|
        (void)(*G.message)((zvoid *)&G, rec, len, 0);
 | 
						|
        (void)(*G.message)((zvoid *)&G, (uch *) ("\n"), 1, 0);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        if (ERR(status = sys$wait(outrab)))
 | 
						|
        {
 | 
						|
            vms_msg(__G__ "[ WriteRecord: sys$wait failed ]\n", status);
 | 
						|
            vms_msg(__G__ "", outrab->rab$l_stv);
 | 
						|
        }
 | 
						|
        outrab->rab$w_rsz = len;
 | 
						|
        outrab->rab$l_rbf = (char *) rec;
 | 
						|
 | 
						|
        if (ERR(status = sys$put(outrab)))
 | 
						|
        {
 | 
						|
            vms_msg(__G__ "[ WriteRecord: sys$put failed ]\n", status);
 | 
						|
            vms_msg(__G__ "", outrab->rab$l_stv);
 | 
						|
            return PK_DISK;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return PK_COOL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void close_outfile(__G)
 | 
						|
    __GDEF
 | 
						|
{
 | 
						|
    int status;
 | 
						|
 | 
						|
    status = (*_flush_routine)(__G__ NULL, 0, 1);
 | 
						|
    if (status)
 | 
						|
        return /* PK_DISK */;
 | 
						|
    if (G.cflag)
 | 
						|
        return /* PK_COOL */;   /* Don't close stdout */
 | 
						|
    /* return */ (*_close_routine)(__G);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static int _close_rms(__GPRO)
 | 
						|
{
 | 
						|
    int status;
 | 
						|
    struct XABPRO pro;
 | 
						|
 | 
						|
    /* Link XABRDT, XABDAT and optionally XABPRO */
 | 
						|
    if (xabrdt != NULL)
 | 
						|
    {
 | 
						|
        xabrdt->xab$l_nxt = NULL;
 | 
						|
        outfab->fab$l_xab = (void *) xabrdt;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        rdt.xab$l_nxt = NULL;
 | 
						|
        outfab->fab$l_xab = (void *) &rdt;
 | 
						|
    }
 | 
						|
    if (xabdat != NULL)
 | 
						|
    {
 | 
						|
        xabdat->xab$l_nxt = outfab->fab$l_xab;
 | 
						|
        outfab->fab$l_xab = (void *)xabdat;
 | 
						|
    }
 | 
						|
 | 
						|
    if (xabpro != NULL)
 | 
						|
    {
 | 
						|
        if ( !G.X_flag )
 | 
						|
            xabpro->xab$l_uic = 0;    /* Use default (user's) uic */
 | 
						|
        xabpro->xab$l_nxt = outfab->fab$l_xab;
 | 
						|
        outfab->fab$l_xab = (void *) xabpro;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        pro = cc$rms_xabpro;
 | 
						|
        pro.xab$w_pro = G.pInfo->file_attr;
 | 
						|
        pro.xab$l_nxt = outfab->fab$l_xab;
 | 
						|
        outfab->fab$l_xab = (void *) &pro;
 | 
						|
    }
 | 
						|
 | 
						|
    sys$wait(outrab);
 | 
						|
 | 
						|
    status = sys$close(outfab);
 | 
						|
#ifdef DEBUG
 | 
						|
    if (ERR(status))
 | 
						|
    {
 | 
						|
        vms_msg(__G__
 | 
						|
          "\r[ Warning: cannot set owner/protection/time attributes ]\n",
 | 
						|
          status);
 | 
						|
        vms_msg(__G__ "", outfab->fab$l_stv);
 | 
						|
    }
 | 
						|
#endif
 | 
						|
    free_up();
 | 
						|
    return PK_COOL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static int _close_qio(__GPRO)
 | 
						|
{
 | 
						|
    int status;
 | 
						|
 | 
						|
    pka_fib.FIB$L_ACCTL =
 | 
						|
        FIB$M_WRITE | FIB$M_NOTRUNC ;
 | 
						|
    pka_fib.FIB$W_EXCTL = 0;
 | 
						|
 | 
						|
    pka_fib.FIB$W_FID[0] =
 | 
						|
    pka_fib.FIB$W_FID[1] =
 | 
						|
    pka_fib.FIB$W_FID[2] =
 | 
						|
    pka_fib.FIB$W_DID[0] =
 | 
						|
    pka_fib.FIB$W_DID[1] =
 | 
						|
    pka_fib.FIB$W_DID[2] = 0;
 | 
						|
 | 
						|
    status = sys$qiow(0, pka_devchn, IO$_DEACCESS, &pka_acp_sb,
 | 
						|
                      0, 0,
 | 
						|
                      &pka_fibdsc, 0, 0, 0,
 | 
						|
                      &pka_atr, 0);
 | 
						|
 | 
						|
    sys$dassgn(pka_devchn);
 | 
						|
    if ( !ERR(status) )
 | 
						|
        status = pka_acp_sb.status;
 | 
						|
    if ( ERR(status) )
 | 
						|
    {
 | 
						|
        vms_msg(__G__ "[ Deaccess QIO failed ]\n",status);
 | 
						|
        return PK_DISK;
 | 
						|
    }
 | 
						|
    return PK_COOL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
#if 0   /* currently not used anywhere ! */
 | 
						|
void dump_rms_block(p)
 | 
						|
    unsigned char *p;
 | 
						|
{
 | 
						|
    unsigned char bid, len;
 | 
						|
    int err;
 | 
						|
    char *type;
 | 
						|
    char buf[132];
 | 
						|
    int i;
 | 
						|
 | 
						|
    err = 0;
 | 
						|
    bid = p[0];
 | 
						|
    len = p[1];
 | 
						|
    switch (bid)
 | 
						|
    {
 | 
						|
        case FAB$C_BID:
 | 
						|
            type = "FAB";
 | 
						|
            break;
 | 
						|
        case XAB$C_ALL:
 | 
						|
            type = "xabALL";
 | 
						|
            break;
 | 
						|
        case XAB$C_KEY:
 | 
						|
            type = "xabKEY";
 | 
						|
            break;
 | 
						|
        case XAB$C_DAT:
 | 
						|
            type = "xabDAT";
 | 
						|
            break;
 | 
						|
        case XAB$C_RDT:
 | 
						|
            type = "xabRDT";
 | 
						|
            break;
 | 
						|
        case XAB$C_FHC:
 | 
						|
            type = "xabFHC";
 | 
						|
            break;
 | 
						|
        case XAB$C_PRO:
 | 
						|
            type = "xabPRO";
 | 
						|
            break;
 | 
						|
        default:
 | 
						|
            type = "Unknown";
 | 
						|
            err = 1;
 | 
						|
            break;
 | 
						|
    }
 | 
						|
    printf("Block @%08X of type %s (%d).", p, type, bid);
 | 
						|
    if (err)
 | 
						|
    {
 | 
						|
        printf("\n");
 | 
						|
        return;
 | 
						|
    }
 | 
						|
    printf(" Size = %d\n", len);
 | 
						|
    printf(" Offset - Hex - Dec\n");
 | 
						|
    for (i = 0; i < len; i += 8)
 | 
						|
    {
 | 
						|
        int j;
 | 
						|
 | 
						|
        printf("%3d - ", i);
 | 
						|
        for (j = 0; j < 8; j++)
 | 
						|
            if (i + j < len)
 | 
						|
                printf("%02X ", p[i + j]);
 | 
						|
            else
 | 
						|
                printf("   ");
 | 
						|
        printf(" - ");
 | 
						|
        for (j = 0; j < 8; j++)
 | 
						|
            if (i + j < len)
 | 
						|
                printf("%03d ", p[i + j]);
 | 
						|
            else
 | 
						|
                printf("    ");
 | 
						|
        printf("\n");
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#endif                          /* never */
 | 
						|
#endif                          /* DEBUG */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static void vms_msg(__GPRO__ char *string, int status)
 | 
						|
{
 | 
						|
    static char msgbuf[256];
 | 
						|
 | 
						|
    $DESCRIPTOR(msgd, msgbuf);
 | 
						|
    int msglen = 0;
 | 
						|
 | 
						|
    if (ERR(lib$sys_getmsg(&status, &msglen, &msgd, 0, 0)))
 | 
						|
        Info(slide, 1, ((char *)slide,
 | 
						|
             "%s[ VMS status = %d ]\n", string, status));
 | 
						|
    else
 | 
						|
    {
 | 
						|
        msgbuf[msglen] = '\0';
 | 
						|
        Info(slide, 1, ((char *)slide, "%s[ %s ]\n", string, msgbuf));
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#ifndef SFX
 | 
						|
 | 
						|
char *do_wild( __G__ wld )
 | 
						|
    __GDEF
 | 
						|
    char *wld;
 | 
						|
{
 | 
						|
    int status;
 | 
						|
 | 
						|
    static char filenam[256];
 | 
						|
    static char efn[256];
 | 
						|
    static char last_wild[256];
 | 
						|
    static struct FAB fab;
 | 
						|
    static struct NAM nam;
 | 
						|
    static int first_call=1;
 | 
						|
    static ZCONST char deflt[] = "[]*.zip";
 | 
						|
 | 
						|
    if ( first_call || strcmp(wld, last_wild) )
 | 
						|
    {   /* (Re)Initialize everything */
 | 
						|
 | 
						|
        strcpy( last_wild, wld );
 | 
						|
        first_call = 1;            /* New wild spec */
 | 
						|
 | 
						|
        fab = cc$rms_fab;
 | 
						|
        fab.fab$l_fna = last_wild;
 | 
						|
        fab.fab$b_fns = strlen(last_wild);
 | 
						|
        fab.fab$l_dna = (char *) deflt;
 | 
						|
        fab.fab$b_dns = sizeof(deflt)-1;
 | 
						|
        fab.fab$l_nam = &nam;
 | 
						|
        nam = cc$rms_nam;
 | 
						|
        nam.nam$l_esa = efn;
 | 
						|
        nam.nam$b_ess = sizeof(efn)-1;
 | 
						|
        nam.nam$l_rsa = filenam;
 | 
						|
        nam.nam$b_rss = sizeof(filenam)-1;
 | 
						|
 | 
						|
        if ( !OK(sys$parse(&fab)) )
 | 
						|
            return (char *)NULL;     /* Initialization failed */
 | 
						|
        first_call = 0;
 | 
						|
        if ( !OK(sys$search(&fab)) )
 | 
						|
        {
 | 
						|
            strcpy( filenam, wld );
 | 
						|
            return filenam;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        if ( !OK(sys$search(&fab)) )
 | 
						|
        {
 | 
						|
            first_call = 1;        /* Reinitialize next time */
 | 
						|
            return (char *)NULL;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    filenam[nam.nam$b_rsl] = 0;
 | 
						|
    return filenam;
 | 
						|
 | 
						|
} /* end function do_wild() */
 | 
						|
 | 
						|
#endif /* !SFX */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
static ulg unix_to_vms[8]={ /* Map from UNIX rwx to VMS rwed */
 | 
						|
                            /* Note that unix w bit is mapped to VMS wd bits */
 | 
						|
                                                              /* no access */
 | 
						|
    XAB$M_NOREAD | XAB$M_NOWRITE | XAB$M_NODEL | XAB$M_NOEXE,    /* --- */
 | 
						|
    XAB$M_NOREAD | XAB$M_NOWRITE | XAB$M_NODEL,                  /* --x */
 | 
						|
    XAB$M_NOREAD |                               XAB$M_NOEXE,    /* -w- */
 | 
						|
    XAB$M_NOREAD,                                                /* -wx */
 | 
						|
                   XAB$M_NOWRITE | XAB$M_NODEL | XAB$M_NOEXE,    /* r-- */
 | 
						|
                   XAB$M_NOWRITE | XAB$M_NODEL,                  /* r-x */
 | 
						|
                                                 XAB$M_NOEXE,    /* rw- */
 | 
						|
    0                                                            /* rwx */
 | 
						|
                                                              /* full access */
 | 
						|
};
 | 
						|
 | 
						|
#define SETDFPROT   /* We are using undocumented VMS System Service     */
 | 
						|
                    /* SYS$SETDFPROT here. If your version of VMS does  */
 | 
						|
                    /* not have that service, undef SETDFPROT.          */
 | 
						|
                    /* IM: Maybe it's better to put this to Makefile    */
 | 
						|
                    /* and DESCRIP.MMS */
 | 
						|
 | 
						|
#ifdef SETDFPROT
 | 
						|
extern int SYS$SETDFPROT();
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
int mapattr(__G)
 | 
						|
    __GDEF
 | 
						|
{
 | 
						|
    ulg  tmp=G.crec.external_file_attributes, theprot;
 | 
						|
    static ulg  defprot = -1L,
 | 
						|
                sysdef,owndef,grpdef,wlddef;  /* Default protection fields */
 | 
						|
 | 
						|
 | 
						|
    /* IM: The only field of XABPRO we need to set here is */
 | 
						|
    /*     file protection, so we need not to change type */
 | 
						|
    /*     of G.pInfo->file_attr. WORD is quite enough. */
 | 
						|
 | 
						|
    if ( defprot == -1L )
 | 
						|
    {
 | 
						|
        /*
 | 
						|
         * First time here -- Get user default settings
 | 
						|
         */
 | 
						|
 | 
						|
#ifdef SETDFPROT    /* Undef this if linker cat't resolve SYS$SETDFPROT */
 | 
						|
        defprot = 0L;
 | 
						|
        if ( !ERR(SYS$SETDFPROT(0,&defprot)) )
 | 
						|
        {
 | 
						|
            sysdef = defprot & ( (1L<<XAB$S_SYS)-1 ) << XAB$V_SYS;
 | 
						|
            owndef = defprot & ( (1L<<XAB$S_OWN)-1 ) << XAB$V_OWN;
 | 
						|
            grpdef = defprot & ( (1L<<XAB$S_GRP)-1 ) << XAB$V_GRP;
 | 
						|
            wlddef = defprot & ( (1L<<XAB$S_WLD)-1 ) << XAB$V_WLD;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
#endif /* ?SETDFPROT */
 | 
						|
            umask(defprot = umask(0));
 | 
						|
            defprot = ~defprot;
 | 
						|
            wlddef = unix_to_vms[defprot & 07] << XAB$V_WLD;
 | 
						|
            grpdef = unix_to_vms[(defprot>>3) & 07] << XAB$V_GRP;
 | 
						|
            owndef = unix_to_vms[(defprot>>6) & 07] << XAB$V_OWN;
 | 
						|
            sysdef = owndef << (XAB$V_SYS - XAB$V_OWN);
 | 
						|
            defprot = sysdef | owndef | grpdef | wlddef;
 | 
						|
#ifdef SETDFPROT
 | 
						|
        }
 | 
						|
#endif /* ?SETDFPROT */
 | 
						|
    }
 | 
						|
 | 
						|
    switch (G.pInfo->hostnum) {
 | 
						|
        case UNIX_:
 | 
						|
        case VMS_:  /*IM: ??? Does VMS Zip store protection in UNIX format ?*/
 | 
						|
                    /* GRR:  Yup.  Bad decision on my part... */
 | 
						|
            tmp = (unsigned)(tmp >> 16);  /* drwxrwxrwx */
 | 
						|
            theprot  = (unix_to_vms[tmp & 07] << XAB$V_WLD)
 | 
						|
                     | (unix_to_vms[(tmp>>3) & 07] << XAB$V_GRP)
 | 
						|
                     | (unix_to_vms[(tmp>>6) & 07] << XAB$V_OWN);
 | 
						|
 | 
						|
            if ( tmp & 0x4000 )
 | 
						|
                /* Directory -- set D bits */
 | 
						|
                theprot |= (XAB$M_NODEL << XAB$V_SYS)
 | 
						|
                        | (XAB$M_NODEL << XAB$V_OWN)
 | 
						|
                        | (XAB$M_NODEL << XAB$V_GRP)
 | 
						|
                        | (XAB$M_NODEL << XAB$V_WLD);
 | 
						|
            G.pInfo->file_attr = theprot;
 | 
						|
            break;
 | 
						|
 | 
						|
        case AMIGA_:
 | 
						|
            tmp = (unsigned)(tmp>>16 & 0x0f);   /* Amiga RWED bits */
 | 
						|
            G.pInfo->file_attr =  (tmp << XAB$V_OWN) |
 | 
						|
                                   grpdef | sysdef | wlddef;
 | 
						|
            break;
 | 
						|
 | 
						|
        /* all remaining cases:  expand MSDOS read-only bit into write perms */
 | 
						|
        case FS_FAT_:
 | 
						|
        case FS_HPFS_:
 | 
						|
        case FS_NTFS_:
 | 
						|
        case MAC_:
 | 
						|
        case ATARI_:             /* (used to set = 0666) */
 | 
						|
        case TOPS20_:
 | 
						|
        default:
 | 
						|
            theprot = defprot;
 | 
						|
            if ( tmp & 1 )   /* Test read-only bit */
 | 
						|
            {   /* Bit is set -- set bits in all fields */
 | 
						|
                tmp = XAB$M_NOWRITE | XAB$M_NODEL;
 | 
						|
                theprot |= (tmp << XAB$V_SYS) | (tmp << XAB$V_OWN) |
 | 
						|
                           (tmp << XAB$V_GRP) | (tmp << XAB$V_WLD);
 | 
						|
            }
 | 
						|
            G.pInfo->file_attr = theprot;
 | 
						|
            break;
 | 
						|
    } /* end switch (host-OS-created-by) */
 | 
						|
 | 
						|
    return 0;
 | 
						|
 | 
						|
} /* end function mapattr() */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#ifndef EEXIST
 | 
						|
#  include <errno.h>    /* For mkdir() status codes */
 | 
						|
#endif
 | 
						|
 | 
						|
#include <fscndef.h> /* for filescan */
 | 
						|
 | 
						|
#   define FN_MASK   7
 | 
						|
#   define USE_DEFAULT  (FN_MASK+1)
 | 
						|
 | 
						|
/*
 | 
						|
 * Checkdir function codes:
 | 
						|
 *      ROOT        -   set root path from unzip qq d:[dir]
 | 
						|
 *      INIT        -   get ready for "filename"
 | 
						|
 *      APPEND_DIR  -   append pathcomp
 | 
						|
 *      APPEND_NAME -   append filename
 | 
						|
 *      APPEND_NAME | USE_DEFAULT   -    expand filename using collected path
 | 
						|
 *      GETPATH     -   return resulting filespec
 | 
						|
 *      END         -   free dynamically allocated space prior to program exit
 | 
						|
 */
 | 
						|
 | 
						|
static  int created_dir;
 | 
						|
 | 
						|
int mapname(__G__ renamed)
 | 
						|
            /* returns: */
 | 
						|
            /* 0 (PK_COOL) if no error, */
 | 
						|
            /* 1 (PK_WARN) if caution (filename trunc), */
 | 
						|
            /* 2 (PK_ERR)  if warning (skip file because dir doesn't exist), */
 | 
						|
            /* 3 (PK_BADERR) if error (skip file), */
 | 
						|
            /* 77 (IZ_CREATED_DIR) if has created directory, */
 | 
						|
            /* 10 if no memory (skip file) */
 | 
						|
    __GDEF
 | 
						|
    int renamed;
 | 
						|
{
 | 
						|
    char pathcomp[FILNAMSIZ];   /* path-component buffer */
 | 
						|
    char *pp, *cp=NULL;         /* character pointers */
 | 
						|
    char *lastsemi = NULL;      /* pointer to last semi-colon in pathcomp */
 | 
						|
    char *last_dot = NULL;      /* last dot not converted to underscore */
 | 
						|
    int quote = FALSE;          /* flag:  next char is literal */
 | 
						|
    int dotname = FALSE;        /* flag:  path component begins with dot */
 | 
						|
    int error = 0;
 | 
						|
    register unsigned workch;   /* hold the character being tested */
 | 
						|
 | 
						|
    if ( renamed )
 | 
						|
    {
 | 
						|
        if ( !(error = checkdir(__G__ pathcomp, APPEND_NAME | USE_DEFAULT)) )
 | 
						|
            strcpy(G.filename, pathcomp);
 | 
						|
        return error;
 | 
						|
    }
 | 
						|
 | 
						|
/*---------------------------------------------------------------------------
 | 
						|
    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;
 | 
						|
 | 
						|
    created_dir = FALSE;        /* not yet */
 | 
						|
 | 
						|
/* GRR:  for VMS, convert to internal format now or later? or never? */
 | 
						|
    if (checkdir(__G__ pathcomp, INIT) == 10)
 | 
						|
        return 10;              /* initialize path buffer, unless no memory */
 | 
						|
 | 
						|
    *pathcomp = '\0';           /* initialize translation buffer */
 | 
						|
    pp = pathcomp;              /* point to translation buffer */
 | 
						|
    if (G.jflag)                /* junking directories */
 | 
						|
/* GRR:  watch out for VMS version... */
 | 
						|
        cp = (char *)strrchr(G.filename, '/');
 | 
						|
    if (cp == 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 G.filename.
 | 
						|
  ---------------------------------------------------------------------------*/
 | 
						|
 | 
						|
    while ((workch = (uch)*cp++) != 0) {
 | 
						|
 | 
						|
        if (quote) {              /* if character quoted, */
 | 
						|
            *pp++ = (char)workch; /*  include it literally */
 | 
						|
            quote = FALSE;
 | 
						|
        } else
 | 
						|
            switch (workch) {
 | 
						|
            case '/':             /* can assume -j flag not given */
 | 
						|
                *pp = '\0';
 | 
						|
                if ((error = checkdir(__G__ pathcomp, APPEND_DIR)) > 1)
 | 
						|
                    return error;
 | 
						|
                pp = pathcomp;    /* reset conversion buffer for next piece */
 | 
						|
                last_dot = NULL;  /* directory names must not contain dots */
 | 
						|
                lastsemi = NULL;  /* leave directory semi-colons alone */
 | 
						|
                break;
 | 
						|
 | 
						|
            case ':':
 | 
						|
                *pp++ = '_';      /* drive names not stored in zipfile, */
 | 
						|
                break;            /*  so no colons allowed */
 | 
						|
 | 
						|
            case '.':
 | 
						|
                if (pp == pathcomp) {     /* nothing appended yet... */
 | 
						|
                    if (*cp == '/') {     /* don't bother appending a "./" */
 | 
						|
                        ++cp;             /*  component to the path:  skip */
 | 
						|
                                          /*  to next char after the '/' */
 | 
						|
                    } else if (*cp == '.' && cp[1] == '/') {   /* "../" */
 | 
						|
                        *pp++ = '.';      /* add first dot, unchanged... */
 | 
						|
                        *pp++ = '.';      /* add second dot, unchanged... */
 | 
						|
                        ++cp;             /* skip second dot */
 | 
						|
                    }                     /* next char is  the '/' */
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
                last_dot = pp;    /* point at last dot so far... */
 | 
						|
                *pp++ = '_';      /* convert dot to underscore for now */
 | 
						|
                break;
 | 
						|
 | 
						|
            case ';':             /* start of VMS version? */
 | 
						|
                if (lastsemi)
 | 
						|
                    *lastsemi = '_';   /* convert previous one to underscore */
 | 
						|
                lastsemi = pp;
 | 
						|
                *pp++ = ';';      /* keep for now; remove VMS vers. later */
 | 
						|
                break;
 | 
						|
 | 
						|
            case ' ':
 | 
						|
                *pp++ = '_';
 | 
						|
                break;
 | 
						|
 | 
						|
            default:
 | 
						|
                if ( isalpha(workch) || isdigit(workch) ||
 | 
						|
                    workch=='$' || workch=='-' )
 | 
						|
                    *pp++ = (char)workch;
 | 
						|
                else
 | 
						|
                    *pp++ = '_';  /* convert everything else to underscore */
 | 
						|
                break;
 | 
						|
            } /* end switch */
 | 
						|
 | 
						|
    } /* end while loop */
 | 
						|
 | 
						|
    *pp = '\0';                   /* done with pathcomp:  terminate it */
 | 
						|
 | 
						|
    /* if not saving them, remove VMS version numbers (appended "###") */
 | 
						|
    if (lastsemi) {
 | 
						|
        pp = lastsemi + 1;        /* expect all digits after semi-colon */
 | 
						|
        while (isdigit((uch)(*pp)))
 | 
						|
            ++pp;
 | 
						|
        if (*pp)                  /* not version number:  convert ';' to '_' */
 | 
						|
            *lastsemi = '_';
 | 
						|
        else if (!G.V_flag)       /* only digits between ';' and end:  nuke */
 | 
						|
            *lastsemi = '\0';
 | 
						|
        /* else only digits and we're saving version number:  do nothing */
 | 
						|
    }
 | 
						|
 | 
						|
    if (last_dot != NULL)         /* one dot is OK:  put it back in */
 | 
						|
        *last_dot = '.';
 | 
						|
 | 
						|
/*---------------------------------------------------------------------------
 | 
						|
    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__ "", APPEND_NAME);   /* create directory, if not found */
 | 
						|
        checkdir(__G__ G.filename, GETPATH);
 | 
						|
        if (created_dir) {
 | 
						|
            if (QCOND2) {
 | 
						|
                Info(slide, 0, ((char *)slide, "   creating: %s\n",
 | 
						|
                  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,
 | 
						|
             "mapname:  conversion of %s failed\n", G.filename));
 | 
						|
        return 3;
 | 
						|
    }
 | 
						|
 | 
						|
    checkdir(__G__ pathcomp, APPEND_NAME);  /* returns 1 if truncated: care? */
 | 
						|
    checkdir(__G__ G.filename, GETPATH);
 | 
						|
 | 
						|
    return error;
 | 
						|
 | 
						|
} /* end function mapname() */
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int checkdir(__G__ pathcomp, fcn)
 | 
						|
/*
 | 
						|
 * 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
 | 
						|
 */
 | 
						|
    __GDEF
 | 
						|
    char *pathcomp;
 | 
						|
    int fcn;
 | 
						|
{
 | 
						|
    int function=fcn & FN_MASK;
 | 
						|
    static char pathbuf[FILNAMSIZ];
 | 
						|
    static char lastdir[FILNAMSIZ]="\t"; /* directory created last time */
 | 
						|
                                         /* initially - impossible dir. spec. */
 | 
						|
    static char *pathptr=pathbuf;        /* For debugger */
 | 
						|
    static char *devptr, *dirptr, *namptr;
 | 
						|
    static int  devlen, dirlen, namlen;
 | 
						|
    static int  root_dirlen;
 | 
						|
    static char *end;
 | 
						|
    static int  first_comp,root_has_dir;
 | 
						|
    static int  rootlen=0;
 | 
						|
    static char *rootend;
 | 
						|
    static int  mkdir_failed=0;
 | 
						|
    int status;
 | 
						|
 | 
						|
/************
 | 
						|
 *** ROOT ***
 | 
						|
 ************/
 | 
						|
 | 
						|
#if (!defined(SFX) || defined(SFX_EXDIR))
 | 
						|
    if (function==ROOT)
 | 
						|
    {        /*  Assume VMS root spec */
 | 
						|
        char  *p = pathcomp;
 | 
						|
        char  *q;
 | 
						|
 | 
						|
        struct
 | 
						|
        {
 | 
						|
            short  len;
 | 
						|
            short  code;
 | 
						|
            char   *addr;
 | 
						|
        } itl [4] =
 | 
						|
        {
 | 
						|
            {  0,  FSCN$_DEVICE,    NULL  },
 | 
						|
            {  0,  FSCN$_ROOT,      NULL  },
 | 
						|
            {  0,  FSCN$_DIRECTORY, NULL  },
 | 
						|
            {  0,  0,               NULL  }   /* End of itemlist */
 | 
						|
        };
 | 
						|
        int fields = 0;
 | 
						|
        struct dsc$descriptor  pthcmp;
 | 
						|
 | 
						|
        /*
 | 
						|
         *  Initialize everything
 | 
						|
         */
 | 
						|
        end = devptr = dirptr = rootend = pathbuf;
 | 
						|
        devlen = dirlen = rootlen = 0;
 | 
						|
 | 
						|
        pthcmp.dsc$a_pointer = pathcomp;
 | 
						|
        if ( (pthcmp.dsc$w_length = strlen(pathcomp)) > 255 )
 | 
						|
            return 4;
 | 
						|
 | 
						|
        status = sys$filescan(&pthcmp, itl, &fields);
 | 
						|
        if ( !OK(status) )
 | 
						|
            return 3;
 | 
						|
 | 
						|
        if ( fields & FSCN$M_DEVICE )
 | 
						|
        {
 | 
						|
            strncpy(devptr = end, itl[0].addr, itl[0].len);
 | 
						|
            dirptr = (end += (devlen = itl[0].len));
 | 
						|
        }
 | 
						|
 | 
						|
        root_has_dir = 0;
 | 
						|
 | 
						|
        if ( fields & FSCN$M_ROOT )
 | 
						|
        {
 | 
						|
            int   len;
 | 
						|
 | 
						|
            strncpy(dirptr = end, itl[1].addr,
 | 
						|
                len = itl[1].len - 1);        /* Cut out trailing ']' */
 | 
						|
            end += len;
 | 
						|
            root_has_dir = 1;
 | 
						|
        }
 | 
						|
 | 
						|
        if ( fields & FSCN$M_DIRECTORY )
 | 
						|
        {
 | 
						|
            char  *ptr;
 | 
						|
            int   len;
 | 
						|
 | 
						|
            len = itl[2].len-1;
 | 
						|
            ptr = itl[2].addr;
 | 
						|
 | 
						|
            if ( root_has_dir /* i.e. root specified */ )
 | 
						|
            {
 | 
						|
                --len;                            /* Cut out leading dot */
 | 
						|
                ++ptr;                            /* ??? [a.b.c.][.d.e] */
 | 
						|
            }
 | 
						|
 | 
						|
            strncpy(dirptr=end, ptr, len);  /* Replace trailing ']' */
 | 
						|
            *(end+=len) = '.';                    /* ... with dot */
 | 
						|
            ++end;
 | 
						|
            root_has_dir = 1;
 | 
						|
        }
 | 
						|
 | 
						|
        /* When user specified "[a.b.c.]" or "[qq...]", we have too many
 | 
						|
        *  trailing dots. Let's cut them out. Now we surely have at least
 | 
						|
        *  one trailing dot and "end" points just behind it. */
 | 
						|
 | 
						|
        dirlen = end - dirptr;
 | 
						|
        while ( dirlen > 1 && end[-2] == '.' )
 | 
						|
            --dirlen,--end;
 | 
						|
 | 
						|
        first_comp = !root_has_dir;
 | 
						|
        root_dirlen = end - dirptr;
 | 
						|
        *(rootend = end) = '\0';
 | 
						|
        rootlen = rootend - devptr;
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
#endif /* !SFX || SFX_EXDIR */
 | 
						|
 | 
						|
 | 
						|
/************
 | 
						|
 *** INIT ***
 | 
						|
 ************/
 | 
						|
 | 
						|
    if ( function == INIT )
 | 
						|
    {
 | 
						|
        if ( strlen(G.filename) + rootlen + 13 > 255 )
 | 
						|
            return 4;
 | 
						|
 | 
						|
        if ( rootlen == 0 )     /* No root given, reset everything. */
 | 
						|
        {
 | 
						|
            devptr = dirptr = rootend = pathbuf;
 | 
						|
            devlen = dirlen = 0;
 | 
						|
        }
 | 
						|
        end = rootend;
 | 
						|
        first_comp = !root_has_dir;
 | 
						|
        if ( dirlen = root_dirlen )
 | 
						|
            end[-1] = '.';
 | 
						|
        *end = '\0';
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
/******************
 | 
						|
 *** APPEND_DIR ***
 | 
						|
 ******************/
 | 
						|
    if ( function == APPEND_DIR )
 | 
						|
    {
 | 
						|
        int cmplen;
 | 
						|
 | 
						|
        cmplen = strlen(pathcomp);
 | 
						|
 | 
						|
        if ( first_comp )
 | 
						|
        {
 | 
						|
            *end++ = '[';
 | 
						|
            if ( cmplen )
 | 
						|
                *end++ = '.';   /*       "dir/..." --> "[.dir...]"    */
 | 
						|
            /*                     else  "/dir..." --> "[dir...]"     */
 | 
						|
            first_comp = 0;
 | 
						|
        }
 | 
						|
 | 
						|
        if ( cmplen == 1 && *pathcomp == '.' )
 | 
						|
            ; /* "..././..." -- ignore */
 | 
						|
 | 
						|
        else if ( cmplen == 2 && pathcomp[0] == '.' && pathcomp[1] == '.' )
 | 
						|
        {   /* ".../../..." -- convert to "...-..." */
 | 
						|
            *end++ = '-';
 | 
						|
            *end++ = '.';
 | 
						|
        }
 | 
						|
 | 
						|
        else if ( cmplen + (end-pathptr) > 255 )
 | 
						|
            return 4;
 | 
						|
 | 
						|
        else
 | 
						|
        {
 | 
						|
            strcpy(end, pathcomp);
 | 
						|
            *(end+=cmplen) = '.';
 | 
						|
            ++end;
 | 
						|
        }
 | 
						|
        dirlen = end - dirptr;
 | 
						|
        *end = '\0';
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
/*******************
 | 
						|
 *** APPEND_NAME ***
 | 
						|
 *******************/
 | 
						|
    if ( function == APPEND_NAME )
 | 
						|
    {
 | 
						|
        if ( fcn & USE_DEFAULT )
 | 
						|
        {   /* Expand renamed filename using collected path, return
 | 
						|
             *  at pathcomp */
 | 
						|
            struct        FAB fab;
 | 
						|
            struct        NAM nam;
 | 
						|
 | 
						|
            fab = cc$rms_fab;
 | 
						|
            fab.fab$l_fna = G.filename;
 | 
						|
            fab.fab$b_fns = strlen(G.filename);
 | 
						|
            fab.fab$l_dna = pathptr;
 | 
						|
            fab.fab$b_dns = end-pathptr;
 | 
						|
 | 
						|
            fab.fab$l_nam = &nam;
 | 
						|
            nam = cc$rms_nam;
 | 
						|
            nam.nam$l_esa = pathcomp;
 | 
						|
            nam.nam$b_ess = 255;            /* Assume large enaugh */
 | 
						|
 | 
						|
            if (!OK(status = sys$parse(&fab)) && status == RMS$_DNF )
 | 
						|
                                         /* Directory not found: */
 | 
						|
            {                            /* ... try to create it */
 | 
						|
                char    save;
 | 
						|
                char    *dirend;
 | 
						|
                int     mkdir_failed;
 | 
						|
 | 
						|
                dirend = (char*)nam.nam$l_dir + nam.nam$b_dir;
 | 
						|
                save = *dirend;
 | 
						|
                *dirend = '\0';
 | 
						|
                if ( (mkdir_failed = mkdir(nam.nam$l_dev, 0)) &&
 | 
						|
                     errno == EEXIST )
 | 
						|
                    mkdir_failed = 0;
 | 
						|
                *dirend = save;
 | 
						|
                if ( mkdir_failed )
 | 
						|
                    return 3;
 | 
						|
                created_dir = TRUE;
 | 
						|
            }                                /* if (sys$parse... */
 | 
						|
            pathcomp[nam.nam$b_esl] = '\0';
 | 
						|
            return 0;
 | 
						|
        }                                /* if (USE_DEFAULT) */
 | 
						|
        else
 | 
						|
        {
 | 
						|
            *end = '\0';
 | 
						|
            if ( dirlen )
 | 
						|
            {
 | 
						|
                dirptr[dirlen-1] = ']'; /* Close directory */
 | 
						|
 | 
						|
                /*
 | 
						|
                 *  Try to create the target directory.
 | 
						|
                 *  Don't waste time creating directory that was created
 | 
						|
                 *  last time.
 | 
						|
                 */
 | 
						|
                if ( STRICMP(lastdir,pathbuf) )
 | 
						|
                {
 | 
						|
                    mkdir_failed = 0;
 | 
						|
                    if ( mkdir(pathbuf,0) )
 | 
						|
                    {
 | 
						|
                        if ( errno != EEXIST )
 | 
						|
                            mkdir_failed = 1;   /* Mine for GETPATH */
 | 
						|
                    }
 | 
						|
                    else
 | 
						|
                        created_dir = TRUE;
 | 
						|
                    strcpy(lastdir,pathbuf);
 | 
						|
                }
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {   /*
 | 
						|
                 * Target directory unspecified.
 | 
						|
                 * Try to create "sys$disk:[]"
 | 
						|
                 */
 | 
						|
                if ( strcmp(lastdir,"sys$disk:[]") )
 | 
						|
                {
 | 
						|
                    strcpy(lastdir,"sys$disk:[]");
 | 
						|
                    mkdir_failed = 0;
 | 
						|
                    if ( mkdir(lastdir,0) && errno != EEXIST )
 | 
						|
                        mkdir_failed = 1;   /* Mine for GETPATH */
 | 
						|
                }
 | 
						|
            }
 | 
						|
            if ( strlen(pathcomp) + (end-pathbuf) > 255 )
 | 
						|
                return 1;
 | 
						|
            strcpy(end, pathcomp);
 | 
						|
            end += strlen(pathcomp);
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
/***************
 | 
						|
 *** GETPATH ***
 | 
						|
 ***************/
 | 
						|
    if ( function == GETPATH )
 | 
						|
    {
 | 
						|
        if ( mkdir_failed )
 | 
						|
            return 3;
 | 
						|
        *end = '\0';                    /* To be safe */
 | 
						|
        strcpy( pathcomp, pathbuf );
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
/***********
 | 
						|
 *** END ***
 | 
						|
 ***********/
 | 
						|
    if ( function == END )
 | 
						|
    {
 | 
						|
        Trace((stderr, "checkdir(): nothing to free...\n"));
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    return 99;  /* should never reach */
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int check_for_newer(__G__ filenam)   /* return 1 if existing file newer or */
 | 
						|
    __GDEF                           /*  equal; 0 if older; -1 if doesn't */
 | 
						|
    char *filenam;                   /*  exist yet */
 | 
						|
{
 | 
						|
#ifdef USE_EF_UT_TIME
 | 
						|
    iztimes z_utime;
 | 
						|
#endif
 | 
						|
    unsigned short timbuf[7];
 | 
						|
    unsigned dy, mo, yr, hh, mm, ss, dy2, mo2, yr2, hh2, mm2, ss2;
 | 
						|
    struct FAB fab;
 | 
						|
    struct XABDAT xdat;
 | 
						|
 | 
						|
 | 
						|
    if (stat(filenam, &G.statbuf))
 | 
						|
        return DOES_NOT_EXIST;
 | 
						|
 | 
						|
    fab  = cc$rms_fab;
 | 
						|
    xdat = cc$rms_xabdat;
 | 
						|
 | 
						|
    fab.fab$l_xab = (char *) &xdat;
 | 
						|
    fab.fab$l_fna = filenam;
 | 
						|
    fab.fab$b_fns = strlen(filenam);
 | 
						|
    fab.fab$l_fop = FAB$M_GET | FAB$M_UFO;
 | 
						|
 | 
						|
    if ((sys$open(&fab) & 1) == 0)       /* open failure:  report exists and */
 | 
						|
        return EXISTS_AND_OLDER;         /*  older so new copy will be made  */
 | 
						|
    sys$numtim(&timbuf,&xdat.xab$q_cdt);
 | 
						|
    fab.fab$l_xab = NULL;
 | 
						|
 | 
						|
    sys$dassgn(fab.fab$l_stv);
 | 
						|
    sys$close(&fab);   /* be sure file is closed and RMS knows about it */
 | 
						|
 | 
						|
#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 = localtime(&(z_utime.mtime));
 | 
						|
 | 
						|
        yr2 = (unsigned)(t->tm_year) + 1900;
 | 
						|
        mo2 = (unsigned)(t->tm_mon) + 1;
 | 
						|
        dy2 = (unsigned)(t->tm_mday);
 | 
						|
        hh2 = (unsigned)(t->tm_hour);
 | 
						|
        mm2 = (unsigned)(t->tm_min);
 | 
						|
        ss2 = (unsigned)(t->tm_sec);
 | 
						|
 | 
						|
        /* round to nearest sec--may become 60,
 | 
						|
           but doesn't matter for compare */
 | 
						|
        ss = (unsigned)((float)timbuf[5] + (float)timbuf[6]*.01 + 0.5);
 | 
						|
        TTrace((stderr, "check_for_newer:  using Unix extra field mtime\n"));
 | 
						|
    } else {
 | 
						|
        yr2 = ((G.lrec.last_mod_file_date >> 9) & 0x7f) + 1980;
 | 
						|
        mo2 = ((G.lrec.last_mod_file_date >> 5) & 0x0f);
 | 
						|
        dy2 = (G.lrec.last_mod_file_date & 0x1f);
 | 
						|
        hh2 = (G.lrec.last_mod_file_time >> 11) & 0x1f;
 | 
						|
        mm2 = (G.lrec.last_mod_file_time >> 5) & 0x3f;
 | 
						|
        ss2 = (G.lrec.last_mod_file_time & 0x1f) * 2;
 | 
						|
 | 
						|
        /* round to nearest 2 secs--may become 60,
 | 
						|
           but doesn't matter for compare */
 | 
						|
        ss = (unsigned)((float)timbuf[5] + (float)timbuf[6]*.01 + 1.) & (~1);
 | 
						|
    }
 | 
						|
#else /* !USE_EF_UT_TIME */
 | 
						|
    yr2 = ((G.lrec.last_mod_file_date >> 9) & 0x7f) + 1980;
 | 
						|
    mo2 = ((G.lrec.last_mod_file_date >> 5) & 0x0f);
 | 
						|
    dy2 = (G.lrec.last_mod_file_date & 0x1f);
 | 
						|
    hh2 = (G.lrec.last_mod_file_time >> 11) & 0x1f;
 | 
						|
    mm2 = (G.lrec.last_mod_file_time >> 5) & 0x3f;
 | 
						|
    ss2 = (G.lrec.last_mod_file_time & 0x1f) * 2;
 | 
						|
 | 
						|
    /* round to nearest 2 secs--may become 60, but doesn't matter for compare */
 | 
						|
    ss = (unsigned)((float)timbuf[5] + (float)timbuf[6]*.01 + 1.) & (~1);
 | 
						|
#endif /* ?USE_EF_UT_TIME */
 | 
						|
    yr = timbuf[0];
 | 
						|
    mo = timbuf[1];
 | 
						|
    dy = timbuf[2];
 | 
						|
    hh = timbuf[3];
 | 
						|
    mm = timbuf[4];
 | 
						|
 | 
						|
    if (yr > yr2)
 | 
						|
        return EXISTS_AND_NEWER;
 | 
						|
    else if (yr < yr2)
 | 
						|
        return EXISTS_AND_OLDER;
 | 
						|
 | 
						|
    if (mo > mo2)
 | 
						|
        return EXISTS_AND_NEWER;
 | 
						|
    else if (mo < mo2)
 | 
						|
        return EXISTS_AND_OLDER;
 | 
						|
 | 
						|
    if (dy > dy2)
 | 
						|
        return EXISTS_AND_NEWER;
 | 
						|
    else if (dy < dy2)
 | 
						|
        return EXISTS_AND_OLDER;
 | 
						|
 | 
						|
    if (hh > hh2)
 | 
						|
        return EXISTS_AND_NEWER;
 | 
						|
    else if (hh < hh2)
 | 
						|
        return EXISTS_AND_OLDER;
 | 
						|
 | 
						|
    if (mm > mm2)
 | 
						|
        return EXISTS_AND_NEWER;
 | 
						|
    else if (mm < mm2)
 | 
						|
        return EXISTS_AND_OLDER;
 | 
						|
 | 
						|
    if (ss >= ss2)
 | 
						|
        return EXISTS_AND_NEWER;
 | 
						|
 | 
						|
    return EXISTS_AND_OLDER;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#ifdef RETURN_CODES
 | 
						|
void return_VMS(__G__ err)
 | 
						|
    __GDEF
 | 
						|
#else
 | 
						|
void return_VMS(err)
 | 
						|
#endif
 | 
						|
    int err;
 | 
						|
{
 | 
						|
    int severity;
 | 
						|
 | 
						|
#ifdef RETURN_CODES
 | 
						|
/*---------------------------------------------------------------------------
 | 
						|
    Do our own, explicit processing of error codes and print message, since
 | 
						|
    VMS misinterprets return codes as rather obnoxious system errors ("access
 | 
						|
    violation," for example).
 | 
						|
  ---------------------------------------------------------------------------*/
 | 
						|
 | 
						|
    switch (err) {
 | 
						|
        case PK_COOL:
 | 
						|
            break;   /* life is fine... */
 | 
						|
        case PK_WARN:
 | 
						|
            Info(slide, 1, ((char *)slide, "\n\
 | 
						|
[return-code %d:  warning error \
 | 
						|
(e.g., failed CRC or unknown compression method)]\n", err));
 | 
						|
            break;
 | 
						|
        case PK_ERR:
 | 
						|
        case PK_BADERR:
 | 
						|
            Info(slide, 1, ((char *)slide, "\n\
 | 
						|
[return-code %d:  error in zipfile \
 | 
						|
(e.g., can't find local file header sig)]\n", err));
 | 
						|
            break;
 | 
						|
        case PK_MEM:
 | 
						|
        case PK_MEM2:
 | 
						|
        case PK_MEM3:
 | 
						|
        case PK_MEM4:
 | 
						|
        case PK_MEM5:
 | 
						|
            Info(slide, 1, ((char *)slide,
 | 
						|
              "\n[return-code %d:  insufficient memory]\n", err));
 | 
						|
            break;
 | 
						|
        case PK_NOZIP:
 | 
						|
            Info(slide, 1, ((char *)slide,
 | 
						|
              "\n[return-code %d:  zipfile not found]\n", err));
 | 
						|
            break;
 | 
						|
        case PK_PARAM:   /* exit(PK_PARAM); gives "access violation" */
 | 
						|
            Info(slide, 1, ((char *)slide, "\n\
 | 
						|
[return-code %d:  bad or illegal parameters specified on command line]\n",
 | 
						|
              err));
 | 
						|
            break;
 | 
						|
        case PK_FIND:
 | 
						|
            Info(slide, 1, ((char *)slide,
 | 
						|
              "\n[return-code %d:  no files found to extract/view/etc.]\n",
 | 
						|
              err));
 | 
						|
            break;
 | 
						|
        case PK_DISK:
 | 
						|
            Info(slide, 1, ((char *)slide,
 | 
						|
              "\n[return-code %d:  disk full or other I/O error]\n", err));
 | 
						|
            break;
 | 
						|
        case PK_EOF:
 | 
						|
            Info(slide, 1, ((char *)slide, "\n\
 | 
						|
[return-code %d:  unexpected EOF in zipfile (i.e., truncated)]\n", err));
 | 
						|
            break;
 | 
						|
        case IZ_CTRLC:
 | 
						|
            Info(slide, 1, ((char *)slide,
 | 
						|
              "\n[return-code %d:  you hit ctrl-C to terminate]\n", err));
 | 
						|
            break;
 | 
						|
        case IZ_UNSUP:
 | 
						|
            Info(slide, 1, ((char *)slide, "\n\
 | 
						|
[return-code %d:  unsupported compression or encryption for all files]\n",
 | 
						|
              err));
 | 
						|
            break;
 | 
						|
        case IZ_BADPWD:
 | 
						|
            Info(slide, 1, ((char *)slide,
 | 
						|
              "\n[return-code %d:  bad decryption password for all files]\n",
 | 
						|
              err));
 | 
						|
            break;
 | 
						|
        default:
 | 
						|
            Info(slide, 1, ((char *)slide,
 | 
						|
              "\n[return-code %d:  unknown return-code (screw-up)]\n", err));
 | 
						|
            break;
 | 
						|
    }
 | 
						|
#endif /* RETURN_CODES */
 | 
						|
 | 
						|
/*---------------------------------------------------------------------------
 | 
						|
    Return an intelligent status/severity level:
 | 
						|
 | 
						|
        $STATUS          $SEVERITY = $STATUS & 7
 | 
						|
        31 .. 16 15 .. 3   2 1 0
 | 
						|
                           -----
 | 
						|
        VMS                0 0 0  0    Warning
 | 
						|
        FACILITY           0 0 1  1    Success
 | 
						|
        Number             0 1 0  2    Error
 | 
						|
                 MESSAGE   0 1 1  3    Information
 | 
						|
                 Number    1 0 0  4    Severe (fatal) error
 | 
						|
 | 
						|
    0x7FFF0000 was chosen (by experimentation) to be outside the range of
 | 
						|
    VMS FACILITYs that have dedicated message numbers.  Hopefully this will
 | 
						|
    always result in silent exits--it does on VMS 5.4.  Note that the C li-
 | 
						|
    brary translates exit arguments of zero to a $STATUS value of 1 (i.e.,
 | 
						|
    exit is both silent and has a $SEVERITY of "success").
 | 
						|
  ---------------------------------------------------------------------------*/
 | 
						|
 | 
						|
    severity = (err == 2 || (err >= 9 && err <= 11) || (err >= 80 && err <= 82))
 | 
						|
               ? 2 : 4;
 | 
						|
    exit(                                       /* $SEVERITY:        */
 | 
						|
         (err == PK_COOL) ? 1 :                 /*   success         */
 | 
						|
         (err == PK_WARN) ? 0x7FFF0000 :        /*   warning         */
 | 
						|
         (0x7FFF0000 | (err << 4) | severity)   /*   error or fatal  */
 | 
						|
        );
 | 
						|
 | 
						|
} /* end function return_VMS() */
 | 
						|
 | 
						|
 | 
						|
#ifdef MORE
 | 
						|
int screenlines(void)
 | 
						|
{
 | 
						|
    /*
 | 
						|
     * For VMS v5.x:
 | 
						|
     *   IO$_SENSEMODE/SETMODE info:  Programming, Vol. 7A, System Programming,
 | 
						|
     *     I/O User's: Part I, sec. 8.4.1.1, 8.4.3, 8.4.5, 8.6
 | 
						|
     *   sys$assign(), sys$qio() info:  Programming, Vol. 4B, System Services,
 | 
						|
     *     System Services Reference Manual, pp. sys-23, sys-379
 | 
						|
     *   fixed-length descriptor info:  Programming, Vol. 3, System Services,
 | 
						|
     *     Intro to System Routines, sec. 2.9.2
 | 
						|
     * GRR, 15 Aug 91 / SPC, 07 Aug 1995
 | 
						|
     */
 | 
						|
 | 
						|
#ifndef OUTDEVICE_NAME
 | 
						|
#define OUTDEVICE_NAME  "SYS$OUTPUT"
 | 
						|
#endif
 | 
						|
 | 
						|
    static int scrnlines = -1;
 | 
						|
 | 
						|
    static ZCONST struct dsc$descriptor_s OutDevDesc =
 | 
						|
        {(sizeof(OUTDEVICE_NAME) - 1), DSC$K_DTYPE_T, DSC$K_CLASS_S,
 | 
						|
         OUTDEVICE_NAME};
 | 
						|
     /* {dsc$w_length, dsc$b_dtype, dsc$b_class, dsc$a_pointer}; */
 | 
						|
 | 
						|
    short  OutDevChan, iosb[4];
 | 
						|
    long   status;
 | 
						|
    struct tt_characts
 | 
						|
    {
 | 
						|
        uch class, type;
 | 
						|
        ush pagewidth;
 | 
						|
        uch ttcharsbits[3];
 | 
						|
        uch pagelength;
 | 
						|
    }      ttmode;              /* total length = 8 bytes */
 | 
						|
 | 
						|
 | 
						|
    if (scrnlines < 0)
 | 
						|
    {
 | 
						|
        /* assign a channel to standard output */
 | 
						|
        status = sys$assign(&OutDevDesc, &OutDevChan, 0, 0);
 | 
						|
        if (status & 1)
 | 
						|
        {
 | 
						|
            /* use sys$qiow and the IO$_SENSEMODE function to determine
 | 
						|
             * the current tty status.
 | 
						|
             */
 | 
						|
            status = sys$qiow(0, OutDevChan, IO$_SENSEMODE, &iosb, 0, 0,
 | 
						|
                              &ttmode, sizeof(ttmode), 0, 0, 0, 0);
 | 
						|
            /* deassign the output channel by way of clean-up */
 | 
						|
            (void) sys$dassgn(OutDevChan);
 | 
						|
        }
 | 
						|
 | 
						|
        scrnlines = ( ( (status & 1) &&
 | 
						|
                        ((status = iosb[0]) & 1) &&
 | 
						|
                        (ttmode.pagelength >= 5)
 | 
						|
                      )
 | 
						|
                     ? (int) (ttmode.pagelength)        /* TT device value */
 | 
						|
                     : (24) );                          /* VT 100 default  */
 | 
						|
    }
 | 
						|
 | 
						|
    return (scrnlines);
 | 
						|
}
 | 
						|
#endif /* MORE */
 | 
						|
 | 
						|
 | 
						|
#ifndef SFX
 | 
						|
 | 
						|
/************************/
 | 
						|
/*  Function version()  */
 | 
						|
/************************/
 | 
						|
 | 
						|
void version(__G)
 | 
						|
    __GDEF
 | 
						|
{
 | 
						|
    int len;
 | 
						|
#ifdef VMS_VERSION
 | 
						|
    char buf[40];
 | 
						|
#endif
 | 
						|
#ifdef __DECC_VER
 | 
						|
    char buf2[40];
 | 
						|
    int  vtyp;
 | 
						|
#endif
 | 
						|
 | 
						|
/*  DEC C in ANSI mode does not like "#ifdef MACRO" inside another
 | 
						|
    macro when MACRO is equated to a value (by "#define MACRO 1").   */
 | 
						|
 | 
						|
    len = sprintf((char *)slide, LoadFarString(CompiledWith),
 | 
						|
 | 
						|
#ifdef __GNUC__
 | 
						|
      "gcc ", __VERSION__,
 | 
						|
#else
 | 
						|
#  if defined(DECC) || defined(__DECC) || defined (__DECC__)
 | 
						|
      "DEC C",
 | 
						|
#    ifdef __DECC_VER
 | 
						|
      (sprintf(buf2, " %c%d.%d-%03d",
 | 
						|
               ((vtyp = (__DECC_VER / 10000) % 10) == 6 ? 'T' :
 | 
						|
                (vtyp == 8 ? 'S' : 'V')),
 | 
						|
               __DECC_VER / 10000000,
 | 
						|
               (__DECC_VER % 10000000) / 100000, __DECC_VER % 1000), buf2),
 | 
						|
#    else
 | 
						|
      "",
 | 
						|
#    endif
 | 
						|
#  else
 | 
						|
#  ifdef VAXC
 | 
						|
      "VAX C", "",
 | 
						|
#  else
 | 
						|
      "unknown compiler", "",
 | 
						|
#  endif
 | 
						|
#  endif
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef VMS_VERSION
 | 
						|
#  if defined(__alpha)
 | 
						|
      "OpenVMS",   /* version has trailing spaces ("V6.1   "), so truncate: */
 | 
						|
      (sprintf(buf, " (%.4s for Alpha)", VMS_VERSION), buf),
 | 
						|
#  else /* VAX */
 | 
						|
      (VMS_VERSION[1] >= '6')? "OpenVMS" : "VMS",
 | 
						|
      (sprintf(buf, " (%.4s for VAX)", VMS_VERSION), buf),
 | 
						|
#  endif
 | 
						|
#else
 | 
						|
      "VMS",
 | 
						|
      "",
 | 
						|
#endif /* ?VMS_VERSION */
 | 
						|
 | 
						|
#ifdef __DATE__
 | 
						|
      " on ", __DATE__
 | 
						|
#else
 | 
						|
      "", ""
 | 
						|
#endif
 | 
						|
    );
 | 
						|
 | 
						|
    (*G.message)((zvoid *)&G, slide, (ulg)len, 0);
 | 
						|
 | 
						|
} /* end function version() */
 | 
						|
 | 
						|
#endif /* !SFX */
 | 
						|
#endif /* VMS */
 |