4.4BSD/usr/src/contrib/mkmf/src/misc.c
/*
* Copyright (c) 1983, 1985, 1991, 1993 Peter J. Nicklin.
* Copyright (c) 1991, 1993 Version Technology.
* All Rights Reserved.
*
* $License: VT.1.1 $
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met: (1) Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer. (2) Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution. (3) All advertising materials mentioning
* features or use of this software must display the following
* acknowledgement: ``This product includes software developed by
* Version Technology.'' Neither the name of Version Technology nor
* the name of Peter J. Nicklin may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY VERSION TECHNOLOGY ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL VERSION TECHNOLOGY BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* Report problems and direct questions to nicklin@netcom.com
*
* $Header: misc.c,v 4.10 93/05/25 21:49:09 nicklin Exp $
*
* Author: Peter J. Nicklin
*/
#include <ctype.h>
#include <stdio.h>
#include <sys/types.h>
#include "Mkmf.h"
#include "config.h"
#include "dir.h"
#include "hash.h"
#include "macro.h"
#include "null.h"
#include "path.h"
#include "target.h"
#include "stringx.h"
#include "suffix.h"
#include "yesno.h"
/*
* answer() installs a line from stdin in the macro definition table.
* exit(1) is called if EOF, error, or out of memory.
*/
void
answer(mdefkey, mdefval)
char *mdefkey; /* macro definition key */
int mdefval; /* macro definition value */
{
extern HASH *MDEFTABLE; /* macro definition table */
char answerbuf[ANSWERBUFSIZE]; /* answer from stdin */
char *gets(); /* get a line from stdin */
HASHBLK *htinstall(); /* install hash table entry */
if (gets(answerbuf) == NULL)
exit(1);
if (*answerbuf != '\0')
if (htinstall(mdefkey, answerbuf, mdefval, MDEFTABLE) == NULL)
exit(1);
}
/*
* fastcopy() copies file to stream fp. Returns integer YES if successful,
* otherwise NO.
*/
fastcopy(filename, ofp)
char *filename; /* file to be copied */
register FILE *ofp; /* output stream */
{
register int ifd; /* input file descriptor */
register int n; /* byte count */
char buf[BUFSIZ]; /* I/O buffer */
if ((ifd = OPEN(filename, 0, 0644)) == -1)
{
pperror("");
return(NO);
}
while ((n = read(ifd, buf, BUFSIZ)) > 0)
write(fileno(ofp), buf, n);
close(ifd);
return(YES);
}
/*
* findmf() locates the makefile to be edited. The type of makefile
* is returned in target. The pathname to the makefile is returned
* in mfpath. Returns YES if makefile or makefile template can be
* opened, otherwise NO.
*/
findmf(mfname, mfpath, target)
char *mfname; /* name of target makefile */
char *mfpath; /* path to target makefile */
TARGET *target; /* type of makefile target */
{
extern int CFLAG; /* makefile creation message */
int readmf(); /* read makefile */
int targettype; /* type of makefile requested */
void findmftemplate(); /* find makefile template */
targettype = target->type;
if (FILEXIST(mfname))
{
if (!FILEWRITE(mfname))
{
pperror(mfname);
target->type = VERROR;
return(NO);
}
if (readmf(mfname, target) == VERROR)
return(NO);
if (targettype != VUNKNOWN && targettype != target->type)
{
if (targettype == VPROGRAM)
{
warns("%s not a program makefile", mfname);
}
else if (targettype == VLIBRARY)
{
warns("%s not a library makefile", mfname);
}
else {
warns("%s: unknown makefile type", mfname);
}
return(NO);
}
strcpy(mfpath, mfname);
}
else {
target->type = (targettype == VLIBRARY) ? VLIBRARY : VPROGRAM;
findmftemplate(mfpath, target);
if (readmf(mfpath, target) == VERROR)
return(NO);
if (CFLAG == YES)
warn2("creating %s from %s", mfname, mfpath);
}
return(YES);
}
/*
* findmftemplate() returns the pathname of a makefile template in mfpath.
*/
void
findmftemplate(mfpath, target)
char *mfpath; /* path to target makefile */
TARGET *target; /* type of makefile target */
{
extern char *MAKEFILE; /* makefile template name */
extern int FFLAG; /* makefile template pathname flag */
extern int LIBOBJ; /* load object file into library? */
char *cwp; /* current project pathname pointer */
char *getcwp(); /* get current project pathname */
char *mktname(); /* make template name */
char *pathcat(); /* pathname concatenation */
char tname[MAXNAMLEN+1]; /* template name */
if (FFLAG == YES)
{
strcpy(mfpath, MAKEFILE);
return;
}
strcpy(tname, MAKEFILE);
if (strrchr(tname, '.') == NULL)
switch (target->type)
{
case VPROGRAM:
mktname(tname, SPROGRAM);
break;
case VLIBRARY:
if (LIBOBJ == 1)
{
mktname(tname, SLIBRARY2);
}
else {
mktname(tname, SLIBRARY);
}
break;
}
cwp = getcwp();
if (cwp == NULL ||
!FILEXIST(pathcat(mfpath, pathcat(mfpath, cwp, MKMFLIB), tname)))
pathcat(mfpath, pathcat(mfpath, INSTALLDIR, MKMFLIB), tname);
}
/*
* gettoken() copies the next token from token buffer to token. Returns a
* pointer to the first character after the token, or null upon reaching
* the end of the token buffer.
*/
char *
gettoken(token, tp)
register char *token; /* receiving token */
register char *tp; /* token buffer pointer */
{
while (isspace(*tp) && *tp != '\0')
tp++;
if (*tp == '\0')
{
*token = '\0';
return(NULL);
}
while (!isspace(*tp) && *tp != '\0')
*token++ = *tp++;
*token = '\0';
return(tp);
}
/*
* getoption() copies the next matching option from token buffer to token.
* Returns a pointer to the first character after the token, or null upon
* reaching the end of the token buffer.
*/
char *
getoption(token, tp, option)
register char *token; /* receiving token */
register char *tp; /* token buffer pointer */
register char *option; /* option leader string */
{
int optlen = strlen(option); /* option length */
if ((tp = gettoken(token, tp)) == NULL)
return(NULL);
/* skip non-matching options */
while (strncmp(token, option, optlen) != 0)
{
if ((tp = gettoken(token, tp)) == NULL)
{
return(NULL);
}
}
if (EQUAL(token, option))
tp = gettoken(token, tp); /* -X option */
else
(void) gettoken(token, token+optlen); /* -Xoption */
return(tp);
}
/*
* getpath() copies the next pathname from path buffer to path. Returns a
* pointer to the first character after the path, or null upon reaching
* the end of the path buffer.
*/
char *
getpath(path, pp)
register char *path; /* receiving path */
register char *pp; /* path buffer pointer */
{
while ((isspace(*pp) || *pp == ':') && *pp != '\0')
pp++;
if (*pp == '\0')
{
*path = '\0';
return(NULL);
}
while (!(isspace(*pp) || *pp == ':') && *pp != '\0')
*path++ = *pp++;
*path = '\0';
return(pp);
}
/*
* libobj() returns NO if the definition of the OBJS macro contains regular
* object file names, and YES if it contains $(LIBRARY)(objfile) file names
* (indicating that each object file should be inserted into a library
* immediately after compilation). Only the first line of the macro is
* scanned for $(LIBRARY).
*/
int
libobj(bp)
register char *bp; /* buffer pointer */
{
register char *sbp; /* save buffer pointer */
register char *mp; /* macro name pointer */
while (*bp++ != '=')
continue;
if (WHITESPACE(*bp))
bp++;
for (mp = DLIBRARY, sbp = bp; *mp == *bp && *mp != '\0'; mp++, bp++)
continue;
if (*mp == '\0')
return(YES);
for (mp = dLIBRARY, bp = sbp; *mp == *bp && *mp != '\0'; mp++, bp++)
continue;
if (*mp == '\0')
return(YES);
return(NO);
}
/*
* mktname() concatenates a suffix to a makefile template name. Returns
* name if successful, otherwise NULL.
*/
char *
mktname(base, suffix)
char *base; /* template basename */
char *suffix; /* template suffix */
{
if (strlen(base) + strlen(suffix) > MAXNAMLEN)
{
warn("makefile template name too long");
return(NULL);
}
else {
return(strcat(base, suffix));
}
}
/*
* nocore() places an "out of memory" error message on the standard error
* output stream stderr.
*/
nocore()
{
warn("out of memory");
}
/*
* putobj() converts a source file name to an object file name and then
* writes the file name to stream. Returns the length of the file name.
*/
putobj(s, stream)
register char *s; /* source file name */
register FILE *stream; /* output stream */
{
register int baselen = 0; /* length of object file basename */
register char *dot; /* pointer to suffix */
char *pathsep; /* pathname separator */
static int psfxlen = 0; /* length of object prefix & suffix */
extern int LIBOBJ; /* load object file into library? */
extern char OBJSFX[]; /* object file name suffix */
if (psfxlen == 0)
{
psfxlen = strlen(OBJSFX);
if (LIBOBJ) psfxlen += strlen(DLIBRARY) + 2;
}
if ((pathsep = strrchr(s, _PSC)) != NULL)
s = pathsep + 1;
dot = strrchr(s, '.');
if (LIBOBJ)
{
fprintf(stream, "%s(", DLIBRARY);
while (s != dot)
{
putc(*s++, stream);
baselen++;
}
fprintf(stream, "%s)", OBJSFX);
}
else {
while (s != dot)
{
putc(*s++, stream);
baselen++;
}
fprintf(stream, "%s", OBJSFX);
}
return(psfxlen+baselen);
}
/*
* readmf() reads a makefile and loads CFLAGS, FFLAGS, and SUFFIX definitions
* into the macro definition table if they do not already exist. Returns
* integer VLIBRARY, VPROGRAM, or VUNKNOWN according to the type of makefile,
* or VERROR if cannot open makefile.
*/
readmf(mfname, target)
char *mfname; /* name of makefile */
TARGET *target; /* type of makefile target */
{
register char *bp; /* buffer pointer */
extern char IOBUF[]; /* I/O buffer line */
extern HASH *MDEFTABLE; /* macro definition table */
extern int LIBOBJ; /* load object file into library? */
char *findmacro(); /* is the line a macro definition? */
char *findrule(); /* is the line a rule definition? */
char *getlin(); /* get a line from input stream */
char *getmacro(); /* get macro def from input stream */
char macrodef[MACRODEFSIZE]; /* macro definition buffer */
char macroname[MACRONAMSIZE]; /* macro name buffer */
char rulename[2*SUFFIXSIZE+3]; /* transformation rule name */
FILE *fopen(); /* open file */
FILE *fp; /* file pointer */
HASHBLK *htinstall(); /* install hash table entry */
HASHBLK *htlookup(); /* find hash table entry */
int libobj(); /* is object file loaded into library?*/
int storerule(); /* store transformation rule */
void purgcontinue(); /* get rid of continuation lines */
target->type = target->dest = VUNKNOWN;
if ((fp = fopen(mfname, "r")) == NULL)
{
pperror(mfname);
target->type = VERROR;
return(target->type);
}
while (getlin(fp) != NULL)
{
if (EQUAL(IOBUF, DEPENDMARK))
break;
for (bp = IOBUF; *bp == ' '; bp++)
continue;
if (findmacro(macroname, bp) != NULL)
{
if (EQUAL(macroname, MPROGRAM))
{
target->type = VPROGRAM;
}
else if (EQUAL(macroname, MLIBRARY))
{
target->type = VLIBRARY;
}
else if (EQUAL(macroname, MDESTDIR))
{
target->dest = VDESTDIR;
}
if (EQUAL(macroname, MOBJECTS))
{
if (libobj(bp) == YES)
LIBOBJ = 1;
purgcontinue;
}
/* does macro definition already exist? */
if (htlookup(macroname, MDEFTABLE) != NULL)
continue;
if (htinstall(macroname, getmacro(macrodef, fp),
VREADONLY, MDEFTABLE) == NULL)
{
fclose(fp);
return(NO);
}
}
else if (*bp == '.' && findrule(rulename, bp) != NULL)
{
if (storerule(rulename) == NO)
{
fclose(fp);
return(NO);
}
}
}
fclose(fp);
return(target->type);
}