/*
 *	f o p n x n
 */

/*)LIBRARY
*/

#ifdef	DOCUMENTATION

Title	fopnxn	Open a file on another node (using RFA)
Index	fopnxn	Open a file on another node (using RFA)

synopsis
	.s.nf
	NFILE *
	fopnxn(name, mode, inisiz, recsiz);
	char		*name;	/* File to open 	*/
	char		*mode;	/* Open modes		*/
	int		inisiz;	/* initial size of file */
	int		recsiz;	/* record size for random access files */
	.s.f
Description

	Fopnxn() provides the services of fopenx() across DECnet. The
	usage is the same as fopenx(), with some exceptions:

	.s.list
	.le ;The file name must include a node name and uic.
	.le ;The file pointer returned can only be used with
	rgetb(), rputb() and rclose().
	.le ;The remote node must have DECnet object 128 defined
	as the cooresponding RFA (remote file access) task. 
	.le ;On error, both $$ferr and $$nerr should be checked.
	.els.s

	See the description of fopenx() for more details on the other
	arguments.

	Returns NULL on error. $$ferr is set to IE.BAD if the node
	name or uic are omitted. Actual file errors retuen the FCS error
	code in $$ferr with the network error code, $$nerr = 1. 
	Network errors will set $$nerr, with the value of $$ferr
	unpredicatable.

	The NFILE structure created when a file is successfully openned
	contains some of the FDB information from the remote file. See
	stdnet.h for details.

Implementation Details

	Fopnxn() does not set a default uic and device, so
	they must be specified. It is also safer since the remote
	system may not have the same device or uic.

	The RFA object on the remote node does the actual file open
	or create. On successfull completion of the call, the remote 
	RFA task will have the file open.
	.s
	Don't use fopnxn on non-disk devices, the results are
	unpredicatable.
	.s
	Note that "no buffer space available" (IE.NBF or E$$NSP) and
	"invalid lun" (IE.ILU or E$$NOC) may be generated by fopenx()
	on the remote side and returned.
	.s
	The NFILE pointer returned will only work with rgetb(), rputb()
	and rclose(). Using is with regular C IO functions will crash
	the task.
	.s
	Access mode checks are done in this function before the network
	code is called.
Bugs

	Only works with RSX FCS. You need to known what your doing.

#endif


#include <stdio.h>
#include <cx.h>
#include <stdnet.h>

#define IE_BAD	-1	/* bad parameter ferr value */

extern int $$ferr;

NFILE *
fopnxn(fnam, mode, inisiz, recsiz)
char *fnam;
char *mode;
int inisiz;	/* initial size of file */
int recsiz;	/* record size for fixed length file */
{
  char *nodep;		/* remote node name */
  char *filp;		/* pointer to filename less node name */
  char filspc[40];	/* private copy of file spec */
  char *chk_fnam();

  if (scan(mode) == NULL) {	/* check option args */
    $$ferr = IE_BAD;	/* report bad args */
    return(NULL);
  }

  strcpy(filspc, fnam);		/* get private copy of file spec */
  nodep = filspc;		/* set pointers */

  if (!(filp = chk_fnam(filspc))) return(NULL);

  return(rmt_opn(nodep, filp, mode, inisiz, recsiz));
}


char *chk_fnam(fspc)	/* find and check file spec */
char *fspc;
{
  char *fp;	/* beginning of file name string */
  char *cp;

  $$ferr = IE_BAD;	/* assume bad args */

/* check for :: separating node name and file name */

  if ((fp = strchr(fspc, ':')) == NULL) return(NULL);
  *fp++ = NULL;		/* terminate node name string */
  if (*fp++ != ':') return(NULL);	/* double :: req. for node nm */

/* check if uic was specified */

  if ((cp = strchr(fp, '[')) == NULL) {
    $$ferr = -52;	/* IE.BDI - bad directory syntax */
    return(NULL);
  }
  $$ferr = IS_SUC;
  return(fp);
}

static int scan(modep)	/* scan option string */
char *modep;		/* options passed by caller */
{
  char *p;
  int af;		/* access count flag, must be 1 */

  af = 0;
  for (p = modep; *p != NULL; p++) {
    switch (*p)	{
      case 'r':
      case 'a':
      case 'm':
      case 'w': af++;
      		continue;

      case 'n':		/* legal options */
      case 'u':
      case 'p':
      case 's':
      case 'x':
      case 'l':	continue;

      default:  return(NULL);
      }
    } /* end options string scan */

  if (af == 1) return(1);	/* only one access mode allowed */
  else return(NULL);
}
