From: ROSSJI@JS-JTF.AF.MIL ("Jim Ross")
Newsgroups: comp.os.vms
Subject: Summary: Logical name translation from VAX C
Date: 12 Oct 92 03:21:00 GMT
Distribution: world
Organization: The Internet

I've been overwhelmed with help in response to my request for a VAX C 
example of obtaining the translation of a logical name. Overwhelmed with
the number of willing mentors, the variety of approaches, and the quality
of assistance available to someone from "everyone" given nothing more than
a relatively efficient channel of communication between all parties.

I must share the solutions with "everyone" as most were properly mailed
directly to me.

Thanks!
Jim Ross
-------------------------------------------------------------------------

Return-Path: <carl@SOL1.GPS.CALTECH.EDU>

Here's a simple example.  If this doesn't help, let me know what you're trying
that doesn't work.

#include psldef.h
#include lnmdef
#include descrip
main()
{	$DESCRIPTOR(tabnam, "LNM$JOB");
	$DESCRIPTOR(lognam, "SYS$LOGIN");
	char equnam[33];
	long equlen = 0, stat;
	unsigned char acmode = PSL$C_EXEC;
	struct item_list_3
	{	unsigned short buflen, itmcod;
		void *bufaddr;
		long *rsllen;
	} itmlst[] =
	{	{	32, LNM$_STRING, equnam, &equlen },
		{	0,	0,	0,	0	}
	};

	if(((stat =SYS$TRNLNM(0, &tabnam, &lognam, &acmode, itmlst)) & 7) != 1)
		SYS$EXIT(stat);
	equnam[equlen] = '\0';
	puts(equnam);
}
Carl J Lydick | INTERnet: CARL@SOL1.GPS.CALTECH.EDU | NSI/HEPnet: SOL1::CARL
--------------------------------------------------------------------------------

Return-Path: <infopiz!infocomm.com!mark@decwrl.dec.com>

This is the easiest way:

main()
{
	printf("SYS$MANAGER = %s\n", getenv("SYS$MANAGER"));
}

--
Mark Pizzolato - INFO COMM Computer Consulting, Redwood City, Ca
PHONE:	(415)369-9366	UUCP:  decwrl!infopiz!mark or uunet!lupine!infopiz!mark
DOMAIN:	mark@infocomm.com
---------------------------------------------------------------------------

Return-Path: <GAVRON@ALPHA.SUNQUEST.COM>

	$ cc retlnm
	$ link retlnm

	$ define test "ONE VALUE"
	$ run retlnm

	$ define test "MULTIPLE","VALUE","EXAMPLE","CODE"
	$ run retlnm

retlnm.c:

#define table "LNM$PROCESS"
#define logical "TEST"

#include <ssdef.h>			/* System service status returns */
#include <lnmdef.h>			/* Logical Name constants	*/
#include <descrip.h>			/* Descriptor building tools	*/

typedef union {				/* Item list structure */
    	struct {
                short s_buflen;		/* Buffer length */
                short s_itemcode;	/* Item code */
                char  *s_bufaddr;	/* Buffer address */
                short *s_retlen;	/* Return length */
                } s;
        unsigned long end;		/* Used to signal end of item list */
        } ITEMLIST;

/* Make it so we can do array[index].entity instead of array[index].s.entity */
#define buflen          s.s_buflen
#define itemcode        s.s_itemcode
#define bufaddr         s.s_bufaddr
#define retlen          s.s_retlen

int sys$trnlnm(),sys$exit();		/* Forward declare system services */
int lib$put_output();			/* and run time library calls */


/*
 * retlnm()	- Return all translations of a logical name
 */
#ifdef __alpha
main()	  /* Sigh.  ALPHA DEC C requires main() to give us an entry point */
#else
cmain()	  /* If we don't call it main() we don't have to link with VAXCRTL */
#endif
{
   $DESCRIPTOR(tabnam,table);			/* Logical name table */
   $DESCRIPTOR(lognam,logical);			/* Logical name to look for */
   unsigned long index;				/* Index to multiple values */
   unsigned long max_index;			/* Maximum index */
   unsigned long ss_stat;			/* For system service returns */
   char equivalence[LNM$C_NAMLENGTH + 1];	/* Buffer for value */
   struct dsc$descriptor_s equiv_desc;		/* Descriptor for same */

   ITEMLIST max[2];				/* Itemlist to get max index */
   ITEMLIST value[3];				/* Itemlist to get values */

   /* Let's make the equivalence descriptor point to the buffer */
   equiv_desc.dsc$a_pointer 	= (char *)&equivalence;
   equiv_desc.dsc$w_length	= sizeof(equivalence) -1;
   equiv_desc.dsc$b_class	= DSC$K_CLASS_S;	 /* Static descriptor */
   equiv_desc.dsc$b_dtype	= DSC$K_DTYPE_T;	 /* Holds Text */

   /* First set up itemlist to return the maximum index in use for this
      logical name. */
  
   max[0].itemcode	= LNM$_MAX_INDEX;
   max[0].buflen	= 4;
   max[0].bufaddr	= (char *)&max_index;
   max[0].retlen	= 0;

   /* We terminate the item list with a longword of zero */
   max[1].end		= 0;

   /* Let's get that max index: */

   ss_stat = sys$trnlnm(0,			/* attr */
			&tabnam,		/* tabnam */
			&lognam,		/* lognam */
			0,			/* acmode */
			&max);			/* itmlst */

   if (ss_stat != SS$_NORMAL) sys$exit(ss_stat);

   /* At this point we have an unsigned longword max_index with a value
      of 0-127 (inclusive).  0 means there is 1 translation, and 127
      means there are 128 translations.  We now create the itemlist to
      get values, and loop from 0 to max_index, seeking values.

      Note: We could have created this item list up top, but WHY waste
	    the CPU power in the case that the logical name has no
  	    translation.  Best case - there is a translation and we do
	    the work down here.  Worst case - there is no translation 
	    and we save the overhead. */

   /* Part one of the itemlist sets the index for part 2.  */

   value[0].itemcode	=	LNM$_INDEX;
   value[0].buflen	=	4;
   value[0].bufaddr	= 	(char *)&index;
   value[0].retlen	=	0;

   /* Part two actually does the equivalence retrieval for the index
      given in part one */

   value[1].itemcode	=	LNM$_STRING;
   value[1].buflen	= 	sizeof(equivalence)-1;
   value[1].bufaddr	= 	(char *)equiv_desc.dsc$a_pointer;
   value[1].retlen	=	(char *)&equiv_desc.dsc$w_length;

   /* Part three terminates the item list */
   value[2].end 	=	0;

   /* Do the loop: */

   for (index = 0; (index <= max_index) && (ss_stat == SS$_NORMAL); index++) {
      ss_stat = sys$trnlnm(0,			/* attr */
			&tabnam,		/* tabnam */
			&lognam,		/* lognam */
			0,			/* acmode */
			&value);		/* itmlst */

      /* Display results: */

      if (ss_stat == SS$_NORMAL) {
	 lib$put_output(&equiv_desc);
         }

      } /* end for loop */

} /* end main code */
    
	Ehud
 
--
Ehud Gavron        (EG76)     
gavron@aces.com
--------------------------------------------------------------------------

Return-Path: <FORREST@RIGEL.TAMU.EDU>

   I have included some code below that I use in translating the system table
logical ACS_PASSWDLOG   which points to a filename string to which we want
to log transactions. The code segment is from an installed privileged image 
that some of our helpdesk people run to set passwords and increase diskquota 
for our clients.  Hope it helps.

$ SHOW LOG/FULL ACS_PASSWD*

(LNM$PROCESS_TABLE)	[kernel]
			[no protection information]

(LNM$JOB_81920140)	[kernel]  [shareable]  [Quota=(512,1024)]
			[Protection=(RWED,RWED,,)]  [Owner=[ACSXS,FORREST]]

(LNM$GROUP_000040)	[kernel]  [shareable,group]
			[Protection=(RWED,R,R,)]  [Owner=[40,0]]

(LNM$SYSTEM_TABLE)	[kernel]  [shareable,system]
			[Protection=(RWE,RWE,R,R)]  [Owner=[SYST,SYSTEM]]

  "ACS_PASSWDLOG" [exec] = "ACS_SYSTEM:[MOD_PASS_QUOTA]MOD_PASS_QUOTA.LOG"

(DECW$LOGICAL_NAMES)	[exec]  [shareable]
			[Protection=(RWED,RWED,R,R)]  [Owner=[SYST,SYSTEM]]



------------------------- get_logical.c --------------------------------- 
#include <stdio.h>
#include <descrip.h>
#include <psldef.h>
#include <lnmdef.h>
#include <ssdef.h>

void get_message( unsigned long int ierrorstatus ) ;


void lookup_file_from_logical( char *ptr_chlogical_string, 
                               char *ptr_chfilename,
                               unsigned short int length_chfilename )
 {                     

   struct ItemList {
                     unsigned short int buffer_length ; short int item_code ;
                     void *buffer_address ;  short int *return_length_address ;
                   } logical_name[2] ;
                     

   struct dsc$descriptor_s chdsc_logical_table_search_list,
                           chdsc_logical_name ;
                            

   unsigned long int attribute_case = 0 , ireturn_status = 0 ;
   char logical_table_search_list[255] =  "LNM$SYSTEM_TABLE" ;
   unsigned char  access_mode[1] = PSL$C_SUPER ;
   short int ireturn_length = 0 ;

  /*
   * Set up the structures to translate the logical
   */                                              

      /* type is character */
   chdsc_logical_table_search_list.dsc$b_dtype = DSC$K_DTYPE_T ; 
      /* string descriptor */
   chdsc_logical_table_search_list.dsc$b_class = DSC$K_CLASS_S ; 
      /* number of characters */
   chdsc_logical_table_search_list.dsc$w_length =
         strlen( &(logical_table_search_list[0]) ) ;
     /* address of the string */
   chdsc_logical_table_search_list.dsc$a_pointer =
         &(logical_table_search_list[0])  ;


      /* type is character */
   chdsc_logical_name.dsc$b_dtype = DSC$K_DTYPE_T ; 
      /* string descriptor */
   chdsc_logical_name.dsc$b_class = DSC$K_CLASS_S ; 
      /* number of characters */
   chdsc_logical_name.dsc$w_length =
         strlen( ptr_chlogical_string ) ;
     /* address of the string */
   chdsc_logical_name.dsc$a_pointer = ptr_chlogical_string ;

   logical_name[0].buffer_length = (unsigned short int) length_chfilename ;
   logical_name[0].item_code = (short int) LNM$_STRING ;
   logical_name[0].buffer_address = (void *) ptr_chfilename ;
   logical_name[0].return_length_address = (short int *) &ireturn_length ;
   logical_name[1].buffer_length = (unsigned short int) 0 ;
   logical_name[1].item_code = (short int) 0 ;
   logical_name[1].buffer_address = (void *) NULL ;
   logical_name[1].return_length_address = (short int *) NULL ;

  /*                          
   * Translate the logical
   */

   attribute_case = LNM$M_CASE_BLIND ;
   ireturn_status = sys$trnlnm(&attribute_case, 
                               &chdsc_logical_table_search_list,
                               &chdsc_logical_name, 
                               &(access_mode[0]),
                               &logical_name);

  if( ireturn_status != SS$_NORMAL )
   {
    (void) get_message(ireturn_status);
    if( ( ireturn_status & 1 ) != 1 )
     {
      fprintf(stderr,"Error in translating logical name.\n");
      fprintf(stderr,"Cannot continue... Exiting 4.\n");
      fflush(stderr);
      fflush(stdout);
      exit(4);
     }
   }


   if( ireturn_length > length_chfilename  )
    {
     fprintf(stderr,"Error in translating logical name. ");
     fprintf(stderr," ireturn_length > ( length_filename - 1 )\n");
     fprintf(stderr,"Cannot continue.  Exiting 4.\n");
     fflush(stderr);
     fflush(stdout);
     exit(4);
    }
   ptr_chfilename[ (int) ireturn_length ] = '\0' ;
}



 /* ................................................................... */


   void get_message(long unsigned int ierror)
   {
     char cherror[256];
     short int returned_length;
     long unsigned int msgstatus;
     int i;
     struct dsc$descriptor_s dsc_errmsg;
     fflush(stdout) ;
     fflush(stderr) ;
     dsc_errmsg.dsc$b_dtype   = DSC$K_DTYPE_T; /* type is character */
     dsc_errmsg.dsc$b_class   = DSC$K_CLASS_S; /* string descriptor */
     dsc_errmsg.dsc$w_length  = 256;
     dsc_errmsg.dsc$a_pointer = &(cherror[0]);
     for ( i = 0; i <= 256; i = i + 1)
       {
        cherror[i] = '\0';
       }
     msgstatus = sys$getmsg(ierror, &returned_length, &dsc_errmsg, 0, 0);
     cherror[256] = '\0' ;
     if ( ( msgstatus & 1 ) == 0 )
       {
        fprintf(stderr," Unable to translate the error return status.\n");
        fprintf(stderr,
           " Status = Hex-%x (Decimal-%lu) for sys$getmsg() call.\n",msgstatus,
           msgstatus);
       }
     else
       {
        fprintf(stderr," VMS ERROR CODE= Hex-%x (Decimal-%lu) \n",ierror,
                ierror);
        fprintf(stderr," The corresponding VMS error message is:\n");
        fprintf(stderr,"%s\n",&cherror[0]);
       }
     if ( ( ierror & 1 ) != 0  )
      {
       fprintf(stderr," This was a success code.\n") ;
      }
     else
      {
       fprintf(stderr," This was an error code.\n");
      }
     fflush(stderr) ;
     fflush(stdout) ;
 }


 Bob Forrest 
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Programmer/Analyst I              HEPnet:    FNBIT::UTDAL::RIGEL::FORREST
 Texas A&M University              SPAN:      UTSPAN::UTADNX::RIGEL::FORREST
 Academic Computing Services       THEnet:    RIGEL::FORREST                
 WERC Room #020                    BITnet:    FORREST@TAMRIGEL              
 Mail Stop 3154                    SESquinet: FORREST@RIGEL.TAMU.EDU        
 College Station, Texas 77843-3154 Phone:     409-845-9577
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
---------------------------------------------------------------------------

Received: From MC.MARICOPA.EDU by CRVAX.SRI.COM with TCP; Fri,  9 OCT 92 01:54:19 PDT


	Although I haven't written a function to call the sys$trnlnm system 
service directly, I have written some general-purpose functions to call the 
lib$ routines to return a logical name (and a symbol name) equivalence string.
I know this isn't exactly what you asked for, but may provide an alternative:

	#include <descrip.h>

	#define $STRDESC(name,string)	struct dsc$descriptor_s name = \
		{ strlen(string), DSC$K_DTYPE_T, DSC$K_CLASS_S, string }

	char *get_logical(char *logical)
	{
		static char equiv[255];
		$DESCRIPTOR(buffer,equiv);
		$STRDESC(log,logical);
		unsigned short len;
	
		if (lib$sys_trnlog(&log,&len,&buffer) & 1) {
			equiv[len] = 0;
			if (strcmp(logical,equiv) == 0)
				return(0);
			else
				return(&equiv);
		}
		else
			return(0);
	}

	char *get_symbol(char *symbol)
	{
		static char equiv[255];
		$DESCRIPTOR(buffer,equiv);
		$STRDESC(sym,symbol);
	
		if (lib$get_symbol(&sym,&buffer) & 1)
			return(&equiv);
		else
			return(0);
	}


	Both functions return a pointer to the equivalence name string if the 
logical (or symbol) name is found. One note, though -- the get_logical() 
function will use lib$sys_trnlog's defaults for table, access mode, and 
search disable mask. By default it searches the process, group, and system 
name tables. Hope this helps. If you STILL want to use $trnlnm, you have to 
build an item_list_3 structure and pass your options through that. I've found 
the lib$ routines to be a usefull alternative to calling many of the system 
service services.

-------------------------------------------------------------------------

Return-Path: <simons/G=Colin/I=CB/S=Sewell/O=H.A.Simons.Ltd/OU=CORP@mhs.attmail.com>

to set up descriptors in VAXC, include the header file
descrip.h. then define the descriptor with the $DESCRIPTOR
macro.

	$DESCRIPTOR( lnm$jobdsc, "LNM$JOB" )

this creates the lnm$jobdsc descriptor structure and
initializes it. then pass it to the system service by
reference (&lnm$jobdsc).

you'll want to create an item list for sys$trnlnm. i've defined
some simple macros to do this:

struct $item
    {
    unsigned short int	itm$w_bufsiz;	    /* Length in bytes of item	    */
    unsigned short int	itm$w_itmcod;	    /* Item code		    */
    unsigned char	(*itm$l_bufadr)[];  /* Address of item value	    */
    unsigned short int	*itm$l_retlen;	    /* Address to return length	    */
    } ;

typedef struct $item	$itmlst;

when declaring the item list, define it as one longer than
what you need to take care of the terminating zero.

an example to translate SYS$LOGIN:

#include descrip
#include lnmdef
#include ssdef

struct $item
    {
    unsigned short int	itm$w_bufsiz;	    /* Length in bytes of item	    */
    unsigned short int	itm$w_itmcod;	    /* Item code		    */
    unsigned char	(*itm$l_bufadr)[];  /* Address of item value	    */
    unsigned short int	*itm$l_retlen;	    /* Address to return length	    */
    };

typedef struct $item	$itmlst;

static unsigned long translate() MAIN_PROGRAM

{
    unsigned long   status;
    $itmlst	    lnmlst[2];
    char	    equnam[LNM$C_NAMLENGTH+1];
    unsigned short  equnamlen;

    $DESCRIPTOR( lnm$file_dev,	"LNM$FILE_DEV" );
    $DESCRIPTOR( sys$login,	"SYS$LOGIN");

    lnmlst[0].itm$w_bufsiz = sizeof(equnam) - 1;
    lnmlst[0].itm$w_itmcod = LNM$_STRING;
    lnmlst[0].itm$l_bufadr = equnam;
    lnmlst[0].itm$l_retlen = &equnamlen;

    lnmlst[1].itm$w_bufsiz = 0;
    lnmlst[1].itm$w_itmcod = 0;

    status = sys$trnlnm( 0, &lnm$file_dev, &sys$login, 0, &lnmlst );
    if (!(status & 1)) return status;

    equnam[equnamlen] = '\0';

    printf( "translation of SYS$LOGIN is %s\n", equnam );

    return SS$_NORMAL;

}

does this help?
---------------------------------------------------------------------

Return-Path: <"WARNER::DAMBIK"@FNAL.FNAL.GOV>

The VAX C RTL function getenv provides an easy way to translate simple 
logicals:

	char *string;
	string = getenv("Logical_Name");

Or you can use sys$trnlnm:

	#include descrip

	int sts;
	$DESCRIPTOR(lnmtable_d, "LNM$PROCESS_TABLE");	/* Logical table */
	$DESCRIPTOR(lognam_d, "Logical_Name");		/* Logical name */
	struct {        	/* Item list structure */
	    unsigned short buflen;     /* Item buffer length */
	    unsigned short itmcod;     /* Item code */
	    int *bufferp;              /* Pointer to item's buffer */
	    unsigned long *rtnlenp;    /* Pointer to return length */
	    } items[2];		/* One item and one list terminator */
	unsigned short elength;	/* Return Length of equivalence string */
	char trnlog[81];	/* Returns equivalence string */

	/* Initialize the item list for $TRNLNM. */
	items[0].buflen = sizeof(trnlog) - 1;	/* Size of name buffer */
	items[0].itmcod = LNM$_STRING;		/* Request string */
	items[0].bufferp = trnlog;		/* Translated logical */
	items[0].rtnlenp = &elength;		/* Return length */

	items[1].buflen = 0;		/* Terminate list */
        items[1].itmcod = 0;

	sts = sys$trnlnm( 0, &lnmtable_d, &lognam_d, 0, items);
	if (!(sts&1)) lib$signal(sts);