/*
* expFormat.c
*
* Time-stamp: "2007-07-04 11:18:40 bkorb"
* Last Committed: $Date: 2007/07/04 20:51:11 $
*
* $Id: expFormat.c,v 4.22 2007/07/04 20:51:11 bkorb Exp $
* This module implements formatting expression functions.
*
* 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 .
*/
static char const zGpl[] =
"%2$s%1$s is free software: you can redistribute it and/or modify it\n"
"%2$sunder the terms of the GNU General Public License as published by the\n"
"%2$sFree Software Foundation, either version 3 of the License, or\n"
"%2$s(at your option) any later version.\n%2$s\n"
"%2$s%1$s is distributed in the hope that it will be useful, but\n"
"%2$sWITHOUT ANY WARRANTY; without even the implied warranty of\n"
"%2$sMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
"%2$sSee the GNU General Public License for more details.\n%2$s\n"
"%2$sYou should have received a copy of the GNU General Public License along\n"
"%2$swith this program. If not, see .";
static char const zLgpl[] =
"%2$s%1$s is free software: you can redistribute it and/or modify it\n"
"%2$sunder the terms of the GNU Lesser General Public License as published\n"
"%2$sby the Free Software Foundation, either version 3 of the License, or\n"
"%2$s(at your option) any later version.\n%2$s\n"
"%2$s%1$s is distributed in the hope that it will be useful, but\n"
"%2$sWITHOUT ANY WARRANTY; without even the implied warranty of\n"
"%2$sMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
"%2$sSee the GNU Lesser General Public License for more details.\n%2$s\n"
"%2$sYou should have received a copy of the GNU Lesser General Public License\n"
"%2$salong with this program. If not, see .";
static char const zBsd[] =
"%2$s%1$s is free software copyrighted by %3$s.\n%2$s\n"
"%2$sRedistribution and use in source and binary forms, with or without\n"
"%2$smodification, are permitted provided that the following conditions\n"
"%2$sare met:\n"
"%2$s1. Redistributions of source code must retain the above copyright\n"
"%2$s notice, this list of conditions and the following disclaimer.\n"
"%2$s2. Redistributions in binary form must reproduce the above copyright\n"
"%2$s notice, this list of conditions and the following disclaimer in the\n"
"%2$s documentation and/or other materials provided with the distribution.\n"
"%2$s3. Neither the name ``%3$s'' nor the name of any other\n"
"%2$s contributor may be used to endorse or promote products derived\n"
"%2$s from this software without specific prior written permission.\n"
"%2$s\n"
"%2$s%1$s IS PROVIDED BY %3$s ``AS IS'' AND ANY EXPRESS\n"
"%2$sOR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n"
"%2$sWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
"%2$sARE DISCLAIMED. IN NO EVENT SHALL %3$s OR ANY OTHER CONTRIBUTORS\n"
"%2$sBE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n"
"%2$sCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n"
"%2$sSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR\n"
"%2$sBUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n"
"%2$sWHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n"
"%2$sOTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n"
"%2$sADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
static char const zDne1[] =
"%s -*- buffer-read-only: t -*- vi: set ro:\n"
"%s\n";
static char const zDne[] = "%6$s"
"%1$sDO NOT EDIT THIS FILE (%2$s)\n"
"%1$s\n"
"%1$sIt has been AutoGen-ed %3$s\n"
"%1$sFrom the definitions %4$s\n"
"%1$sand the template file %5$s";
static char const zDne2[] = "%6$s"
"%1$sEDIT THIS FILE WITH CAUTION (%2$s)\n"
"%1$s\n"
"%1$sIt has been AutoGen-ed %3$s\n"
"%1$sFrom the definitions %4$s\n"
"%1$sand the template file %5$s";
tSCC zOwnLen[] = "owner length";
tSCC zPfxLen[] = "prefix length";
tSCC zProgLen[] = "program name length";
tSCC zPfxMsg[] = "%s may not exceed %d chars\n";
tSCC zFmtAlloc[] = "asprintf allocation";
/*=gfunc dne
*
* what: '"Do Not Edit" warning'
*
* exparg: prefix, string for starting each output line
* exparg: first_prefix, for the first output line, opt
* exparg: optpfx, shifted prefix, opt
*
* doc: Generate a "DO NOT EDIT" or "EDIT WITH CARE" warning string.
* Which depends on whether or not the @code{--writable} command line
* option was set. The first argument is a per-line string prefix.
* The optional second argument is a prefix for the first-line and,
* in read-only mode, activates the editor hints.
* @*
* @example
* -*- buffer-read-only: t -*- vi: set ro:
* @end example
* @noindent
* The warning string also includes information about the template used
* to construct the file and the definitions used in its instantiation.
*
* The optional third argument is used when the first argument is actually
* an invocation option and the prefix arguments get shifted.
* The first argument must be, specifically, "@code{-d}". That is used
* to signify that the date stamp should not be inserted into the output.
=*/
SCM
ag_scm_dne( SCM prefix, SCM first, SCM opt )
{
int noDate = 0;
char zScribble[ 128 ];
char* pzRes;
tCC* pzFirst = zNil;
SCM res;
size_t pfxLen = AG_SCM_STRLEN( prefix );
tCC* pzPrefix = ag_scm2zchars( prefix, "dne-prefix" );
/*
* Check for the ``-d'' option
*/
if ((pfxLen == 2) && (strncmp(pzPrefix, "-d", (size_t)2) == 0)) {
noDate = 1;
pfxLen = AG_SCM_STRLEN( first );
pzPrefix = ag_scm2zchars( first, "dne-prefix" );
first = opt;
}
if (pfxLen > 128 )
AG_ABEND( aprf( zPfxMsg, zPfxLen, 128 ));
/*
* IF we also have a 'first' prefix string,
* THEN we set it to something other than ``zNil'' and deallocate later.
*/
if (AG_SCM_STRING_P( first )) {
int len = AG_SCM_STRLEN( first );
if (len >= 128)
AG_ABEND( aprf( zPfxMsg, zPfxLen, 128 ));
pzFirst = aprf( ENABLED_OPT( WRITABLE ) ? "%s\n" : zDne1,
ag_scm2zchars( first, "first-prefix" ), pzPrefix );
}
if (noDate) {
zScribble[0] = NUL;
} else {
time_t curTime = time( NULL );
struct tm* pTime = localtime( &curTime );
strftime( zScribble, (size_t)128, "%A %B %e, %Y at %r %Z", pTime );
}
{
char const* pz;
if (! ENABLED_OPT( DEFINITIONS ))
pz = "<>";
else if (*pzOopsPrefix != NUL)
pz = "<>";
else {
pz = OPT_ARG( DEFINITIONS );
if (strcmp( pz, "-" ) == 0)
pz = "stdin";
}
pzRes = aprf( ENABLED_OPT( WRITABLE ) ? zDne2 : zDne,
pzPrefix, pCurFp->pzOutName, zScribble,
pz, pzTemplFileName, pzFirst );
}
if (pzRes == NULL)
AG_ABEND( "Allocating Do-Not-Edit string" );
res = AG_SCM_STR02SCM( pzRes );
/*
* Deallocate any temporary buffers. pzFirst either points to
* the zNil string, or to an allocated buffer.
*/
AGFREE( (void*)pzRes );
if (pzFirst != zNil)
AGFREE( (void*)pzFirst );
return res;
}
/*=gfunc error
*
* what: display message and exit
*
* exparg: @message@message to display before exiting@@
* doc:
*
* The argument is a string that printed out as part of an error
* message. The message is formed from the formatting string:
*
* @example
* DEFINITIONS ERROR in %s line %d for %s: %s\n
* @end example
*
* The first three arguments to this format are provided by the
* routine and are: The name of the template file, the line within
* the template where the error was found, and the current output
* file name.
*
* After displaying the message, the current output file is removed
* and autogen exits with the EXIT_FAILURE error code. IF, however,
* the argument begins with the number 0 (zero), or the string is the
* empty string, then processing continues with the next suffix.
=*/
SCM
ag_scm_error( SCM res )
{
tSCC zFmt[] = "DEFINITIONS %s in %s line %d for %s:\n\t%s\n";
tSCC zErr[] = "ERROR";
tSCC zWarn[] = "Warning";
tSCC zBadMsg[] = "??? indecipherable error message ???";
tCC* pzMsg;
tSuccess abrt = FAILURE;
char zNum[16];
int msgLen;
switch (gh_type_e( res )) {
case GH_TYPE_BOOLEAN:
if (SCM_FALSEP( res ))
abrt = PROBLEM;
pzMsg = zNil;
break;
case GH_TYPE_NUMBER:
{
unsigned long val = gh_scm2ulong( res );
if (val == 0)
abrt = PROBLEM;
snprintf( zNum, sizeof( zNum ), "%d", (int)val );
pzMsg = zNum;
break;
}
case GH_TYPE_CHAR:
zNum[0] = gh_scm2char( res );
if ((zNum[0] == NUL) || (zNum[0] == '0'))
abrt = PROBLEM;
zNum[1] = NUL;
pzMsg = zNum;
break;
case GH_TYPE_STRING:
pzMsg = ag_scm2zchars( res, "error string" );
msgLen = AG_SCM_STRLEN( res );
while (isspace( *pzMsg ) && (--msgLen > 0)) pzMsg++;
/*
* IF the message starts with the number zero,
* OR the message is the empty string,
* THEN this is just a warning that is ignored
*/
if (msgLen <= 0)
abrt = PROBLEM;
else if (isdigit( *pzMsg ) && (strtol( pzMsg, NULL, 0 ) == 0))
abrt = PROBLEM;
break;
default:
pzMsg = zBadMsg;
}
/*
* IF there is a message,
* THEN print it.
*/
if (*pzMsg != NUL) {
char* pz = aprf( zFmt, (abrt != PROBLEM) ? zErr : zWarn,
pCurTemplate->pzTplFile, pCurMacro->lineNo,
pCurFp->pzOutName, pzMsg );
if (abrt != PROBLEM)
AG_ABEND( pz );
fputs( pz, pfTrace );
AGFREE( (void*)pz );
}
longjmp( fileAbort, abrt );
/* NOTREACHED */
return SCM_UNDEFINED;
}
/*=gfunc gpl
*
* what: GNU General Public License
* general_use:
*
* exparg: prog-name, name of the program under the GPL
* exparg: prefix, String for starting each output line
*
* doc:
*
* Emit a string that contains the GNU General Public License.
* It takes two arguments:
* @code{prefix} contains the string to start each output line, and
* @code{prog_name} contains the name of the program the copyright is
* about.
*
=*/
SCM
ag_scm_gpl( SCM prog_name, SCM prefix )
{
char* pzPfx = ag_scm2zchars( prefix, "GPL line prefix" );
char* pzPrg = ag_scm2zchars( prog_name, "program name" );
char* pzRes;
SCM res;
/*
* Get the addresses of the program name and prefix strings.
* Make sure they are reasonably sized (<256 for program name
* and <128 for a line prefix). Copy them to the scratch buffer.
*/
if (AG_SCM_STRLEN( prog_name ) >= 256)
AG_ABEND( aprf( zPfxMsg, zProgLen, 256 ));
if (AG_SCM_STRLEN( prefix ) >= 128)
AG_ABEND( aprf( zPfxMsg, zPfxLen, 128 ));
/*
* Allocate-sprintf the result string, then put it in a new SCM.
*/
pzRes = aprf( zGpl, pzPrg, pzPfx );
res = AG_SCM_STR02SCM( pzRes );
AGFREE( (void*)pzRes );
return res;
}
/*=gfunc lgpl
*
* what: GNU Library General Public License
* general_use:
*
* exparg: prog_name, name of the program under the LGPL
* exparg: owner, Grantor of the LGPL
* exparg: prefix, String for starting each output line
*
* doc:
*
* Emit a string that contains the GNU Library General Public License.
* It takes three arguments: @code{prefix} contains the string to
* start each output line. @code{owner} contains the copyright owner.
* @code{prog_name} contains the name of the program the copyright is about.
=*/
SCM
ag_scm_lgpl( SCM prog_name, SCM owner, SCM prefix )
{
char* pzPfx = ag_scm2zchars( prefix, "GPL line prefix" );
char* pzPrg = ag_scm2zchars( prog_name, "program name" );
char* pzOwner = ag_scm2zchars( owner, "owner" );
char* pzRes;
SCM res;
/*
* Get the addresses of the program name prefix and owner strings.
* Make sure they are reasonably sized (<256 for program name
* and <128 for a line prefix). Copy them to the scratch buffer.
*/
if (AG_SCM_STRLEN( prog_name ) >= 256)
AG_ABEND( aprf( zPfxMsg, zProgLen, 256 ));
if (AG_SCM_STRLEN( prefix ) >= 128)
AG_ABEND( aprf( zPfxMsg, zPfxLen, 128 ));
if (AG_SCM_STRLEN( owner ) >= 256)
AG_ABEND( aprf( zPfxMsg, zOwnLen, 256 ));
/*
* Allocate-sprintf the result string, then put it in a new SCM.
*/
pzRes = aprf( zLgpl, pzPrg, pzPfx, pzOwner );
res = AG_SCM_STR02SCM( pzRes );
AGFREE( (void*)pzRes );
return res;
}
/*=gfunc bsd
*
* what: BSD Public License
* general_use:
*
* exparg: prog_name, name of the program under the BSD
* exparg: owner, Grantor of the BSD License
* exparg: prefix, String for starting each output line
*
* doc:
*
* Emit a string that contains the Free BSD Public License.
* It takes three arguments:
* @code{prefix} contains the string to start each output line.
* @code{owner} contains the copyright owner.
* @code{prog_name} contains the name of the program the copyright is about.
*
=*/
SCM
ag_scm_bsd( SCM prog_name, SCM owner, SCM prefix )
{
char* pzPfx = ag_scm2zchars( prefix, "GPL line prefix" );
char* pzPrg = ag_scm2zchars( prog_name, "program name" );
char* pzOwner = ag_scm2zchars( owner, "owner" );
char* pzRes;
SCM res;
if (! ( AG_SCM_STRING_P( prog_name )
&& AG_SCM_STRING_P( owner )
&& AG_SCM_STRING_P( prefix )))
return SCM_UNDEFINED;
/*
* Get the addresses of the program name prefix and owner strings.
* Make sure they are reasonably sized (<256 for program name
* and <128 for a line prefix). Copy them to the scratch buffer.
*/
if (AG_SCM_STRLEN( prog_name ) >= 256)
AG_ABEND( aprf( zPfxMsg, zProgLen, 256 ));
if (AG_SCM_STRLEN( prefix ) >= 128)
AG_ABEND( aprf( zPfxMsg, zPfxLen, 128 ));
if (AG_SCM_STRLEN( owner ) >= 256)
AG_ABEND( aprf( zPfxMsg, zOwnLen, 256 ));
/*
* Allocate-sprintf the result string, then put it in a new SCM.
*/
pzRes = aprf( zBsd, pzPrg, pzPfx, pzOwner );
res = AG_SCM_STR02SCM( pzRes );
AGFREE( (void*)pzRes );
return res;
}
/*=gfunc license
*
* what: an arbitrary license
* general_use:
*
* exparg: lic_name, file name of the license
* exparg: prog_name, name of the licensed program or library
* exparg: owner, Grantor of the License
* exparg: prefix, String for starting each output line
*
* doc:
* Emit a string that contains the named license. The license text
* is read from a file named, @code{lic_name}.lic, searching the standard
* directories. The file contents are used as a format argument
* to @code{printf}(3), with @code{prog_name} and @code{owner} as
* the two string formatting arguments. Each output line is automatically
* prefixed with the string @code{prefix}.
=*/
SCM
ag_scm_license( SCM license, SCM prog_name, SCM owner, SCM prefix )
{
char* pzPfx = ag_scm2zchars( prefix, "GPL line prefix" );
char* pzPrg = ag_scm2zchars( prog_name, "program name" );
char* pzOwner = ag_scm2zchars( owner, "owner" );
static struct {
tCC* pzFN;
tmap_info_t mi;
} lic = { NULL, { NULL, 0, 0, 0, 0, 0, 0, 0 }};
char* pzRes;
if (! AG_SCM_STRING_P( license ))
return SCM_UNDEFINED;
{
tSCC* apzSfx[] = { "lic", NULL };
static char zRealFile[ AG_PATH_MAX ];
char* pzLicense = ag_scm2zchars( license, "license file name" );
/*
* Find the template file somewhere
*/
if (! SUCCESSFUL( findFile( pzLicense, zRealFile, apzSfx, NULL )))
AG_ABEND( aprf( zCannot, ENOENT, "map license file", pzLicense,
strerror( ENOENT )));
if ((lic.pzFN != NULL) && (strcmp( zRealFile, lic.pzFN ) != 0)) {
text_munmap( &lic.mi );
AGFREE( (void*)lic.pzFN );
lic.pzFN = NULL;
}
if (lic.pzFN == NULL) {
text_mmap(zRealFile, PROT_READ|PROT_WRITE, MAP_PRIVATE, &lic.mi);
if (TEXT_MMAP_FAILED_ADDR(lic.mi.txt_data))
AG_ABEND( aprf( "Could not open license file '%s'", pzLicense));
AGDUPSTR( lic.pzFN, zRealFile, "license file name" );
}
}
/*
* Trim trailing white space.
*/
{
char* pz = (char*)lic.mi.txt_data + lic.mi.txt_size;
while (isspace( pz[-1] ) && (pz > (char*)lic.mi.txt_data))
pz--;
*pz = NUL;
}
/*
* Get the addresses of the program name prefix and owner strings.
* Make sure they are reasonably sized (<256 for program name
* and <128 for a line prefix). Copy them to the scratch buffer.
*/
if (AG_SCM_STRLEN( prog_name ) >= 256)
AG_ABEND( aprf( zPfxMsg, zProgLen, 256 ));
if (AG_SCM_STRLEN( prefix ) >= 128)
AG_ABEND( aprf( zPfxMsg, zPfxLen, 128 ));
if (AG_SCM_STRLEN( owner ) >= 256)
AG_ABEND( aprf( zPfxMsg, zOwnLen, 256 ));
/*
* Reformat the string with the given arguments
*/
pzRes = aprf( (char*)lic.mi.txt_data, pzPrg, pzOwner );
{
int pfx_size = strlen( pzPfx );
char* pzScan = pzRes;
char* pzOut;
char* pzSaveRes;
size_t out_size = pfx_size;
/*
* Figure out how much space we need (text size plus
* a prefix size for each newline)
*/
for (;;) {
switch (*(pzScan++)) {
case NUL:
goto exit_count;
case '\n':
out_size += pfx_size;
/* FALLTHROUGH */
default:
out_size++;
}
} exit_count:;
/*
* Create our output buffer and insert the first prefix
*/
pzOut = pzSaveRes = ag_scribble( out_size );
strcpy( pzOut, pzPfx );
pzOut += pfx_size;
pzScan = pzRes;
for (;;) {
switch (*(pzOut++) = *(pzScan++)) {
case NUL:
goto exit_copy;
case '\n':
strcpy( pzOut, pzPfx );
pzOut += pfx_size;
break;
default:
break;
}
}
exit_copy:;
/*
* We allocated a temporary buffer that has all the
* formatting done, but need the prefixes on each line.
*/
AGFREE( (void*)pzRes );
return AG_SCM_STR2SCM(pzSaveRes, (size_t)((pzOut - pzSaveRes) - 1));
}
}
/*
* Local Variables:
* mode: C
* c-file-style: "stroustrup"
* indent-tabs-mode: nil
* End:
* end of agen5/expFormat.c */