blob: a6667cbca61af30b87ab9ab4b264709ca9646f31 [file] [log] [blame]
/* --COPYRIGHT--,EPL
* Copyright (c) 2008-2019 Texas Instruments Incorporated
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Texas Instruments - initial implementation
*
* --/COPYRIGHT--*/
/*
* ======== xdc.c ========
* XDC Build Tool
*
* usage: xdc [-n] <goal> ... [-P package ...]
*
* Options:
* -h, -?, --help - display this message
* --help-make - display GNU make command options
* -k - don't stop on the first error (keep going for as
* long as possible)
* -n - don't do build just echo build commands
* -r[a] - use .xdcenv.mak to define XDCROOT, XDCPATH ...
* -P pkg ... - add package(s) to list of packages to build
* -PR dir ... - add all packages located under dir to the list
* of packages to build
* -Pr dir ... - add all packages whose repository is dir to the list
* of packages to build
* -PD pkg ... - add package(s) pkg and all packages that it
* (recursively)requires to the list of packages to build
*/
#define xdc__deprecated_types
#include <xdc/std.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <xdc/services/host/lib/xutl.h>
#include <sys/stat.h>
#define MAXNAME 512
#define MAXARG (2 * MAXNAME)
#define MAXARGS 128
#define MAXNEW 16
#if defined(xdc_target__os_Linux)
#include <unistd.h>
#define HOSTOS "HOSTOS=Linux"
#define LMAKE "../bin/gmake.x86U"
#endif
#if defined(xdc_target__os_MacOS)
#include <unistd.h>
#define HOSTOS "HOSTOS=MacOS"
#define LMAKE "../bin/gmake.x86_64M"
#endif
#if defined(xdc_target__os_Windows)
#define HOSTOS "HOSTOS=Windows"
#define LMAKE "..\\bin\\release\\gmake.exe"
#define DIRSTR "\\"
#define PATHSTR ";"
#define MAKE "bin" DIRSTR "gmake.exe"
#include <windows.h> /* GetModuleFileName */
#include <io.h>
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#else /* Unix */
#define DIRSTR "/"
#define PATHSTR ":"
#define MAKE "bin" DIRSTR "gmake"
#endif
#define PACKPREFIX "PACKAGES="
#define PACKSUFFIX ""
#define XDCREPO "packages" /* repo name under XDCROOT */
#define XDCTOPMAKE (DIRSTR "xdc" DIRSTR "bld" DIRSTR "xdc_top.mak")
#define XDCMAKE (DIRSTR "xdc" DIRSTR "bld" DIRSTR "xdc.mak")
static Bool rflag = FALSE;
static Bool nflag = FALSE;
static Int verbose = 0;
static String root; /* root path; i.e., $(XDCROOT) */
static Char rootDef[MAXARG]; /* XDCROOT=$(XDCROOT) */
static String repoName = XDCREPO; /* repository containing xdc packages */
static Char repoDef[MAXARG]; /* XDCREPO=$(XDCREPO) */
#if 0
static Char hostName[MAXARG]; /* HOSTNAME=<host-name> */
#endif
static Char makeCmd[MAXARG]; /* full path to make command */
static Char makeFile[MAXARG]; /* $(XDCROOT)/$(XDCREPO)/XDCTOPMAKE if
* '-P[...]' option is supplied; otherwise
* $(XDCROOT)/$(XDCREPO)/XDCMAKE
*/
static String pkgsDef; /* PACKAGES="..." */
static String xdcPathDef = NULL; /* XDCPATH= definition on command line */
static String makeArgv[MAXARGS];
static Int makeArgc = 0;
static String progName;
static String usage = \
"usage: %s [-h?|--help] [--help-make] [-k] [-n] [-r[a]] [def ...] [goal ...]\n"\
" [@opt-file] [-P[rRD] package-dir ...]\n\n" \
" -h, -?, --help - display this message and exit\n" \
" --help-make - display GNU make command options\n" \
" -k - don't stop on first build error (keep going)\n" \
" -n - show the make command but don't execute it\n" \
" -r[a] - (rebuild) use existing .xdcenv.mak to define XDC\n" \
" environment variables XDCROOT and XDCPATH. If -ra\n" \
" is specified, XDCARGS and XDCTARGETS are also read\n"\
" from this file rather than from the environment.\n" \
" --xdcpath=path - set the XDCPATH to path. This is identical to\n" \
" passing the definition XDCPATH=path on the \n" \
" command line.\n" \
" [def ...] - def is a name=value pair that overrides the value\n"\
" of the environment variable named name within this\n"\
" invocation of xdc\n" \
" [goal ...] - goal is any valid GNU make command option or goal.\n"\
" Common options and goals include:\n" \
" .help - display package-specific goals\n" \
" all - build all files\n" \
" clean - delete all generated files\n" \
" test - build and run all tests\n" \
" release - build all package release archives\n"\
" @opt-file - treat all options contained in the file opt-file\n"\
" as though they were directly inserted at the \n"\
" location of this @ option. This option may be \n"\
" repeated anywhere on the command line. Each option\n"\
" in opt-files must appear on a separate line and\n"\
" contain only characters that should be part of \n"\
" the option; no quote processing is done and all\n"\
" space or tab characters are part of the option.\n"\
" -P[rRD] dir .. - build specified goal(s) in all directories\n" \
" named after -P that contain a build script.\n" \
" If -PD is specified, build the package based at\n" \
" dir and (recursively) all other prerequisites of\n"\
" this package.\n" \
" If -Pr is specified, build all packages whose\n" \
" repository is dir.\n" \
" If -PR is specified, recursively descend into\n" \
" specified directories and build every package that\n"\
" contains a build script.\n";
static String optsUsage = \
" XDCOPTIONS options that affect output messages but never the\n"
" package bits actually generated include:\n"
" -d debug makefile generation\n"
" -q don't display any banners in recursive builds\n"
" -t don't display date timestamps in banners\n"
" -v show complete commands as they're executed\n"
" XDCPATH the user settable portion of the package path\n"
" XDCARGS arguments that are passed to the package's build \n"
" script, package.bld. The package's build script\n"
" references the arguments from the global array \n"
" arguments.\n"
" XDCBUILDCFG if defined and the file './config.bld' does not exist,\n"
" this variable names a file that will be used in-lieu of\n"
" the config.bld file found along the package path.\n"
" XDCTARGETS a string of white space separated target names that \n"
" name the set of targets to build for, if the set is not\n"
" already specified by the config.bld file\n";
static void checkXdcOptions(String arg);
static Void d2u(String buf);
static String findFile(String file, String path);
static Void findMake(Char *buffer, Uns max);
static char **genEnvp(String root, char *envp[]);
static String getRoot(String progName);
static Bool isFile(String name);
static Void printSetEnv(String env);
static Void printVers(String progName);
/*
* ======== main ========
*/
int main(int argc, char *argv[], char *envp[])
{
Int status = 0;
Int i, j;
SizeT len;
String vs, err;
progName = argv[0];
XUTL_init();
argv = XUTL_expandArgv(argc, argv, &argc, &err);
if (argv == NULL) {
fprintf(stderr, "%s: unable to expand command line arguments: %s\n",
progName, err);
exit(1);
}
if ((vs = getenv("XDC_VERBOSE")) != NULL) {
verbose = atoi(vs);
}
root = getRoot(progName);
sprintf(makeCmd, "%s%s", root, DIRSTR MAKE);
makeArgv[makeArgc++] = makeCmd;
makeArgv[makeArgc++] = "-r";
makeArgv[makeArgc++] = "-R";
makeArgv[makeArgc++] = HOSTOS;
#if 0
sprintf(hostName, "HOSTNAME=%s", getHostName());
makeArgv[makeArgc++] = hostName;
#endif
sprintf(rootDef, "XDCROOT=%s", root);
d2u(rootDef);
makeArgv[makeArgc++] = rootDef;
/* we're in a non-standard repository, define XDCREPO */
if (strcmp(repoName, XDCREPO) != 0) {
sprintf(repoDef, "XDCREPO=%s", repoName);
makeArgv[makeArgc++] = repoDef;
}
sprintf(makeFile, "%s" DIRSTR "%s%s", root, repoName, XDCMAKE);
makeArgv[makeArgc++] = "-f";
makeArgv[makeArgc++] = makeFile;
/* parse options */
for (i = 1; i < argc; i++) {
if (makeArgc >= MAXARGS) {
fprintf(stderr, "%s: out of memory.\n", progName);
exit(1);
}
if (argv[i][0] == '-') {
switch (argv[i][1]) {
case 'r': {
/* add "_USEXDCENV_=path" to make's argument list */
if (rflag == FALSE) {
if (argv[i][2] == 'a') {
makeArgv[makeArgc++] = "_USEXDCENV_=path+args";
}
else {
makeArgv[makeArgc++] = "_USEXDCENV_=path";
}
}
rflag = TRUE;
break;
}
case 'n': {
nflag = TRUE;
break;
}
case 'P': {
Int n;
/* this is a "big" make, so re-define the makefile */
sprintf(makeFile, "%s" DIRSTR "%s%s",
root, repoName, XDCTOPMAKE);
/* construct "PACKAGES=..." definition for make */
len = 32; /* enough for PACKAGES="" + null-termination */
for (j = i; j < argc; j++) {
len += strlen(argv[j]) + 1;
}
if ((pkgsDef = (String)malloc(len)) == NULL) {
fprintf(stderr, "%s: out of memory.\n", progName);
exit(1);
}
pkgsDef[0] = '\0';
switch (argv[i][2]) {
case '\0': {
break;
}
case 'r':
case 'D':
case 'R': {
if (argv[i][3] == '\0') {
pkgsDef[0] = argv[i][2];
pkgsDef[1] = '\0';
break;
}
/* intensionally fall into default case */
}
default: {
/* unregognized -P[...] option */
fprintf(stderr, usage, progName);
exit(1);
}
}
strcat(pkgsDef, PACKPREFIX);
for (n = 0, i++; i < argc; i++) {
strcat(pkgsDef, argv[i]);
if ((argc - i) > 1) {
/* delimit by semi to preserve spaces */
strcat(pkgsDef, ";");
}
n++;
}
strcat(pkgsDef, PACKSUFFIX);
/* -P[...] requires at least one additional argument */
if (n <= 0) {
fprintf(stderr, usage, progName);
exit(1);
}
/* add "PACKAGES= ..." to make's argument list */
makeArgv[makeArgc++] = pkgsDef;
break;
}
case 'h':
case '?': {
fprintf(stderr, usage, progName);
fprintf(stderr, "\nEnvironment Variables\n");
fprintf(stderr, optsUsage);
exit(0);
break;
}
case '-': {
if (strncmp("help-make", argv[i] + 2, 9) == 0) {
makeArgv[makeArgc++] = "-h";
/* set up args for call to gmake */
break;
}
if (strncmp("help", argv[i] + 2, 4) == 0) {
fprintf(stderr, usage, progName);
fprintf(stderr, "\nEnvironment Variables\n");
fprintf(stderr, optsUsage);
exit(0);
break;
}
if (strncmp("xdcpath", argv[i] + 2, 7) == 0) {
String src;
if (argv[i][9] == '\0') {
i++;
if (i >= argc) {
fprintf(stderr, usage, progName);
exit(1);
}
src = argv[i];
}
else {
src = argv[i] + 10;
}
xdcPathDef = (String)malloc(strlen(src) + 32);
if (xdcPathDef == NULL) {
fprintf(stderr, "%s: out of memory\n", progName);
exit(1);
}
sprintf(xdcPathDef, "XDCPATH=%s", src);
makeArgv[makeArgc++] = xdcPathDef;
break;
}
if (strncmp("xdc", argv[i] + 2, 3) == 0) {
/* unknown --xdc* option */
fprintf(stderr, usage, progName);
exit(1);
}
if (strncmp("ver", argv[i] + 2, 3) == 0) {
printVers(progName);
printf("\n");
}
/* FALL THROUGH */
}
default: {
makeArgv[makeArgc++] = argv[i];
break;
}
}
}
else {
if (strncmp("XDCPATH=", argv[i], 8) == 0) {
xdcPathDef = argv[i];
}
checkXdcOptions(argv[i]);
makeArgv[makeArgc++] = argv[i];
}
}
/* replace consecutive semicolons in XDCPATH by single semicolon */
if (xdcPathDef != NULL) {
for (i = 0, j = 0; xdcPathDef[i] != '\0'; i++) {
if (!((xdcPathDef[i] == ';') && (xdcPathDef[i + 1] == ';'))) {
xdcPathDef[j] = xdcPathDef[i];
j++;
}
}
xdcPathDef[j] = '\0';
}
/* now "range check" the environment settings */
checkXdcOptions(NULL);
/* if we can't find make in XDCROOT/bin, try alternatives */
if (access(makeArgv[0], 00) != 0) {
findMake(makeArgv[0], MAXNAME);
}
/* set PATH in environment before executing or displaying command */
envp = genEnvp(root, envp);
/* if verbose flag is set, display the commands to be executed */
if (nflag == TRUE || verbose >= 1) {
if (verbose >= 2) {
for (i = 0; envp[i] != NULL; i++) {
printf("%s\n", envp[i]);
}
printf("\n");
}
/* display the make command */
for (i = 0; i < makeArgc; i++) {
if (i > 0 && strpbrk(makeArgv[i], " \t;") != NULL) {
printf("\"%s\" ", makeArgv[i]);
}
else {
printf("%s ", makeArgv[i]);
}
}
printf("\n");
fflush(stdout);
}
if (nflag == FALSE) {
/* execute make command */
if ((status = XUTL_run(makeArgv[0], makeArgv, envp))) {
fprintf(stderr, "%s: can't execute '%s' ", progName, makeArgv[0]);
perror("because");
}
}
/* if the exec failed, return its error status */
return (status);
}
/*
* ======== checkXdcOptions ========
*/
static void checkXdcOptions(String arg)
{
String opts = NULL;
static Bool checked = FALSE;
if (checked) {
return;
}
if (arg == NULL) {
opts = getenv("XDCOPTIONS");
}
else if (strncmp("XDCOPTIONS=", arg, 11) == 0) {
opts = arg + 11;
checked = TRUE;
}
if (opts != NULL) {
Char *tok = strtok(opts, "-tdgvq \t\n\r");
if (tok != NULL) {
fprintf(stderr,
"%s: Warning: unknown setting for XDCOPTIONS (='%s')\n",
progName, opts);
fprintf(stderr, optsUsage);
}
}
}
/*
* ======== d2u ========
* Convert DOS path string into unix path string
*/
static Void d2u(String buf)
{
Char *cp;
for (cp = buf; *cp != '\0'; cp++) {
if (*cp == '\\') {
*cp = '/';
}
}
}
/*
* ======== findMake ========
*/
static Void findMake(Char *buffer, Uns max)
{
String path, tmp;
String tools, mach;
Int n;
String names[] = {
#if defined(xdc_target__os_Windows)
"gmake.exe", "gnumake.exe", "make.exe"
#else
"gmake", "gnumake", "make"
#endif
};
# define MAXEXE 16 /* MAXEXE > max string len in names[] */
/* look in XDCROOT first (to support alternative installations) */
if ((strlen(root) + MAXEXE) > max) {
return;
}
for (n = 0; n < (sizeof(names) / sizeof(String)); n++) {
sprintf(buffer, "%s" DIRSTR "%s", root, names[n]);
if (access(buffer, 00) == 0) {
return;
}
}
/* if TOOLS is defined, try iliad tree and the tools */
if ((tools = getenv("TOOLS")) != NULL && (mach = getenv("_M")) != NULL) {
sprintf(buffer, "%s" DIRSTR "%s", root, LMAKE);
if (access(buffer, 00) == 0) {
return;
}
else {
if ((strlen(tools) + strlen(mach) + MAXEXE + 8) > max) {
return;
}
for (n = 0; n < (sizeof(names) / sizeof(String)); n++) {
sprintf(buffer, "%s" DIRSTR "bin%s" DIRSTR "%s",
tools, mach, names[n]);
if (access(buffer, 00) == 0) {
return;
}
}
}
}
/* if we still can't find it, try the user's path */
if ((path = getenv("PATH")) != NULL
|| (path = getenv("Path")) != NULL) {
for (n = 0; n < (sizeof(names) / sizeof(String)); n++) {
if ((tmp = findFile(names[n], path)) != NULL) {
strcpy(buffer, tmp);
return;
}
}
}
/* last ditch effort: let OS try to find gnumake */
strcpy(buffer, "gnumake");
}
/*
* ======== findFile ========
*/
static String findFile(String file, String path)
{
static Char nameBuf[MAXNAME + 1];
String pathBuf = NULL;
String tmp;
SizeT len;
/* if the nameBuf is too small we fail */
if (file == NULL || (len = strlen(file)) > MAXNAME) {
return (NULL);
}
/* if file is a full path name, test it unadorned */
if (file[0] == DIRSTR[0] || file[1] == ':') {
if (isFile(nameBuf)) {
strcpy(nameBuf, file);
return (nameBuf);
}
}
if (path == NULL) {
return (NULL);
}
/* otherwise, try every prefix in path */
if ((pathBuf = (Char *)malloc(strlen(path) + 1)) != NULL) {
strcpy(pathBuf, path);
tmp = strtok(pathBuf, PATHSTR);
for (; tmp != NULL; tmp = strtok(NULL, PATHSTR)) {
if ((len + 1 + strlen(tmp)) <= MAXNAME) {
sprintf(nameBuf, "%s%s%s", tmp, DIRSTR, file);
if (isFile(nameBuf)) {
free(pathBuf);
return (nameBuf);
}
}
}
free(pathBuf);
}
return (NULL);
}
/*
* ======== genEnvp ========
* Generates environment for build tools:
* o redefine XDCROOT and XDCPATH as necessary
* o Add root to the beginning of PATH environment variable to ensure
* that our build tools are used within make.
* o remove CLASSPATH from environment to avoid in appropriate
* versions of Java or Java classes.
* o remove ENV to prevent shell from executing commands in the
* file named by $ENV for every shell use by gmake. It is for
* performance purposes only.
* o remove MAKEFLAGS to prevent xdc's make from reading make options
* set by a make calling xdc; e.g., the silent flag will prevent
* XDCOPTIONS=v from doing what is expected.
* o remove MAKELEVEL to prevent xdc's make from getting confused
* by a make calling xdc; e.g., a non-zero MAKELEVEL triggers
* the "print directories" feature (unless explicitly disabled)
*/
static char **genEnvp(String root, char *envp[])
{
Int i, j;
Int envc;
char **newEnvp = NULL;
String tmp;
/* clone envp so we don't mess with the C runtime's copy */
for (envc = i = 0; envp[i] != NULL; i++) {
envc++;
}
if ((newEnvp = malloc((envc + MAXNEW + 1) * sizeof(String))) == NULL) {
fprintf(stderr, "%s: out of memory\n", progName);
exit(1);
}
memcpy(newEnvp, envp, envc * sizeof(String));
newEnvp[envc] = NULL;
envp = newEnvp;
/* re-define selected environment variables */
for (i = 0; envp[i] != NULL; i++) {
/* redefine XDCROOT (if necessary) */
if (strncmp("XDCROOT=", envp[i], 8) == 0) {
envp[i] = rootDef;
if (nflag) {
printSetEnv(envp[i]);
}
}
else if (xdcPathDef != NULL && strncmp("XDCPATH=", envp[i], 8) == 0) {
/* we need to put XDCPATH in the environment because GNU make
* does not set the environment for commands run via $(shell ...)
* and we want all such commands to see the path specified on
* the command line
*/
envp[i] = xdcPathDef;
xdcPathDef = NULL;
if (nflag) {
printSetEnv(envp[i]);
}
}
else {
/* redefine PATH */
String prefix[] = {"PATH=", "Path=", "path="};
for (j = 0; j < (sizeof(prefix) / sizeof(String)); j++) {
if (strncmp(prefix[j], envp[i], strlen(prefix[j])) == 0) {
String path;
String mach;
SizeT len = strlen(envp[i]) + strlen(root) + 32;
if ((path = (String)malloc(len)) == NULL) {
fprintf(stderr, "%s: out of memory\n", progName);
exit(1);
}
if ((mach = getenv("_M")) != NULL) {
sprintf(path, "%s" DIRSTR "bin%s", root, mach);
if (access(path, 00) != 0) {
mach = "";
}
}
else {
mach = "";
}
/* add $XDCROOT/bin$_M to end of existing path */
sprintf(path, "%s" PATHSTR "%s" DIRSTR "bin%s",
envp[i], root, mach);
envp[i] = path;
if (nflag) {
printSetEnv(envp[i]);
}
}
}
}
}
/* remove undesirable environment variables */
for (envc = i = 0; envp[i] != NULL; i++) {
String removeTab[] = {
"CLASSPATH=",
"ENV=",
"MAKELEVEL=", "MAKEFLAGS="
};
for (j = 0; j < (sizeof(removeTab) / sizeof(String)); j++) {
if (strncmp(removeTab[j], envp[i], strlen(removeTab[j])) == 0) {
if (nflag) {
printSetEnv(removeTab[j]);
}
break;
}
}
/* if envp[i] is not in the undesirable list, add it to the env */
if (j >= (sizeof(removeTab) / sizeof(String))) {
envp[envc++] = envp[i];
}
}
/* add XDCPATH,xdc definition */
tmp = getenv("XDCPATH");
if (tmp != NULL) {
String envDef;
if ((envDef = malloc(strlen(tmp) * sizeof (char) + 80)) == NULL) {
fprintf(stderr, "%s: out of memory\n", progName);
exit(1);
}
sprintf(envDef, "XDCPATH,xdc=%s", tmp);
d2u(envDef);
newEnvp[envc++] = envDef;
if (nflag) {
printSetEnv(envDef);
}
}
/* add XDCPATH definition, if it's not already in the environment */
if (xdcPathDef != NULL) {
/* we need to put XDCPATH in the environment because GNU make
* does not set the environment for commands run via $(shell ...)
*/
newEnvp[envc++] = xdcPathDef;
if (nflag) {
printSetEnv(xdcPathDef);
}
}
/* NULL terminate and return new environment array */
newEnvp[envc] = NULL;
return (newEnvp);
}
#if 0
/*
* ======== getHostName ========
*/
static String getHostName(Void)
{
static Char name[MAXNAME + 1];
#if defined(xdc_target__os_Windows)
static Bool init = FALSE;
if (init == FALSE) {
WSADATA wsaData;
init = TRUE;
if ( WSAStartup( MAKEWORD( 1, 1 ), &wsaData) != 0 ) {
/* we could not find a usable WinSock DLL. */
return("");
}
}
#endif
if (gethostname(name, MAXNAME) != 0) {
return("");
}
name[MAXNAME] = '\0';
return (name);
}
#endif
/*
* ======== getRepo ========
* Update root by stripping the package directories from the end.
*
* Returns a pointer to the first character of the last directory
* containing the package; e.g.,
*/
static String getRepo(String root, String pname)
{
Char *cp;
String token;
cp = root + strlen(root) - 1;
do {
/* get next package token to match */
token = strrchr(pname, '.');
if (token == NULL) {
token = pname;
}
else {
token++;
}
/* strip trailing directory characters */
while (cp > root && (*cp == '/' || *cp == '\\')) {
*cp-- = '\0';
}
/* find the start of the last directory in root */
while (cp > root && (*cp != '/' && *cp != '\\')) {
cp--;
}
if (strcmp(cp + 1, token) != 0) {
return (NULL); /* package name and directory names don't match */
}
/* remove token from root and pname */
*cp = '\0';
if (token != pname) {
token[-1] = '\0'; /* -1 needed to remove leading '.' */
}
} while (token != pname);
/* strip trailing directory characters */
while (cp > root && (*cp == '/' || *cp == '\\')) {
*cp-- = '\0';
}
/* find the start of the repository in root */
while (cp > root && (*cp != '/' && *cp != '\\')) {
cp--;
}
return (cp);
}
/*
* ======== getRoot ========
* Return the installation directory of the XDCtools
*
* This executable can be run from one of two places:
* 1. XDCROOT
* 2. XDCROOT/<some_repository>/<some_package>
*
* To determine the XDCROOT we first locate the directory containing
* this executable. If this directory is the package providing this
* executable (e.g., xdc.services.host.bin), XDCROOT is the directory
* containing this package's repository; otherwise, XDCROOT is the
* directory containing this executable.
*
* Warning: this function uses rootDef as a scratch buffer.
*/
static String getRoot(String progName)
{
String pname;
String root;
/* find where this executable lives */
if ((root = XUTL_getProgPath(progName)) == NULL) {
fprintf(stderr,
"%s: can't determine XDCROOT: %s\n", progName,
XUTL_getLastErrorString());
exit(1);
}
/* as an optimization, first check for default root/$(XDCREPO) */
sprintf(rootDef, "%s%c" XDCREPO, root, DIRSTR[0]);
if (XUTL_isDir(rootDef)) {
return (root);
}
/* check to see if root is the base of a package */
if ((pname = XUTL_getPackageName(root, FALSE)) != NULL) {
Char *cp;
/* make a copy of root; so getRepo can modify it */
rootDef[strlen(root)] = '\0';
/* strip <some_repository>/<some_package> from the copy of root */
if ((cp = getRepo(rootDef, pname)) != NULL) {
/* if getRepo succeeds, apply the changes to root */
root[strlen(rootDef)] = '\0';
/* extract non-default repository name; redefine repoName */
repoName = root + (cp - rootDef);
*repoName++ = '\0';
}
}
if (pname != NULL) {
#if 0
printf("xdc: pkg name %s, root = %s, repo = %s\n",
pname, root, repoName);
#endif
free(pname);
}
return (root);
}
/*
* ======== isFile ========
* Return TRUE iff name exists and is not a directory
*/
static Bool isFile(String name)
{
struct stat buf;
if (stat(name, &buf) == 0 && !S_ISDIR(buf.st_mode)) {
return (TRUE);
}
return (FALSE);
}
/*
* ======== printSetEnv ========
*/
static Void printSetEnv(String env)
{
printf("set %s\n", env);
}
/*
* ======== printVers ========
*/
#define _NAME_ "xdc"
#define _DATE_ __DATE__
#define _CSUM_ "0"
#include "../ident.c"
static Void printVers(String progName)
{
fprintf(stderr, "%s: version %s, %s\n", progName,
__VERS + 8, __DATE); /* "used" to prevent compiler warnings */
}