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
}
Back to
Home
Neil Rieck
Waterloo, Ontario, Canada.