add directory study

This commit is contained in:
gohigh
2024-02-19 00:25:23 -05:00
parent b1306b38b1
commit f3774e2f8c
4001 changed files with 2285787 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
# Makefile for make! (Minix PC)
CFLAGS = -Dunix -DMINIXPC
OBJS = check.s input.s macro.s main.s make.s reader.s rules.s
make : $(OBJS)
$(CC) -i -o make $(OBJS)
clean:
@rm -f *.s *.bak make core
$(OBJS): h.h

View File

@@ -0,0 +1,12 @@
# Makefile for make! (Minix ST)
CFLAGS = -O -Dunix
OBJS = check.o input.o macro.o main.o \
make.o reader.o rules.o
make : $(OBJS)
$(CC) -o make $(OBJS)
chmem =20000 make
$(OBJS): h.h

View File

@@ -0,0 +1,128 @@
/*************************************************************************
*
* m a k e : c h e c k . c
*
* debugging stuff: Check structures for make.
*========================================================================
* Edition history
*
* # Date Comments By
* --- -------- ---------------------------------------------------- ---
* 1 ?? ??
* 2 23.08.89 adapted to new name tree structure RAL
* 3 30.08.89 indention changed PSH,RAL
* 4 06.09.89 prt output redirected to stdout RAL
* ------------ Version 2.0 released ------------------------------- RAL
*
*************************************************************************/
#include "h.h"
/*
* Prints out the structures as defined in memory. Good for check
* that you make file does what you want (and for debugging make).
*/
void prt()
{
register struct name *np;
register struct depend *dp;
register struct line *lp;
register struct cmd *cp;
register struct macro *mp;
register int i;
for (mp = macrohead; mp; mp = mp->m_next)
printf("%s = %s\n", mp->m_name, mp->m_val);
putchar('\n');
for (i = 0; i <= maxsuffarray ; i++)
for (np = suffparray[i]->n_next; np; np = np->n_next)
{
if (np->n_flag & N_DOUBLE)
printf("%s::\n", np->n_name);
else
printf("%s:\n", np->n_name);
if (np == firstname)
printf("(MAIN NAME)\n");
for (lp = np->n_line; lp; lp = lp->l_next)
{
putchar(':');
for (dp = lp->l_dep; dp; dp = dp->d_next)
printf(" %s", dp->d_name->n_name);
putchar('\n');
for (cp = lp->l_cmd; cp; cp = cp->c_next)
#ifdef os9
printf("- %s\n", cp->c_cmd);
#else
printf("-\t%s\n", cp->c_cmd);
#endif
putchar('\n');
}
putchar('\n');
}
}
/*
* Recursive routine that does the actual checking.
*/
void check(np)
struct name *np;
{
register struct depend *dp;
register struct line *lp;
if (np->n_flag & N_MARK)
fatal("Circular dependency from %s", np->n_name,0);
np->n_flag |= N_MARK;
for (lp = np->n_line; lp; lp = lp->l_next)
for (dp = lp->l_dep; dp; dp = dp->d_next)
check(dp->d_name);
np->n_flag &= ~N_MARK;
}
/*
* Look for circular dependancies.
* ie.
* a: b
* b: a
* is a circular dep
*/
void circh()
{
register struct name *np;
register int i;
for (i = 0; i <= maxsuffarray ; i++)
for (np = suffparray[i]->n_next; np; np = np->n_next)
check(np);
}
/*
* Check the target .PRECIOUS, and mark its dependentd as precious
*/
void precious()
{
register struct depend *dp;
register struct line *lp;
register struct name *np;
if (!((np = newname(".PRECIOUS"))->n_flag & N_TARG))
return;
for (lp = np->n_line; lp; lp = lp->l_next)
for (dp = lp->l_dep; dp; dp = dp->d_next)
dp->d_name->n_flag |= N_PREC;
}

View File

@@ -0,0 +1,341 @@
/*************************************************************************
*
* m a k e : h . h
*
* include file for make
*========================================================================
* Edition history
*
* # Date Comments By
* --- -------- ---------------------------------------------------- ---
* 1 ?? ??
* 2 23.08.89 LZ increased,N_EXISTS added,suffix as macro added RAL
* 3 30.08.89 macro flags added, indention changed PSH,RAL
* 4 03.09.89 fixed LZ eliminated, struct str added,... RAL
* 5 06.09.89 TABCHAR,M_MAKE added RAL
* 6 09.09.89 tos support added, EXTERN,INIT,PARMS added PHH,RAL
* 7 17.09.89 __STDC__ added, make1 decl. fixed , N_EXEC added RAL
* ------------ Version 2.0 released ------------------------------- RAL
*
*************************************************************************/
#ifdef unix
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <time.h>
#include <utime.h>
#endif
#ifdef eon
#include <sys/stat.h>
#include <sys/err.h>
#endif
#ifdef os9
#include <time.h>
#include <os9.h>
#include <modes.h>
#include <direct.h>
#include <errno.h>
#endif
#ifdef tos
struct DOSTIME {short time,date; }; /* time structure of TOS */
#ifdef LATTICE
#include <error.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <osbind.h>
#endif LATTICE
#ifdef TURBO
#include <tos.h>
#include <errno.h>
#include <string.h>
#endif TURBO
#endif tos
#include <ctype.h>
#include <stdio.h>
#ifdef eon
#define MNOENT ER_NOTF
#else
#define MNOENT ENOENT
#endif
#ifndef uchar
#ifdef os9
#define uchar char
#define void int
#define fputc putc
#else
#define uchar unsigned char
#endif
#endif
#define bool uchar
#ifndef time_t
#define time_t long
#endif
#define TRUE (1)
#define FALSE (0)
#define max(a,b) ((a)>(b)?(a):(b))
#ifdef unix
#define DEFN1 "makefile"
#define DEFN2 "Makefile"
#endif
#ifdef eon
#define DEFN1 "makefile"
#define DEFN2 "Makefile"
#endif
#ifdef tos
#define DEFN1 "makefile."
#define DEFN2 (char *)0
#endif
#ifdef os9
#define DEFN1 "makefile"
#define DEFN2 (char *)0
#endif
#ifdef os9
#define TABCHAR ' '
#else
#define TABCHAR '\t'
#endif
#define LZ1 (2048) /* Initial input/expand string size */
#define LZ2 (256) /* Initial input/expand string size */
/*
* A name. This represents a file, either to be made, or existant
*/
struct name
{
struct name *n_next; /* Next in the list of names */
char *n_name; /* Called */
struct line *n_line; /* Dependencies */
time_t n_time; /* Modify time of this name */
uchar n_flag; /* Info about the name */
};
#define N_MARK 0x01 /* For cycle check */
#define N_DONE 0x02 /* Name looked at */
#define N_TARG 0x04 /* Name is a target */
#define N_PREC 0x08 /* Target is precious */
#define N_DOUBLE 0x10 /* Double colon target */
#define N_EXISTS 0x20 /* File exists */
#define N_ERROR 0x40 /* Error occured */
#define N_EXEC 0x80 /* Commands executed */
/*
* Definition of a target line.
*/
struct line
{
struct line *l_next; /* Next line (for ::) */
struct depend *l_dep; /* Dependents for this line */
struct cmd *l_cmd; /* Commands for this line */
};
/*
* List of dependents for a line
*/
struct depend
{
struct depend *d_next; /* Next dependent */
struct name *d_name; /* Name of dependent */
};
/*
* Commands for a line
*/
struct cmd
{
struct cmd *c_next; /* Next command line */
char *c_cmd; /* Command line */
};
/*
* Macro storage
*/
struct macro
{
struct macro *m_next; /* Next variable */
char *m_name; /* Called ... */
char *m_val; /* Its value */
uchar m_flag; /* Infinite loop check */
};
#define M_MARK 0x01 /* for infinite loop check */
#define M_OVERRIDE 0x02 /* command-line override */
#define M_MAKE 0x04 /* for MAKE macro */
/*
* String
*/
struct str
{
char **ptr; /* ptr to real ptr. to string */
int len; /* length of string */
int pos; /* position */
};
/* Declaration, definition & initialization of variables */
#ifndef EXTERN
#define EXTERN extern
#endif
#ifndef INIT
#define INIT(x)
#endif
extern int errno;
extern char **environ;
EXTERN char *myname;
EXTERN bool domake INIT(TRUE); /* Go through the motions option */
EXTERN bool ignore INIT(FALSE); /* Ignore exit status option */
EXTERN bool conterr INIT(FALSE); /* continue on errors */
EXTERN bool silent INIT(FALSE); /* Silent option */
EXTERN bool print INIT(FALSE); /* Print debuging information */
EXTERN bool rules INIT(TRUE); /* Use inbuilt rules */
EXTERN bool dotouch INIT(FALSE); /* Touch files instead of making */
EXTERN bool quest INIT(FALSE); /* Question up-to-dateness of file */
EXTERN bool useenv INIT(FALSE); /* Env. macro def. overwrite makefile def.*/
EXTERN bool dbginfo INIT(FALSE); /* Print lot of debugging information */
EXTERN bool ambigmac INIT(FALSE); /* guess undef. ambiguous macros (*,<) */
EXTERN struct name *firstname;
EXTERN char *str1;
EXTERN char *str2;
EXTERN struct str str1s;
EXTERN struct str str2s;
EXTERN struct name **suffparray; /* ptr. to array of ptrs. to name chains */
EXTERN int sizesuffarray INIT(20); /* size of suffarray */
EXTERN int maxsuffarray INIT(0); /* last used entry in suffarray */
EXTERN struct macro *macrohead;
EXTERN bool expmake; /* TRUE if $(MAKE) has been expanded */
EXTERN int lineno;
#ifdef tos
#ifdef LATTICE
EXTERN int _mneed INIT(60000); /* VERY important for TOS with LATTICE C*/
#endif LATTICE
#endif tos
#ifdef eon
#define MEMSPACE (16384)
EXTERN unsigned memspace = MEMSPACE;
#endif
/* Defines function declarations for all functions */
#ifdef __STDC__
#define CONST const
#define LINT_ARGS
#else
#define CONST /* */
#endif
#ifndef PARMS
#ifdef LINT_ARGS
#define PARMS(x) x
#else
#define PARMS(x) ()
#endif
#endif
/*
:.,$s/(PARMS\(.*\));/PARMS\1;/
*/
extern time_t time PARMS(( time_t *));
extern char *ctime PARMS (( CONST time_t *));
extern char *getenv PARMS (( CONST char *));
extern char *fgets PARMS (( char *, int, FILE *));
extern char *strchr PARMS (( CONST char *, int));
extern char *strrchr PARMS (( CONST char *, int));
#ifndef __STDC__
extern char *malloc PARMS (( unsigned));
extern char *realloc PARMS (( char *, unsigned)); /* OS9 ? */
#else
extern void *malloc PARMS (( unsigned));
extern void *realloc PARMS (( void *, unsigned)); /* OS9 ? */
#endif
/* main.c */
void main PARMS (( int, char **));
void setoption PARMS ((char));
void usage PARMS (());
void fatal PARMS (( char *, char *, int));
/* check.c */
void prt PARMS (());
void check PARMS (( struct name *));
void circh PARMS (());
void precious PARMS (());
/* input.c */
void init PARMS (());
void strrealloc PARMS (( struct str *));
struct name *newname PARMS (( char *));
struct name *testname PARMS (( char *));
struct depend *newdep PARMS (( struct name *, struct depend *));
struct cmd *newcmd PARMS (( char *, struct cmd *));
void newline PARMS (( struct name *, struct depend *, struct cmd *, int));
void input PARMS (( FILE *));
/* macro.c */
struct macro *getmp PARMS (( char *));
char *getmacro PARMS (( char *));
struct macro *setmacro PARMS (( char *, char *));
void setDFmacro PARMS (( char *, char *));
void doexp PARMS (( struct str *, char *));
void expand PARMS (( struct str *));
/* make.c */
int dosh PARMS (( char *, char *));
void docmds1 PARMS (( struct name *, struct line *));
void docmds PARMS (( struct name *));
#ifdef tos
int Tosexec PARMS (( char *));
time_t mstonix PARMS (( struct DOSTIME *));
#endif
#ifdef os9
void getmdate PARMS (( int, struct sgtbuf *));
time_t cnvtime PARMS (( struct sgtbuf *));
void time PARMS (( time_t *));
#endif
void modtime PARMS (( struct name *));
void touch PARMS (( struct name *));
int make PARMS (( struct name *, int));
void make1 PARMS (( struct name *, struct line *, struct depend *,char *, char *));
void implmacros PARMS (( struct name *, struct line *, char **,char **));
void dbgprint PARMS (( int, struct name *, char *));
/* reader.c */
void error PARMS (( char *, char *));
bool getline PARMS (( struct str *, FILE *));
char *gettok PARMS (( register char **));
/* rules.c */
bool dyndep PARMS (( struct name *, char **, char **));
void makerules PARMS (());
/*
* Return a pointer to the suffix of a name
*/
#define suffix(name) strrchr(name,(int)'.')
EXTERN int _ctypech;
#define mylower(x) (islower(_ctypech=(x)) ? _ctypech :tolower(_ctypech))
#define myupper(x) (isupper(_ctypech=(x)) ? _ctypech :toupper(_ctypech))

View File

@@ -0,0 +1,401 @@
/*************************************************************************
*
* m a k e : i n p u t . c
*
* Parse a makefile
*========================================================================
* Edition history
*
* # Date Comments By
* --- -------- ---------------------------------------------------- ---
* 1 ?? ??
* 2 23.08.89 new name tree structure introduced to speed up make,
* testname introduced to shrink the memory usage RAL
* 3 30.08.89 indention changed PSH,RAL
* 4 03.09.89 fixed LZ eliminated RAL
* 5 06.09.89 ; command added RAL
* ------------ Version 2.0 released ------------------------------- RAL
*
*************************************************************************/
#include "h.h"
static struct name *lastrrp;
static struct name *freerp = (struct name *)NULL;
void init()
{
if( (suffparray = (struct name **) malloc( sizesuffarray *
sizeof(struct name *))) == (struct name **) NULL)
fatal("No memory for suffarray",(char *)0,0);
if ((*suffparray = (struct name *)malloc(sizeof (struct name)))
== (struct name *)0)
fatal("No memory for name",(char *)0,0);
(*suffparray)->n_next = (struct name *)0;
if ((str1 = malloc(LZ1)) == (char *)0)
fatal("No memory for str1",(char *)0,0);
str1s.ptr = &str1;
str1s.len = LZ1;
if ((str2 = malloc(LZ2)) == (char *)0)
fatal("No memory for str2",(char *)0,0);
str2s.ptr = &str2;
str2s.len = LZ2;
}
void strrealloc(strs)
struct str *strs;
{
strs->len *= 2;
if( (*strs->ptr = realloc( *strs->ptr, strs->len)) == (char *) NULL)
fatal("No memory for string reallocation",(char *)0,0);
}
/*
* Intern a name. Return a pointer to the name struct
*/
struct name *newname(name)
char *name;
{
register struct name *rp;
register struct name *rrp;
register char *cp;
register int i;
register char *suff; /* ptr. to suffix in current name */
register struct name **sp; /* ptr. to ptr. to chain of names */
if ( (suff = suffix(name)) != (char *)NULL) {
for (i = 1, sp = suffparray, sp++;
i <= maxsuffarray && strcmp(suff, (*sp)->n_name) != 0;
sp++,i++);
if (i > maxsuffarray) {
if ( i >= sizesuffarray) { /* must realloc suffarray */
sizesuffarray *= 2;
if( (suffparray = (struct name **) realloc((char *) suffparray,
sizesuffarray * sizeof(struct name *))) == (struct name **) NULL)
fatal("No memory for suffarray",(char *)0,0);
}
maxsuffarray++;
sp = &suffparray[i];
if ((*sp = (struct name *)malloc(sizeof (struct name)))
== (struct name *)0)
fatal("No memory for name",(char *)0,0);
(*sp)->n_next = (struct name *)0;
if ((cp = malloc(strlen(suff)+1)) == (char *)0)
fatal("No memory for name",(char *)0,0);
strcpy(cp, suff);
(*sp)->n_name = cp;
}
}
else
sp = suffparray;
for ( rp = (*sp)->n_next, rrp = *sp; rp; rp = rp->n_next, rrp = rrp->n_next )
if (strcmp(name, rp->n_name) == 0) return rp;
if ( freerp == (struct name *)NULL) {
if ((rp = (struct name *)malloc(sizeof (struct name))) == (struct name *)0)
fatal("No memory for name",(char *)0,0);
}
else {
rp = freerp;
freerp = (struct name *)NULL;
}
rrp->n_next = rp;
rp->n_next = (struct name *)0;
if ((cp = malloc(strlen(name)+1)) == (char *)0)
fatal("No memory for name",(char *)0,0);
strcpy(cp, name);
rp->n_name = cp;
rp->n_line = (struct line *)0;
rp->n_time = (time_t)0;
rp->n_flag = 0;
lastrrp = rrp;
return rp;
}
/*
* Test a name.
* If the name already exists return the ptr. to its name structure.
* Else if the file exists 'intern' the name and return the ptr.
* Otherwise don't waste memory and return a NULL pointer
*/
struct name *testname(name)
char *name;
{
register struct name *rp;
lastrrp = (struct name *)NULL;
rp = newname( name);
if (rp->n_line || rp->n_flag & N_EXISTS)
return(rp);
modtime(rp);
if (rp->n_flag & N_EXISTS)
return(rp);
if (lastrrp != (struct name *)NULL) {
free (rp->n_name);
lastrrp->n_next = (struct name *)NULL;
freerp = rp;
}
return((struct name *)NULL);
}
/*
* Add a dependant to the end of the supplied list of dependants.
* Return the new head pointer for that list.
*/
struct depend *newdep(np, dp)
struct name *np;
struct depend *dp;
{
register struct depend *rp;
register struct depend *rrp;
if ((rp = (struct depend *)malloc(sizeof (struct depend)))
== (struct depend *)0)
fatal("No memory for dependant",(char *)0,0);
rp->d_next = (struct depend *)0;
rp->d_name = np;
if (dp == (struct depend *)0) return rp;
for (rrp = dp; rrp->d_next; rrp = rrp->d_next) ;
rrp->d_next = rp;
return dp;
}
/*
* Add a command to the end of the supplied list of commands.
* Return the new head pointer for that list.
*/
struct cmd *newcmd(str, cp)
char *str;
struct cmd *cp;
{
register struct cmd *rp;
register struct cmd *rrp;
register char *rcp;
if (rcp = strrchr(str, '\n')) *rcp = '\0'; /* Loose newline */
while (isspace(*str)) str++;
if (*str == '\0') return cp; /* If nothing left, the exit */
if ((rp = (struct cmd *)malloc(sizeof (struct cmd))) == (struct cmd *)0)
fatal("No memory for command",(char *)0,0);
rp->c_next = (struct cmd *)0;
if ((rcp = malloc(strlen(str)+1)) == (char *)0)
fatal("No memory for command",(char *)0,0);
strcpy(rcp, str);
rp->c_cmd = rcp;
if (cp == (struct cmd *)0) return rp;
for (rrp = cp; rrp->c_next; rrp = rrp->c_next) ;
rrp->c_next = rp;
return cp;
}
/*
* Add a new 'line' of stuff to a target. This check to see
* if commands already exist for the target. If flag is set,
* the line is a double colon target.
*
* Kludges:
* i) If the new name begins with a '.', and there are no dependents,
* then the target must cease to be a target. This is for .SUFFIXES.
* ii) If the new name begins with a '.', with no dependents and has
* commands, then replace the current commands. This is for
* redefining commands for a default rule.
* Neither of these free the space used by dependents or commands,
* since they could be used by another target.
*/
void newline(np, dp, cp, flag)
struct name *np;
struct depend *dp;
struct cmd *cp;
int flag;
{
bool hascmds = FALSE; /* Target has commands */
register struct line *rp;
register struct line *rrp;
/* Handle the .SUFFIXES case */
if (np->n_name[0] == '.' && !dp && !cp) {
for (rp = np->n_line; rp; rp = rrp) {
rrp = rp->l_next;
free(rp);
}
np->n_line = (struct line *)0;
np->n_flag &= ~N_TARG;
return;
}
/* This loop must happen since rrp is used later. */
for ( rp = np->n_line, rrp = (struct line *)0; rp; rrp = rp, rp = rp->l_next)
if (rp->l_cmd) hascmds = TRUE;
if (hascmds && cp && !(np->n_flag & N_DOUBLE))
/* Handle the implicit rules redefinition case */
if (np->n_name[0] == '.' && dp == (struct depend *)0) {
np->n_line->l_cmd = cp;
return;
}
else
error("Commands defined twice for target %s", np->n_name);
if (np->n_flag & N_TARG)
if (!(np->n_flag & N_DOUBLE) != !flag) /* like xor */
error("Inconsistent rules for target %s", np->n_name);
if ((rp = (struct line *)malloc(sizeof (struct line))) == (struct line *)0)
fatal("No memory for line",(char *)0,0);
rp->l_next = (struct line *)0;
rp->l_dep = dp;
rp->l_cmd = cp;
if (rrp)
rrp->l_next = rp;
else
np->n_line = rp;
np->n_flag |= N_TARG;
if (flag) np->n_flag |= N_DOUBLE;
}
/*
* Parse input from the makefile, and construct a tree structure
* of it.
*/
void input(fd)
FILE *fd;
{
char *p; /* General */
char *q;
register char *a;
struct name *np;
struct depend *dp;
struct cmd *cp;
bool dbl;
if (getline(&str1s, fd)) return; /* Read the first line */
for(;;) {
if (*str1 == TABCHAR) /* Rules without targets */
error("Rules not allowed here",(char *)0);
p = str1;
while (isspace(*p)) p++; /* Find first target */
while (((q = strchr(p, '=')) != (char *)0) &&
(p != q) && (q[-1] == '\\')) /* Find value */
{
a = q - 1; /* Del \ chr; move rest back */
p = q;
while(*a++ = *q++)
;
}
if (q != (char *)0) {
*q++ = '\0'; /* Separate name and val */
while (isspace(*q))
q++;
if (p = strrchr(q, '\n'))
*p = '\0';
p = str1;
if ((a = gettok(&p)) == (char *)0)
error("No macro name",(char *)0);
setmacro(a, q);
if (getline(&str1s, fd))
return;
continue;
}
/* Search for commands on target line --- do not expand them ! */
q = str1;
cp = (struct cmd *)0;
if ((a = strchr(q, ';')) != (char *)0) {
*a++ = '\0'; /* Separate dependents and commands */
if ( a) cp = newcmd(a, cp);
}
expand(&str1s);
p = str1;
while (((q = strchr(p, ':')) != (char *)0) &&
(p != q) && (q[-1] == '\\')) /* Find dependents */
{
a = q - 1; /* Del \ chr; move rest back */
p = q;
while(*a++ = *q++) ;
}
if (q == (char *)0)
error("No targets provided",(char *)0);
*q++ = '\0'; /* Separate targets and dependents */
if (*q == ':') { /* Double colon */
dbl = 1;
q++;
}
else
dbl = 0;
for (dp = (struct depend *)0; ((p = gettok(&q)) != (char *)0);)
/* get list of dep's */
{
np = newname(p); /* Intern name */
dp = newdep(np, dp); /* Add to dep list */
}
*((q = str1) + strlen(str1) + 1) = '\0';
/* Need two nulls for gettok (Remember separation) */
if (getline(&str2s, fd) == FALSE) { /* Get commands */
while (*str2 == TABCHAR) {
cp = newcmd(&str2[0], cp);
if (getline(&str2s, fd))
break;
}
}
while ((p = gettok(&q)) != (char *)0) /* Get list of targ's */
{
np = newname(p); /* Intern name */
newline(np, dp, cp, dbl);
if (!firstname && p[0] != '.')
firstname = np;
}
if (feof(fd)) /* EOF? */
return;
while (strlen(str2) >= str1s.len) strrealloc(&str1s);
strcpy(str1, str2);
}
}

View File

@@ -0,0 +1,200 @@
/*************************************************************************
*
* m a k e : m a c r o . c
*
* Macro control for make
*========================================================================
* Edition history
*
* # Date Comments By
* --- -------- ---------------------------------------------------- ---
* 1 ?? ??
* 2 23.08.89 Error message corrected RAL
* 3 30.08.89 macro flags added, indention ch. PSH,RAL
* 4 03.09.89 fixed LZ eliminated, doexp(...) changed RAL
* 5 06.09.89 M_MAKE added, setDFmacro added RAL
* 6 20.09.89 work around for Minix PC ACK bug BE,RAL
* ------------ Version 2.0 released ------------------------------- RAL
*
*************************************************************************/
#include "h.h"
static char buf[256];
struct macro *getmp(name)
char *name;
{
register struct macro *rp;
for (rp = macrohead; rp; rp = rp->m_next)
if (strcmp(name, rp->m_name) == 0)
return rp;
return (struct macro *)0;
}
char *getmacro(name)
char *name;
{
struct macro *mp;
if (mp = getmp(name))
return mp->m_val;
/* else*/
return "";
}
struct macro *setmacro(name, val)
char *name;
char *val;
{
register struct macro *rp;
register char *cp;
/* Replace macro definition if it exists */
for (rp = macrohead; rp; rp = rp->m_next)
if (strcmp(name, rp->m_name) == 0) {
if(rp->m_flag & M_OVERRIDE) return rp; /* mustn't change */
free(rp->m_val); /* Free space from old */
break;
}
if (!rp) /* If not defined, allocate space for new */
{
if ((rp = (struct macro *)malloc(sizeof (struct macro)))
== (struct macro *)0)
fatal("No memory for macro",(char *)0,0);
rp->m_next = macrohead;
macrohead = rp;
rp->m_flag = FALSE;
if ((cp = malloc(strlen(name)+1)) == (char *)0)
fatal("No memory for macro",(char *)0,0);
strcpy(cp, name);
rp->m_name = cp;
}
if ((cp = malloc(strlen(val)+1)) == (char *)0)
fatal("No memory for macro",(char *)0,0);
strcpy(cp, val); /* Copy in new value */
rp->m_val = cp;
return rp;
}
void setDFmacro(name, val)
char *name;
char *val;
{
char *c,*tmp;
int len;
static char filename[]="@F";
static char dirname[] ="@D";
setmacro(name,val);
*filename = *name;
*dirname = *name;
/* Null string -- not defined macro */
if ( !(*val)) {
setmacro(filename,"");
setmacro(dirname,"");
return;
}
if (!(c = strrchr(val,(int)'/'))) {
setmacro(filename,val);
setmacro(dirname,"./");
return;
}
setmacro(filename,c+1);
len = c - val + 1;
if((tmp = malloc(len + 1)) == (char *) 0)
fatal("No memory for tmp",(char *)0,0);
strncpy(tmp,val,len);
tmp[len] = '\0';
setmacro(dirname,tmp);
free(tmp);
return;
}
/*
* Do the dirty work for expand
*/
void doexp(to, from)
struct str *to;
char *from;
{
register char *rp;
register char *p;
char *q;
struct macro *mp;
int temp; /* work-around for ACK bug (PC)*/
rp = from;
temp= to->pos;
p = &(*to->ptr)[temp];
while (*rp) {
if (*rp != '$') {
*p++ = *rp++;
to->pos++;
}
else {
q = buf;
if (*++rp == '{')
while (*++rp && *rp != '}')
*q++ = *rp;
else if (*rp == '(')
while (*++rp && *rp != ')')
*q++ = *rp;
else if (!*rp) {
*p++ = '$';
to->pos++;
break;
}
else
*q++ = *rp;
*q = '\0';
if (*rp)
rp++;
if (!(mp = getmp(buf)))
mp = setmacro(buf, "");
if (mp->m_flag & M_MARK)
fatal("Infinitely recursive macro %s", mp->m_name,0);
mp->m_flag |= M_MARK;
if ( mp->m_flag & M_MAKE) expmake = TRUE;
doexp(to, mp->m_val);
temp = to->pos;
p = &(*to->ptr)[temp];
mp->m_flag &= ~M_MARK;
}
if (to->pos >= to->len) {
strrealloc (to);
temp = to->pos;
p = &(*to->ptr)[temp];
}
}
*p = '\0';
}
/*
* Expand any macros in str.
*/
void expand(strs)
struct str *strs;
{
char *a;
if ((a = malloc(strlen(*strs->ptr)+1)) == (char *)0)
fatal("No memory for temporary string",(char *)0,0);
strcpy(a, *strs->ptr);
strs->pos = 0;
doexp(strs, a);
free(a);
}

View File

@@ -0,0 +1,289 @@
/*************************************************************************
*
* m a k e : m a i n . c
*
*========================================================================
* Edition history
*
* # Date Comments By
* --- -------- ---------------------------------------------------- ---
* 1 ?? ??
* 2 01.07.89 strcmp(makefile,..) only if makefile a valid ptr. RAL
* 3 23.08.89 initname() added RAL
* 4 30.08.89 argument parsing impr., indention ch., macro fl. add.PSH,RAL
* 5 03.09.89 k-option added, initname -> init changed RAL
* 6 06.09.89 environment, MAKEFLAGS, e,d,a options added, RAL
* 7 09.09.89 tos support added, fatal args added, fopen makefile PHH,RAL
* 8 17.09.89 setoptions fixed for __STDC__ RAL
* ------------ Version 2.0 released ------------------------------- RAL
*
*************************************************************************/
/*
* make:
*
* -a try to guess undefined ambiguous macros (*,<)
* -d print debugging info
* -e environment macro def. overwrite makefile def.
* -f makefile name
* -i ignore exit status
* -k continue on errors
* -n pretend to make
* -p print all macros & targets
* -q question up-to-dateness of target. Return exit status 1 if not
* -r don't not use inbuilt rules
* -s make silently
* -t touch files instead of making them
* -m Change memory requirements (EON only)
*/
#define EXTERN
#define INIT(x) = x
#define INITARRAY
#include "h.h"
static char version[]= "2.0";
static char *makefile; /* The make file */
static FILE *ifd; /* Input file desciptor */
static char *ptrmakeflags;
static char makeflags[] = "MAKEFLAGS= ";
/* there must be enough 'space' for all possible flags ! */
void main(argc, argv)
int argc;
char **argv;
{
register char *p; /* For argument processing */
int estat = 0; /* For question */
register struct name *np;
struct macro *mp;
int targc; /* temporary for multiple scans */
char **targv;
char **nargv; /* for removing items from argv */
char **envp; /* enivironment ptr */
ptrmakeflags = &makeflags[10];
myname = (argc-- < 1) ? "make" : *argv++;
#ifdef tos
myname = "Make";
#endif
targc = argc;
targv = nargv = argv;
while (targc--) {
if((p = strchr(*targv, '=')) != (char *)NULL) {
*p = '\0';
mp = setmacro(*targv, p + 1);
mp->m_flag |= M_OVERRIDE;
--argc;
} else
*nargv++ = *targv;
++targv;
}
targc = argc;
targv = nargv = argv;
while (targc--) {
if (**targv == '-') {
--argc;
p = *targv++;
while (*++p != '\0') {
switch(mylower(*p)) {
case 'f': /* Alternate file name */
if (*++p == '\0') {
--argc;
if (targc-- == 0)
usage();
p = *targv++;
}
makefile = p;
goto end_of_args;
#ifdef eon
case 'm': /* Change space requirements */
if (*++p == '\0') {
--argc;
if (targc-- <= 0)
usage();
p = *targv++;
}
memspace = atoi(p);
goto end_of_args;
#endif
default :
setoption(*p);
break;
}
}
end_of_args:;
} else
*nargv++ = *targv++;
}
/* evaluate and update environment MAKEFLAGS */
if((p =getenv("MAKEFLAGS")) != (char *)0)
while(*p) setoption(*p++);
for( p = ptrmakeflags; !isspace((int)*p); p++) ;
*p = '\0';
putenv(makeflags);
#ifdef eon
if (initalloc(memspace) == 0xffff) /* Must get memory for alloc */
fatal("Cannot initalloc memory",(char *)0,0);
#endif
if (makefile && strcmp(makefile, "-") == 0) /* use stdin as makefile */
ifd = stdin;
else if (!makefile) { /* If no file, then use default */
if ((ifd = fopen(DEFN1, "r")) == (FILE *)0) {
if (errno != MNOENT || !DEFN2)
fatal("Can't open %s; error %02x", DEFN1, errno);
else if ((ifd = fopen(DEFN2, "r")) == (FILE *)0)
fatal("Can't open %s; error %02x", DEFN2, errno);
}
}
else if ((ifd = fopen(makefile, "r")) == (FILE *)0)
fatal("Can't open %s; error %2x", makefile, errno);
init();
makerules();
mp = setmacro("MAKE", myname);
mp->m_flag |= M_MAKE;
setmacro("$", "$");
/* set environment macros */
envp = environ; /* get actual environment ptr. */
while (*envp) {
if((p = strchr(*envp, '=')) != (char *)NULL) {
*p = '\0';
mp = setmacro(*envp, p + 1);
*p = '=';
if (useenv) mp->m_flag |= M_OVERRIDE;
} else
fatal("invalid environment: %s",*envp,0);
++envp;
}
input(ifd); /* Input all the gunga */
fclose(ifd); /* Finished with makefile */
lineno = 0; /* Any calls to error now print no line number */
if (print)
prt(); /* Print out structures */
np = newname(".SILENT");
if (np->n_flag & N_TARG) silent = TRUE;
np = newname(".IGNORE");
if (np->n_flag & N_TARG) ignore = TRUE;
precious();
if (!firstname)
fatal("No targets defined",(char *)0,0);
circh(); /* Check circles in target definitions */
if (!argc)
estat = make(firstname, 0);
else
while (argc--) {
estat |= make(newname(*argv++), 0);
}
if (quest)
exit(estat);
else
exit(0);
}
#ifdef __STDC__
void setoption(char option)
#else
void setoption(option)
char option;
#endif
{
register char *c;
option = mylower(option);
switch(option) {
case 'n': /* Pretend mode */
domake = FALSE;
break;
case 'i': /* Ignore fault mode */
ignore = TRUE;
break;
case 'k': /* Continue on errror */
conterr = TRUE;
break;
case 's': /* Silent about commands */
silent = TRUE;
break;
case 'p':
print = TRUE;
break;
case 'r':
rules = FALSE;
break;
case 't':
dotouch = TRUE;
break;
case 'q':
quest = TRUE;
break;
case 'e':
useenv = TRUE;
break;
case 'd':
dbginfo = TRUE;
break;
case 'a':
ambigmac = TRUE;
break;
default: /* Wrong option */
usage();
}
for( c = ptrmakeflags; !isspace((int)*c); c++)
if ( *c == option) return;
*c = option;
}
void usage()
{
fprintf(stderr, "Syntax: %s [{options | macro=val | target}]\n", myname);
fprintf(stderr, "Function: maintaining computer programs V%s\n",version);
fprintf(stderr, "Options : -a : try to guess undefined ambiguous macros (*,<)\n");
fprintf(stderr, " -d : print debugging information\n");
fprintf(stderr, " -e : environment macro def. overwrite makefile def.\n");
fprintf(stderr, " -f filename : makefile name (default: makefile, Makefile)\n");
fprintf(stderr, " -i : ignore exit status of executed commands\n");
fprintf(stderr, " -k : continue with unrelated branches on errors\n");
fprintf(stderr, " -n : pretend to make\n");
fprintf(stderr, " -p : print all macros & targets\n");
fprintf(stderr, " -q : question up-to-dateness of target\n");
fprintf(stderr, " -r : don't use inbuilt rules\n");
fprintf(stderr, " -s : make silently\n");
fprintf(stderr, " -t : touch files instead of making them\n");
fprintf(stderr, "Environment: MAKEFLAGS\n");
exit(1);
}
void fatal(msg, a1, a2)
char *msg;
char *a1;
int a2;
{
fprintf(stderr, "%s: ", myname);
fprintf(stderr, msg, a1, a2);
fputc('\n', stderr);
exit(1);
}

View File

@@ -0,0 +1,127 @@
/*************************************************************************
*
* m a k e : r e a d e r . c
*
* Read in makefile
*========================================================================
* Edition history
*
* # Date Comments By
* --- -------- ---------------------------------------------------- ---
* 1 ?? ??
* 2 23.08.89 cast to NULL added RAL
* 3 30.08.89 indention changed PSH,RAL
* 4 03.09.89 fixed LZ eliminated RAL
* ------------ Version 2.0 released ------------------------------- RAL
*
*************************************************************************/
#include "h.h"
/*
* Syntax error handler. Print message, with line number, and exits.
*/
void error(msg, a1)
char *msg;
char *a1;
{
fprintf(stderr, "%s: ", myname);
fprintf(stderr, msg, a1);
if (lineno) fprintf(stderr, " near line %d", lineno);
fputc('\n', stderr);
exit(1);
}
/*
* Read a line into the supplied string. Remove
* comments, ignore blank lines. Deal with quoted (\) #, and
* quoted newlines. If EOF return TRUE.
*/
bool getline(strs, fd)
struct str *strs;
FILE *fd;
{
register char *p;
char *q;
int tmppos;
strs->pos = 0;
for (;;) {
if (strs->pos >= strs->len -128)
strrealloc(strs);
if (fgets(*strs->ptr + strs->pos, strs->len - strs->pos, fd) == (char *)0)
return TRUE; /* EOF */
lineno++;
while ((p = strchr(*strs->ptr + strs->pos, '\n')) == (char *)0) {
tmppos = strs->len -1;
strrealloc(strs);
if (fgets(*strs->ptr + tmppos, strs->len - tmppos, fd) == (char *)0)
error("Unexpected EOF",(char *)0);
}
if (p[-1] == '\\')
{
p[-1] = '\n';
strs->pos = p - *strs->ptr;
continue;
}
p = *strs->ptr;
while (((q = strchr(p, '#')) != (char *)0) &&
(p != q) && (q[-1] == '\\'))
{
char *a;
a = q - 1; /* Del \ chr; move rest back */
p = q;
while (*a++ = *q++)
;
}
if (q != (char *)0)
{
q[0] = '\n';
q[1] = '\0';
}
p = *strs->ptr;
while (isspace(*p)) /* Checking for blank */
p++;
if (*p != '\0')
return FALSE;
strs->pos = 0;
}
}
/*
* Get a word from the current line, surounded by white space.
* return a pointer to it. String returned has no white spaces
* in it.
*/
char *gettok(ptr)
register char **ptr;
{
register char *p;
while (isspace(**ptr)) /* Skip spaces */
(*ptr)++;
if (**ptr == '\0') /* Nothing after spaces */
return ((char *)NULL);
p = *ptr; /* word starts here */
while ((**ptr != '\0') && (!isspace(**ptr)))
(*ptr)++; /* Find end of word */
*(*ptr)++ = '\0'; /* Terminate it */
return(p);
}

View File

@@ -0,0 +1,325 @@
/*************************************************************************
*
* m a k e : r u l e s . c
*
* Control of the implicit suffix rules
*========================================================================
* Edition history
*
* # Date Comments By
* --- -------- ---------------------------------------------------- ---
* 1 ?? ??
* 2 01.07.89 $<,$* bugs fixed, impl. r. ending in expl. r. added RAL
* 3 23.08.89 suffix as macro, testname intr., algorithem to find
* source dep. made more intelligent (see Readme3) RAL
* 4 30.08.89 indention changed PSH,RAL
* 5 03.09.89 fixed LZ eliminated RAL
* 6 07.09.89 rules of type '.c', .DEFAULT added, dep. search impr.RAL
* ------------ Version 2.0 released ------------------------------- RAL
*
*************************************************************************/
#include "h.h"
/*
* Dynamic dependency. This routine applies the suffis rules
* to try and find a source and a set of rules for a missing
* target. If found, np is made into a target with the implicit
* source name, and rules. Returns TRUE if np was made into
* a target.
*/
bool dyndep(np,pbasename,pinputname)
struct name *np;
char **pbasename; /* Name without suffix */
char **pinputname;
{
register char *p;
register char *q;
register char *suff; /* Old suffix */
struct name *op = (struct name *)0,*optmp; /* New dependent */
struct name *sp; /* Suffix */
struct line *lp,*nlp;
struct depend *dp,*ndp;
struct cmd *cmdp;
char *newsuff;
bool depexists = FALSE;
p = str1;
q = np->n_name;
suff = suffix(q);
while (*q && (q < suff || !suff)) *p++ = *q++;
*p = '\0';
if ((*pbasename = malloc(strlen(str1)+1)) == (char *)0 )
fatal("No memory for basename",(char *)0,0);
strcpy(*pbasename,str1);
if ( !suff) suff = p - str1 + *pbasename; /* set suffix to nullstring */
if (!((sp = newname(".SUFFIXES"))->n_flag & N_TARG)) return FALSE;
/* search all .SUFFIXES lines */
for (lp = sp->n_line; lp; lp = lp->l_next)
/* try all suffixes */
for (dp = lp->l_dep; dp; dp = dp->d_next) {
/* compose implicit rule name (.c.o)...*/
newsuff = dp->d_name->n_name;
while (strlen(suff)+strlen(newsuff)+1 >= str1s.len) strrealloc(&str1s);
p = str1;
q = newsuff;
while (*p++ = *q++) ;
p--;
q = suff;
while (*p++ = *q++) ;
/* look if the rule exists */
sp = newname(str1);
if (sp->n_flag & N_TARG) {
/* compose resulting dependency name */
while (strlen(*pbasename) + strlen(newsuff)+1 >= str1s.len)
strrealloc(&str1s);
q = *pbasename;
p = str1;
while (*p++ = *q++) ;
p--;
q = newsuff;
while (*p++ = *q++) ;
/* test if dependency file or an explicit rule exists */
if ((optmp= testname(str1)) != (struct name *)0) {
/* store first possible dependency as default */
if ( op == (struct name *)0) {
op = optmp;
cmdp = sp->n_line->l_cmd;
}
/* check if testname is an explicit dependency */
for ( nlp=np->n_line; nlp; nlp=nlp->l_next) {
for( ndp=nlp->l_dep; ndp; ndp=ndp->d_next) {
if ( strcmp( ndp->d_name->n_name, str1) == 0) {
op = optmp;
cmdp = sp->n_line->l_cmd;
ndp = (struct depend *) 0;
goto found2;
}
depexists = TRUE;
}
}
/* if no explicit dependencies : accept testname */
if (!depexists) goto found;
}
}
}
if ( op == (struct name *)0) {
if( np->n_flag & N_TARG) { /* DEFAULT handling */
if (!((sp = newname(".DEFAULT"))->n_flag & N_TARG)) return FALSE;
if (!(sp->n_line)) return FALSE;
cmdp = sp->n_line->l_cmd;
for ( nlp=np->n_line; nlp; nlp=nlp->l_next) {
if ( ndp=nlp->l_dep) {
op = ndp->d_name;
ndp = (struct depend *)0;
goto found2;
}
}
newline(np, (struct depend *)0, cmdp, 0);
*pinputname = (char *)0;
*pbasename = (char *)0;
return TRUE;
}
else return FALSE;
}
found:
ndp = newdep(op, (struct depend *)0);
found2:
newline(np, ndp, cmdp, 0);
*pinputname = op->n_name;
return TRUE;
}
/*
* Make the default rules
*/
void makerules()
{
struct cmd *cp;
struct name *np;
struct depend *dp;
#ifdef eon
setmacro("BDSCC", "asm");
/* setmacro("BDSCFLAGS", ""); */
cp = newcmd("$(BDSCC) $(BDSCFLAGS) -n $<", (struct cmd *)0);
np = newname(".c.o");
newline(np, (struct depend *)0, cp, 0);
setmacro("CC", "c");
setmacro("CFLAGS", "-O");
cp = newcmd("$(CC) $(CFLAGS) -c $<", (struct cmd *)0);
np = newname(".c.obj");
newline(np, (struct depend *)0, cp, 0);
setmacro("M80", "asm -n");
/* setmacro("M80FLAGS", ""); */
cp = newcmd("$(M80) $(M80FLAGS) $<", (struct cmd *)0);
np = newname(".mac.o");
newline(np, (struct depend *)0, cp, 0);
setmacro("AS", "zas");
/* setmacro("ASFLAGS", ""); */
cp = newcmd("$(ZAS) $(ASFLAGS) -o $@ $<", (struct cmd *)0);
np = newname(".as.obj");
newline(np, (struct depend *)0, cp, 0);
np = newname(".as");
dp = newdep(np, (struct depend *)0);
np = newname(".obj");
dp = newdep(np, dp);
np = newname(".c");
dp = newdep(np, dp);
np = newname(".o");
dp = newdep(np, dp);
np = newname(".mac");
dp = newdep(np, dp);
np = newname(".SUFFIXES");
newline(np, dp, (struct cmd *)0, 0);
#endif
#ifdef tos
#define unix
#endif
/*
* Some of the UNIX implicit rules
*/
#ifdef unix
setmacro("CC", "cc");
setmacro("CFLAGS", "-O");
#ifdef MINIXPC
cp = newcmd("$(CC) -S $(CFLAGS) $<", (struct cmd *)0);
np = newname(".c.s");
#else
cp = newcmd("$(CC) -c $(CFLAGS) $<", (struct cmd *)0);
np = newname(".c.o");
#endif MINIXPC
newline(np, (struct depend *)0, cp, 0);
#ifdef MINIXPC
cp = newcmd("$(CC) $(CFLAGS) -i -o $@ $<", (struct cmd *)0);
#else
cp = newcmd("$(CC) $(CFLAGS) -o $@ $<", (struct cmd *)0);
#endif MINIXPC
np = newname(".c");
newline(np, (struct depend *)0, cp, 0);
setmacro("AS", "as");
cp = newcmd("$(AS) -o $@ $<", (struct cmd *)0);
np = newname(".s.o");
newline(np, (struct depend *)0, cp, 0);
setmacro("YACC", "yacc");
/*setmacro("YFLAGS", ""); */
cp = newcmd("$(YACC) $(YFLAGS) $<", (struct cmd *)0);
cp = newcmd("mv y.tab.c $@", cp);
np = newname(".y.c");
newline(np, (struct depend *)0, cp, 0);
cp = newcmd("$(YACC) $(YFLAGS) $<", (struct cmd *)0);
#ifdef MINIXPC
cp = newcmd("$(CC) $(CFLAGS) -S y.tab.c", cp);
cp = newcmd("mv y.tab.s $@", cp);
np = newname(".y.s");
#else
cp = newcmd("$(CC) $(CFLAGS) -c y.tab.c", cp);
cp = newcmd("mv y.tab.o $@", cp);
np = newname(".y.o");
#endif MINIXPC
cp = newcmd("rm y.tab.c", cp);
newline(np, (struct depend *)0, cp, 0);
setmacro("FLEX", "flex");
cp = newcmd("$(FLEX) $(FLEX_FLAGS) $<", (struct cmd *)0);
cp = newcmd("mv lex.yy.c $@", cp);
np = newname(".l.c");
newline(np, (struct depend *)0, cp, 0);
cp = newcmd("$(FLEX) $(FLEX_FLAGS) $<", (struct cmd *)0);
#ifdef MINIXPC
cp = newcmd("$(CC) $(CFLAGS) -S lex.yy.s", cp);
cp = newcmd("mv lex.yy.s $@", cp);
np = newname(".l.s");
#else
cp = newcmd("$(CC) $(CFLAGS) -c lex.yy.c", cp);
cp = newcmd("mv lex.yy.o $@", cp);
np = newname(".l.o");
#endif MINIXPC
cp = newcmd("rm lex.yy.c", cp);
newline(np, (struct depend *)0, cp, 0);
np = newname(".o");
dp = newdep(np, (struct depend *)0);
np = newname(".s");
dp = newdep(np, dp);
np = newname(".c");
dp = newdep(np, dp);
np = newname(".y");
dp = newdep(np, dp);
np = newname(".l");
dp = newdep(np, dp);
np = newname(".SUFFIXES");
newline(np, dp, (struct cmd *)0, 0);
#endif unix
#ifdef os9
/*
* Fairlight use an enhanced version of the C sub-system.
* They have a specialised macro pre-processor.
*/
setmacro("CC", "cc");
setmacro("CFLAGS", "-z");
cp = newcmd("$(CC) $(CFLAGS) -r $<", (struct cmd *)0);
np = newname(".c.r");
newline(np, (struct depend *)0, cp, 0);
np = newname(".ca.r");
newline(np, (struct depend *)0, cp, 0);
np = newname(".a.r");
newline(np, (struct depend *)0, cp, 0);
np = newname(".o.r");
newline(np, (struct depend *)0, cp, 0);
np = newname(".mc.r");
newline(np, (struct depend *)0, cp, 0);
np = newname(".mca.r");
newline(np, (struct depend *)0, cp, 0);
np = newname(".ma.r");
newline(np, (struct depend *)0, cp, 0);
np = newname(".mo.r");
newline(np, (struct depend *)0, cp, 0);
np = newname(".r");
dp = newdep(np, (struct depend *)0);
np = newname(".mc");
dp = newdep(np, dp);
np = newname(".mca");
dp = newdep(np, dp);
np = newname(".c");
dp = newdep(np, dp);
np = newname(".ca");
dp = newdep(np, dp);
np = newname(".ma");
dp = newdep(np, dp);
np = newname(".mo");
dp = newdep(np, dp);
np = newname(".o");
dp = newdep(np, dp);
np = newname(".a");
dp = newdep(np, dp);
np = newname(".SUFFIXES");
newline(np, dp, (struct cmd *)0, 0);
#endif
}