Plan 9 from Bell Labs’s /usr/web/sources/contrib/steve/root/sys/src/cmd/mkmk/hints.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


/* Beware - some guesswork in here */
#include <u.h>
#include <libc.h>
#include <ctype.h>
#include <bio.h>
#include "mkmk.h"

/*
 * Global hints are those needed by every file, even if it doesn't
 * include config.h, and thus they are passed on the command line.
 * Local hints are also passed on the command line, unless we are
 * in Autoconf mode, in which case they go into the config.h file.
 */
List *Glbhints = nil;
List *Lochints = nil;

typedef struct {
	char *name;
	char *macro;
} Macdef;

/*
 * any attempt to include these files requires the definition
 * of the given macro name or plan9's APE system will cause
 * a compilation error. This list is complete at the time or writing
 * but will become inaccurate with time.
 */
Macdef Filehints[] = {
	{ "bsd.h",		"_BSD_EXTENSION" },
	{ "netdb.h",		"_BSD_EXTENSION" },
	{ "select.h",		"_BSD_EXTENSION" },
	{ "sys/ioctl.h",	"_BSD_EXTENSION" },
	{ "sys/resource.h",	"_BSD_EXTENSION" },
	{ "sys/time.h",		"_BSD_EXTENSION" },
	{ "sys/select.h",	"_BSD_EXTENSION" },
	{ "sys/socket.h",	"_BSD_EXTENSION" },
	{ "sys/systime.h",	"_BSD_EXTENSION" },
	{ "sys/uio.h",		"_BSD_EXTENSION" },
	{ "regexp.h",		"_REGEXP_EXTENSION" },
	{ "u.h",		"_PLAN9_EXTENSION" },
	{ "cursor.h",		"_PLAN9_EXTENSION" },
	{ "draw.h",		"_PLAN9_EXTENSION" },
	{ "event.h",		"_PLAN9_EXTENSION" },
	{ "fmt.h",		"_PLAN9_EXTENSION" },
	{ "keyboard.h",		"_PLAN9_EXTENSION" },
	{ "lib9.h",		"_PLAN9_EXTENSION" },
	{ "lock.h",		"_PLAN9_EXTENSION" },
	{ "mouse.h",		"_PLAN9_EXTENSION" },
	{ "qlock.h",		"_PLAN9_EXTENSION" },
	{ "ar.h",		"_RESEARCH_SOURCE" },
	{ "libv.h",		"_RESEARCH_SOURCE" },
	{ "libl.h",		"_RESEARCH_SOURCE" },
	{ "error.h",		"_RESEARCH_SOURCE" },
	{ "inttypes.h",		"_SUSV2_SOURCE" },
	{ "fcntl.h",		"_POSIX_SOURCE" },
	{ "grp.h",		"_POSIX_SOURCE" },
	{ "pwd.h",		"_POSIX_SOURCE" },
	{ "unistd.h",		"_POSIX_SOURCE" },
};

/*
 * Arbitary defines that GNU Autoconf wants and we support.
 */
char *Wellknown[] = {
	{ "HAVE_WORKING_FORK" },		// yes our fork does work
	{ "STDC_HEADERS" },			// unistd, stdlib and some friends
	{ "TIME_WITH_SYS_TIME" },		// we have both time.h and sys/time.h
	{ "GETPGRP_VOID" },			// getgrp() returns a void
	{ "HAVE_UTIME_NULL" },			// utime() accepts nil for times
	{ "SELECT_TYPE_ARG234=fd_set" },	// the type of args for select()
	{ "_POSIX_SOURCE" },			// yes, we are POSIX compliant
	{ "HAVE_ANSI_COMPILER" },		// yes, we are ANSI compiliant too

};

static void
addhint(List **lp, char *macro, char *value)
{
	if(looksym(macro, nil) != nil)
		return;
	addlist(lp, macro);
	setsym(macro, value);
}

static char *
looktab(List **lp, char *macro, char **first, char **last)
{
	char **t;

	for(t = first; t < last; t++)
		if(strcmp(macro, *t) == 0){
			addhint(lp, macro, "1");
			return "1";
		}
	return nil;
}

/*
 * This could cause problems. we only realise we need _LIMITS_EXTENSION when
 * its already too late, we have included limits.h, without this macro active
 * and missed the extra info. If the extension macros are only used in the C code
 * all is well but if their value is test in #if statements then we are stuffed
 * we I only guess at "1" for each limit. I should probably parse the sys/limits.h
 * file when I detect the first preprocessor use of any of the #defines in it but
 * I have not been bitten by this yet.
 */
#include "syslimits.h"

static char *
extendedlimits(char *macro)
{
	char **t;

	for(t = Syslimits; t < &Syslimits[nelem(Syslimits)]; t++)
		if(strcmp(macro, *t) == 0){
			addhint(&Glbhints, "_LIMITS_EXTENSION", "1");
			return "1";
		}
	return nil;
}

/*
 * Found a HAVE_funcname or FUNC_funcname test, lookup funcname
 * in all the system libraries I expect to link with.
 */
static char *
function_name(char *macro, char *func)
{
	if(inlibrary(func) == 0)
		return nil;

	/*
	 * people tend to assume strdup() is part of POSIX
	 */
	if(strcmp(func, "strdup") == 0)
		addhint(&Glbhints, "_BSD_EXTENSION", "1");
	addhint(&Lochints, macro, "1");
	return "1";
}

/*
 * Found HAVE_file_H so we check the system include "file" exists
 */
static char *
incfile_exists(char *macro, char *str, List *incdirs)
{
	int rc;
	char *s;
	List *l;
	
	for (l = incdirs; l; l = l->next){
		s = emallocz(strlen(l->name)+strlen(str)+2, 0);
		strcpy(s, l->name);
		strcat(s, "/");
		strcat(s, str);
		rc = access(s, 4);
		free(s);
		if(rc != -1){
			addhint(&Lochints, macro, "1");
			return "1";
		}
	}
	return nil;
}

/*
 * I found an #if #elif or #ifdef referencing a macro which doesn't exist,
 * so I check to see if I think it "should" exist and define it if so.
 */
char *
macrohint(char *macro, List *incdirs)
{
	char *val, *s, *name;

	if((val = looktab(&Lochints, macro, Wellknown, &Wellknown[nelem(Wellknown)])) != nil)
		return val;

	if((val = extendedlimits(macro)) != nil)
		return val;

	if(strncmp(macro, "FUNC_", 5) == 0){
		name = estrdup(macro+5);
		for(s = name; *s; s++)
			*s = tolower(*s);
		val = function_name(macro, name);
		free(name);
		return val;
	}

	if(strncmp(macro, "HAVE_", 5) == 0){
		name = estrdup(macro+5);
	
		for(s = name; *s; s++)
			*s = tolower(*s);

		if((s = strrchr(name, '_')) != nil && strcmp(s, "_h") == 0){
			*s = '.';
			for(s = name; *s; s++)
				if(*s == '_')
					*s = '/';

			val = incfile_exists(macro, name, incdirs);
			free(name);
			return val;
		}

		val = function_name(macro, name);
		free(name);
		return val;
	}


	return nil;
}

/*
 * this inclide file has been used, check if we can 
 * infer any macros that need to be #define as a result.
 *
 * This is mainly for plan9 headers which raise an error if
 * the apropriate _XXXX_EXTENSION macro is not set when they are used.
 */
void
includehint(char *file)
{
	Macdef *nv;

	for(nv = Filehints; nv < &Filehints[nelem(Filehints)]; nv++)
		if(strcmp(file, nv->name) == 0){
			if(looksym(nv->name, nil) == nil)
				addhint(&Glbhints, nv->macro, "1");
			break;
		}
}

/*
 * assumes the GNU practice of naming 
 * packages directories e.g. make-3.78
 */
void
gnu_pkgvers(void)
{
	char buf[128], str[128], *ver, *pkg;

	getwd(buf, sizeof(buf));

	ver = nil;
	if((pkg = strrchr(buf, '/')) != nil){
		pkg++;
		if((ver = strchr(pkg, '-')) != nil)
			*ver++ = 0;
	}

	if(pkg)
		snprint(str, sizeof(str), "\"%s\"", pkg);
	else
		snprint(str, sizeof(str), "\"unknown\"");
	addhint(&Lochints, "PACKAGE", str);

	if(ver)
		snprint(str, sizeof(str), "\"%s\"", ver);
	else
		snprint(str, sizeof(str), "\"unknown\"");
	addhint(&Lochints, "VERSION", str);
}


Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.