OpenVMS Source Code Demos

basic_calling_c_demo4_part2

//========================================================================================
// title  : basic_calling_c_demo4_part2.c
// author : Neil Rieck	(https://neilrieck.net) (mailto:n.rieck@bell.net)
// notes  : 1)	This file contains code for two functions which will be called from BASIC.
//		This means there is no main() or transfer address to call from a CLI
//	    2)	VMS-BASIC-1.7 up-cases everything written to the symbol table. This means
//		all C symbols must be up-cased as well. This is done by actually using
//		upper case or compiling with C with switch /NAMES=(UPPERCASE,TRUNCATED)
//	    3) OpenVMS RTL String Manipulation (STR$) Manual
//		http://h30266.www3.hpe.com/odl/axpos/opsys/vmsos84/5936/5936PRO.HTML
// history:
// ver who when     what
// --- --- -------- ----------------------------------------------------------------------
// 100 NSR 20151209 original effort
//     NSR 20151210 cleaned up the code while adding documentation
//     NSR 20170520 added a third method to display the inbound data
//========================================================================================
#define __NEW_STARLET 1						// enable strict starlet (>= OpenVMS70)
#include <stdio.h>						//
#include <stdlib.h>						//
#include <string.h>						//
#include <descrip.h>						// for VMS string descriptors in C
#include <str$routines.h>					// for VMS string descriptors in VMS
//
//	VMSIFY
//      a macro for use in the VMS world (VMS strings employ this structure)
//	notes:	1. this macro can be used to create VMS strings in c space
//		2. the $DESCRIPTOR macro does something similar employing sizeof-1
//		3. this macro combines two operations
//		4. use str$copy_dx() to copy string data up to the calling program
//
#define VMSIFY(a,b) {					\
    a.dsc$b_dtype = DSC$K_DTYPE_T;			\
    a.dsc$b_class = DSC$K_CLASS_S;			\
    a.dsc$w_length = strlen(b);				\
    a.dsc$a_pointer = (char *) malloc(strlen(b));	\
    strncpy(a.dsc$a_pointer,b,a.dsc$w_length);		\
}
//	VMSIFY2
//      a macro for use in the VMS world (VMS strings employ this structure)
//	notes:	1. this macro can be used to create VMS strings in VMS space
//		2. the $DESCRIPTOR macro does something similar employing sizeof-1
//		3. this macro combines two operations
//		4. unlike malloc, memory allocated via "str$get1_dx" will survive
//		   after this module exits.
//
#define VMSIFY2(a,b) {						\
    a.dsc$b_dtype = DSC$K_DTYPE_T;				\
    a.dsc$b_class = DSC$K_CLASS_D;				\
    a.dsc$w_length = strlen(b);					\
    a.dsc$a_pointer = NULL;					\
    rc = str$get1_dx(&a.dsc$w_length,&a);			\
    if ((rc & 7)!=1) printf("-e-str$get1_dx-rc: %ld\n",rc);	\
    strncpy(a.dsc$a_pointer,b,a.dsc$w_length);			\
}
//
//==============================================================================
// c function: basic_calling_c_demo_c1
//
// BASIC declaration:
//	external long function basic_calling_c_demo_c1(string by desc)
//==============================================================================
long basic_calling_c_demo_c1(	struct dsc$descriptor_d * p1	) {
	char				*buf;			//
	int				rc;			//
	int				hack;			//
	char				c_misc[100];		//
	struct	dsc$descriptor_s	vms_misc1;		//
	struct	dsc$descriptor_s	vms_misc2;		//
	struct	dsc$descriptor_s	vms_misc3;		//
	//
	printf("c function: basic_calling_c_demo_c1\n");
	//------------------------------------------------------
	//	display string variable passed here
	//------------------------------------------------------
	//
	//	this next will fail because VMS strings are not null terminated
	//
//	printf("method1 p1 = %s\n",p1->dsc$a_pointer);		//
	//
	//	this next block of lines will work properly in C
	//
	printf("method1 p1 = %.*s\n", p1->dsc$w_length, p1->dsc$a_pointer);
	//
	//	method 2
	//
	printf("method2 p1 = ");				//
	fwrite(p1->dsc$a_pointer,1,p1->dsc$w_length,stdout);	//
	printf("\n");						//
	//
	//	method 3
	//
	buf = malloc(p1->dsc$w_length+1);			// allocate some local memory
	if (buf==0) {						// this should never happen
	    printf("-e-oops, no memory available\n");		//	''
	    exit;						//	''
	}
	strncpy(buf,p1->dsc$a_pointer,p1->dsc$w_length);	// copy data into memory
	buf[p1->dsc$w_length] = '\0';				// null terminate
	printf("method3 p1 = %s\n", buf);			// display it
	free(buf);						// release local memory
	//------------------------------------------------------
	//	inspect inbound params (just a little hacking)
	//------------------------------------------------------
	printf("hack p1-type  : %ld\n",p1->dsc$b_dtype);
	printf("hack p1-class : %ld\n",p1->dsc$b_class);
	printf("hack p1-length: %ld\n",p1->dsc$w_length);

	//------------------------------------------------------
	//	prep to return more string data to the calling routine
	//------------------------------------------------------
	sprintf(c_misc, " stuff tacked on");			// prep
#define hack 1							// choose 1 or 2
#if (hack==1)
	//
	//	will only work provided malloc'd data is copied before this module exits
	//
	printf("using method 1 to concat\n");			//
	VMSIFY(vms_misc1, c_misc);				//
	rc = str$concat(p1, p1, &vms_misc1);			//
	if ((rc & 7) != 1)					//
	    printf("-e-str$concat-rc:%ld\n",rc);		//
	free (vms_misc1.dsc$a_pointer);				// not really necessary
#else
	//
	//	This method creates a VMS string "up there" (associated with the
	//	calling module's memory space) and is then manipulated "up there"
	//	This is just shown as a proof of concept.
	//
	printf("using method 2 to concat\n");			//
	VMSIFY2(vms_misc2, c_misc);				//
	VMSIFY2(vms_misc3, "");					// created outside this routine
	rc = str$concat(&vms_misc3, p1, &vms_misc2);		//
	if ((rc & 7) != 1)					//
	    printf("-e-str$concat-rc:%ld\n",rc);		//
	rc = str$copy_dx(p1, &vms_misc3);			//
	if ((rc & 7) != 1)					//
	    printf("-e-str$copy_dx-rc:%ld\n",rc);		//
#endif
	//------------------------------------------------------
	//	adios
	//------------------------------------------------------
	return (1);						// return something
}

home Back to Home
Neil Rieck
Waterloo, Ontario, Canada.