/**
* @file expFormat.c
*
* This module implements formatting expression functions.
*
* @addtogroup autogen
* @{
*/
/*
* This file is part of AutoGen.
* AutoGen Copyright (C) 1992-2016 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 <http://www.gnu.org/licenses/>.
*/
typedef enum {
LSEG_INFO = 1,
LSEG_DESC = 2,
LSEG_FULL = 3,
LSEG_NAME = 4
} lic_segment_e_t;
/**
* Remove horizontal white space at the ends of lines.
* "dne" and licensing text passes through this before
* making an SCM out of the result.
*
* @param[in,out] text the text to work on.
*/
static void
trim_trailing_white(char * text)
{
char * start = text++;
if (*start == NUL)
return;
for (;;) {
switch (*text++) {
case NUL:
return;
case NL:
if (IS_HORIZ_WHITE_CHAR(text[-2]))
goto doit;
default:
break;
}
}
doit:
start = SPN_HORIZ_WHITE_BACK(start, text - 2);
*(start++) = NL;
char * dest = start;
for (;;) {
switch (*(dest++) = *(text++)) {
case NUL:
return;
case NL:
if (IS_HORIZ_WHITE_CHAR(dest[-2])) {
dest = SPN_HORIZ_WHITE_BACK(start, dest - 2);
start = dest;
*(dest++) = NL;
}
default:
break;
}
}
}
/*=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 may be an option: @samp{-D} or @samp{-d}, causing the
* second and (potentially) third arguments to be interpreted as the first
* and second arguments. The only useful option is @samp{-D}:
*
* @table @samp
* @item -D
* will add date, timestamp and version information.
* @item -d
* is ignored, but still accepted for compatibility with older versions
* of the "dne" function where emitting the date was the default.
* @end table
*
* If one of these options is specified, then the "prefix" and "first"
* arguments are obtained from the following arguments. The presence (or
* absence) of this option can be overridden with the environment variable,
* @samp{AUTOGEN_DNE_DATE}. The date is disabled if the value is empty or
* starts with one of the characters, @samp{0nNfF} -- zero or the first
* letter of "no" or "false".
*
* The @code{prefix} argument is a per-line string prefix. The optional
* second argument is a prefix for the first line only and, in read-only
* mode, activates 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.
=*/
SCM
ag_scm_dne(SCM prefix, SCM first, SCM opt)
{
char const * date_str;
char const * pzFirst;
char const * pzPrefix;
if (! scm_is_string(prefix))
return SCM_UNDEFINED;
date_str = zNil;
pzFirst = zNil;
{
size_t pfxLen = scm_c_string_length(prefix);
pzPrefix = ag_scm2zchars(prefix, "dne-prefix");
/*
* Check for a -d option (ignored) or a -D option (emit date)
* by default, "dne" will not emit a date in the output.
*/
if ((pfxLen == 2) && (*pzPrefix == '-')) {
switch (pzPrefix[1]) {
case 'D':
date_str = NULL;
pzPrefix = ag_scm2zchars(first, "dne-prefix");
first = opt;
break;
case 'd':
pzPrefix = ag_scm2zchars(first, "dne-prefix");
first = opt;
break;
}
}
}
do {
char const * pz = getenv("AUTOGEN_DNE_DATE");
if (pz == NULL) break; /* use selection from template */
switch (*pz) {
case NUL:
case '0': /* zero */
case 'n':
case 'N': /* no */
case 'f':
case 'F': /* false */
date_str = zNil; /* template user says "no DNE date" */
break;
default:
date_str = NULL; /* template user says "INCLUDE DNE date" */
}
} while (0);
/*
* IF we also have a 'first' prefix string,
* THEN we set it to something other than ``zNil'' and deallocate later.
*/
if (scm_is_string(first))
pzFirst = aprf(ENABLED_OPT(WRITABLE) ? "%s\n" : EXP_FMT_DNE1,
ag_scm2zchars(first, "pfx-1"), pzPrefix);
if (date_str == NULL) {
static char const tim_fmt[] =
" %B %e, %Y at %r by AutoGen " AUTOGEN_VERSION;
size_t const tsiz = sizeof(tim_fmt) + sizeof("september") * 2;
time_t curTime = time(NULL);
struct tm * pTime = localtime(&curTime);
date_str = scribble_get((ssize_t)tsiz);
strftime((char *)date_str, tsiz, tim_fmt, pTime);
}
{
char const * pz;
out_stack_t * pfp = cur_fpstack;
char const * tpl_name = strrchr(tpl_fname, DIRCH);
if (tpl_name == NULL)
tpl_name = tpl_fname;
else
tpl_name++;
while (pfp->stk_flags & FPF_UNLINK) pfp = pfp->stk_prev;
if (! ENABLED_OPT(DEFINITIONS))
pz = "<<no definitions>>";
else if (*oops_pfx != NUL)
pz = "<<CGI-definitions>>";
else {
pz = OPT_ARG(DEFINITIONS);
if (strcmp(pz, "-") == 0)
pz = "stdin";
}
pz = aprf(ENABLED_OPT(WRITABLE) ? EXP_FMT_DNE2 : EXP_FMT_DNE,
pzPrefix, pfp->stk_fname, date_str,
pz, tpl_name, pzFirst);
if (pz == NULL)
AG_ABEND("Allocating Do-Not-Edit string");
trim_trailing_white(C(char *, pz));
date_str = pz;
}
/*
* Deallocate any temporary buffers. pzFirst either points to
* the zNil string, or to an allocated buffer.
*/
if (pzFirst != zNil)
AGFREE(pzFirst);
{
SCM res = scm_from_latin1_string(date_str);
AGFREE(date_str);
return res;
}
}
/*=gfunc warn
*
* what: display warning message and continue
*
* exparg: @ message @ message to display @@
* doc:
*
* The argument is a string that printed out to stderr.
* The message is formed from the formatting string:
*
* @example
* @code{WARNING:} %s\n
* @end example
*
* The template processing resumes after printing the message.
=*/
SCM
ag_scm_warn(SCM res)
{
char const * msg = ag_scm2zchars(res, "warn str");
if ((msg == NULL) || (*msg == NUL))
AG_ABEND("warn called without a message string");
fprintf(stderr, WARN_FMT, msg);
return SCM_UNDEFINED;
}
/*=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)
{
char const * msg;
tSuccess abrt = FAILURE;
char num_bf[16];
size_t msg_ln;
switch (ag_scm_type_e(res)) {
case GH_TYPE_BOOLEAN:
if (scm_is_false(res))
abrt = PROBLEM;
msg = zNil;
break;
case GH_TYPE_NUMBER:
{
unsigned long val = AG_SCM_TO_ULONG(res);
if (val == 0)
abrt = PROBLEM;
snprintf(num_bf, sizeof(num_bf), "%d", (int)val);
msg = num_bf;
break;
}
case GH_TYPE_CHAR:
num_bf[0] = (char)SCM_CHAR(res);
if ((num_bf[0] == NUL) || (num_bf[0] == '0'))
abrt = PROBLEM;
num_bf[1] = NUL;
msg = num_bf;
break;
case GH_TYPE_STRING:
msg = ag_scm2zchars(res, "error string");
msg = SPN_WHITESPACE_CHARS(msg);
msg_ln = strlen(msg);
/*
* 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 (msg_ln == 0)
abrt = PROBLEM;
else if (IS_DEC_DIGIT_CHAR(*msg) && (strtol(msg, NULL, 0) == 0))
abrt = PROBLEM;
break;
default:
msg = BAD_MSG_STR;
}
/*
* IF there is a message,
* THEN print it.
*/
if (*msg != NUL) {
char const * typ = (abrt != PROBLEM) ? ERROR_STR : WARN_STR;
char * pz = aprf(DEF_NOTE_FMT, typ,
current_tpl->td_file, cur_macro->md_line,
cur_fpstack->stk_fname, msg);
if (abrt != PROBLEM)
AG_ABEND(pz);
fputs(pz, trace_fp);
AGFREE(pz);
}
longjmp(abort_jmp_buf, abrt);
/* NOTREACHED */
return SCM_UNDEFINED;
}
/**
* Assemble the copyright preamble and long license description.
*
* @param txt a pointer to the first of two newlines separating
* copyright information from the description.
*/
static void
assemble_full_desc(char * txt, char const * pfx)
{
char * pd;
char * md;
size_t prefix_len = strlen(pfx) + 1;
while ( (prefix_len > 0)
&& IS_WHITESPACE_CHAR(pfx[prefix_len - 2]))
prefix_len--;
/*
* Preserve the first newline. Set the move destination
* out past where we will be inserting the "<PFX>\n" marker.
*/
pd = txt + 1; /* prefix destination */
md = pd + prefix_len; /* move destination */
while (*txt == NL) txt++;
/*
* Maybe there were exactly enough NL characters we don't need to move
*/
if (md != txt)
memmove(md, txt, strlen(txt) + 1);
memmove(pd, pfx, --prefix_len);
pd[prefix_len] = NL;
/*
* Look for a trailing license name and trim it and trailing white space
*/
txt = strstr(md, "\n\n");
if (txt == NULL)
txt = md + strlen(md);
while ( (txt > md)
&& IS_WHITESPACE_CHAR(txt[-1])) txt--;
*txt = NUL;
}
/**
* Trim off the license name. It is the third double-newline stanza
* in the license file.
*
* @param p a pointer to the first of two newlines separating
* copyright information from the description.
* @return pointer to second stanza, sans the license name trailer.
*/
static char *
trim_lic_name(char * p)
{
char * res;
/* skip the leading white space. It starts with NL. */
p = SPN_WHITESPACE_CHARS(p + 1);
if (*p == NUL)
return p;
res = p;
/*
* The last section ends with two consecutive new lines.
* All trailing newlines are trimmed (not all white space).
*/
p = strstr(p, "\n\n");
if (p == NULL)
p = res + strlen(res);
while ( (p > res)
&& IS_WHITESPACE_CHAR(p[-1])) p--;
*p = NUL;
return res;
}
/**
* Extract the license name. It is the third double-newline stanza
* in the license file.
*
* @param txt a pointer to the first of two newlines separating
* copyright information from the description.
* @return pointer to the license name trailer.
*/
static char *
get_lic_name(char * p)
{
char * scan = p;
while (*(++scan) == NL) ; /* skip the leading NL's. */
/*
* Find the third stanza. If there. If not, we supply some static
* text: "an unknown license"
*/
scan = strstr(scan, "\n\n");
if (scan == NULL) {
strcpy(p, EXP_FMT_BAD_LIC);
return p;
}
while (*scan == NL) scan++;
return scan;
}
/**
* Find the kind of text being requested. It may be "full" (the first
* two stanzas), "info" (the first -- copyright info + license name),
* "description" (the second -- a one paragraph description), or
* "name" -- the third stanza.
*
* @param txt a pointer to the first of two newlines separating
* copyright information from the description.
* @return pointer to the requested text.
*/
static char *
find_lic_text(
lic_segment_e_t segment, SCM lic, ssize_t * txt_len, char const * pfx)
{
static char const * const lic_sfx[] = { FIND_LIC_TEXT_SFX, NULL };
char const * lic_pz = ag_scm2zchars(lic, "license");
char fname[ AG_PATH_MAX ];
char * ftext;
ssize_t flen;
/*
* auto-convert "bsd" into "mbsd" for compatibility.
*/
if (strcmp(lic_pz, FIND_LIC_TEXT_MBSD+1) == 0)
lic_pz = FIND_LIC_TEXT_MBSD;
if (! SUCCESSFUL(find_file(lic_pz, fname, lic_sfx, NULL)))
return NULL;
{
struct stat stbf;
if (stat(fname, &stbf) != 0)
AG_CANT(FIND_LIC_TEXT_NO_LIC, fname);
if (! S_ISREG(stbf.st_mode)) {
errno = EINVAL;
AG_CANT(FIND_LIC_TEXT_BAD_FILE, fname);
}
flen = stbf.st_size;
}
ftext = scribble_get(flen + EXP_FMT_BAD_LIC_LEN + 1);
*txt_len = flen;
{
FILE * fp = fopen(fname, "r");
if (fp == NULL)
AG_CANT(FIND_LIC_TEXT_OPEN, fname);
if (fread(ftext, 1, (size_t)flen, fp) != (size_t)flen)
AG_CANT(FIND_LIC_TEXT_BAD_FILE, fname);
ftext[flen] = NUL;
fclose(fp);
}
if (dep_fp != NULL)
add_source_file(fname);
{
char * p = strstr(ftext, DOUBLE_NEWLINE);
if (p == NULL)
AG_ABEND(aprf(FIND_LIC_TEXT_INVAL, fname));
switch (segment) {
case LSEG_INFO: p[1] = NUL; break;
case LSEG_DESC: ftext = trim_lic_name(p); break;
case LSEG_NAME: ftext = get_lic_name(p); break;
case LSEG_FULL: assemble_full_desc(p, pfx); break;
}
}
return ftext;
}
/**
* Construct an SCM for the kind of text being requested.
*
* It may be "full" (the first two stanzas), "info" (the first -- copyright
* info + license name), "description" (the second -- a one paragraph
* description), or "name" -- the third stanza.
*
* @param seg which segment of license is desired
* @param lic The name of the license
* @param prog the name of the program
* @param pfx a per-line prefix
* @param owner who owns the copyright
* @param years the copyright years
*
* @return the SCM-ized string
*/
static SCM
construct_license(
lic_segment_e_t seg, SCM lic, SCM prog, SCM pfx, SCM owner, SCM years)
{
static SCM subs = SCM_UNDEFINED;
static SCM empty = SCM_UNDEFINED;
SCM vals = SCM_UNDEFINED;
char * lic_text;
ssize_t text_len;
char const * pfx_pz = ag_scm2zchars(pfx, "lic-prefix");
if (subs == SCM_UNDEFINED) {
static char const * const slst[] = {
MK_LIC_PROG, MK_LIC_PFX, MK_LIC_OWN, MK_LIC_YRS
};
subs = scm_gc_protect_object(
scm_list_4(scm_from_latin1_string(slst[0]),
scm_from_latin1_string(slst[1]),
scm_from_latin1_string(slst[2]),
scm_from_latin1_string(slst[3])));
empty = scm_gc_protect_object(scm_from_latin1_string(""));
}
if (! scm_is_string(lic))
AG_ABEND(MK_LIC_NOT_STR);
lic_text = find_lic_text(seg, lic, &text_len, pfx_pz);
if (lic_text == NULL)
AG_ABEND(aprf(MK_LIC_NO_LIC, ag_scm2zchars(lic, "lic")));
if (! scm_is_string(owner)) owner = empty;
if (! scm_is_string(years)) years = empty;
vals = scm_list_4(prog, pfx, owner, years);
do_multi_subs(&lic_text, &text_len, subs, vals);
trim_trailing_white(lic_text);
return scm_from_latin1_string(lic_text);
}
/*=gfunc license_full
*
* what: Emit the licensing information and description
* general_use:
*
* exparg: license, name of license type
* exparg: prog-name, name of the program under the GPL
* exparg: prefix, String for starting each output line
* exparg: owner, owner of the program, optional
* exparg: years, copyright years, optional
*
* doc:
*
* Emit all the text that @code{license-info} and @code{license-description}
* would emit (@pxref{SCM license-info, @code{license-info}},
* and @pxref{SCM license-description, @code{license-description}}),
* with all the same substitutions.
*
* All of these depend upon the existence of a license file named after the
* @code{license} argument with a @code{.lic} suffix. That file should
* contain three blocks of text, each separated by two or more consecutive
* newline characters (at least one completely blank line).
*
* The first section describes copyright attribution and the name of the usage
* licence. For GNU software, this should be the text that is to be displayed
* with the program version. Four text markers can be replaced: <PFX>,
* <program>, <years> and <owner>.
*
* The second section is a short description of the terms of the license.
* This is typically the kind of text that gets displayed in the header of
* source files. Only the <PFX>, <owner> and <program> markers are
* substituted.
*
* The third section is strictly the name of the license.
* No marker substitutions are performed.
*
* @example
* <PFX>Copyright (C) <years> <owner>, all rights reserved.
* <PFX>
* <PFX>This is free software. It is licensed for use,
* <PFX>modification and redistribution under the terms
* <PFX>of the GNU General Public License, version 3 or later
* <PFX> <http://gnu.org/licenses/gpl.html>
*
* <PFX><program> is free software: you can redistribute it
* <PFX>and/or modify it under the terms of the GNU General
* <PFX>Public License as published by the Free Software ...
*
* the GNU General Public License, version 3 or later
* @end example
=*/
SCM
ag_scm_license_full(SCM lic, SCM prog, SCM pfx, SCM owner, SCM years)
{
return construct_license(LSEG_FULL, lic, prog, pfx, owner, years);
}
/*=gfunc license_description
*
* what: Emit a license description
* general_use:
*
* exparg: license, name of license type
* exparg: prog-name, name of the program under the GPL
* exparg: prefix, String for starting each output line
* exparg: owner, owner of the program, optional
*
* doc:
*
* Emit a string that contains a detailed license description, with
* substitutions for program name, copyright holder and a per-line prefix.
* This is the text typically used as part of a source file header.
* For more details, @xref{SCM license-full, the license-full command}.
*
=*/
SCM
ag_scm_license_description(SCM lic, SCM prog, SCM pfx, SCM owner)
{
return construct_license(LSEG_DESC, lic, prog, pfx, owner, SCM_UNDEFINED);
}
/*=gfunc license_info
*
* what: Emit the licensing information and copyright years
* general_use:
*
* exparg: license, name of license type
* exparg: prog-name, name of the program under the GPL
* exparg: prefix, String for starting each output line
* exparg: owner, owner of the program, optional
* exparg: years, copyright years, optional
*
* doc:
*
* Emit a string that contains the licensing description, with some
* substitutions for program name, copyright holder, a list of years when the
* source was modified, and a per-line prefix. This text typically includes a
* brief license description and is often printed out when a program starts
* running or as part of the @code{--version} output.
* For more details, @xref{SCM license-full, the license-full command}.
*
=*/
SCM
ag_scm_license_info(SCM lic, SCM prog, SCM pfx, SCM owner, SCM years)
{
return construct_license(LSEG_INFO, lic, prog, pfx, owner, years);
}
/*=gfunc license_name
*
* what: Emit the name of the license
* general_use:
*
* exparg: license, name of license type
*
* doc:
*
* Emit a string that contains the full name of the license.
=*/
SCM
ag_scm_license_name(SCM lic)
{
ssize_t text_len;
char * txt = find_lic_text(LSEG_NAME, lic, &text_len, "");
char * e;
if (txt != NULL) {
txt = SPN_WHITESPACE_CHARS(txt);
e = SPN_WHITESPACE_BACK(txt, txt);
*e = NUL;
lic = scm_from_latin1_string(txt);
}
return lic;
}
/*=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.
* This function is now deprecated. Please @xref{SCM license-description}.
=*/
SCM
ag_scm_gpl(SCM prog_name, SCM prefix)
{
static SCM lic = SCM_UNDEFINED;
if (lic == SCM_UNDEFINED)
lic = scm_gc_protect_object(
scm_from_latin1_string(FIND_LIC_TEXT_LGPL+1));
return ag_scm_license_description(lic, prog_name, prefix, SCM_UNDEFINED);
}
/*=gfunc agpl
*
* what: GNU Affero 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 Affero General Public License.
* This function is now deprecated. Please @xref{SCM license-description}.
=*/
SCM
ag_scm_agpl(SCM prog_name, SCM prefix)
{
static SCM lic = SCM_UNDEFINED;
if (lic == SCM_UNDEFINED)
lic = scm_gc_protect_object(
scm_from_latin1_string(FIND_LIC_TEXT_AGPL));
return ag_scm_license_description(lic, prog_name, prefix, SCM_UNDEFINED);
}
/*=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.
* This function is now deprecated. Please @xref{SCM license-description}.
=*/
SCM
ag_scm_lgpl(SCM prog_name, SCM owner, SCM prefix)
{
static SCM lic = SCM_UNDEFINED;
if (lic == SCM_UNDEFINED)
lic = scm_gc_protect_object(
scm_from_latin1_string(FIND_LIC_TEXT_LGPL));
return ag_scm_license_description(lic, prog_name, prefix, owner);
}
/*=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.
* This function is now deprecated. Please @xref{SCM license-description}.
*
=*/
SCM
ag_scm_bsd(SCM prog_name, SCM owner, SCM prefix)
{
static SCM lic = SCM_UNDEFINED;
if (lic == SCM_UNDEFINED)
lic = scm_gc_protect_object(
scm_from_latin1_string(FIND_LIC_TEXT_MBSD));
return ag_scm_license_description(lic, prog_name, prefix, owner);
}
/*=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.
* This function is now deprecated. Please @xref{SCM license-description}.
=*/
SCM
ag_scm_license(SCM license, SCM prog_name, SCM owner, SCM prefix)
{
char const * prefx = ag_scm2zchars(prefix, "line pfx");
char const * pname = ag_scm2zchars(prog_name, "p name");
char const * ownrz = ag_scm2zchars(owner, "owner");
static struct {
char const * pzFN;
tmap_info_t mi;
} lic = { NULL, { NULL, 0, 0, 0, 0, 0, 0, 0 }};
char * pzRes;
if (! scm_is_string(license))
return SCM_UNDEFINED;
{
static char const * const apzSfx[] = { MK_LIC_SFX, NULL };
static char fname[ AG_PATH_MAX ];
char const * l_file = ag_scm2zchars(license, "lic file");
/*
* Find the template file somewhere
*/
if (! SUCCESSFUL(find_file(l_file, fname, apzSfx, NULL))) {
errno = ENOENT;
AG_CANT(MK_LIC_NO_LIC, l_file);
}
if ((lic.pzFN != NULL) && (strcmp(fname, lic.pzFN) != 0)) {
text_munmap(&lic.mi);
AGFREE(lic.pzFN);
lic.pzFN = NULL;
}
if (lic.pzFN == NULL) {
text_mmap(fname, PROT_READ|PROT_WRITE, MAP_PRIVATE, &lic.mi);
if (TEXT_MMAP_FAILED_ADDR(lic.mi.txt_data))
AG_ABEND(aprf(MK_LIC_NO_OPEN, l_file));
if (dep_fp != NULL)
add_source_file(l_file);
AGDUPSTR(lic.pzFN, fname, "lic f name");
}
}
/*
* Trim trailing white space.
*/
{
char * pz = (char *)lic.mi.txt_data + lic.mi.txt_size;
while ( (pz > (char *)lic.mi.txt_data)
&& IS_WHITESPACE_CHAR(pz[-1]))
pz--;
*pz = NUL;
}
/*
* Get the addresses of the program name prefix and owner strings.
* Make sure they are reasonably sized (less than
* SCRIBBLE_SIZE). Copy them to the scratch buffer.
*/
if (scm_c_string_length(prog_name) >= SCRIBBLE_SIZE)
AG_ABEND(aprf(MK_LIC_TOO_BIG_FMT, MK_LIC_BIG_PROG, SCRIBBLE_SIZE));
if (scm_c_string_length(prefix) >= SCRIBBLE_SIZE)
AG_ABEND(aprf(MK_LIC_TOO_BIG_FMT, MK_LIC_BIG_PFX, SCRIBBLE_SIZE));
if (scm_c_string_length(owner) >= SCRIBBLE_SIZE)
AG_ABEND(aprf(MK_LIC_TOO_BIG_FMT, MK_LIC_BIG_OWN, SCRIBBLE_SIZE));
/*
* Reformat the string with the given arguments
*/
pzRes = aprf((char *)lic.mi.txt_data, pname, ownrz);
{
int pfx_size = (int)strlen(prefx);
char * pzScan = pzRes;
char * pzOut;
char * pzSaveRes;
ssize_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 NL:
out_size += pfx_size;
/* FALLTHROUGH */
default:
out_size++;
}
} exit_count:;
/*
* Create our output buffer and insert the first prefix
*/
pzOut = pzSaveRes = scribble_get(out_size);
strcpy(pzOut, prefx);
pzOut += pfx_size;
pzScan = pzRes;
for (;;) {
switch (*(pzOut++) = *(pzScan++)) {
case NUL:
goto exit_copy;
case NL:
strcpy(pzOut, prefx);
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(pzRes);
return scm_from_latin1_stringn(
pzSaveRes, (size_t)((pzOut - pzSaveRes) - 1));
}
}
/**
* @}
*
* Local Variables:
* mode: C
* c-file-style: "stroustrup"
* indent-tabs-mode: nil
* End:
* end of agen5/expFormat.c */