From: dyson@iowasp.physics.uiowa.edu (Rick Dyson)
Subject: XV(v2.11) for VMS: new GIFMAPF.C => DECNET access
Organization: Department of Physics and Astronomy, University of Iowa
Date: Wed, 15 Apr 1992 20:15:02 GMT

/*
 * I've modified gifmapf.c (included below) to fallback to reading the file
 * via RMS if the search operation does not return a device, which is required
 * for mapping the file via $CRMPSC.
 * 
 * With this change,
 *              XV node::disk:[dir]*.gif
 * will now work.
 *
 * >>Dave
 *
 * Comments follow that were made by several people concerning DECNET
 * access of a GIF with XV.  There is a minor mod of VMS.C that is
 * mentioned a couple paragraphs down that you might consider making.
 * Use your own discretion... (or indiscretion....;)
 * 
 * BTW, mapping the file to memory is faster than reading the file record by
 * record, but it doesn't seem any faster than reading the whole file at once
 * with a single fread() call.  The mapping method does save you the trouble
 * of fighting with VAXCRTL/RMS to get it to handle files with certain record
 * attributes, however.
 * 
 * >I've defined DEVICE_LIST_ROOT to allow selecting different disks, and this
 * >works well, where each directory name in this directory is the name of
 * >a concealed logical name pointing to another device.
 * >
 * >However, this won't work when the logical name includes a node name.
 * 
 * To put remote node disk/directories into DEVICE_LIST_ROOT, you make for
 * that directory name a logical of the form "node::disk:", where disk may
 * be a device name or concealed logical defined on the remote node.  Note
 * that the directory name logical does not have the concealed attribute in
 * this case.
 * 
 * This should be all you need to do, but it turns out that stat() calls
 * won't recognize directories over DECnet links, so you can't get past the
 * root level.  You need to comment out the following line in VMS.C to make
 * it work:
 * 
 *                       else return (stat ( f, st ));
 * 
 * 
 * This change makes XV slightly less robust, but it is a small price to pay
 * for the increased functionality.  Once you've gone to the new directory,
 * the "/" entry in the directory list is replaced by "/node", but you can
 * still navigate back to device_list_root.
 * 
 * 
 * David L. Jones               |      Phone:    (614) 292-6929
 * Ohio State Unviversity       |      Internet:
 * 1971 Neil Ave. Rm. 406       |               jonesd@kcgl1.eng.ohio-state.edu
 * Columbus, OH 43210           |               jones-d@eng.ohio-state.edu
 *
 */

/*
 *
 * Define substitute routines for the fopen/fclose/fread/fgetc calls done by
 * the gif decoder.  Map the gif file to memory and access via page faults.
 */
#include stdio
#include atrdef
#include fab
#include fibdef
#include nam
#include iodef
#include secdef
typedef struct {
    unsigned char *pos;		/* points to next char to read */
    unsigned char *start;
    unsigned char *end;
    int chan, size;
} map_block;

static int map_block_in_use = 0;
static int max_mapped = 0;	/* largest address region used */
static unsigned char *max_region = NULL;
static map_block giffile;
map_block *gif_fopen_fallback();
/*
 * Open file for access.  A returned size of -1 indicates error.
 */
map_block *gif_fopen ( Filestring )
    char *Filestring;
{
    unsigned char *address, *inadr[2], *retadr[2];
    int size, status, channel, func_code;
    int sys$assign(), sys$qiow(), sys$crmpsc(), sys$expreg();
    short int iosb[4];
    struct { long length; char *adr; } desc, fib_desc;
    struct {
	unsigned char rtype, rattrib;
	unsigned short int  rsize, hiblk[2], efblk[2], ffbyte;
	unsigned char bktsize, vfcsize;
	unsigned short int maxrec, defext, gbc, fill[4], versions;
    } fat;			/* File attributes block (RMS) */
   struct FAB fab;		/* File access block (RMS) */
   struct NAM nam;		/* Name block (RMS) */
   struct fibdef fib;		/* File information block (XQP) */
   struct atrdef atr[2];	/* Read attributes descriptor list */
   char esa[256], rsa[256];	/* aux storage for nam block */

   /*
    * Close currently open file and init block to error status (size = -1).
    */
   if ( map_block_in_use ) (void) gif_fclose();
   giffile.start = giffile.end = giffile.pos = "";
   giffile.size = -1;

      /* Use RMS services to lookup fspec, initialize FAB and NAM blocks */

      fab = cc$rms_fab;
      fab.fab$l_fna = Filestring; fab.fab$b_fns = strlen ( Filestring );
      fab.fab$l_dna = ".GIF"; fab.fab$b_dns = strlen ( fab.fab$l_dna );
      fab.fab$l_fop = FAB$M_NAM;	/* file options */
      fab.fab$l_nam = &nam;
      nam = cc$rms_nam;
      nam.nam$b_ess = 255;
      nam.nam$l_esa = &esa;
      nam.nam$b_rss = 255;
      nam.nam$l_rsa = &rsa;

      /* use $parse and $search for find file, device and FID will end up in
         nam  block */

      status = sys$parse ( &fab );  if ((status&3) != 1) return &giffile;
      status = sys$search ( &fab ); if ((status&3) != 1) return &giffile;

      /* Define descriptor to assign and load FID in FIB */

      desc.length = nam.nam$t_dvi[0];		/* length */
      desc.adr = &nam.nam$t_dvi[1];
      func_code = IO$_ACCESS + IO$M_ACCESS; /* actually open the file */
      fib.fib$r_fid_overlay.fib$w_fid[0] = nam.nam$w_fid[0];
      fib.fib$r_fid_overlay.fib$w_fid[1] = nam.nam$w_fid[1];
      fib.fib$r_fid_overlay.fib$w_fid[2] = nam.nam$w_fid[2];

   /* If no device name, try it with real open (DECnet operation) */

   if ( desc.length == 0 ) return gif_fopen_fallback ( Filestring );

   /* build atrribute descriptor list for returning record attributes */

   atr[0].atr$w_size = sizeof(fat);
   atr[0].atr$w_type = ATR$C_RECATTR;
   atr[0].atr$l_addr = &fat;
   atr[1].atr$w_size = 0; atr[1].atr$w_type = 0;

   /* assign channel to disk specified in NAM block. */

   channel = 0;
   status = sys$assign ( &desc, &channel, 0, 0 );
   if ((status&3) != 1) return &giffile;

    /* build FIB and access (open file) */
   fib_desc.length = 10; fib_desc.adr = (char *) &fib;
    fib.fib$r_acctl_overlay.fib$l_acctl = 0;
    status = sys$qiow
	( 0, channel, func_code, &iosb, 0, 0, &fib_desc, 0, 0, 0, &atr, 0 );
    if ( (status&1) == 1 ) status = iosb[0];
    if ( (status&1) != 1 ) return &giffile;

    /* Determine size of file and create section */
    size = fat.efblk[0];
    size = (size<<16) | fat.efblk[1];	/* invert word order */
    size = (size-1)*512 + fat.ffbyte;

    /*
     * Make a large region of P0 space to hold contents of file plus
     * 500 blocks spare.
     */
    if ( max_mapped <= size ) {
	int pages;
	pages = ((size+511)/512) + 500;
        status = sys$expreg ( pages, &retadr, 0, 0 );
        if ( (status&1) != 1 ) return &giffile;
        max_region = retadr[0];
        max_mapped = (pages*512) - 1;
    }

    /* Map file into address space. */
    inadr[0] = max_region;
    inadr[1] = &max_region[size-1];
    status = sys$crmpsc ( &inadr, &retadr, 0, 0, 0, 0, 0,
		channel, (size+511)/512, 0, 0, 64 );
    if ( (status&1) != 1 ) return &giffile;
    address = retadr[0];
    map_block_in_use = 1;

    /*
     * Allocate structure to store file state and initialize it.
     */
    giffile.start = address;
    giffile.end = &address[size];
    giffile.pos = address;
    giffile.chan = channel;
    giffile.size = size;
    return &giffile;
}

int gif_fclose ( )
{
    void sys$dassgn();
    if ( map_block_in_use && (giffile.size > 0) ) sys$purgws ( &giffile.start );
    map_block_in_use = 0;
    sys$dassgn ( giffile.chan );
    return 0;
}

int gif_fgetc ( )
{
    int result;
    if ( giffile.pos >= giffile.end ) return -1;
    result = *giffile.pos++;
    return result;
}

int gif_fread ( buffer, unit, count )
    unsigned char *buffer;
    unsigned int unit, count;	/* max count is 65535 */
{
    unsigned char *next_pos;
    /* determin number of charaters to move */
    count *= unit;
    if ( giffile.pos >= giffile.end ) return 0;
    next_pos = &giffile.pos[count];
    while ( next_pos >= giffile.end ) next_pos = &giffile.pos[--count];

    LIB$MOVC3 ( &count, giffile.pos, buffer );
    giffile.pos = next_pos;
    return count;
}

unsigned char *gif_freadm ( unit, count )
    unsigned int unit, count;	/* max count is 65535 */
{
    unsigned char *cur_pos, *next_pos;
    /* determin number of charaters to move */
    count *= unit;
    if ( giffile.pos >= giffile.end ) return NULL;
    cur_pos = giffile.pos;
    next_pos = &cur_pos[count];
    while ( next_pos >= giffile.end ) --next_pos;
    giffile.pos = next_pos;
    return cur_pos;
}

int gif_fget_counted ( map, desc )
    map_block *map;
    struct { int len; char *addr; } *desc;
{
    int length;
    if ( map->pos < map->end ) {
	/* Get length of record and truncate to EOF if needed */
	for ( length = *map->pos++; &map->pos[length] > map->end; --length);

	/* fill out descriptor and update position pointer */
	desc->len = length;
	desc->addr = map->pos;
	map->pos = &map->pos[length];
	return 1;
    }
    return 2160;
}
/*
 * Fallback to reading file into memory with C RTL functions.
 */
map_block *gif_fopen_fallback ( Filestring )
    char *Filestring;
{
    unsigned char *address;
    int size, status, channel, func_code;
    int sys$assign();
    struct { long length; char *adr; } desc;
    FILE *fp;

    /* printf("Loading network file..."); */

    fp = fopen ( Filestring, "rb" );
    if ( fp == (FILE *) NULL )
	{ /* printf(" could not open.\n"); */ return &giffile; }

    /* find the size of the file by positioning to end. */
    fseek(fp, 0L, 2);
    size = ftell(fp);
    /* printf(" size is %d bytes.\n", size ); */
    fseek(fp, 0L, 0);

    /* determine if we must allocat new block or can reuse existing one */
    if ( max_mapped <= size ) {
        /*
         * Make a large region of P0 space to hold contents of file plus
         * 500 blocks spare.
         */
	int pages, retadr[2], sys$expreg();
	pages = ((size+511)/512) + 500;
        status = sys$expreg ( pages, &retadr, 0, 0 );
        if ( (status&1) != 1 ) return &giffile;
        max_region = retadr[0];
        max_mapped = (pages*512) - 1;
    }
    address = max_region;

    /* read data into memory and close file */
    status = fread(address, size, 1, fp );
    fclose ( fp );
    if ( status != 1 ) return &giffile;		/* error in read */

    map_block_in_use = 1;

    desc.length = 3; desc.adr = "NL:"; channel = 0;
    status = sys$assign ( &desc, &channel, 0, 0 );

    /*
     * Allocate structure to store file state and initialize it.
     */
    giffile.start = address;
    giffile.end = &address[size];
    giffile.pos = address;
    giffile.chan = channel;
    giffile.size = size;
    return &giffile;
}
-- 
Richard L. Dyson               INTERNET:  Dyson@IowaSP.Physics.UIowa.EDU
Graduate Research Assistant    NSI/DECnet:  IOWASP::DYSON or 7231::DYSON
Department of Physics & Astronomy   H: (319) 338--6117
The University of Iowa              O: (319) 335--1879
Iowa City, IA 52242-1479


Xref: sparky vmsnet.misc:433 comp.os.vms:8196