/* @(#)archconf.c	1.10 03/11/27 Copyright 1996 J. Schilling */
#ifndef lint
static	char sccsid[] =
	"@(#)archconf.c	1.10 03/11/27 Copyright 1996 J. Schilling";
#endif
/*
 *	Make program
 *	Architecture autoconfiguration support
 *
 *	Copyright (c) 1996 by J. Schilling
 */
/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; see the file COPYING.  If not, write to the Free Software
 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include <mconfig.h>
#include <stdio.h>
#include <standard.h>
#include <unixstd.h>
#include <strdefs.h>
#include <schily.h>
#include "make.h"

#ifdef	NO_SYSINFO
#	ifdef	HAVE_SYS_SYSTEMINFO_H
#		undef	HAVE_SYS_SYSTEMINFO_H
#	endif
#endif

EXPORT	void	setup_arch	__PR((void));
LOCAL	BOOL	do_uname	__PR((void));
LOCAL	BOOL	do_sysinfo	__PR((void));
LOCAL	void	do_gethostname	__PR((void));
LOCAL	void	do_defs		__PR((void));
LOCAL	void	do_archheuristics __PR((void));
LOCAL	void	archcvt		__PR((char *));
#ifdef	HAVE_SYS_SYSTEMINFO_H
LOCAL	void	unblank		__PR((char *));
#endif

/*
 * External interface to archconf.c. The code tries its best to get the
 * architecture definitions by calling sysinfo(), uname() or by heuristic.
 */
EXPORT void
setup_arch()
{
	if (!do_sysinfo() &&		/* Call sysinfo(2): preferred	*/
			!do_uname()) {	/* Call uname(2): still OK	*/
		/*
		 * If nothing else helps, at least try to set up $(MAKE_HOST)
		 * and some other macros that may be retrieved from
		 * CPP definitions.
		 */
		do_gethostname();	/* Try to get host name		*/
		do_defs();		/* Evaluate CPP definitions	*/
	}

	do_archheuristics();
}

#ifdef	HAVE_UNAME		/* NeXT Step has sys/utsname but not uname() */
#include <sys/utsname.h>

/*
 * This is the interface to the syscall uname(2).
 * Note that the system call is done directly and not by calling the uname
 * shell command. If your system returns wrong information with the uname(2)
 * call, you need to fix it here.
 */
LOCAL BOOL
do_uname()
{
	struct	utsname	un;

	if (uname(&un) < 0) {
		errmsg("Cannot get host arch (uname).\n");
		return (FALSE);
	}
/*
	printf("sysname: %s nodename: %s release: %s version: %s machine: %s\n",
	un.sysname,
	un.nodename,
	un.release,
	un.version,
	un.machine);
*/
	archcvt(un.sysname);
	archcvt(un.release);
	archcvt(un.version);
	archcvt(un.machine);

	define_var("MAKE_OS", un.sysname);
	define_var("MAKE_HOST", un.nodename);
	define_var("MAKE_OSREL", un.release);
	define_var("MAKE_OSVERSION", un.version);
	define_var("MAKE_MACH", un.machine);

	return (TRUE);
}
#else

/*
 * Dummy for platforms that don't implement uname(2).
 */
LOCAL BOOL
do_uname()
{
	return (FALSE);
}
#endif

#ifdef	HAVE_SYS_SYSTEMINFO_H
#include <sys/systeminfo.h>

/*
 * sysinfo(2) is the preferred way to request architecture information.
 * Unfortunately, it is only present on SVr4 compliant systems.
 */
LOCAL BOOL
do_sysinfo()
{
	char	nbuf[NAMEMAX];

	if (sysinfo(SI_SYSNAME, nbuf, sizeof (nbuf)) < 0)
		return (FALSE);
	archcvt(nbuf);
	define_var("MAKE_OS", nbuf);

	if (sysinfo(SI_HOSTNAME, nbuf, sizeof (nbuf)) < 0)
		return (FALSE);
	define_var("MAKE_HOST", nbuf);

	if (sysinfo(SI_RELEASE, nbuf, sizeof (nbuf)) < 0)
		return (FALSE);
	archcvt(nbuf);
	define_var("MAKE_OSREL", nbuf);

	if (sysinfo(SI_VERSION, nbuf, sizeof (nbuf)) < 0)
		return (FALSE);
	archcvt(nbuf);
	define_var("MAKE_OSVERSION", nbuf);

	if (sysinfo(SI_MACHINE, nbuf, sizeof (nbuf)) < 0)
		return (FALSE);
	archcvt(nbuf);
	define_var("MAKE_MACH", nbuf);

	if (sysinfo(SI_ARCHITECTURE, nbuf, sizeof (nbuf)) < 0)
		return (FALSE);
	archcvt(nbuf);
	define_var("MAKE_ARCH", nbuf);

#ifdef	SI_PLATFORM
	if (sysinfo(SI_PLATFORM, nbuf, sizeof (nbuf)) < 0)
		return (FALSE);
	define_var("MAKE_MODEL", nbuf);
#endif

	if (sysinfo(SI_HW_PROVIDER, nbuf, sizeof (nbuf)) < 0)
		return (FALSE);
	unblank(nbuf);
/*	archcvt(nbuf);*/
	define_var("MAKE_BRAND", nbuf);

	if (sysinfo(SI_HW_SERIAL, nbuf, sizeof (nbuf)) < 0)
		return (FALSE);
/*	archcvt(nbuf);*/
	define_var("MAKE_SERIAL", nbuf);

	return (TRUE);
}
#else

/*
 * Dummy for platforms that don't implement sysinfo(2).
 */
LOCAL BOOL
do_sysinfo()
{
	return (FALSE);
}
#endif

#ifdef	HAVE_GETHOSTNAME

/*
 * Don't care for systems that implement a similar functionality in
 * sysinfo(2) or uname(2). This function is only called if
 * sysinfo(2) or uname(2) do not exists.
 */
LOCAL void
do_gethostname()
{
	char	nbuf[NAMEMAX];

	if (gethostname(nbuf, sizeof (nbuf)) < 0)
		return;

	define_var("MAKE_HOST", nbuf);
}
#else

/*
 * Dummy for platforms that don't implement gethostname(2).
 */
LOCAL void
do_gethostname()
{
}
#endif

/*
 * Try to retrieve some information from CPP definitions.
 */
LOCAL void
do_defs()
{
#ifdef	IS_MSDOS
	define_var("MAKE_OS", "msdos");
#endif
#ifdef	IS_TOS
	define_var("MAKE_OS", "tos");
#endif
#ifdef	IS_MAC
	define_var("MAKE_OS", "macos");
#endif
#ifdef	__NeXT__
	define_var("MAKE_OS", "nextstep");
	define_var("MAKE_OSREL", "3.0");
	define_var("MAKE_OSVERSION", "1");
#ifdef	__ARCHITECTURE__
	define_var("MAKE_MACH", __ARCHITECTURE__);
#endif
#endif	/* __NeXT__ */
}

/*
 * Do some additional heuristic for systems that are already known
 * but may need some more macro definitions for completion.
 */
LOCAL void
do_archheuristics()
{
	obj_t	*o;
	char	*name;

	/*
	 * Try to define global processor architecture
	 */
	o = objlook("MAKE_ARCH", FALSE);
	if (o == NULL) {
		o = objlook("MAKE_MACH", FALSE);
		if (o != NULL && o->o_list != NULL) {
			name = o->o_list->l_obj->o_name;
			if (strstr(name, "sun3"))
				define_var("MAKE_ARCH", "mc68020");
			if (strstr(name, "sun4"))
				define_var("MAKE_ARCH", "sparc");
		}
	}

	/*
	 * Try to define global machine architecture
	 */
	o = objlook("MAKE_MACH", FALSE);
	if (o != NULL && o->o_list != NULL) {
		name = o->o_list->l_obj->o_name;

		if (strstr(name, "sun3"))
			define_var("MAKE_M_ARCH", "sun3");
		if (strstr(name, "sun4"))
			define_var("MAKE_M_ARCH", "sun4");
	}

	o = objlook("MAKE_OS", FALSE);
	if (o != NULL && o->o_list != NULL &&
/*				streql(o->o_list->l_obj->o_name, "SunOS")) {*/
				streql(o->o_list->l_obj->o_name, "sunos")) {
		o = objlook("MAKE_OSREL", FALSE);
		if (o != NULL && o->o_list != NULL &&
					o->o_list->l_obj->o_name[0] >= '5')
/*			define_lvar("MAKE_OSDEFS", "-D__SOL2 -D__SVR4");*/
			define_var("MAKE_OSDEFS", "-D__SVR4");
	}
}

/*
 * Alle Namen in Kleinbuchstaben wandeln,
 * '/' in '-' wandeln.
 * '\\' in '-' wandeln.
 * ' ' in '-' wandeln.
 */
#include <ctype.h>

LOCAL void
archcvt(p)
	register char	*p;
{
	register Uchar	c;

	while ((c = (Uchar)*p) != '\0') {
		if (c == '/')
			*p = '-';
		if (c == '\\')
			*p = '-';
		if (c == ' ')
			*p = '-';
		if (isupper(c))
			*p = tolower(c);
		p++;
	}
}

#ifdef	HAVE_SYS_SYSTEMINFO_H
LOCAL void
unblank(p)
	register char	*p;
{
	register char	c;

	while ((c = *p) != '\0') {
		if (c == ' ')
			*p = '-';
		p++;
	}
}
#endif
