
/*
 *         PVM version 3.3:  Parallel Virtual Machine System
 *               University of Tennessee, Knoxville TN.
 *           Oak Ridge National Laboratory, Oak Ridge TN.
 *                   Emory University, Atlanta GA.
 *      Authors:  A. L. Beguelin, J. J. Dongarra, G. A. Geist,
 *    W. C. Jiang, R. J. Manchek, B. K. Moore, and V. S. Sunderam
 *                   (C) 1992 All Rights Reserved
 *
 *                              NOTICE
 *
 * Permission to use, copy, modify, and distribute this software and
 * its documentation for any purpose and without fee is hereby granted
 * provided that the above copyright notice appear in all copies and
 * that both the copyright notice and this permission notice appear in
 * supporting documentation.
 *
 * Neither the Institutions (Emory University, Oak Ridge National
 * Laboratory, and University of Tennessee) nor the Authors make any
 * representations about the suitability of this software for any
 * purpose.  This software is provided ``as is'' without express or
 * implied warranty.
 *
 * PVM version 3 was funded in part by the U.S. Department of Energy,
 * the National Science Foundation and the State of Tennessee.
 */

/*
 *	cruft.c
 *
 *	Missing links and other wonk.
 *
$Log: pvmcruft.c,v $
 * Revision 1.5  1994/11/07  22:48:09  manchek
 * added tweaks for SX3, SCO
 *
 * Revision 1.4  1994/07/18  19:21:05  manchek
 * pvmputenv() matched variable name substrings (need to compare = too)
 *
 * Revision 1.3  1994/06/03  20:38:22  manchek
 * version 3.3.0
 *
 * Revision 1.2  1993/10/04  20:28:27  manchek
 * added pvmdsockfile() function
 *
 * Revision 1.1  1993/08/30  23:26:50  manchek
 * Initial revision
 *
 */

#include <stdio.h>
#ifdef IMA_TITN
#include <bsd/sys/types.h>
#else
#include <sys/types.h>
#endif
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <ctype.h>
#ifdef	SYSVSTR
#include <string.h>
#define	CINDEX(s,c)	strchr(s,c)
#else
#include <strings.h>
#define	CINDEX(s,c)	index(s,c)
#endif
#include "global.h"
#include "protoglarp.h"
#include "pvmalloc.h"
#include "tdpro.h"


/***************
 **  Globals  **
 **           **
 ***************/

char *getenv();

extern int pvm_useruid;				/* from pvmd.c or lpvm.c */


/***************
 **  Private  **
 **           **
 ***************/

static char rcsid[] = "$Id: pvmcruft.c,v 1.5 1994/11/07 22:48:09 manchek Exp $";


int
pvmput32(p, n)
	char *p;
	int n;
{
	*p++ = n >> 24;
	*p++ = n >> 16;
	*p++ = n >> 8;
	*p = n;
	return 0;
}


int
pvmput16(p, n)
	char *p;
	int n;
{
	*p++ = n >> 8;
	*p = n;
	return 0;
}


int
pvmput8(p, n)
	char *p;
	int n;
{
	*p = n;
	return 0;
}


int
pvmget32(p)
	char *p;
{
	return ((0xff & p[0]) << 24)
	+ ((0xff & p[1]) << 16)
	+ ((0xff & p[2]) << 8)
	+ (0xff & p[3]);
}


int
pvmget16(p)
	char *p;
{
	return ((0xff & p[0]) << 8) + (0xff & p[1]);
}


int
pvmget8(p)
	char *p;
{
	return 0xff & *p;
}


#ifdef NOGETDTBLSIZ

#ifdef IMA_TITN

int
getdtablesize()
{
	return 64;
}

#else	/*IMA_TITN*/

#ifdef IMA_SX3

int
getdtablesize()
{
	return 64*8;
}

#else /*IMA_SX3*/

#include <unistd.h>

int
getdtablesize()
{
	return sysconf(_SC_OPEN_MAX);
}

#endif /*IMA_SX3*/
#endif	/*IMA_TITN*/

#endif /*NOGETDTBLSIZ*/

#if defined(IMA_TITN) || defined(I860_NODE) || defined(I860_SRM) || defined(IMA_SCO)
int
ffs(x)
	int x;
{
	int n = 1, m = 1;

	if (!x)
		return 0;
	while (!(x & m)) {
		m += m;
		n++;
	}
	return n;
}

#endif


extern char **environ;

/*	pvmputenv()
*
*	Replacement for systems that don't have putenv.
*	Tries to be conservative, i.e. doesn't assume that environ
*	points to malloc'd space.
*
*	String must never be freed...
*/

int
pvmputenv(s)
	char *s;	/* string of form "NAME=Value" */
{
	char *p;					/* gp */
	int l;						/* length of env var name or env */
	static char **myen = 0;		/* last environ that i created */
	char **newen;				/* new env if extending */
	char **ep, **ep2;			/* gp */

	/* sanity check the string and locate the '=' */

	if (!s)
		return -1;
	for (p = s; *p && *p != '='; p++);
	if (p == s || !*p)
		return -1;
	l = p - s + 1;	/* must include '=' */

	/* search current environ for name */

	for (ep = environ; *ep; ep++)
		if (!strncmp(*ep, s, l))
			break;

	if (*ep) {	/* already there, replace it */
		*ep = s;

	} else {	/* not there, must extend environ */

	/* length needed is? */

		for (l = 2, ep = environ; *ep; l++, ep++);

		if (environ == myen) {	/* mine, reallocate */
			if (!(newen = (char**)realloc((char *)environ,
					(unsigned)(l * sizeof(char*)))))
				return -1;

		} else {	/* not mine, alloc new and copy */
			if (!(newen = (char**)malloc((unsigned)(l * sizeof(char*)))))
				return -1;
			for (ep = environ, ep2 = newen; *ep2++ = *ep++; );
		}
		newen[l - 2] = s;
		newen[l - 1] = 0;
		environ = myen = newen;
	}
	return 0;
}


/*	pvmxtoi()
*
*	Yet another version of ascii hex to integer
*/

pvmxtoi(p)
	char *p;
{
	int i = 0;
	char c;

	while (isxdigit(c = *p++)) {
		i = (i << 4) + c - (isdigit(c) ? '0' : (isupper(c) ? 'A' : 'a') - 10);
	}
	return i;
}


#ifndef	I860_NODE

/*	hex_inadport()
*
*	Takes a string of format 00000000:0000 and returns a sockaddr_in.
*/

hex_inadport(s, sad)
	char *s;
	struct sockaddr_in *sad;
{
	sad->sin_addr.s_addr = htonl((unsigned)pvmxtoi(s));
	s = (s = CINDEX(s, ':')) ? s + 1 : "";
	sad->sin_port = htons((unsigned short)pvmxtoi(s));
}


/*	inadport_decimal()
*
*	Returns printable string corr. to sockaddr_in with addr in decimal.
*/

char *
inadport_decimal(sad)
	struct sockaddr_in *sad;
{
	static char buf[32];
	int a;

	a = ntohl(0xffffffff & sad->sin_addr.s_addr);
	sprintf(buf, "%d.%d.%d.%d:%d",
			0xff & (a >> 24),
			0xff & (a >> 16),
			0xff & (a >> 8),
			0xff & a,
			0xffff & (int)ntohs(sad->sin_port));
	return buf;
}


/*	inadport_hex()
*
*	Returns printable string corr. to sockaddr_in with addr in hex.
*/

char *
inadport_hex(sad)
	struct sockaddr_in *sad;
{
	static char buf[16];
	int a;

	a = ntohl(0xffffffff & sad->sin_addr.s_addr);
	sprintf(buf, "%08x:%04x", a, 0xffff & (int)ntohs(sad->sin_port));
	return buf;
}

#endif	/*I860_NODE*/


#ifdef	NOTMPNAM
char *
pvmtmpnam(buf)
	char *buf;
{
	static int n = 0;
	static char scratch[32];

	if (!buf)
		buf = scratch;
	sprintf(buf, "/tmp/tmp%06d.%d", getpid(), n++ % 10000);
	return buf;
}
#endif	/*NOTMPNAM*/


pvmhdump(p, n, pad)
	char *p;	/* bytes */
	int n;		/* length */
	char *pad;
{
	int i;
	pad = pad ? pad : "";
	for (i = 0; n-- > 0; i = ++i & 15) {
		fprintf(stderr, "%s%02x%s",
			i ? "" : pad,
			0xff & *p++,
			n && i != 15 ? " " : "\n");
	}
	return 0;
}


/*	pvmgethome()
*
*	Return path of user homedir.
*/

char *
pvmgethome()
{
	static char *hd = 0;

	if (!hd) {
		if (hd = getenv("HOME")) {
			hd = STRALLOC(hd);

		} else {
			pvmlogerror("warning: can't getenv(HOME), using /\n");
			hd = "/";
		}
	}
	return hd;
}


/*	pvmgetroot()
*
*	Return absolute path of PVM top level directory.
*/

char *
pvmgetroot()
{
	static char *rd = 0;

	if (!rd && !(rd = getenv("PVM_ROOT"))) {
		pvmlogerror("PVM_ROOT environment variable not set.\n");
		pvmbailout(0);
		exit(1);		/* the other meaning of bail out */
	}
	return rd;
}


/*	pvmgetpvmd()
*
*	Return absolute path of pvmd startup script.
*/

char *
pvmgetpvmd()
{
	char *r;
	static char *pp = 0;

	if (!pp) {
		if (PVMDFILE[0] == '/')
			pp = PVMDFILE;
		else {
			r = pvmgetroot();
			pp = TALLOC(strlen(r) + strlen(PVMDFILE) + 2, char, "pvmdpath");
			sprintf(pp, "%s/%s", r, PVMDFILE);
		}
	}
	return pp;
}


/*	pvmdsockfile()
*
*	Returns name of file where pvmd advertises its sockaddr.
*	Assumes global pvm_useruid is set before calling.
*/

char *
pvmdsockfile()
{
	static char buf[160];

	char hna[128];
	char *p;

#ifdef	SHAREDTMP
	if (gethostname(hna, sizeof(hna)-1) == -1) {
		pvmlogerror("pvmdsockfile() can't gethostname()\n");
		return (char*)0;
	}
	if (p = CINDEX(hna, '.'))
		*p = 0;
	(void)sprintf(buf, TDSOCKNAME, pvm_useruid, hna);

#else
	(void)sprintf(buf, TDSOCKNAME, pvm_useruid);
#endif

	return buf;
}

