/*
* defDirect.c
* $Id: defDirect.c,v 4.15 2007/07/04 20:51:11 bkorb Exp $
*
* Time-stamp: "2007-07-04 11:15:44 bkorb"
* Last Committed: $Date: 2007/07/04 20:51:11 $
*
* This module processes definition file directives.
*
* blocksort spacing=2 \
* output=defDirect-sorted.c \
* input=defDirect.c \
* pat='^/\*=directive' \
* start='^doDir_IGNORE' \
* trail='\+\+\+ End of Directives'
*
* This file is part of AutoGen.
* AutoGen copyright (c) 1992-2007 by Bruce Korb - all rights reserved
*
* AutoGen 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 3 of the License, or
* (at your option) any later version.
*
* AutoGen 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. If not, see .
*/
tSCC zNoEndif[] = "Definition error: in %s line %d, #endif not found\n";
tSCC zNoMatch[] = "Definition error: in %s line %d, "
"#%s no matching start/if directive\n";
tSCC zCheckList[] = "\n#";
static int ifdefLevel = 0;
static teDirectives
findDirective( char* pzDirName );
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* processDirective
*
* THIS IS THE ONLY EXTERNAL ENTRY POINT
*
* A directive character has been found.
* Decide what to do and return a pointer to the character
* where scanning is to resume.
*/
LOCAL char*
processDirective( char* pzScan )
{
const tDirTable* pTbl = dirTable;
char* pzDir;
char* pzEnd;
/*
* Search for the end of the #-directive.
* Replace "\\\n" sequences with " ".
*/
for (;;) {
pzEnd = strchr( pzScan, '\n' );
if (pzEnd == NULL) {
/*
* The end of the directive is the end of the string
*/
pzEnd = pzScan + strlen( pzScan );
break;
}
pCurCtx->lineNo++;
if (pzEnd[-1] != '\\') {
/*
* The end of the directive is the end of the line
* and the line has not been continued.
*/
*(pzEnd++) = NUL;
break;
}
/*
* Replace the escape-newline pair with spaces and
* find the next end of line
*/
pzEnd[-1] = pzEnd[0] = ' ';
}
/*
* Ignore ``#!'' as a comment, enabling a definition file to behave
* as a script that gets interpreted by autogen. :-)
*/
if (*pzScan == '!')
return pzEnd;
/*
* Find the start of the directive name
*/
while (isspace(*pzScan)) pzScan++;
pzDir = pzScan;
/*
* Find the *END* of the directive name
*/
while (ISNAMECHAR( *pzScan )) pzScan++;
/*
* IF there is anything that follows the name, ...
*/
if (*pzScan != NUL) {
/*
* IF something funny immediately follows the directive name,
* THEN we will ignore it completely.
*/
if (! isspace( *pzScan ))
return pzEnd;
/*
* Terminate the name being defined
* and find the start of anything else.
*/
*pzScan++ = NUL;
while (isspace(*pzScan)) pzScan++;
}
/*
* Trim off trailing white space
*/
{
char* pz = pzScan + strlen( pzScan );
while ((pz > pzScan) && isspace( pz[-1] )) pz--;
*pz = NUL;
}
pTbl = dirTable + (int)findDirective( pzDir );
return (*(pTbl->pDirProc))( pzScan, pzEnd );
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Figure out the index of a directive. We will return the directive
* count if it is a bogus name.
*/
static teDirectives
findDirective( char* pzDirName )
{
teDirectives res = (teDirectives)0;
const tDirTable* pTbl = dirTable;
do {
if ( (strneqvcmp( pzDirName, pTbl[res].pzDirName,
(int)pTbl[res].nameSize ) == 0)
&& ( isspace( pzDirName[ pTbl[res].nameSize ])
|| (pzDirName[ pTbl[res].nameSize ] == NUL) ) )
return res;
} while (++res < DIRECTIVE_CT);
{
char ch;
if (strlen( pzDirName ) > 32) {
ch = pzDirName[32];
pzDirName[32] = NUL;
} else {
ch = NUL;
}
fprintf( pfTrace, "WARNING: in %s on line %d unknown directive:\n"
"\t#%s\n", pCurCtx->pzCtxFname, pCurCtx->lineNo, pzDirName );
if (ch != NUL)
pzDirName[32] = ch;
}
return res;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Support routines for the directives
*
* skipToEndif
*
* Skip through the text to a matching "#endif". We do this when we
* have processed the allowable text (found an "#else" after
* accepting the preceeding text) or when encountering a "#if*def"
* while skipping a block of text due to a failed test.
*/
static char*
skipToEndif( char* pzStart )
{
char* pzScan = pzStart;
char* pzRet;
for (;;) {
/*
* 'pzScan' is pointing to the first character on a line.
* Check for a directive on the current line before scanning
* later lines.
*/
if (*pzScan == '#')
pzScan++;
else {
char* pz = strstr( pzScan, zCheckList );
if (pz == NULL)
AG_ABEND( aprf( zNoEndif, pCurCtx->pzCtxFname,
pCurCtx->lineNo ));
pzScan = pz + STRSIZE( zCheckList );
}
while (isspace( *pzScan )) pzScan++;
switch (findDirective( pzScan )) {
case DIR_ENDIF:
{
/*
* We found the endif we are interested in
*/
char* pz = strchr( pzScan, '\n' );
if (pz != NULL)
pzRet = pz+1;
else pzRet = pzScan + strlen( pzScan );
goto leave;
}
case DIR_IFDEF:
case DIR_IFNDEF:
/*
* We found a nested ifdef/ifndef
*/
pzScan = skipToEndif( pzScan );
break;
default:
/*
* We do not care what we found
*/
break; /* ignore it */
} /* switch (findDirective( pzScan )) */
}
leave:
while (pzStart < pzRet) {
if (*(pzStart++) == '\n')
pCurCtx->lineNo++;
}
return pzRet;
}
static char*
skipToEndmac( char* pzStart )
{
char* pzScan = pzStart;
char* pzRet;
for (;;) {
/*
* 'pzScan' is pointing to the first character on a line.
* Check for a directive on the current line before scanning
* later lines.
*/
if (*pzScan == '#')
pzScan++;
else {
char* pz = strstr( pzScan, zCheckList );
if (pz == NULL)
AG_ABEND( aprf( zNoEndif, pCurCtx->pzCtxFname,
pCurCtx->lineNo ));
pzScan = pz + STRSIZE( zCheckList );
}
while (isspace( *pzScan )) pzScan++;
if (findDirective( pzScan ) == DIR_ENDMAC) {
/*
* We found the endmac we are interested in
*/
char* pz = strchr( pzScan, '\n' );
if (pz != NULL)
pzRet = pz+1;
else pzRet = pzScan + strlen( pzScan );
break;
}
}
while (pzStart < pzRet) {
if (*(pzStart++) == '\n')
pCurCtx->lineNo++;
}
return pzRet;
}
/*
* skipToElseEnd
*
* Skip through the text to a matching "#endif" or "#else" or
* "#elif*def". We do this when we are skipping code due to a failed
* "#if*def" test.
*/
static char*
skipToElseEnd( char* pzStart )
{
char* pzScan = pzStart;
char* pzRet;
for (;;) {
/*
* 'pzScan' is pointing to the first character on a line.
* Check for a directive on the current line before scanning
* later lines.
*/
if (*pzScan == '#')
pzScan++;
else {
char* pz = strstr( pzScan, zCheckList );
if (pz == NULL)
AG_ABEND( aprf( zNoEndif, pCurCtx->pzCtxFname,
pCurCtx->lineNo ));
pzScan = pz + STRSIZE( zCheckList );
}
while (isspace( *pzScan )) pzScan++;
switch (findDirective( pzScan )) {
case DIR_ELSE:
/*
* We found an "else" directive for an "ifdef"/"ifndef"
* that we were skipping over. Start processing the text.
*/
ifdefLevel++;
/* FALLTHROUGH */
case DIR_ENDIF:
{
/*
* We reached the end of the "ifdef"/"ifndef" we were
* skipping (or we dropped in from above).
* Start processing the text.
*/
char* pz = strchr( pzScan, '\n' );
if (pz != NULL)
pzRet = pz+1;
else pzRet = pzScan + strlen( pzScan );
goto leave;
}
case DIR_IFDEF:
case DIR_IFNDEF:
/*
* We have found a nested "ifdef"/"ifndef".
* Call "skipToEndif()" to find *its* end, then
* resume looking for our own "endif" or "else".
*/
pzScan = skipToEndif( pzScan );
break;
default:
/*
* We either don't know what it is or we do not care.
*/
break;
} /* switch (findDirective( pzScan )) */
}
leave:
while (pzStart < pzRet) {
if (*(pzStart++) == '\n')
pCurCtx->lineNo++;
}
return pzRet;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Special routines for each directive. These routines are *ONLY*
* called from the table when the input is being processed.
* After this routine are either declarations or definitions of
* directive handling routines. The documentation for these routines
* is extracted from this file. See 'makedef.sh' for how it works.
* Each declared directive should have either a 'dummy:' section
* (if the directive is to be ignored) or a 'text:' section
* (if there is some form of implementation). If the directive
* needs or may take arguments (e.g. '#define'), then there should
* also be an 'arg:' section describing the argument(s).
*/
static char*
doDir_IGNORE( char* pzArg, char* pzScan )
{
return pzScan;
}
/*=directive assert
*
* arg: `shell-script` | (scheme-expr) |
*
* text:
* If the @code{shell-script} or @code{scheme-expr} do not yield @code{true}
* valued results, autogen will be aborted. If @code{} or
* nothing at all is provided, then this directive is ignored.
*
* When writing the shell script, remember this is on a preprocessing
* line. Multiple lines must be backslash continued and the result is a
* single long line. Separate multiple commands with semi-colons.
*
* The result is @code{false} (and fails) if the result is empty, the
* number zero, or a string that starts with the letters 'n' or 'f' ("no"
* or "false").
=*/
static void
check_assert_str( char const* pz, char const* pzArg )
{
static char const fmt[] = "#assert yielded \"%s\":\n\t`%s`";
while (isspace(*pz)) pz++;
if (isdigit(*pz)) {
if (atoi(pz) == 0)
AG_ABEND( aprf( fmt, "0 (zero)", pzArg ));
} else switch (*pz) {
case 'f': case 'F': case 'n': case 'N': case NUL:
AG_ABEND( aprf( fmt, pz, pzArg ));
}
}
static char*
doDir_assert( char* pzArg, char* pzScan )
{
switch (*pzArg) {
case '`':
{
char* pzS = pzArg+1;
char* pzR;
pzR = strrchr(pzS, '`');
if (pzR == NULL)
break; /* not a valid script */
*pzR = NUL;
pzS = runShell( (char const*)pzS );
check_assert_str( pzS, pzArg );
free(pzS);
break;
}
case '(':
{
SCM res = ag_scm_c_eval_string_from_file_line(
pzArg, pCurCtx->pzCtxFname, pCurCtx->lineNo );
tCC* pzR = resolveSCM( res );
check_assert_str( pzR, pzArg );
break;
}
default:
break;
}
return pzScan;
}
/*=directive define
*
* arg: name [ ]
*
* text:
* Will add the name to the define list as if it were a DEFINE program
* argument. Its value will be the first non-whitespace token following
* the name. Quotes are @strong{not} processed.
*
* After the definitions file has been processed, any remaining entries
* in the define list will be added to the environment.
=*/
static char*
doDir_define( char* pzArg, char* pzScan )
{
char* pzName = pzArg;
/*
* Skip any #defines that do not look reasonable
*/
if (! isalpha( *pzArg ))
return pzScan;
while (ISNAMECHAR( *pzArg )) pzArg++;
/*
* IF this is a macro definition (rather than a value def),
* THEN we will ignore it.
*/
if (*pzArg == '(')
return pzScan;
/*
* We have found the end of the name.
* IF there is no more data on the line,
* THEN we do not have space for the '=' required by PUTENV.
* Therefore, move the name back over the "#define"
* directive itself, giving us the space needed.
*/
if (! isspace( *pzArg )) {
char* pzS = pzName;
char* pzD = --pzName;
*pzArg = NUL;
while ((*(pzD++) = *(pzS++)) != NUL) ;
pzD[-1] = '=';
pzD[ 0] = NUL;
} else {
/*
* Otherwise, insert the '=' and move any data up against it.
* We only accept one name-type, space separated token.
* We are not ANSI-C. ;-)
*/
char* pz = pzArg+1;
*pzArg++ = '=';
while (isspace( *pz )) pz++;
for (;;) {
if ((*pzArg++ = *pz++) == NUL)
break;
if (! ISNAMECHAR( *pz )) {
*pzArg = NUL;
break;
}
}
}
SET_OPT_DEFINE( pzName );
return pzScan;
}
/*=directive elif
*
* text:
* This must follow an @code{#if}
* otherwise it will generate an error.
* It will be ignored.
=*/
static char*
doDir_elif( char* pzArg, char* pzScan )
{
tSCC z[] =
"`#elif' directive encountered out of context\n\tin %s on line %d\n";
AG_ABEND( aprf( z, pCurCtx->pzCtxFname, pCurCtx->lineNo ));
/* NOTREACHED */
return NULL;
}
/*=directive else
*
* text:
* This must follow an @code{#if}, @code{#ifdef} or @code{#ifndef}.
* If it follows the @code{#if}, then it will be ignored. Otherwise,
* it will change the processing state to the reverse of what it was.
=*/
static char*
doDir_else( char* pzArg, char* pzScan )
{
if (--ifdefLevel < 0)
AG_ABEND( aprf( zNoMatch, pCurCtx->pzCtxFname, pCurCtx->lineNo,
"else" ));
return skipToEndif( pzScan );
}
/*=directive endif
*
* text:
* This must follow an @code{#if}, @code{#ifdef} or @code{#ifndef}.
* In all cases, this will resume normal processing of text.
=*/
static char*
doDir_endif( char* pzArg, char* pzScan )
{
if (--ifdefLevel < 0)
AG_ABEND( aprf( zNoMatch, pCurCtx->pzCtxFname, pCurCtx->lineNo,
"endif" ));
return pzScan;
}
/*=directive endmac
*
* text:
* This terminates a "macdef", but must not ever be encountered directly.
=*/
static char*
doDir_endmac( char* pzArg, char* pzScan )
{
AG_ABEND( aprf( zNoMatch, pCurCtx->pzCtxFname, pCurCtx->lineNo,
"endmac" ));
/* NOTREACHED */
return NULL;
}
/*=directive endshell
*
* text:
* Ends the text processed by a command shell into autogen definitions.
=*/
static char*
doDir_endshell( char* pzArg, char* pzScan )
{
/*
* In actual practice, the '#endshell's must be consumed inside
* the 'doDir_shell()' procedure.
*/
AG_ABEND( aprf( zNoMatch, pCurCtx->pzCtxFname, pCurCtx->lineNo,
"endshell" ));
/* NOTREACHED */
return NULL;
}
/*=directive error
*
* arg: [ ]
*
* text:
* This directive will cause AutoGen to stop processing
* and exit with a status of EXIT_FAILURE.
=*/
static char*
doDir_error( char* pzArg, char* pzScan )
{
AG_ABEND( aprf( "#error directive -- in %s on line %d\n\t%s\n",
pCurCtx->pzCtxFname, pCurCtx->lineNo, pzArg ));
/* NOTREACHED */
return NULL;
}
/*=directive ident
*
* dummy: Ident directives are ignored.
=*/
/*=directive if
*
* arg: [ ]
*
* text:
* @code{#if} expressions are not analyzed. @strong{Everything} from here
* to the matching @code{#endif} is skipped.
=*/
static char*
doDir_if( char* pzArg, char* pzScan )
{
return skipToEndif( pzScan );
}
/*=directive ifdef
*
* arg: name-to-test
*
* text:
* The definitions that follow, up to the matching @code{#endif} will be
* processed only if there is a corresponding @code{-Dname} command line
* option or if a @code{#define} of that name has been previously encountered.
=*/
static char*
doDir_ifdef( char* pzArg, char* pzScan )
{
if (getDefine( pzArg, AG_FALSE ) == NULL)
return skipToElseEnd( pzScan );
ifdefLevel++;
return pzScan;
}
/*=directive ifndef
*
* arg: name-to-test
*
* text:
* The definitions that follow, up to the matching @code{#endif} will be
* processed only if there is @strong{not} a corresponding @code{-Dname}
* command line option or there was a canceling @code{-Uname} option.
=*/
static char*
doDir_ifndef( char* pzArg, char* pzScan )
{
if (getDefine( pzArg, AG_FALSE ) != NULL)
return skipToElseEnd( pzScan );
ifdefLevel++;
return pzScan;
}
/*=directive include
*
* arg: unadorned-file-name
*
* text:
* This directive will insert definitions from another file into
* the current collection. If the file name is adorned with
* double quotes or angle brackets (as in a C program), then the
* include is ignored.
=*/
static char*
doDir_include( char* pzArg, char* pzScan )
{
tSCC* apzSfx[] = { "def", NULL };
tScanCtx* pCtx;
size_t inclSize;
char zFullName[ AG_PATH_MAX + 1 ];
/*
* Ignore C-style includes. This allows "C" files to be processed
* for their "#define"s.
*/
if ((*pzArg == '"') || (*pzArg == '<'))
return pzScan;
pCurCtx->pzScan = pzScan;
if (! SUCCESSFUL(
findFile( pzArg, zFullName, apzSfx, pCurCtx->pzCtxFname ))) {
tSCC zFmt[] = "WARNING: cannot find `%s' definitions file\n";
fprintf( pfTrace, zFmt, pzArg );
return pzScan;
}
/*
* Make sure the specified file is a regular file and we can get
* the correct size for it.
*/
{
struct stat stbf;
if (stat( zFullName, &stbf ) != 0) {
fprintf( pfTrace, "WARNING %d (%s): cannot stat `%s' "
"for include\n", errno, strerror( errno ), zFullName );
return pzScan;
}
if (! S_ISREG( stbf.st_mode )) {
fprintf( pfTrace, "WARNING: `%s' must be regular file to "
"include\n", zFullName );
return pzScan;
}
inclSize = stbf.st_size;
if (outTime <= stbf.st_mtime)
outTime = stbf.st_mtime + 1;
}
if (inclSize == 0)
return pzScan;
/*
* Get the space for the output data and for context overhead.
* This is an extra allocation and copy, but easier than rewriting
* 'loadData()' for this special context.
*/
{
size_t sz = sizeof( tScanCtx ) + 4 + inclSize;
pCtx = (tScanCtx*)AGALOC( sz, "include def header" );
memset( (void*)pCtx, 0, sz );
pCtx->lineNo = 1;
}
/*
* Link it into the context stack
*/
pCtx->pCtx = pCurCtx;
pCurCtx = pCtx;
AGDUPSTR( pCtx->pzCtxFname, zFullName, "def file name" );
pCtx->pzScan =
pCtx->pzData =
pzScan = (char*)(pCtx + 1);
/*
* Read all the data. Usually in a single read, but loop
* in case multiple passes are required.
*/
{
FILE* fp = fopen( zFullName, "r" FOPEN_TEXT_FLAG );
char* pz = pzScan;
if (fp == NULL)
AG_ABEND( aprf( zCannot, errno, "open file", zFullName,
strerror( errno )));
do {
size_t rdct = fread((void*)pz, (size_t)1, inclSize, fp);
if (rdct == 0)
AG_ABEND( aprf( zCannot, errno, "read file", zFullName,
strerror( errno )));
pz += rdct;
inclSize -= rdct;
} while (inclSize > 0);
fclose( fp );
*pz = NUL;
}
return pzScan;
}
/*=directive let
*
* dummy: let directives are ignored.
=*/
/*=directive line
*
* text:
*
* Alters the current line number and/or file name. You may wish to
* use this directive if you extract definition source from other files.
* @command{getdefs} uses this mechanism so AutoGen will report the correct
* file and approximate line number of any errors found in extracted
* definitions.
=*/
static char*
doDir_line( char* pzArg, char* pzScan )
{
/*
* The sequence must be: #line "file-name-string"
*
* Start by scanning up to and extracting the line number.
*/
while (isspace( *pzArg )) pzArg++;
if (! isdigit( *pzArg ))
return pzScan;
pCurCtx->lineNo = strtol( pzArg, &pzArg, 0 );
/*
* Now extract the quoted file name string.
* We dup the string so it won't disappear on us.
*/
while (isspace( *pzArg )) pzArg++;
if (*(pzArg++) != '"')
return pzScan;
{
char* pz = strchr( pzArg, '"' );
if (pz == NULL)
return pzScan;
*pz = NUL;
}
AGDUPSTR( pCurCtx->pzCtxFname, pzArg, "#line file name" );
return pzScan;
}
/*=directive macdef
*
* text:
* This is a new AT&T research preprocessing directive. Basically, it is
* a multi-line #define that may include other preprocessing directives.
=*/
static char*
doDir_macdef( char* pzArg, char* pzScan )
{
return skipToEndmac( pzScan );
}
/*=directive option
*
* arg: opt-name [ ]
*
* text:
*
* This directive will pass the option name and associated text to the
* AutoOpts optionLoadLine routine (@pxref{libopts-optionLoadLine}). The
* option text may span multiple lines by continuing them with a backslash.
* The backslash/newline pair will be replaced with two space characters.
* This directive may be used to set a search path for locating template files
* For example, this:
*
* @example
* #option templ-dirs $ENVVAR/dirname
* @end example
* @noindent
* will direct autogen to use the @code{ENVVAR} environment variable to find
* a directory named @code{dirname} that (may) contain templates. Since these
* directories are searched in most recently supplied first order, search
* directories supplied in this way will be searched before any supplied on
* the command line.
=*/
static char*
doDir_option( char* pzArg, char* pzScan )
{
optionLoadLine( &autogenOptions, pzArg );
return pzScan;
}
/*=directive pragma
*
* dummy: pragma directives are ignored.
=*/
/*=directive shell
*
* text:
* Invokes @code{$SHELL} or @file{/bin/sh} on a script that should
* generate AutoGen definitions. It does this using the same server
* process that handles the back-quoted @code{`} text.
* @strong{CAUTION}@: let not your @code{$SHELL} be @code{csh}.
=*/
static char*
doDir_shell( char* pzArg, char* pzScan )
{
tSCC zShellText[] = "Computed Definitions";
tSCC zEndShell[] = "\n#endshell";
tScanCtx* pCtx;
char* pzText = pzScan;
/*
* The output time will always be the current time.
* The dynamic content is always current :)
*/
outTime = time( NULL );
/*
* IF there are no data after the '#shell' directive,
* THEN we won't write any data
* ELSE we have to find the end of the data.
*/
if (strncmp( pzText, zEndShell+1, STRSIZE( zEndShell )-1) == 0)
return pzScan;
{
char* pz = strstr( pzScan, zEndShell );
if (pz == NULL)
AG_ABEND( aprf("Missing #endshell after '#shell' in %s on line %d\n",
pCurCtx->pzCtxFname, pCurCtx->lineNo ));
while (pzScan < pz) {
if (*(pzScan++) == '\n') pCurCtx->lineNo++;
}
*pzScan = NUL;
}
/*
* Advance the scan pointer to the next line after '#endshell'
* IF there is no such line,
* THEN the scan will resume on a zero-length string.
*/
pzScan = strchr( pzScan + STRSIZE( zEndShell ), '\n' );
if (pzScan == NULL)
pzScan = (void*)zNil;
/*
* Save the scan pointer into the current context
*/
pCurCtx->pzScan = pzScan;
if (pzShellProgram == NULL)
pzShellProgram = getDefine( zShellEnv, AG_TRUE );
/*
* Run the shell command. The output text becomes the
* "file text" that is used for more definitions.
*/
pzText = runShell( pzText );
if ( (pzText == NULL)
|| (*pzText == NUL))
return pzScan;
/*
* Get the space for the output data and for context overhead.
* This is an extra allocation and copy, but easier than rewriting
* 'loadData()' for this special context.
*/
pCtx = (tScanCtx*)AGALOC( sizeof( tScanCtx ) + strlen( pzText ) + 4,
"shell output" );
/*
* Link the new scan data into the context stack
*/
pCtx->pCtx = pCurCtx;
pCurCtx = pCtx;
/*
* Set up the rest of the context structure
*/
AGDUPSTR( pCtx->pzCtxFname, zShellText, "shell text" );
pCtx->pzScan =
pCtx->pzData = (char*)(pCtx+1);
pCtx->lineNo = 0;
strcpy( pCtx->pzScan, pzText );
AGFREE( pzText );
return pCtx->pzScan;
}
/*=directive undef
*
* arg: name-to-undefine
*
* text:
* Will remove any entries from the define list
* that match the undef name pattern.
=*/
static char*
doDir_undef( char* pzArg, char* pzScan )
{
SET_OPT_UNDEFINE( pzArg );
return pzScan;
}
/*+++ End of Directives +++*/
/*
* Local Variables:
* mode: C
* c-file-style: "stroustrup"
* indent-tabs-mode: nil
* End:
* end of agen5/defDirect.c */