//
// aegis - project change supervisor
// Copyright (C) 1991-1993, 1995, 1997, 1999, 2002-2008 Peter Miller
//
// This program 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.
//
// This program 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
// .
//
#ifndef SUB_H
#define SUB_H
#include
#include
#include
#include
#include
#include
struct project_ty; // forward
struct sub_context_ty; // forward
class nstring; // forward
class wstring; // forward
class wstring_list; // forward
/**
* The sub_context_ty class represents the context (variables &co) for
* a substitution.
*/
class sub_context_ty
{
public:
/**
* The destructor.
*/
~sub_context_ty();
/**
* The default constructor.
*/
sub_context_ty(const char *file = 0, int line = 0);
/**
* The clear method is used to clear all of the substitution
* variables. Not usually needed manually, as this is done
* automatically at the end of every substitute().
*/
void clear();
/**
* The var_set_format method is used to set the value of a
* substitution variable. These variables are command specific,
* as opposed to the functions which are always present. The
* user documentation does NOT make this distinction by using the
* names "variable" and "function", they are always referred to as
* "substitutions".
*
* \param name
* The name of the variable to be set.
* \param fmt
* The format string for the value (see printf(3) fdor more
* information) and the format parameters follow in the succeeding
arguments.
*/
void var_set_format(const char *name, const char *fmt, ...)
ATTR_PRINTF(3, 4);
/**
* The var_set_vformat method is used to set a substitution variable
* with a formatted value.
*
* \param name
* The name of the variable to be set.
* \param fmt
* The format string for the value (see vprintf(3) for more
* information).
* \param args
* The format parameters.
*/
void var_set_vformat(const char *name, const char *fmt, va_list args)
ATTR_VPRINTF(3);
/**
* The var_set_string method is used to set a substitution variable.
*
* \param name
* The name of the variable to be set.
* \param value
* The value of the variable to be set.
*/
void var_set_string(const char *name, string_ty *value);
/**
* The var_set_string method is used to set a substitution variable.
*
* \param name
* The name of the variable to be set.
* \param value
* The value of the variable to be set.
*/
void var_set_string(const char *name, const nstring &value);
/**
* The var_set_charstar method is used to set a substitution variable.
*
* \param name
* The name of the variable to be set.
* \param value
* The value of the variable to be set.
*/
void var_set_charstar(const char *name, const char *value);
/**
* The var_set_long method is used to set a substitution variable.
*
* \param name
* The name of the variable to be set.
* \param value
* The value of the variable to be set.
*/
void var_set_long(const char *name, long value);
/**
* The var_set_time method is used to set a substitution variable.
*
* \param name
* The name of the variable to be set.
* \param value
* The value of the variable to be set.
*/
void var_set_time(const char *name, time_t value);
/**
* The var_optional method is used to mark a substitution variable
* as optional, meaning that is doesn't have to be used.
*
* \param name
* The name of the optional variable.
*/
void var_optional(const char *name);
/**
* The var_append_if_unused method is used to mark a substitution
* variable as one which is appended if it is not used anywhere in
* the substituition.
*
* \param name
* The name of the substitution variable.
*/
void var_append_if_unused(const char *name);
/**
* The var_override method is used to mark a substitution
* variable as one which is to override a built-in substitution.
*
* \param name
* The name of the substitution variable.
* \note
* Use sparingly.
*/
void var_override(const char *name);
/**
* The var_resubstitute method is used to mark a substitution
* variable as one which is to have its substitution value
* re-interpreted for more substitutions. The default is not to do
* this.
*
* \param name
* The name of the substitution variable.
* \note
* Use sparingly.
*/
void var_resubstitute(const char *name);
/**
* The errno_setx method is used to set the $ERRNO value in the
* given substitition context.
*
* \note
* There is no method to directly read errno and set it, because
* there is at least one malloc() library call and possibly several
* others before you get arround to calling this function.
* You *must* instead copy the value of errno immediatly after
* the offending system call, and before doing inything towards
* preparing the error message.
*/
void errno_setx(int value);
/**
* The substitute method is used to perform substitutions on
* strings. Usually command strings, but not always.
*
* The format of substitutions, and the commonly available
* substitutions, are described in aesub(5).
*
* \param cp
* The change to provide context for the substitution.
* \param the_command
* The string to be sustituted into.
*/
string_ty *substitute(change::pointer cp, string_ty *the_command);
/**
* The substitute_p method is used to substitute into the given string.
*
* \param pp
* The project to provide context for the substitution.
* \param the_command
* The string to be sustituted into.
* See aesub(5) for valid substitutions.
*/
string_ty *substitute_p(project_ty *pp, string_ty *the_command);
/**
* The sub_intl method is used to substitute into the given string.
*
* \param substme
* The string to be sustituted into.
* See aesub(5) for valid substitutions.
*/
string_ty *subst_intl(const char *substme);
/**
* The subst_intl_project method is used to set the project for the
* substitution context.
*
* \param pp
* The project for context.
*/
void subst_intl_project(struct project_ty *pp);
/**
* The subst_intl_change method is used to set the change for the
* substitution context.
*
* \param cp
* The change for context.
*/
void subst_intl_change(change::pointer cp);
/**
* The error_intl method is used to internationalize an error
* message (vis the gettext function) then substitute it, and then
* print it.
*
* \param message
* The error message to be processed.
*/
void error_intl(const char *message);
/**
* The fatal_intl method is used to internationalize an error
* message (vis the gettext function) then substitute it, then
* print it, and then exit with exist status 1.
*
* \param message
* The error message to be processed.
* \note
* This method does not return.
*/
void fatal_intl(const char *message) NORETURN;
/**
* The verbose_intl method is used to internationalize an error
* message (vis the gettext function) then substitute it, and then
* print it. If the verbose option is not in effect, nothing will
* be printed.
*
* \param message
* The error message to be processed.
*/
void verbose_intl(const char *message);
/**
* The error_set method is used to mark a substitution context as
* erroneous. This occurs when there is something wrong with the
* message being substituted.
*
* \param message
* The error message describing what is wrong with the
* substitution message currently being processed.
* \note
* This method is only to be used by the built-in functions as
* feedback when something goes wrong.
*/
void error_set(const char *message);
/**
* The project_get method is used to obtain a pointer to the
* project for this context.
*
* \returns
* Pointer to the project, or NULL if no project is relevant at
* this point.
* \note
* This method is only to be used by the built-in functions to
* obtain their context.
*/
project_ty *project_get();
/**
* The change_get method is used to obtain a pointer to the
* change for this context.
*
* \returns
* Pointer to the change, or NULL if no change is relevant at
* this point.
* \note
* This method is only to be used by the built-in functions to
* obtain their context.
*/
change::pointer change_get();
/**
* The errno_sequester_get method is used to obtain the sequestered
* errno value. This method shall only be called by sub_errno().
*/
int errno_sequester_get() const;
/**
* The subst method is used to substitute the given string.
*
* \param msg
* The string to be substituted into.
* \returns
* The string result of the substitution.
*/
wstring subst(const wstring &msg);
/**
* The subst_inst_wide method is used to substitute the given
* string. The message will be passed through gettext before being
* substituted.
*
* \param msg
* The string to be substituted into.
* \returns
* The string result of the substitution.
*/
wstring subst_intl_wide(const char *msg);
private:
sub_diversion_stack diversion_stack;
sub_functor_list var_list;
change::pointer cp;
project_ty *pp;
const char *suberr;
int errno_sequester;
const char *file_name;
int line_number;
/**
* The diversion_close method is used to release a diversion when
* it has been exhausted.
*/
void diversion_close();
enum getc_type
{
getc_type_control,
getc_type_data
};
/**
* The getc_meta method is used to get a character from the current
* input string. When the current string is exhaused, the previous
* string is resumed.
*
* \returns
* the chacater, or NUL to indicate end of input
*/
wchar_t getc_meta(getc_type &c);
/**
* The getc_meta_undo function is used to give back a character
* output by getc_meta.
*
* \param c
* character being given back
* \note
* Only push back what was read.
*/
void getc_meta_undo(wchar_t c);
/**
* The getch method is used to get the next character of input from
* the diversion stack and characterize it appropriately.
*
* It calls the dollar() method at the appropriate times.
*/
wchar_t getch(getc_type &tr);
/**
* The dollar method is used to perform dollar ($) substitutions.
* On entry, the $ is expected to have been consumed.
*
* The substitution is usually achieved as a side-effect, by using
* the diversion_stack.
*
* \returns
* wchar_t a character to deliver as output, or L'\0' if none.
*/
wchar_t dollar();
/**
* The execute method is used to perform a substitution once all
* the arguments are known. The firsdt (0'th) argument is the name
* of the substitution to perform.
*/
void execute(const wstring_list &arg);
/**
* The copy constructor. Do not use.
*/
sub_context_ty(const sub_context_ty &);
/**
* The assignment operator. Do not use.
*/
sub_context_ty &operator=(const sub_context_ty &);
};
inline sub_context_ty *
sub_context_New(const char *file, int line)
{
return new sub_context_ty(file, line);
}
inline sub_context_ty *
sub_context_new()
{
return new sub_context_ty();
}
inline void
sub_context_delete(sub_context_ty *scp)
{
delete scp;
}
inline void
sub_var_clear(sub_context_ty *scp)
{
scp->clear();
}
inline void ATTR_PRINTF(3, 4)
sub_var_set_format(sub_context_ty *scp, const char *name, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
scp->var_set_vformat(name, fmt, ap);
va_end(ap);
}
/**
* The sub_var_set_string function is used to set the value of a
* substitution variable.
*
* \param scp
* The substitution context to set the variable within.
* \param name
* The name of the variable to be set.
* \param value
* The value of the variable to be set.
*/
inline void
sub_var_set_string(sub_context_ty *scp, const char *name, string_ty *value)
{
scp->var_set_string(name, value);
}
/**
* The sub_var_set_string function is used to set the value of a
* substitution variable.
*
* \param scp
* The substitution context to set the variable within.
* \param name
* The name of the variable to be set.
* \param value
* The value of the variable to be set.
*/
inline void
sub_var_set_string(sub_context_ty *scp, const char *name, const nstring &value)
{
scp->var_set_string(name, value);
}
inline void
sub_var_set_charstar(sub_context_ty *scp, const char *name, const char *value)
{
scp->var_set_charstar(name, value);
}
inline void
sub_var_set_long(sub_context_ty *scp, const char *name, long value)
{
scp->var_set_long(name, value);
}
inline void
sub_var_set_time(sub_context_ty *scp, const char *name, time_t value)
{
scp->var_set_time(name, value);
}
inline void
sub_var_optional(sub_context_ty *scp, const char *name)
{
scp->var_optional(name);
}
inline void
sub_var_append_if_unused(sub_context_ty *scp, const char *name)
{
scp->var_append_if_unused(name);
}
inline void
sub_var_override(sub_context_ty *scp, const char *name)
{
scp->var_override(name);
}
inline void
sub_var_resubstitute(sub_context_ty *scp, const char *name)
{
scp->var_resubstitute(name);
}
/**
* Set the $ERRNO value in the given substitition context.
*
* \note
* There is no method to directly read errno and set it, because
* there is at least one malloc() library call and possibly several
* others before you get around to calling this function.
* You *must* instead copy the value of errno immediatly after
* the offending system call, and before doing anything towards
* preparing the error message.
*/
inline void
sub_errno_setx(sub_context_ty *scp, int value)
{
scp->errno_setx(value);
}
inline string_ty *
substitute(sub_context_ty *scp, change::pointer cp, string_ty *the_command)
{
if (!scp)
{
sub_context_ty inner;
return inner.substitute(cp, the_command);
}
return scp->substitute(cp, the_command);
}
inline string_ty *
substitute_p(sub_context_ty *scp, struct project_ty *pp, string_ty *the_command)
{
if (!scp)
{
sub_context_ty inner;
return inner.substitute_p(pp, the_command);
}
return scp->substitute_p(pp, the_command);
}
inline string_ty *
subst_intl(sub_context_ty *scp, const char *substme)
{
if (!scp)
{
sub_context_ty inner;
return inner.subst_intl(substme);
}
return scp->subst_intl(substme);
}
inline void
subst_intl_project(sub_context_ty *scp, struct project_ty *pp)
{
if (!scp)
{
sub_context_ty inner;
inner.subst_intl_project(pp);
}
else
scp->subst_intl_project(pp);
}
inline void
subst_intl_change(sub_context_ty *scp, change::pointer cp)
{
if (!scp)
{
sub_context_ty inner;
inner.subst_intl_change(cp);
}
else
scp->subst_intl_change(cp);
}
inline void
error_intl(sub_context_ty *scp, const char *message)
{
if (!scp)
{
sub_context_ty inner;
inner.error_intl(message);
}
else
scp->error_intl(message);
}
inline void
fatal_intl(sub_context_ty *, const char *) NORETURN;
inline void
fatal_intl(sub_context_ty *scp, const char *message)
{
if (!scp)
{
sub_context_ty inner;
inner.fatal_intl(message);
}
else
scp->fatal_intl(message);
}
inline void
verbose_intl(sub_context_ty *scp, const char *message)
{
if (!scp)
{
sub_context_ty temp;
temp.verbose_intl(message);
}
else
scp->verbose_intl(message);
}
//
// The inline i18n function does nothing by itself, but it serves as a
// keyword for the xgettext program, when extracting internationalized
// msgid keys.
//
inline const char *
i18n(const char *x)
{
return x;
}
inline DEPRECATED void
sub_context_error_set(sub_context_ty *scp, const char *message)
{
scp->error_set(message);
}
inline project_ty *
sub_context_project_get(sub_context_ty *scp)
{
return scp->project_get();
}
inline change::pointer
sub_context_change_get(sub_context_ty *scp)
{
return scp->change_get();
}
#endif // SUB_H