[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference vmszoo::rms_openvms

Title:RMS asks, 'R U Journaled?'
Moderator:STAR::TSPEERUVEL
Created:Tue Mar 11 1986
Last Modified:Wed Jun 04 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:3031
Total number of notes:12302

3008.0. "shared write and read in C: how to?" by AWECIM::MILLIGAN () Thu Jan 30 1997 13:01

Hello RMS experts,

I'm in the process of writing a C program which will open a "log" file
and will periodically append text to that file. The text will include
several "newlines". There will be multiple instances of this program
running concurrently. The multi-line message from instance "A" cannot
be intermixed with the multi-line message from instance "B". And
finally, I need to be able to type/cont this shared log file from
a separate terminal session.

What I've come up with so far is something like:

	FILE *pF = fopen("foo.log", "a", "ctx=xplct", "rfm=vfc", "rat=cr", 
          "shr=get,put,upd");
		o
		o
		o
	fprintf(pF, "Multi line message\nMust remain\nContiguous\n");
	fflush(pF);
		o
		o
		o

This comes close to producing the desired behaviour, but it seems
to be discarding the first two bytes of each message:
	lti line message
	Must remain
	Contiguous
In addition, I seem to be unable to use the DCL type/cont or
type/tail command to view this file while it is open by any
of the writing processes.  How can I acheive the desired results?

					Thanks,

					Rob Milligan
					CIM Engineering
					Digital Semiconductor
					Hudson, MA
					dtn: 225-4868
					e-mail: robert.milligan@hlo.mts.dec.com
T.RTitleUserPersonal
Name
DateLines
3008.1EPS::VANDENHEUVELHeinFri Jan 31 1997 22:4421
    
    I do not know whether the C RTL muddles the picture but in
    RMS native terms a variable length record with embedded new-
    lines will remain a single record. So if you can not get to
    a solution using C IO you can always just call $PUT directly
    and that'll do the job. You may want to consider using STREAM_LF
    files after all. In that case something 'cute' will happen.
    During the put, all the data will be entered into the file as
    a single record with embedded LFs. Upon reading the data, the LFs
    in the record will turn into terminators and will break up that
    chunk of data into multiple lines. Perhaps exactly what you want?
    The writers can not be interupted, the readers will see 'normal'
    single lines.
    
    Sharing RMS files is straightforward, C mussdles again a little.
    Numerous other topics here discuss this. Also check the C conference.
    You may need FFLUSH and/or FSYNC calls to make fresh data visible.
    If all fails, just use sprintf and then call SYS$PUT directly!
    
    Hein.
    
3008.2Call RMS Directly; Alternatives...XDELTA::HOFFMANSteve, OpenVMS EngineeringMon Feb 03 1997 12:3910
   You've got enough OpenVMS-isms on that fopen, that you might as well
   just call RMS directly.  It'll likely be easier, and you won't have
   C contributing confusions due to the (necessary and expected) UNIX
   emulation provided by the CRTL.  (The UNIX record locking and file
   sharing support is quite different from that of OpenVMS.)

   Alternatively, consider using a single "logging" application, or use
   per-application-instantiation (seperate) log files.

3008.3yes, direct RMS calls seem to be the answer ...AWECIM::MILLIGANFri Feb 07 1997 19:44120
For what it's worth, I've been able to acheive the desired results with code based upon the following
sample program.  Many thanks to the previous replies to get me pointed in the right direction. -rm

/*
** file:
**   rmsfun.c
** description:
**   This sample program demonstrates how one might have an application
**   program written in C "log" messages to a text file. The program
**   will open a log file and will periodically append text to that file.
**   The text will include several "newlines". There may be multiple
**   instances of this program running concurrently. The multi-line
**   message from program instance "A" cannot be intermixed with the
**   multi-line message from program instance "B". Both type/continuous
**   and type/tail of this shared log file work as expected.
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <rms.h>
#include <stsdef.h>
#include <starlet.h>

#ifndef TRUE
#define TRUE (1)
#endif

#ifndef FALSE
#define FALSE (0)
#endif


#define LOG_FILE_NAME "rmsfun.log"
#define LOG_LOCK_TIMEOUT (10)
#define LOG_LOOP_MAX (20)
#define VMS_SUCCESS(lRetVal) \
  ((lRetVal & STS$M_SUCCESS) ? TRUE : FALSE)


int
main(void)
{
  struct FAB aFab;
  struct RAB aRab;
  unsigned long lRet;
  int iPID, iCnt;
  char cFileName[] = LOG_FILE_NAME;
  char cMsgBuf[1024] = "";

  iPID = getpid();		/* to uniquely identify the writer ... */

  aFab = cc$rms_fab;		/* set default file access block values ... */
  aFab.fab$b_fac = FAB$M_PUT;
  aFab.fab$l_fna = cFileName;
  aFab.fab$b_fns = (unsigned char)strlen(cFileName);
  aFab.fab$l_fop = FAB$M_DFW | FAB$M_CIF;
  aFab.fab$b_org = FAB$C_SEQ;
  aFab.fab$b_rat = FAB$M_CR;
  aFab.fab$b_rfm = FAB$C_STMLF;
  aFab.fab$b_shr = FAB$M_SHRPUT | FAB$M_SHRGET | FAB$M_SHRUPD;

  lRet = sys$create(&aFab, 0, 0);	/* open/create file ... */
  if (! VMS_SUCCESS(lRet))
    {
    printf("Could not create/open file >%s<, status: >%u<\n", cFileName, lRet);
    exit(lRet);
    }

  aRab = cc$rms_rab;		/* set default record access block args ... */
  aRab.rab$l_fab = &aFab;
  aRab.rab$b_rac = RAB$C_SEQ;
  aRab.rab$l_rbf = cMsgBuf;
  aRab.rab$l_rop = RAB$M_EOF | RAB$M_NLK | RAB$M_RLK | RAB$M_TMO | RAB$M_WAT;
  aRab.rab$w_rsz = (unsigned short)strlen(cMsgBuf);
  aRab.rab$b_tmo = (unsigned char)LOG_LOCK_TIMEOUT;

  for(iCnt = 0; iCnt < LOG_LOOP_MAX; iCnt++)	/* now do some test msgs ... */
    {

    lRet = sys$connect(&aRab, 0, 0);		/* connect RAB to FAB ... */
    if (! VMS_SUCCESS(lRet))
      {
      printf("Could not connect to file >%s<, status: >%u<\n", cFileName, lRet);
      exit(lRet);
      }

    sprintf(cMsgBuf,
      "%x: Line number 1, pass >%d<\n%x: Line number 2, pass >%d<\n%x: Line number 3, pass >%d<\n\n",
      iPID, iCnt, iPID, iCnt, iPID, iCnt);
    aRab.rab$w_rsz = (unsigned short)strlen(cMsgBuf);
    lRet = sys$put(&aRab, 0, 0);		/* then put ... */
    if (! VMS_SUCCESS(lRet))
      {
      printf("Could not put to file >%s<, pass: >%d<, status: >%u<\n",
        cFileName, lRet);
      exit(lRet);
      }

    lRet = sys$disconnect(&aRab, 0, 0);		/* then disconnect ... */
    if (! VMS_SUCCESS(lRet))
      {
      printf("Could not disconnect from file >%s<, status: >%u<\n",
        cFileName, lRet);
      exit(lRet);
      }
    }

  lRet = sys$close(&aFab, 0, 0);		/* now close ... */
  if (! VMS_SUCCESS(lRet))
    {
    printf("Could not close file >%s<, status: >%u<\n", cFileName, lRet);
    exit(lRet);
    }

  return(0);
}