[0001]
[0002]
[0003]
[0004]
[0005]
[0006]
[0007]
[0008]
[0009]
[0010]
[0011]
[0012]
[0013]
[0014]
[0015]
[0016]
[0017]
[0018]
[0019]
[0020]
[0021]
[0022]
[0023]
[0024]
[0025]
[0026]
[0027]
[0028]
[0029]
[0030]
[0031]
[0032]
[0033]
[0034]
[0035]
[0036]
[0037]
[0038]
[0039]
[0040]
[0041]
[0042]
[0043]
[0044]
[0045]
[0046]
[0047]
[0048]
[0049]
[0050]
[0051]
[0052]
[0053]
[0054]
[0055]
[0056]
[0057]
[0058]
[0059]
[0060]
[0061]
[0062]
[0063]
[0064]
[0065]
[0066]
[0067]
[0068]
[0069]
[0070]
[0071]
[0072]
[0073]
[0074]
[0075]
[0076]
[0077]
[0078]
[0079]
[0080]
[0081]
[0082]
[0083]
[0084]
[0085]
[0086]
[0087]
[0088]
[0089]
[0090]
[0091]
[0092]
[0093]
[0094]
[0095]
[0096]
[0097]
[0098]
[0099]
[0100]
[0101]
[0102]
[0103]
[0104]
[0105]
[0106]
[0107]
[0108]
[0109]
[0110]
[0111]
[0112]
[0113]
[0114]
[0115]
[0116]
[0117]
[0118]
[0119]
[0120]
[0121]
[0122]
[0123]
[0124]
[0125]
[0126]
[0127]
[0128]
[0129]
[0130]
[0131]
[0132]
[0133]
[0134]
[0135]
[0136]
[0137]
[0138]
[0139]
[0140]
[0141]
[0142]
[0143]
[0144]
[0145]
[0146]
[0147]
[0148]
[0149]
[0150]
[0151]
[0152]
[0153]
[0154]
[0155]
[0156]
[0157]
[0158]
[0159]
[0160]
[0161]
[0162]
[0163]
[0164]
[0165]
[0166]
[0167]
[0168]
[0169]
[0170]
[0171]
[0172]
[0173]
[0174]
[0175]
[0176]
[0177]
[0178]
[0179]
[0180]
[0181]
[0182]
[0183]
[0184]
[0185]
[0186]
[0187]
[0188]
[0189]
[0190]
[0191]
[0192]
[0193]
[0194]
[0195]
[0196]
[0197]
[0198]
[0199]
[0200]
[0201]
[0202]
[0203]
[0204]
[0205]
[0206]
[0207]
[0208]
[0209]
[0210]
[0211]
[0212]
[0213]
[0214]
[0215]
[0216]
[0217]
[0218]
[0219]
[0220]
[0221]
[0222]
[0223]
[0224]
[0225]
[0226]
[0227]
[0228]
[0229]
[0230]
[0231]
[0232]
[0233]
[0234]
[0235]
[0236]
[0237]
[0238]
[0239]
[0240]
[0241]
[0242]
[0243]
[0244]
[0245]
[0246]
[0247]
[0248]
[0249]
[0250]
[0251]
[0252]
[0253]
[0254]
[0255]
[0256]
[0257]
[0258]
[0259]
[0260]
[0261]
[0262]
[0263]
[0264]
[0265]
[0266]
[0267]
[0268]
[0269]
[0270]
[0271]
/*
 * Routines for reading VMS library modules using C fgets semantics.
 * The lbr_read_directory routine will return index 1 module names over
 * successive calls.
 *
 *  int lbr_open ( char *name, char *defname, lbr_index *new );
 *  int lbr_close ( lbr_index lptr );
 *  int lbr_set_module ( lbr_index lptr, char *module );
 *  int lbr_fgets ( char *str, int maxchar, lbr_index lptr );
 *  int lbr_read_directory ( char *name, int maxchar, lbr_index lptr );
 *
 *  Author: David Jones
 *  Date:    7-MAY-1994
 *  Revised: 10-MAY-1994	Ported to AXP, cleanup up bugs.
 */

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <descrip.h>
#include <lbrdef.h>
#include <lhidef.h>

#include "lbrio.h"

/*
 * Include file doe not define the system routine entry points.
 */
int LBR$INI_CONTROL(), LBR$OPEN(), LBR$OPEN(), LBR$CLOSE(), LBR$GET_HEADER();
int LBR$LOOKUP_KEY(), LBR$SET_LOCATE(), LBR$GET_RECORD(), LBR$GET_INDEX();

/**************************************************************************/
/* Open help library for access given name and index.
 *   Input:
 *	name	Char *.  Library name to open.
 *	defname Char *.  Default filespec for open (e.g. SYS$HELP:.HLB).
 *    output:
 *	new	lbr_index *.  Receives pointer to control structure for
 *			 library access.
 *    Return value:
 *		Value returned in VMS condition value (odd == success).
 */
int lbr_open ( char *name, char *defname, lbr_index *new )
{
    int status, func, type;
    lbr_index lptr;
    $DESCRIPTOR (fns,"");
    $DESCRIPTOR (dns,"sys$help:*.hlb");
    /*
     * Allocate control block and zero it.
     */
    lptr = (lbr_index) malloc ( sizeof(struct lbr_control) );
    *new = lptr;
    if ( !lptr ) return 12;
    lptr->index = (void *) 0;
    lptr->rfa[0] = lptr->rfa[1] = 0;
    lptr->dir_alloc = 0;
    /*
     * Initialize control index.  Put constants in variables so we
     * can properly pass the arguments by reference.
     */
    func = LBR$C_READ;
    type = LBR$C_TYP_UNK;
    status = LBR$INI_CONTROL ( &lptr->index, &func, &type );
#ifdef DEBUG
    if ( (status&1)==0) printf("init_control status: %d %d\n", status,lptr->index );
#endif
    if ( (status&1) == 0 ) { free ( lptr ); return status; }
    /*
     * Open the library.
     */
    fns.dsc$w_length = strlen(name);
    fns.dsc$a_pointer = name;
    dns.dsc$w_length = strlen(defname);
    dns.dsc$a_pointer = defname;
    
    status = LBR$OPEN ( &lptr->index, &fns, 0, &dns, 0, 0, 0 );
#ifdef DEBUG
    printf("status of lbr open: %d, index=%d\n", status, lptr->index );
#endif
    /*
     * Use locate mode to read records (high performance).
     */
    if ( (status&1) == 0 ) free ( lptr );
    else {
	status = LBR$SET_LOCATE ( &lptr->index );
        if ( (status&1) == 0 ) free ( lptr );
    }
    return status;
}
/**************************************************************************/
/* Close library openned by lbr_open.  Free allocated memory.
 */
int lbr_close ( lbr_index lptr )
{
    int status;
    if ( !lptr ) return 12;		/* bad pointer */

    status = LBR$CLOSE ( &lptr->index );
    if ( lptr->dir_alloc > 0 ) free ( lptr->dir_names );
    free ( lptr );
    return status;
}
/**************************************************************************/
/* Lookup module key in library and save RFA address.  This routine
 * must be called prior to lbr_fgets.
 *
 *   input:
 * 	lptr	lbr_index.  Pointer returned by lbr_open.
 *	module	char *.  Module name to read.
 *
 *   Return value:
 *		VMS condition code returned by LBR$LOOKUP_KEY().
 */
int lbr_set_module ( lbr_index lptr, char *module )
{
    int status, one, LBR$SET_INDEX();
    $DESCRIPTOR ( key, "" );

    lptr->used = 0;
    lptr->cur_length = 0;
    key.dsc$w_length = strlen ( module );
    key.dsc$a_pointer = module;
    status = LBR$LOOKUP_KEY ( &lptr->index, &key, &lptr->rfa );
#ifdef DEBUG
    printf("Status of module %s lookup: %d %d\n", module, status, lptr->rfa);
#endif
    return status;
}
/**************************************************************************/
/* Read record from library.  Emulate fgets call, append linefeed to each
 * record.  Note that function value is a VMS status, not a character pointer
 * however.
 *
 *   input:
 *	maxchar	int.  Length of str output array.
 *	lptr	lbr_index.  Pointer returned by lbr_open;
 *   output:
 *	str	Char *.  Buffer to receive record read.
 *   Return value:
 *		VMS condition code returned by LBR$GET_RECORD().
 */
int lbr_fgets ( char *str, int maxchar, lbr_index lptr )
{
    int status, length;
    struct dsc$descriptor cur_rec;

    length = lptr->cur_length - lptr->used;
    if ( length <= 0 ) {
        /*
         * Get next record.
         */
        status = LBR$GET_RECORD ( &lptr->index, 0, &cur_rec );
        if ( (status&1) == 0 ) { 
	    *str = 0; 
	    lptr->cur_length = 0;
	    return status; 
	}
	length = cur_rec.dsc$w_length;
        lptr->cur_length = length + 1;		/* implied line feed */
        lptr->cur_rec = cur_rec.dsc$a_pointer;
	lptr->used = 0;

    } else if ( length == 1 ) {
	/*
	 * Only implied linefeed left in buffer.
	 */
	if ( maxchar > 1 ) *str++ = '\n'; 
	*str = '\0';
	lptr->used = lptr->cur_length;
	return 1;
    } else {
	/*
	 * Set cur_rec.
	 */
	cur_rec.dsc$w_length = length - 1;
	cur_rec.dsc$a_pointer = &lptr->cur_rec[lptr->used];
	length = cur_rec.dsc$w_length;
    }
    /*
     * Copy to user buffer.
     */
    if ( length >= maxchar ) length = maxchar - 1;
    memcpy ( str, cur_rec.dsc$a_pointer, length );
    if ( length < (maxchar - 1) ) str[length++] = '\n'; 
    lptr->used += length;
    str[length++] = 0;

#ifdef DEBUG
    printf("status of get_record: %d, length: %d '%s", status, 
	lptr->cur_length, str );
#endif
    return status;
}
/**************************************************************************/
/* Internal routine for getting library module directory with LBR$GET_INDEX.
 *  A bizarre oversight in LBR$GET_INDEX's design means we have to use
 *  a module-wide variable (load_tmp) to pass context information to this
 *  routine.
 */
static lbr_index load_tmp;
static int lbr_fill_dir ( struct dsc$descriptor *name, long *rfa,
lbr_index tptr )
{
    int length;
    lbr_index lptr;

    lptr = load_tmp;
    length = name->dsc$w_length;
    while ( length + lptr->dir_size + 1 >= lptr->dir_alloc ) {
#ifdef DEBUG
	printf("Reallocating directory\n");
#endif
	lptr->dir_names = realloc 
		( lptr->dir_names, (lptr->dir_alloc+length+1)*2 );
	lptr->dir_alloc *= 2;
    }

    memcpy ( &lptr->dir_names[lptr->dir_size], name->dsc$a_pointer, length );
    lptr->dir_names[lptr->dir_size+length] = '\0';
    lptr->dir_size += length + 1;
    return 1;
}

/**************************************************************************/
/* Return next module name in libraries directory.
 *
 *   input:
 *	maxchar	Int.  Size of output name array.
 *	lptr	lbr_index.  Pointer returned by lbr_open().
 *   output:
 *	name	char *.  Module name.
 *   return value:
 *		VMS condition code returned by LBR$GET_INDEX().
 */
int lbr_read_directory ( char *name, int maxchar, lbr_index lptr )
{
    int status, count, inum, length;
    /*
     * Initialize.
     */
    if ( lptr->dir_alloc <= 0 ) {
	struct lhidef header;
	status = LBR$GET_HEADER ( &lptr->index, &header );
	count = header.lhi$l_modcnt;

	lptr->dir_alloc = count * 20;
	lptr->dir_size = lptr->dir_pos = 0;
	lptr->dir_names = malloc ( lptr->dir_alloc );

	load_tmp = lptr;	/* bogus */
	inum = 1;
	status = LBR$GET_INDEX ( &lptr->index, &inum, lbr_fill_dir, lptr );
    } else status = 1;

    if ( lptr->dir_pos >= lptr->dir_size ) return 2160;

    length = strlen ( &lptr->dir_names[lptr->dir_pos] );
    if ( length < maxchar ) {
	strcpy ( name, &lptr->dir_names[lptr->dir_pos] );
    } else {
	strncpy ( name, &lptr->dir_names[lptr->dir_pos], maxchar-1 );
	name[maxchar-1] = '\0';
    }
#ifdef DEBUG
printf("read dir pos: %d, name: '%s'\n", lptr->dir_pos, name );
#endif
    lptr->dir_pos += length + 1;
    return status;
}