summaryrefslogtreecommitdiff
path: root/agen5/expFormat.c
diff options
context:
space:
mode:
Diffstat (limited to 'agen5/expFormat.c')
-rw-r--r--agen5/expFormat.c874
1 files changed, 874 insertions, 0 deletions
diff --git a/agen5/expFormat.c b/agen5/expFormat.c
new file mode 100644
index 0000000..1679e36
--- /dev/null
+++ b/agen5/expFormat.c
@@ -0,0 +1,874 @@
+
+/**
+ * @file expFormat.c
+ *
+ * Time-stamp: "2012-03-04 13:54:56 bkorb"
+ *
+ * This module implements formatting expression functions.
+ *
+ * This file is part of AutoGen.
+ * AutoGen Copyright (c) 1992-2012 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;
+
+/*=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: -d
+ *
+ * This will suppress the variable text (date and version information).
+ * If specified, then the "prefix" and "first" arguments are shifted
+ * to the next arguments.
+ *
+ * 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)
+{
+ char const * date_str;
+ char const * pzRes;
+ char const * pzFirst;
+ size_t pfxLen;
+ char const * pzPrefix;
+ SCM res;
+
+ if (! AG_SCM_STRING_P(prefix))
+ return SCM_UNDEFINED;
+
+ date_str = NULL;
+ pzFirst = zNil;
+ pfxLen = AG_SCM_STRLEN(prefix);
+ pzPrefix = ag_scm2zchars(prefix, "dne-prefix");
+
+ /*
+ * Check for the ``-d'' option
+ */
+ if ((pfxLen == 2) && (strncmp(pzPrefix, "-d", (size_t)2) == 0)) {
+ date_str = zNil;
+ pfxLen = AG_SCM_STRLEN(first);
+ pzPrefix = ag_scm2zchars(first, "dne-prefix");
+ first = opt;
+ }
+
+ /*
+ * 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))
+ pzFirst = aprf(ENABLED_OPT(WRITABLE) ? "%s\n" : EXP_FMT_DNE1,
+ ag_scm2zchars(first, "first-prefix"), 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 = ag_scribble(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";
+ }
+
+ pzRes = aprf(ENABLED_OPT(WRITABLE) ? EXP_FMT_DNE2 : EXP_FMT_DNE,
+ pzPrefix, pfp->stk_fname, date_str,
+ pz, tpl_name, 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)
+{
+ char const * pzMsg;
+ tSuccess abrt = FAILURE;
+ char zNum[16];
+ int msgLen;
+
+ switch (ag_scm_type_e(res)) {
+ case GH_TYPE_BOOLEAN:
+ if (AG_SCM_FALSEP(res))
+ abrt = PROBLEM;
+ pzMsg = zNil;
+ break;
+
+ case GH_TYPE_NUMBER:
+ {
+ unsigned long val = AG_SCM_TO_ULONG(res);
+ if (val == 0)
+ abrt = PROBLEM;
+ snprintf(zNum, sizeof(zNum), "%d", (int)val);
+ pzMsg = zNum;
+ break;
+ }
+
+ case GH_TYPE_CHAR:
+ zNum[0] = AG_SCM_CHAR(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");
+ pzMsg = SPN_WHITESPACE_CHARS(pzMsg);
+ msgLen = strlen(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 (IS_DEC_DIGIT_CHAR(*pzMsg) && (strtol(pzMsg, NULL, 0) == 0))
+ abrt = PROBLEM;
+ break;
+
+ default:
+ pzMsg = BAD_MSG_STR;
+ }
+
+ /*
+ * IF there is a message,
+ * THEN print it.
+ */
+ if (*pzMsg != NUL) {
+ char* pz = aprf(DEF_NOTE_FMT, (abrt != PROBLEM) ? ERROR_STR : WARN_STR,
+ current_tpl->td_file, cur_macro->md_line,
+ cur_fpstack->stk_fname, pzMsg);
+ if (abrt != PROBLEM)
+ AG_ABEND(pz);
+ fputs(pz, trace_fp);
+ AGFREE((void*)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;
+ size_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 = ag_scribble(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, flen, fp) != 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(AG_SCM_STR02SCM(slst[0]), AG_SCM_STR02SCM(slst[1]),
+ AG_SCM_STR02SCM(slst[2]), AG_SCM_STR02SCM(slst[3])));
+
+ empty = scm_gc_protect_object(AG_SCM_STR02SCM(""));
+ }
+
+ if (! AG_SCM_STRING_P(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 (! AG_SCM_STRING_P(owner)) owner = empty;
+ if (! AG_SCM_STRING_P(years)) years = empty;
+ vals = scm_list_4(prog, pfx, owner, years);
+
+ do_multi_subs(&lic_text, &text_len, subs, vals);
+
+ return AG_SCM_STR02SCM(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 newline
+ * characters.
+ *
+ * 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. The third section is strictly the name of the license
+ * without any substitution markers. 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>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;
+
+ txt = SPN_WHITESPACE_CHARS(txt);
+ e = SPN_WHITESPACE_BACK(txt, txt);
+ *e = NUL;
+ lic = AG_SCM_STR02SCM(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(AG_SCM_STR02SCM(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(AG_SCM_STR02SCM(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(AG_SCM_STR02SCM(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(AG_SCM_STR02SCM(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 * pzPfx = ag_scm2zchars(prefix, "GPL line prefix");
+ char const * pzPrg = ag_scm2zchars(prog_name, "program name");
+ char const * pzOwner = 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 (! AG_SCM_STRING_P(license))
+ return SCM_UNDEFINED;
+
+ {
+ static char const * const apzSfx[] = { MK_LIC_SFX, NULL };
+ static char fname[ AG_PATH_MAX ];
+ char const * pzLicense = ag_scm2zchars(license, "lic file");
+
+ /*
+ * Find the template file somewhere
+ */
+ if (! SUCCESSFUL(find_file(pzLicense, fname, apzSfx, NULL))) {
+ errno = ENOENT;
+ AG_CANT(MK_LIC_NO_LIC, pzLicense);
+ }
+
+ if ((lic.pzFN != NULL) && (strcmp(fname, lic.pzFN) != 0)) {
+ text_munmap(&lic.mi);
+ AGFREE((void*)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, pzLicense));
+
+ if (dep_fp != NULL)
+ add_source_file(pzLicense);
+
+ 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 (AG_SCM_STRLEN(prog_name) >= SCRIBBLE_SIZE)
+ AG_ABEND(aprf(MK_LIC_TOO_BIG_FMT, MK_LIC_BIG_PROG, SCRIBBLE_SIZE));
+
+ if (AG_SCM_STRLEN(prefix) >= SCRIBBLE_SIZE)
+ AG_ABEND(aprf(MK_LIC_TOO_BIG_FMT, MK_LIC_BIG_PFX, SCRIBBLE_SIZE));
+
+ if (AG_SCM_STRLEN(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, 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 NL:
+ 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 NL:
+ 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 */