/*****************************************************************************
/*
FAO.c
Formatted write using $FAO()-like directives, just a functional subset, it also
differs in some significant ways, including extended functionality. The
functions can write into either specified storage or into the request's output
buffer (probably more efficient that $FAO()ing into storage then copying this
to the network buffer). All parameters are passed via a $FAOL()-like
pointer-to-longword-vector. Strings are always assumed to be null-terminated.
A resultant string is always null-terminated (even after an error), hence the
'BufferSize' can always only store 'BufferSize'-1 characters. 'LengthPtr'
provides storage for the number of characters minus the null-termination.
It is no exageration to state that this functionality has made the sorts of
things undertaken with it ten times easier and more efficient!!
$FAO DIRECTIVES SUPPORTED
-------------------------
!AC counted ASCII string (first byte must be count, i.e. 0 to 255 chars)
!AZ null-terminated string
!SL decimal, signed longword
!SQ signed quadword (indirect character MUST be used (i.e. "!@SQ"))
!UL decimal, unsigned longword
!XL hexadecimal, longword
!ZL zero-filled decimal, unsigned longword
!%D date/time
!%I numeric to ASCII identifier
!%S if the last converted numeric value was not 1 add "S"
!%s if the last converted numeric value was not 1 add "s"
!%T time
!* multiple '*'+1 characters
!+ step-over the next parameter from the vector (anything BUT a "!&@")
!- back-up to the previous parameter in the vector (anything BUT a "!&@")
!< begin specified width output field (cannot nest, must have width!)
!> end specified width output field
!! exclamation mark
WASD EXTENSIONS
---------------
!&. replace non-printable characters with periods (e.g. "!&.AZ")
!&\ replace non-printable characters with slash-escapes (e.g. "!&\\AZ")
!&, comma-ize the following number (e.g. "!&,SL")
!&; HTML-escape the following string (e.g. "!&;AZ")
!&% URL-encode the following string (e.g. "!&%AZ")
!&[ format string as a file specification (requires preceding ODS flag)
!&^ force the following string to upper case
!&! force the following string to lower case
!&_ underline the following string if it contains a space (.. )
!&" quote/escape the following string if it contains a space ("..\"..")
!&+ if !AZ string is not null or empty then add a leading space
!&/ if !AZ string is not null or empty the add a trailing newline
!&8 UTF-8 encode string (8 bit characters only)
!&A address as a parameter, as "&00000000" (for module WATCHing)
!&B boolean (for WATCHing)
!&C a single character
!&D date/time string truncated after the minute
!&E until end-of-line (i.e. up to the next or )
!&F local function address, as "00000000()" (for module WATCHing)
!&H bytes in hexadecimal (field width is number)
!&I dotted-decimal from 32 bit network-order IP address
!&L same as !UL but implicitly comma-ized (as by '!&,')
!&M full status message string (returned from sys$getmsg())
!&m text-only status message string (returned from sys$getmsg())
!&O add " SELECTED" if true, "" if false (for option items)
!&P request URI (mask password, for module WATCHing)
!&R add " CHECKED" if true, "" if false (for radio buttons)
!&S VMS status value, as "%X00000000" (plus message string if non-success)
!&U URL encode
!&W weekday/date/time (field-width applies to date/time component only)
!&X hexadecimal value, as "0x00000000"
!&Z null-terminated string, as "{length}string" (for module WATCHing)
!&? simple conditional, "!&?string if *vector TRUE\rstring if FALSE\r"
!&@ nested format string address from vector (FILO stacks the current one)
!%% same as !&@ (for backward compatibility of strings in WASD_CONFIG_MSG)
The WASD extensions perform two roles. Some modify the way a following
directive is formatted, for example HTML-escaping it. Others provide
additonal format directives to standard $FAO. Field width should always be
placed BEFORE the WASD extensions. Indirection should be indicated immediately
before the respective formatting directive.
Each directive can have a positive, decimal integer between the '!' and the
directive providing a field width, e.g. "!10AZ", or have the field width taken
from the vector using "!#AZ". These behave in the same manner as the sys$fao()
field width parameter.
Any directive may use the indirect character (unlike sys$fao(), where only
numeric directives may). This indicates the vector value is the 32 bit address
of the value, rather than the value itself, e.g. "!@AZ", "!10@UL", etc.
VERSION HISTORY
---------------
29-OCT-2017 MGD bugfix; '%D' do not cancel field-width then "(none)"
02-JAN-2016 MGD bugfix; |if (fw <= 0) fw = 32;| to |if (fw < 0) fw = 32;|
23-APR-2015 MGD bugfix; FaoSAK() sdptr = StrDscBuffer(StrDscPtr);
11-JUL-2013 MGD FaoUrlEncodeTable tilde from "%7e" to "~" (cadaver issue)
11-SEP-2010 MGD '&\' slash-escapes common non-printable codes
27-JUN-2010 MGD '&S' now provides message string if non-success
30-MAY-2010 MGD '&8' UTF-8 encode string (only 8 bit characters)
09-JUN-2007 MGD use STR_DSC
make '!&E' the same functionality as previously '!&L'
and make '!&L' an implicitly comma-ized '!UL'
16-JUL-2005 MGD '&.' replace non-printable characters with periods,
replace ErrorNoticed() with FaoErrorNoticed() in
FaoToStdout() and FaoToOpcom() for the obvious reason
01-MAR-2003 MGD '&+' if not null or empty !AZ adds a leading space,
'&/' if not null or empty !AZ adds a trailing newline,
change behaviour of NULL !AZ to showing an empty string
18-OCT-2002 MGD '&"' quotes if there is a space in the string
19-AUG-2002 MGD '&[' for ODS file naming conversions,
'&^' now force-to-upper-case, '&!' force-to-lower,
'&_' underlines if there is a space in the string
08-AUG-2002 MGD '&U' request URI (mask password) now '&P',
'&U' now URL-encodes a URL (allowing for query string, etc.)
16-JUN-2002 MGD make field-width work for '&,'
31-MAR-2002 MGD '&U' request URI (mask password)
17-MAR-2002 MGD 'SQ' kludge for VAX quadword values
10-JAN-2002 MGD add !&R and !&O
04-AUG-2001 MGD differentiate WASD extensions with '!&',
support module WATCHing
07-JUL-2001 MGD add !IP to FaolSAK()
17-MAY-2001 MGD dignified with a module of it's own
02-FEB-2001 MGD add !%I to FaolSAK()
27-AUG-2000 MGD add !SL to FaolSAK()
04-MAR-2000 MGD add FaolSAK() and it's siblings
FaoToBuffer(), FaolToBuffer(), FaoToNet()
*/
/*****************************************************************************/
#ifdef WASD_VMS_V7
#undef _VMS__V6__SOURCE
#define _VMS__V6__SOURCE
#undef __VMS_VER
#define __VMS_VER 70000000
#undef __CRTL_VER
#define __CRTL_VER 70000000
#endif
/* standard C header files */
#include
#include
#include
#include
#include
/* VMS related header files */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/* application related header files */
#include "wasd.h"
#define WASD_MODULE "FAO"
/******************/
/* global storage */
/******************/
#if WATCH_MOD
BOOL DebugFaoSak;
# define DEBUG_FAOSAK DebugFaoSak
#else
# define DEBUG_FAOSAK 0
#endif
int OpcomMessages,
OpcomTarget;
char *FaoUrlEncodeTable [] =
{
"%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07",
"%08", "%09", "%0a", "%0b", "%0c", "%0d", "%0e", "%0f",
"%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17",
"%18", "%19", "%1a", "%1b", "%1c", "%1d", "%1e", "%1f",
"%20", "%21", "%22", "%23", "$", "%25", "%26", "%27",
"%28", "%29", "*", "%2b", "%2c", "-", ".", "/",
"0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", "%3a", ";", "%3c", "%3d", "%3e", "%3f",
"%40", "A", "B", "C", "D", "E", "F", "G", /* 0x47 */
"H", "I", "J", "K", "L", "M", "N", "O", /* 0x4f */
"P", "Q", "R", "S", "T", "U", "V", "W", /* 0x57 */
"X", "Y", "Z", "%5b", "%5c", "%5d", "%5e", "_", /* 0x5f */
"%60", "a", "b", "c", "d", "e", "f", "g", /* 0x67 */
"h", "i", "j", "k", "l", "m", "n", "o", /* 0x6f */
"p", "q", "r", "s", "t", "u", "v", "w", /* 0x77 */
"x", "y", "z", "%7b", "%7c", "%7d", "~", "%7f",
"%80", "%81", "%82", "%83", "%84", "%85", "%86", "%87",
"%88", "%89", "%8a", "%8b", "%8c", "%8d", "%8e", "%8f",
"%90", "%91", "%92", "%93", "%94", "%95", "%96", "%97",
"%98", "%99", "%9a", "%9b", "%9c", "%9d", "%9e", "%9f",
"%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7",
"%a8", "%a9", "%aa", "%ab", "%ac", "%ad", "%ae", "%af",
"%b0", "%b1", "%b2", "%b3", "%b4", "%b5", "%b6", "%b7",
"%b8", "%b9", "%ba", "%bb", "%bc", "%bd", "%be", "%bf",
"%c0", "%c1", "%c2", "%c3", "%c4", "%c5", "%c6", "%c7",
"%c8", "%c9", "%ca", "%cb", "%cc", "%cd", "%ce", "%cf",
"%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",
"%d8", "%d9", "%da", "%db", "%dc", "%dd", "%de", "%df",
"%e0", "%e1", "%e2", "%e3", "%e4", "%e5", "%e6", "%e7",
"%e8", "%e9", "%ea", "%eb", "%ec", "%ed", "%ee", "%ef",
"%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
"%ff", "%f9", "%fa", "%fb", "%fc", "%fd", "%fe", "%ff"
};
/* keep this for a couple of versions until the above proves itself */
char *FaoUrlEncodeTable2 [] =
{
"%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07",
"%08", "%09", "%0a", "%0b", "%0c", "%0d", "%0e", "%0f",
"%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17",
"%18", "%19", "%1a", "%1b", "%1c", "%1d", "%1e", "%1f",
"%20", "%21", "%22", "%23", "$", "%25", "%26", "%27",
"%28", "%29", "*", "%2b", "%2c", "-", ".", "/",
"0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", "%3a", ";", "%3c", "%3d", "%3e", "%3f",
"%40", "A", "B", "C", "D", "E", "F", "G", /* 0x47 */
"H", "I", "J", "K", "L", "M", "N", "O", /* 0x4f */
"P", "Q", "R", "S", "T", "U", "V", "W", /* 0x57 */
"X", "Y", "Z", "%5b", "%5c", "%5d", "%5e", "_", /* 0x5f */
"%60", "a", "b", "c", "d", "e", "f", "g", /* 0x67 */
"h", "i", "j", "k", "l", "m", "n", "o", /* 0x6f */
"p", "q", "r", "s", "t", "u", "v", "w", /* 0x77 */
"x", "y", "z", "%7b", "%7c", "%7d", "%7e", "%7f",
"%80", "%81", "%82", "%83", "%84", "%85", "%86", "%87",
"%88", "%89", "%8a", "%8b", "%8c", "%8d", "%8e", "%8f",
"%90", "%91", "%92", "%93", "%94", "%95", "%96", "%97",
"%98", "%99", "%9a", "%9b", "%9c", "%9d", "%9e", "%9f",
"%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7",
"%a8", "%a9", "%aa", "%ab", "%ac", "%ad", "%ae", "%af",
"%b0", "%b1", "%b2", "%b3", "%b4", "%b5", "%b6", "%b7",
"%b8", "%b9", "%ba", "%bb", "%bc", "%bd", "%be", "%bf",
"%c0", "%c1", "%c2", "%c3", "%c4", "%c5", "%c6", "%c7",
"%c8", "%c9", "%ca", "%cb", "%cc", "%cd", "%ce", "%cf",
"%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",
"%d8", "%d9", "%da", "%db", "%dc", "%dd", "%de", "%df",
"%e0", "%e1", "%e2", "%e3", "%e4", "%e5", "%e6", "%e7",
"%e8", "%e9", "%ea", "%eb", "%ec", "%ed", "%ee", "%ef",
"%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
"%ff", "%f9", "%fa", "%fb", "%fc", "%fd", "%fe", "%ff"
};
/********************/
/* external storage */
/********************/
#ifdef DBUG
extern BOOL Debug;
#else
#define Debug 0
#endif
extern BOOL OdsExtended;
extern int OutputBufferSize;
extern int ToLowerCase[],
ToUpperCase[];
extern char ErrorSanityCheck[],
SoftwareID[];
extern char *DayName[];
extern HTTPD_PROCESS HttpdProcess;
extern WATCH_STRUCT Watch;
/*****************************************************************************/
/*
FAOL Swiss Army Knife. This is the primary FAO function described in the
module prologue. It will be more than obvious it has been written to optimize
efficiency (in the author's limited appreciation anyway) rather than
readability.
*/
int FaolSAK
(
REQUEST_STRUCT *rqptr,
void *BufferPtr,
int BufferSize,
ushort *LengthPtr,
char *FormatString,
ulong *VectorPtr
)
{
#define FORMAT_STACK_MAX 8
static char HexDigits [] = "0123456789abcdef";
static char HexDigitsUpper [] = "0123456789ABCDEF";
static char EncBuffer [] = "%xx";
static char OneChar [] = "\0";
static $DESCRIPTOR (DayDateTimeFaoDsc, "!AZ, !#%D\0");
static $DESCRIPTOR (HexValueFaoDsc, "0x!8XL\0");
static $DESCRIPTOR (LengthStringFaoDsc, "{!UL}!-!#AZ\0");
static $DESCRIPTOR (Md5FaoDsc, "!8XL!8XL!8XL!8XL\0");
static $DESCRIPTOR (Md5WidthFaoDsc, "!#\0");
static $DESCRIPTOR (PDFaoDsc, "!%D\0");
static $DESCRIPTOR (PIFaoDsc, "!%I\0");
static $DESCRIPTOR (PTFaoDsc, "!%T\0");
static $DESCRIPTOR (SLFaoDsc, "!SL\0");
static $DESCRIPTOR (SLWidthFaoDsc, "!#SL\0");
static $DESCRIPTOR (SQFaoDsc, "!@SQ\0");
static $DESCRIPTOR (SQWidthFaoDsc, "!#@SQ\0");
static $DESCRIPTOR (ULFaoDsc, "!UL\0");
static $DESCRIPTOR (ULWidthFaoDsc, "!#UL\0");
static $DESCRIPTOR (VmsStatusFaoDsc, "%X!8XL\0");
static $DESCRIPTOR (VmsStatusMsgFaoDsc, "%X!8XL (!AZ)\0");
static $DESCRIPTOR (WatchingAddressFaoDsc, "&!8XL/!AZ()\0");
static $DESCRIPTOR (WatchingFunctionFaoDsc, "!8XL()\0");
static $DESCRIPTOR (XLFaoDsc, "!XL\0");
static $DESCRIPTOR (XLWidthFaoDsc, "!#XL\0");
static $DESCRIPTOR (ZLFaoDsc, "!ZL\0");
static $DESCRIPTOR (ZLWidthFaoDsc, "!#ZL\0");
BOOL CommaNumber,
FileSpec,
ForceLowerCase,
ForceUpperCase,
HtmlEscape,
IndirectValue,
PeriodNonPrintable,
QuoteIfSpace,
SlashNonPrintable,
SpaceThenString,
TrailingNewlineString,
UnderlineIfSpace,
UrlEncode,
Utf8Encode;
int ch, fw, ofw, idx,
status,
CommaCount,
DescrLength,
FileOds,
LastNumericValue,
SysGetMsgFlags;
ushort Length;
ulong DayOfWeek,
VectorValue;
ulong Time64 [2];
ulong *ulptr,
*Time64Ptr;
char *bptr, *bzptr, *cptr, *fptr, *sptr, *zptr,
*HexDigitsPtr,
*LastFptr;
char *FormatStack [FORMAT_STACK_MAX];
char FileString [ODS_MAX_FILE_NAME_LENGTH],
String [2048];
$DESCRIPTOR (StringDsc, String);
struct dsc$descriptor *VmsDscPtr;
STR_DSC *sdptr,
*StrDscPtr;
STR_DSC_AUTO (BufferDsc);
#ifdef __VAX
double dValue;
#endif
#if WATCH_MOD
{
static BOOL DebugFaoSakCheck;
if (!DebugFaoSakCheck)
{
DebugFaoSakCheck = true;
DebugFaoSak = getenv ("WASD_DEBUG_FAOSAK");
}
}
#endif
/*********/
/* begin */
/*********/
if (WATCHMOD (rqptr, WATCH_MOD_FAO))
WatchThis (WATCHITM(rqptr), WATCH_MOD_FAO,
"FaolSAK() !&X !UL !&X !AZ",
BufferPtr, BufferSize, LengthPtr, FormatString);
status = SS$_NORMAL;
LastNumericValue = 1;
/* start with output-field-width set to infinite */
ofw = -1;
if (LengthPtr) *LengthPtr = 0;
if (BufferPtr)
{
if (BufferSize == -1)
{
/* writing to specified STR_DSC storage */
sdptr = StrDscPtr = (STR_DSC*)BufferPtr;
sdptr = StrDscBuffer (sdptr);
bptr = STR_DSC_PTR(sdptr) + STR_DSC_LEN(sdptr);
bzptr = STR_DSC_PTR(sdptr) + STR_DSC_SIZE(sdptr);
}
else
{
/* writing to specified char[] storage */
sdptr = StrDscPtr = StrDscExternal (NULL, &BufferDsc,
BufferPtr, BufferSize);
bptr = STR_DSC_PTR(sdptr) = BufferPtr;
bzptr = STR_DSC_PTR(sdptr) + BufferSize-1;
}
}
else
{
/* writing to network buffer */
sdptr = StrDscIfNotBegin (rqptr, &rqptr->NetWriteBufferDsc,
OutputBufferSize);
sdptr = StrDscPtr = StrDscBuffer (sdptr);
bptr = STR_DSC_PTR(sdptr) + STR_DSC_LEN(sdptr);
bzptr = STR_DSC_PTR(sdptr) + STR_DSC_SIZE(sdptr);
}
/* put initial format string into index zero of the format string stack */
idx = 0;
FormatStack[idx] = FormatString;
/*************************/
/* nested format strings */
/*************************/
for (;;)
{
/*****************/
/* format string */
/*****************/
fptr = FormatStack[idx];
while (*fptr)
{
while (*fptr && *fptr != '!' && ofw)
{
/* a literal character */
if (bptr < bzptr)
{
*bptr++ = *fptr++;
ofw--;
continue;
}
if (STR_DSC_IS_EXTERNAL(sdptr)) goto FaolSAKovf;
STR_DSC_LEN(sdptr) = bptr - STR_DSC_PTR(sdptr);
sdptr = StrDscBuffer (StrDscPtr);
bptr = STR_DSC_PTR(sdptr) + STR_DSC_LEN(sdptr);
bzptr = STR_DSC_PTR(sdptr) + STR_DSC_SIZE(sdptr);
}
/* if end of literal characters (i.e. not a '!') then break */
if (!*fptr) break;
/* if no character follows the '!' then just forget it */
LastFptr = fptr;
if (!*++fptr) break;
/*********************/
/* format directives */
/*********************/
if (DEBUG_FAOSAK)
fprintf (stdout, "fptr |%10.10s|\n", fptr);
fw = -1;
IndirectValue = false;
/*********************/
/* field width, etc. */
/*********************/
if (isdigit(*fptr))
{
/* field-width */
fw = atoi(fptr);
while (isdigit(*fptr)) fptr++;
/* for writes into network buffers, let's keep this < 1024 */
if (!BufferPtr) fw &= 0xfff;
}
else
if (*fptr == '#')
{
/* field-width from vector */
fptr++;
fw = (int)*VectorPtr++;
/* for writes into network buffers, let's keep this < 1024 */
if (!BufferPtr) fw &= 0xfff;
}
/** if (DEBUG_FAOSAK) fprintf (stdout, "fw: %d\n", fw); **/
if (*fptr == '@')
{
fptr++;
IndirectValue = true;
}
FileOds = 0;
DescrLength = -1;
CommaNumber = FileSpec = ForceLowerCase = ForceUpperCase =
HtmlEscape = PeriodNonPrintable = QuoteIfSpace =
SpaceThenString = SlashNonPrintable = TrailingNewlineString =
UnderlineIfSpace = UrlEncode = Utf8Encode = false;
while (*fptr == '&')
{
/************************/
/* formatting modifiers */
/************************/
if (SAME2(fptr,'&.'))
{
fptr += 2;
PeriodNonPrintable = true;
continue;
}
if (SAME2(fptr,'&\\'))
{
fptr += 2;
SlashNonPrintable = true;
continue;
}
if (SAME2(fptr,'&,'))
{
fptr += 2;
CommaNumber = true;
continue;
}
if (SAME2(fptr,'&;'))
{
fptr += 2;
HtmlEscape = true;
continue;
}
if (SAME2(fptr,'&%'))
{
fptr += 2;
UrlEncode = true;
continue;
}
if (SAME2(fptr,'&['))
{
fptr += 2;
FileSpec = true;
/* get the numeric value of the file naming schema */
FileOds = *VectorPtr++;
continue;
}
if (SAME2(fptr,'&!'))
{
fptr += 2;
ForceLowerCase = true;
continue;
}
if (SAME2(fptr,'&^'))
{
fptr += 2;
ForceUpperCase = true;
continue;
}
if (SAME2(fptr,'&_'))
{
fptr += 2;
UnderlineIfSpace = true;
continue;
}
if (SAME2(fptr,'&"'))
{
fptr += 2;
QuoteIfSpace = true;
continue;
}
if (SAME2(fptr,'&+'))
{
fptr += 2;
SpaceThenString = true;
continue;
}
if (SAME2(fptr,'&/'))
{
fptr += 2;
TrailingNewlineString = true;
continue;
}
if (SAME2(fptr,'&8'))
{
fptr += 2;
Utf8Encode = true;
continue;
}
break;
}
if (*fptr == '@')
{
fptr++;
IndirectValue = true;
}
/* default is no string to copy if it drops through */
sptr = NULL;
/* directives in guessed order of most common usage */
if (SAME2(fptr,'AZ'))
{
/**************************/
/* null-terminated string */
/**************************/
fptr += 2;
if (IndirectValue)
{
if (!*VectorPtr)
{
status = SS$_ACCVIO;
break;
}
sptr = *(char*)*VectorPtr++;
}
else
sptr = (char*)*VectorPtr++;
if (WATCHMOD (rqptr, WATCH_MOD_FAO))
if (!sptr)
WatchThis (WATCHITM(rqptr), WATCH_MOD_FAO, "(null)");
if (!sptr) sptr = "";
/* null or empty string suppresses these */
if (!sptr[0]) SpaceThenString = TrailingNewlineString = false;
if (DEBUG_FAOSAK) fprintf (stdout, "!AZ |%s|\n", sptr);
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'UL') ||
SAME2(fptr,'&L'))
{
/*********************/
/* unsigned longword */
/*********************/
if (SAME2(fptr,'&L')) CommaNumber = true;
fptr += 2;
if (IndirectValue)
{
if (!*VectorPtr)
{
status = SS$_ACCVIO;
break;
}
LastNumericValue = *(ULONGPTR)VectorPtr++;
}
else
LastNumericValue = *VectorPtr++;
if (DEBUG_FAOSAK)
fprintf (stdout, "!UL %d\n", LastNumericValue);
if (fw > 0 && !CommaNumber)
status = sys$fao (&ULWidthFaoDsc, 0, &StringDsc,
fw, LastNumericValue);
else
status = sys$fao (&ULFaoDsc, 0, &StringDsc,
LastNumericValue);
if (VMSnok (status)) break;
if (!CommaNumber) fw = -1;
sptr = String;
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'XL'))
{
/************************/
/* hexadecimal longword */
/************************/
fptr += 2;
if (IndirectValue)
{
if (!*VectorPtr)
{
status = SS$_ACCVIO;
break;
}
LastNumericValue = *(ULONGPTR)VectorPtr++;
}
else
LastNumericValue = *VectorPtr++;
if (DEBUG_FAOSAK)
fprintf (stdout, "!UL %d\n", LastNumericValue);
if (fw > 0 && !CommaNumber)
status = sys$fao (&XLWidthFaoDsc, 0, &StringDsc,
fw, LastNumericValue);
else
status = sys$fao (&XLFaoDsc, 0, &StringDsc,
LastNumericValue);
if (VMSnok (status)) break;
if (!CommaNumber) fw = -1;
sptr = String;
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'ZL'))
{
/************************/
/* zero-filled longword */
/************************/
fptr += 2;
if (IndirectValue)
{
if (!*VectorPtr)
{
status = SS$_ACCVIO;
break;
}
LastNumericValue = *(ULONGPTR)VectorPtr++;
}
else
LastNumericValue = *VectorPtr++;
if (DEBUG_FAOSAK)
fprintf (stdout, "!UL %d\n", LastNumericValue);
if (fw > 0 && !CommaNumber)
status = sys$fao (&ZLWidthFaoDsc, 0, &StringDsc,
fw, LastNumericValue);
else
status = sys$fao (&ZLFaoDsc, 0, &StringDsc,
LastNumericValue);
if (VMSnok (status)) break;
if (!CommaNumber) fw = -1;
sptr = String;
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'&@') ||
SAME2(fptr,'%%')) /* for backward compatibility */
{
/************************/
/* nested format string */
/************************/
fptr += 2;
if (idx >= FORMAT_STACK_MAX)
{
status = SS$_OVRMAXARG;
break;
}
if (IndirectValue)
{
if (!*VectorPtr)
{
status = SS$_ACCVIO;
break;
}
cptr = *(char*)*VectorPtr++;
}
else
cptr = (char*)*VectorPtr++;
if (!cptr)
{
status = SS$_ACCVIO;
break;
}
/* if empty then just continue with the current format string */
if (!cptr[0]) continue;
/* save the current format string pointer */
FormatStack[idx++] = fptr;
/* set the new format string pointer */
fptr = FormatStack[idx] = cptr;
if (DEBUG_FAOSAK)
fprintf (stdout, "!&@ idx: %d fptr |%s|\n", idx, fptr);
continue;
}
else
if (SAME2(fptr,'&h') ||
SAME2(fptr,'&H'))
{
/***************/
/* hexadecimal */
/***************/
fptr += 2;
if (IndirectValue)
{
if (!*VectorPtr)
{
status = SS$_ACCVIO;
break;
}
cptr = *(char*)*VectorPtr++;
}
else
cptr = (char*)*VectorPtr++;
if (!cptr)
sptr = "(null)";
else
{
if (SAME2(fptr,'&h'))
HexDigitsPtr = HexDigits;
else
HexDigitsPtr = HexDigitsUpper;
zptr = (sptr = String) + sizeof(String)-1;
if (fw < 0) fw = 32;
while (fw-- > 0)
{
if (sptr >= zptr) break;
*sptr++ = HexDigitsPtr[(*(uchar*)cptr >> 4) & 0x0f];
if (sptr >= zptr) break;
*sptr++ = HexDigitsPtr[*(uchar*)cptr & 0x0f];
cptr++;
}
*sptr = '\0';
sptr = String;
}
fw = -1;
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'&I'))
{
/**************************************/
/* dotted-decimal/IPv6-hex IP address */
/**************************************/
fptr += 2;
if (IndirectValue)
{
if (!*VectorPtr)
{
status = SS$_ACCVIO;
break;
}
LastNumericValue = *(ULONGPTR)VectorPtr++;
}
else
LastNumericValue = *VectorPtr++;
/* 'LastNumericValue' can be a pointer or an integer */
sptr = TcpIpAddressToString (LastNumericValue, fw);
fw = -1;
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'&E'))
{
/*****************/
/* the next line */
/*****************/
fptr += 2;
if (IndirectValue)
{
if (!*VectorPtr)
{
status = SS$_ACCVIO;
break;
}
sptr = *(char*)*VectorPtr++;
}
else
sptr = (char*)*VectorPtr++;
if (sptr)
{
for (zptr = sptr;
*zptr && *zptr != '\r' && *zptr != '\n';
zptr++);
/* use field-width to control how much of the string is output */
fw = zptr - sptr;
if (DEBUG_FAOSAK)
fprintf (stdout, "!&L |%*.*s|\n", fw, fw, sptr);
status = sys$fao (&LengthStringFaoDsc, 0, &StringDsc, fw, sptr);
sptr = String;
}
else
sptr = "{0}(null)";
fw = -1;
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'&M') ||
SAME2(fptr,'&m'))
{
/******************/
/* status message */
/******************/
if (SAME2(fptr,'&M'))
SysGetMsgFlags = 15;
else
SysGetMsgFlags = 1;
fptr += 2;
if (IndirectValue)
{
if (!*VectorPtr)
{
status = SS$_ACCVIO;
break;
}
VectorValue = *(ULONGPTR)VectorPtr++;
}
else
VectorValue = *VectorPtr++;
if (DEBUG_FAOSAK)
fprintf (stdout, "!%%M %d\n", VectorValue);
status = sys$getmsg (VectorValue, &Length, &StringDsc,
SysGetMsgFlags, 0);
if (VMSnok (status))
sptr = "*ERROR* sys$getmsg()";
else
{
(sptr = String)[Length] = '\0';
if (SysGetMsgFlags == 15) sptr++;
}
if (DEBUG_FAOSAK)
fprintf (stdout, "sys$getmsg() |%s|\n", String);
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'SQ'))
{
/*******************/
/* signed quadword */
/*******************/
/*
Note that the "!SQ" directive is being used, for VMS 6.2
the "!UQ" && "!UJ" loop infinitely for signed values.
Also note the indirect character MUST be used (i.e. "!@SQ").
Also that VAX doesn't support it - so a kludge is employed.
*/
fptr += 2;
if (IndirectValue)
{
if (!*VectorPtr)
{
status = SS$_ACCVIO;
break;
}
LastNumericValue = 0;
}
else
{
/* must be indirect */
#if WATCH_MOD
fprintf (stdout, "%%HTTPD-W-FAO, SS$_BADPARAM %s:%d\n \\%s\\\n",
FI_LI, fptr-2);
#endif /* WATCH_MOD */
status = SS$_BADPARAM;
break;
}
if (DEBUG_FAOSAK)
fprintf (stdout, "!SQ %d\n", LastNumericValue);
#ifdef __VAX
/* kludge, apparently ok all the way up to 53 bits */
dValue = (double)((ULONGPTR)(*VectorPtr))[0];
dValue += (double)((ULONGPTR)(*VectorPtr))[1] * 4294967296.0;
VectorPtr++;
status = SS$_NORMAL;
if (fw > 0 && !CommaNumber)
sprintf (String, "%*.0f", fw, dValue);
else
sprintf (String, "%.0f", dValue);
#else /* Alpha or ia64 */
if (fw > 0 && !CommaNumber)
status = sys$fao (&SQWidthFaoDsc, 0, &StringDsc,
fw, *VectorPtr++);
else
status = sys$fao (&SQFaoDsc, 0, &StringDsc,
*VectorPtr++);
#endif /* ifdef __VAX */
if (VMSnok (status)) break;
if (!CommaNumber) fw = -1;
sptr = String;
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'SL'))
{
/*******************/
/* signed longword */
/*******************/
fptr += 2;
if (IndirectValue)
{
if (!*VectorPtr)
{
status = SS$_ACCVIO;
break;
}
LastNumericValue = *(ULONGPTR)VectorPtr++;
}
else
LastNumericValue = *VectorPtr++;
if (DEBUG_FAOSAK)
fprintf (stdout, "!SL %d\n", LastNumericValue);
if (fw > 0 && !CommaNumber)
status = sys$fao (&SLWidthFaoDsc, 0, &StringDsc,
fw, LastNumericValue);
else
status = sys$fao (&SLFaoDsc, 0, &StringDsc,
LastNumericValue);
if (VMSnok (status)) break;
if (!CommaNumber) fw = -1;
sptr = String;
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'%D') ||
SAME2(fptr,'&D'))
{
/*************/
/* date/time */
/*************/
cptr = fptr;
fptr += 2;
if (IndirectValue)
{
if (!*VectorPtr)
{
status = SS$_ACCVIO;
break;
}
Time64Ptr = *(ULONGPTR)VectorPtr++;
}
else
Time64Ptr = *VectorPtr++;
if (DEBUG_FAOSAK)
fprintf (stdout, "!%%D %d\n", Time64Ptr);
if (!Time64Ptr) sys$gettim (Time64Ptr = &Time64);
if (QUAD_ZERO(Time64Ptr))
sptr = "(none)";
else
{
status = sys$fao (&PDFaoDsc, 0, &StringDsc, Time64Ptr);
if (VMSnok (status)) break;
for (sptr = String; *sptr && *sptr != '-'; sptr++);
/* absolute times have leading space changed to leading zero */
if (*sptr && String[0] == ' ')
(sptr = String)[0] = '0';
else
if (*sptr)
sptr = String;
else
/* delta times have leading spaces absorbed */
for (sptr = String; *sptr && *sptr == ' '; sptr++);
if (SAME2(cptr,'&D'))
{
/* massage the time a little further */
for (cptr = sptr; *cptr && *cptr != ' '; cptr++);
if (*cptr)
if (sptr[2] == '-')
*cptr++ = ':';
else
*cptr++ = '-';
while (*cptr && *cptr != ':') cptr++;
if (*cptr) cptr++;
while (*cptr && *cptr != ':') cptr++;
*cptr = '\0';
}
}
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'%I'))
{
/***********************/
/* numeric to ASCII ID */
/***********************/
fptr += 2;
if (IndirectValue)
{
if (!*VectorPtr)
{
status = SS$_ACCVIO;
break;
}
VectorValue = *(ULONGPTR)VectorPtr++;
}
else
VectorValue = *VectorPtr++;
if (DEBUG_FAOSAK)
fprintf (stdout, "!%%D %d\n", VectorValue);
status = sys$fao (&PIFaoDsc, 0, &StringDsc, VectorValue);
if (VMSnok (status)) break;
sptr = String;
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'%T'))
{
/********/
/* time */
/********/
fptr += 2;
if (IndirectValue)
{
if (!*VectorPtr)
{
status = SS$_ACCVIO;
break;
}
Time64Ptr = *(ULONGPTR)VectorPtr++;
}
else
Time64Ptr = *VectorPtr++;
if (DEBUG_FAOSAK)
fprintf (stdout, "!%%T %d\n", Time64Ptr);
if (!Time64Ptr) sys$gettim (Time64Ptr = &Time64);
if (QUAD_ZERO(Time64Ptr))
{
sptr = "(none)";
if (fw > 0) fw = -1;
}
else
{
status = sys$fao (&PTFaoDsc, 0, &StringDsc, Time64Ptr);
if (VMSnok (status)) break;
sptr = String;
}
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'%s') ||
SAME2(fptr,'%S'))
{
/******************/
/* add 'S' or 's' */
/******************/
if (DEBUG_FAOSAK)
fprintf (stdout, "!%%%c\n", *(fptr+1));
if (LastNumericValue == 1)
{
fptr += 2;
continue;
}
fptr++;
fw = -1;
if (*fptr++ == 's')
sptr = "s";
else
sptr = "S";
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'AC'))
{
/************************/
/* counted ASCII string */
/************************/
fptr += 2;
if (IndirectValue)
{
if (!*VectorPtr)
{
status = SS$_ACCVIO;
break;
}
cptr = *(char*)*VectorPtr++;
}
else
cptr = (char*)*VectorPtr++;
if (!cptr)
{
status = SS$_ACCVIO;
break;
}
if (DEBUG_FAOSAK)
fprintf (stdout, "!AC %d |%s|\n", (uint)*cptr, cptr+1);
/* get the count byte */
ch = (uint)*cptr++;
while (ch)
{
if (bptr < bzptr)
{
*bptr++ = *cptr++;
ch--;
continue;
}
if (STR_DSC_IS_EXTERNAL(sdptr)) goto FaolSAKovf;
STR_DSC_LEN(sdptr) = bptr - STR_DSC_PTR(sdptr);
sdptr = StrDscBuffer (StrDscPtr);
bptr = STR_DSC_PTR(sdptr) + STR_DSC_LEN(sdptr);
bzptr = STR_DSC_PTR(sdptr) + STR_DSC_SIZE(sdptr);
}
/* only if required drop through to space-fill */
if (fw <= 0) continue;
/* no string to copy */
sptr = NULL;
}
else
if (SAME2(fptr,'&C'))
{
/* a single character */
fptr += 2;
String[0] = *VectorPtr++;
String[1] = '\0';
sptr = String;
fw = -1;
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'&P'))
{
/*****************/
/* mask password */
/*****************/
fptr += 2;
cptr = (char*)*VectorPtr++;
if (!cptr) cptr = "(null)";
zptr = (sptr = String) + sizeof(String)-1;
while (*cptr && sptr < zptr)
{
if (cptr[0] == ':' && cptr[1] == '/' && cptr[2] == '/') break;
*sptr++ = *cptr++;
}
if (*cptr)
{
if (sptr < zptr) *sptr++ = *cptr++;
if (sptr < zptr) *sptr++ = *cptr++;
if (sptr < zptr) *sptr++ = *cptr++;
while (*cptr && *cptr != '/' && *cptr != '@' && sptr < zptr)
*sptr++ = *cptr++;
if (*cptr == '@')
{
if (sptr < zptr) *sptr++ = *cptr++;
while (sptr > String && *sptr != ':') sptr--;
if (*sptr == ':')
{
sptr++;
while (*sptr && *sptr != '@') *sptr++ = '*';
if (*sptr) sptr++;
}
}
while (*cptr && sptr < zptr) *sptr++ = *cptr++;
}
*sptr = '\0';
sptr = String;
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'&U'))
{
/******************/
/* encode URL/URI */
/******************/
fptr += 2;
cptr = (char*)*VectorPtr++;
if (cptr)
StringUrlEncodeURL (cptr, sptr = String, sizeof(String));
else
sptr = "(null)";
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'&W'))
{
/*********************/
/* weekday/date/time */
/*********************/
fptr += 2;
if (IndirectValue)
{
if (!*VectorPtr)
{
status = SS$_ACCVIO;
break;
}
Time64Ptr = *(ULONGPTR)VectorPtr++;
}
else
Time64Ptr = *VectorPtr++;
if (DEBUG_FAOSAK)
fprintf (stdout, "!%%W %d\n", Time64Ptr);
if (!Time64Ptr) sys$gettim (Time64Ptr = &Time64);
if (QUAD_ZERO(Time64Ptr))
{
sptr = "(none)";
if (fw > 0) fw = -1;
}
else
if (VMSnok (lib$day_of_week (Time64Ptr, &DayOfWeek)))
sptr = "*ERROR*1";
else
if (VMSnok (sys$fao (&DayDateTimeFaoDsc, 0, &StringDsc,
DayName[DayOfWeek], fw > 0 ? fw : 23, Time64Ptr)))
sptr = "*ERROR*2";
else
sptr = String;
/* reset the field-width (only applies to date/time) */
if (fw > 0) fw = -1;
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'&R'))
{
/************************/
/* radio button boolean */
/************************/
fptr += 2;
if (IndirectValue)
{
if (!*VectorPtr)
{
status = SS$_ACCVIO;
break;
}
VectorValue = *(ULONGPTR)VectorPtr++;
}
else
VectorValue = *VectorPtr++;
if (DEBUG_FAOSAK)
fprintf (stdout, "!&? %d\n", VectorValue);
if (VectorValue) sptr = " CHECKED"; else sptr = "";
fw = -1;
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'&O'))
{
/*************************/
/* select option boolean */
/*************************/
fptr += 2;
if (IndirectValue)
{
if (!*VectorPtr)
{
status = SS$_ACCVIO;
break;
}
VectorValue = *(ULONGPTR)VectorPtr++;
}
else
VectorValue = *VectorPtr++;
if (DEBUG_FAOSAK)
fprintf (stdout, "!&? %d\n", VectorValue);
if (VectorValue) sptr = " SELECTED"; else sptr = "";
fw = -1;
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'&?'))
{
/**********************/
/* simple conditional */
/**********************/
/* e.g. "!&?string if *vector TRUE\rstring if FALSE\r" */
fptr += 2;
if (IndirectValue)
{
if (!*VectorPtr)
{
status = SS$_ACCVIO;
break;
}
VectorValue = *(ULONGPTR)VectorPtr++;
}
else
VectorValue = *VectorPtr++;
if (DEBUG_FAOSAK)
fprintf (stdout, "!&? %d\n", VectorValue);
if (!VectorValue)
{
/* if false skip over the true string */
while (*fptr && *fptr != '\r') fptr++;
if (*fptr == '\r') fptr++;
if (!*fptr) break;
}
while (*fptr && *fptr != '\r' && fw && ofw)
{
if (bptr < bzptr)
{
*bptr++ = *fptr++;
fw--;
ofw--;
continue;
}
if (STR_DSC_IS_EXTERNAL(sdptr)) goto FaolSAKovf;
STR_DSC_LEN(sdptr) = bptr - STR_DSC_PTR(sdptr);
sdptr = StrDscBuffer (StrDscPtr);
bptr = STR_DSC_PTR(sdptr) + STR_DSC_LEN(sdptr);
bzptr = STR_DSC_PTR(sdptr) + STR_DSC_SIZE(sdptr);
}
if (*fptr != '\r')
{
/* field-width has expired before the return */
while (*fptr && *fptr != '\r') fptr++;
}
if (*fptr == '\r') fptr++;
if (VectorValue)
{
/* was true, skip over the false string */
while (*fptr && *fptr != '\r') fptr++;
if (*fptr == '\r') fptr++;
}
/* only if required drop through to space-fill */
if (fw <= 0) continue;
}
else
if (*fptr == '+')
{
/**************************/
/* discard next parameter */
/**************************/
fptr++;
VectorValue = *VectorPtr++;
if (DEBUG_FAOSAK)
fprintf (stdout, "!+ %d\n", VectorValue);
}
else
if (*fptr == '-')
{
/****************************/
/* reuse previous parameter */
/****************************/
fptr++;
VectorValue = *--VectorPtr;
if (DEBUG_FAOSAK)
fprintf (stdout, "!- %d\n", VectorValue);
}
else
if (*fptr == '!')
{
/****************************/
/* an escaped '!' character */
/****************************/
if (DEBUG_FAOSAK) fprintf (stdout, "!!\n");
fptr++;
sptr = "!";
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (*fptr == '*')
{
/*****************************/
/* multiple '*'+1 characters */
/*****************************/
if (DEBUG_FAOSAK) fprintf (stdout, "!*\n");
if (!*++fptr) fw = 0;
while (fw > 0 && ofw)
{
if (bptr < bzptr)
{
*bptr++ = *fptr;
fw--;
ofw--;
continue;
}
if (STR_DSC_IS_EXTERNAL(sdptr)) goto FaolSAKovf;
STR_DSC_LEN(sdptr) = bptr - STR_DSC_PTR(sdptr);
sdptr = StrDscBuffer (StrDscPtr);
bptr = STR_DSC_PTR(sdptr) + STR_DSC_LEN(sdptr);
bzptr = STR_DSC_PTR(sdptr) + STR_DSC_SIZE(sdptr);
}
if (*fptr) fptr++;
continue;
}
else
if (*fptr == '<')
{
/****************************/
/* begin output-field-width */
/****************************/
if (DEBUG_FAOSAK) fprintf (stdout, "!<\n");
fptr++;
if (ofw >= 0)
{
/* can't nest these little blighters! */
#if WATCH_MOD
fprintf (stdout, "%%HTTPD-W-FAO, SS$_BADPARAM %s:%d\n \\%s\\\n",
FI_LI, fptr-1);
#endif /* WATCH_MOD */
status = SS$_BADPARAM;
break;
}
ofw = fw;
continue;
}
else
if (*fptr == '>')
{
/**************************/
/* end output-field-width */
/**************************/
if (DEBUG_FAOSAK) fprintf (stdout, "!>\n");
fptr++;
if (ofw < 0)
{
/* didn't notice a leading "!<" */
#if WATCH_MOD
fprintf (stdout, "%%HTTPD-W-FAO, SS$_BADPARAM %s:%d\n \\%s\\\n",
FI_LI, fptr-1);
#endif /* WATCH_MOD */
status = SS$_BADPARAM;
break;
}
/* get (any) current outstanding that needs space-filling */
fw = ofw;
/* reset output-field-width to infinite */
ofw = -1;
/* only if required drop through to space-fill */
if (fw <= 0) continue;
}
/***********************/
/* mainly for WATCHing */
/***********************/
else
if (SAME2(fptr,'&A'))
{
/* an "address" as &x00000000 */
fptr += 2;
LastNumericValue = *VectorPtr++;
if (!LastNumericValue)
cptr = "null";
else
if (!(cptr = WatchFunction (LastNumericValue)))
cptr = "?";
status = sys$fao (&WatchingAddressFaoDsc, 0, &StringDsc,
LastNumericValue, cptr);
if (VMSnok (status)) break;
fw = -1;
sptr = String;
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'&B'))
{
/* a boolean */
fptr += 2;
LastNumericValue = *VectorPtr++;
if (LastNumericValue) sptr = "TRUE"; else sptr = "FALSE";
fw = -1;
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'&F'))
{
/* a "function" address as &00000000 */
fptr += 2;
LastNumericValue = *VectorPtr++;
status = sys$fao (&WatchingFunctionFaoDsc, 0, &StringDsc,
LastNumericValue);
if (VMSnok (status)) break;
fw = -1;
sptr = String;
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'&S'))
{
/* VMS status value as %X00000000 */
fptr += 2;
LastNumericValue = *VectorPtr++;
if (LastNumericValue && VMSnok (LastNumericValue))
{
/* for non-success status provide corresponding message */
char Msg [256];
$DESCRIPTOR (MsgDsc, Msg);
SysGetMsgFlags = 15;
status = sys$getmsg (LastNumericValue, &Length, &MsgDsc,
SysGetMsgFlags, 0);
if (VMSnok (status))
strcpy (Msg, "*ERROR* sys$getmsg()");
else
Msg[Length] = '\0';
status = sys$fao (&VmsStatusMsgFaoDsc, 0, &StringDsc,
LastNumericValue, Msg);
}
else
status = sys$fao (&VmsStatusFaoDsc, 0, &StringDsc,
LastNumericValue);
if (VMSnok (status)) break;
fw = -1;
sptr = String;
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'&X'))
{
/* hexadecimal as 0x00000000 */
fptr += 2;
LastNumericValue = *VectorPtr++;
status = sys$fao (&HexValueFaoDsc, 0, &StringDsc,
LastNumericValue);
if (VMSnok (status)) break;
fw = -1;
sptr = String;
/* drop through to buffer the string pointed to by 'sptr' */
}
else
if (SAME2(fptr,'&Z'))
{
/* a null-terminated string as {length}string */
fptr += 2;
sptr = (char*)*VectorPtr++;
if (sptr)
{
status = sys$fao (&LengthStringFaoDsc, 0, &StringDsc,
strlen(sptr), sptr);
sptr = String;
}
else
sptr = "{0}(null)";
if (DEBUG_FAOSAK) fprintf (stdout, "!AZ |%s|\n", sptr);
/* drop through to buffer the string pointed to by 'sptr' */
}
else
{
#if WATCH_MOD
fprintf (stdout, "%%HTTPD-W-FAO, SS$_BADPARAM %s:%d\n \\%s\\\n",
FI_LI, fptr);
#endif /* WATCH_MOD */
status = SS$_BADPARAM;
break;
}
/*********************************/
/* copy a string into the buffer */
/*********************************/
if (DEBUG_FAOSAK)
fprintf (stdout, "sptr |%s|\n", sptr ? sptr : "(null)");
if (sptr)
{
if (CommaNumber)
{
/****************/
/* comma number */
/****************/
Length = strlen(sptr);
while (fw && ofw && Length + ((Length-1) / 3) < fw)
{
if (bptr < bzptr)
{
*bptr++ = ' ';
fw--;
ofw--;
continue;
}
if (STR_DSC_IS_EXTERNAL(sdptr)) goto FaolSAKovf;
STR_DSC_LEN(sdptr) = bptr - STR_DSC_PTR(sdptr);
sdptr = StrDscBuffer (StrDscPtr);
bptr = STR_DSC_PTR(sdptr) + STR_DSC_LEN(sdptr);
bzptr = STR_DSC_PTR(sdptr) + STR_DSC_SIZE(sdptr);
}
if (((Length-1) / 3) >= 1)
{
if (!(CommaCount = Length % 3))
CommaCount = 3;
while (*sptr && fw && ofw)
{
if (bptr < bzptr)
{
if (!CommaCount--)
{
*bptr++ = ',';
fw--;
ofw--;
CommaCount = 3;
}
else
{
*bptr++ = *sptr++;
fw--;
ofw--;
}
continue;
}
if (STR_DSC_IS_EXTERNAL(sdptr)) goto FaolSAKovf;
STR_DSC_LEN(sdptr) = bptr - STR_DSC_PTR(sdptr);
sdptr = StrDscBuffer (StrDscPtr);
bptr = STR_DSC_PTR(sdptr) + STR_DSC_LEN(sdptr);
bzptr = STR_DSC_PTR(sdptr) + STR_DSC_SIZE(sdptr);
}
/* only if required drop through to space-fill */
if (fw <= 0) continue;
sptr = NULL;
}
/* drop thru to copy 3 or less digits into the buffer */
FileSpec = HtmlEscape = QuoteIfSpace = SpaceThenString =
TrailingNewlineString = UnderlineIfSpace = UrlEncode =
Utf8Encode = false;
}
}
if (sptr)
{
if (FileSpec)
{
/**********************/
/* file specification */
/**********************/
switch (FileOds)
{
case 0 :
case MAPURL_PATH_ODS_2 :
if (!ForceUpperCase) ForceLowerCase = true;
/* just leave 'sptr' the way it is! */
break;
#ifdef ODS_EXTENDED
case MAPURL_PATH_ODS_5 :
MapOds5VmsToUrl (FileString, sptr,
sizeof(FileString), true);
sptr = FileString;
break;
#endif /* ODS_EXTENDED */
case MAPURL_PATH_ODS_ADS :
case MAPURL_PATH_ODS_SMB :
MapOdsAdsVmsToUrl (FileString, sptr,
sizeof(FileString), true);
sptr = FileString;
break;
case MAPURL_PATH_ODS_PWK :
MapOdsPwkVmsToUrl (FileString, sptr,
sizeof(FileString), true);
sptr = FileString;
break;
case MAPURL_PATH_ODS_SRI :
MapOdsSriVmsToUrl (FileString, sptr,
sizeof(FileString), true);
sptr = FileString;
break;
default :
return (SS$_BADPARAM);
}
}
if (QuoteIfSpace || SpaceThenString || UnderlineIfSpace)
{
for (cptr = sptr; *cptr && *cptr != ' '; cptr++);
if (*cptr || SpaceThenString)
{
if (QuoteIfSpace)
cptr = "\"";
else
if (SpaceThenString)
cptr = " ";
else
cptr = "";
while (*cptr)
{
if (bptr < bzptr)
{
*bptr++ = *cptr++;
continue;
}
if (STR_DSC_IS_EXTERNAL(sdptr)) goto FaolSAKovf;
STR_DSC_LEN(sdptr) = bptr - STR_DSC_PTR(sdptr);
sdptr = StrDscBuffer (StrDscPtr);
bptr = STR_DSC_PTR(sdptr) + STR_DSC_LEN(sdptr);
bzptr = STR_DSC_PTR(sdptr) + STR_DSC_SIZE(sdptr);
}
}
else
QuoteIfSpace = UnderlineIfSpace = false;
}
if (HtmlEscape)
{
/**********************/
/* HTML-escape string */
/**********************/
while (*sptr && fw && ofw)
{
fw--;
ofw--;
if (Utf8Encode && (*sptr & 0x80))
{
cptr = String;
cptr[0] = ((*sptr & 0xc0) >> 6) | 0xc0;
cptr[1] = (*sptr++ & 0x3f) | 0x80;
cptr[2] = '\0';
}
else
{
if (ForceLowerCase)
ch = TOLO(*sptr++);
else
if (ForceUpperCase)
ch = TOUP(*sptr++);
else
ch = *sptr++;
switch (ch)
{
case '<' :
cptr = "<";
break;
case '>' :
cptr = ">";
break;
case '&' :
cptr = "&";
break;
case '\"' :
if (QuoteIfSpace)
cptr = "\\"";
else
cptr = """;
break;
default :
/* insert this character as-is */
*(cptr = OneChar) = ch;
}
}
/* add the character(s) */
while (*cptr)
{
if (bptr < bzptr)
{
*bptr++ = *cptr++;
continue;
}
if (STR_DSC_IS_EXTERNAL(sdptr)) goto FaolSAKovf;
STR_DSC_LEN(sdptr) = bptr - STR_DSC_PTR(sdptr);
sdptr = StrDscBuffer (StrDscPtr);
bptr = STR_DSC_PTR(sdptr) + STR_DSC_LEN(sdptr);
bzptr = STR_DSC_PTR(sdptr) + STR_DSC_SIZE(sdptr);
}
}
}
else
if (UrlEncode)
{
/*********************/
/* URL-encode string */
/*********************/
while (*sptr && fw && ofw)
{
fw--;
ofw--;
cptr = NULL;
if (Utf8Encode && (*sptr & 0x80))
{
cptr = String;
ch = ((*sptr & 0xc0) >> 6) | 0xc0;
cptr[0]= FaoUrlEncodeTable[(uchar)ch][0];
cptr[1]= FaoUrlEncodeTable[(uchar)ch][1];
cptr[2]= FaoUrlEncodeTable[(uchar)ch][2];
ch = (*sptr++ & 0x3f) | 0x80;
cptr[3]= FaoUrlEncodeTable[(uchar)ch][0];
cptr[4]= FaoUrlEncodeTable[(uchar)ch][1];
cptr[5]= FaoUrlEncodeTable[(uchar)ch][2];
cptr[6] = '\0';
}
else
{
if (ForceLowerCase)
ch = TOLO(*sptr++);
else
if (ForceUpperCase)
ch = TOUP(*sptr++);
else
ch = *sptr++;
if (QuoteIfSpace && ch == '\"')
cptr = "%5c%22";
else
cptr = FaoUrlEncodeTable[(uchar)ch];
}
while (*cptr)
{
if (bptr < bzptr)
{
*bptr++ = *cptr++;
continue;
}
if (STR_DSC_IS_EXTERNAL(sdptr)) goto FaolSAKovf;
STR_DSC_LEN(sdptr) = bptr - STR_DSC_PTR(sdptr);
sdptr = StrDscBuffer (StrDscPtr);
bptr = STR_DSC_PTR(sdptr) + STR_DSC_LEN(sdptr);
bzptr = STR_DSC_PTR(sdptr) + STR_DSC_SIZE(sdptr);
}
}
}
else
{
/******************/
/* literal string */
/******************/
ch = '\0';
while (*sptr && fw && ofw)
{
if (bptr < bzptr)
{
if (ch)
{
*bptr++ = ch;
ch = '\0';
sptr++;
}
else
if (QuoteIfSpace && *sptr == '\"')
{
*bptr++ = '\\';
ch = *sptr;
}
else
if (PeriodNonPrintable && !isprint(*sptr))
{
*bptr++ = '.';
sptr++;
}
else
if (SlashNonPrintable && !isprint(*sptr))
{
switch (*sptr)
{
case '\a' : ch = 'a'; break;
case '\b' : ch = 'b'; break;
case '\f' : ch = 'f'; break;
case '\n' : ch = 'n'; break;
case '\r' : ch = 'r'; break;
case '\t' : ch = 't'; break;
case '\v' : ch = 'v'; break;
default : ch = '.';
}
*bptr++ = '\\';
}
else
if (Utf8Encode && (*sptr & 0x80))
{
*bptr++ = ((*sptr & 0xc0) >> 6) | 0xc0;
if (bptr < bzptr)
*bptr++ = (*sptr++ & 0x3f) | 0x80;
else
ch = (*sptr & 0x3f) | 0x80;
}
else
if (ForceLowerCase)
*bptr++ = TOLO(*sptr++);
else
if (ForceUpperCase)
*bptr++ = TOUP(*sptr++);
else
*bptr++ = *sptr++;
fw--;
ofw--;
continue;
}
if (STR_DSC_IS_EXTERNAL(sdptr)) goto FaolSAKovf;
STR_DSC_LEN(sdptr) = bptr - STR_DSC_PTR(sdptr);
sdptr = StrDscBuffer (StrDscPtr);
bptr = STR_DSC_PTR(sdptr) + STR_DSC_LEN(sdptr);
bzptr = STR_DSC_PTR(sdptr) + STR_DSC_SIZE(sdptr);
}
}
if (QuoteIfSpace || TrailingNewlineString || UnderlineIfSpace)
{
if (QuoteIfSpace)
cptr = "\"";
else
if (TrailingNewlineString)
cptr = "\n";
else
cptr = " ";
while (*cptr)
{
if (bptr < bzptr)
{
*bptr++ = *cptr++;
continue;
}
if (STR_DSC_IS_EXTERNAL(sdptr)) goto FaolSAKovf;
STR_DSC_LEN(sdptr) = bptr - STR_DSC_PTR(sdptr);
sdptr = StrDscBuffer (StrDscPtr);
bptr = STR_DSC_PTR(sdptr) + STR_DSC_LEN(sdptr);
bzptr = STR_DSC_PTR(sdptr) + STR_DSC_SIZE(sdptr);
}
}
}
/***************************************************/
/* if positive field-width, right-fill with spaces */
/***************************************************/
if (fw <= 0) continue;
while (fw > 0 && ofw)
{
if (bptr < bzptr)
{
*bptr++ = ' ';
fw--;
ofw--;
continue;
}
if (STR_DSC_IS_EXTERNAL(sdptr)) goto FaolSAKovf;
STR_DSC_LEN(sdptr) = bptr - STR_DSC_PTR(sdptr);
sdptr = StrDscBuffer (StrDscPtr);
bptr = STR_DSC_PTR(sdptr) + STR_DSC_LEN(sdptr);
bzptr = STR_DSC_PTR(sdptr) + STR_DSC_SIZE(sdptr);
}
}
/*********************/
/* end format string */
/*********************/
if (VMSnok (status)) break;
/* if there are still pointers on the format stack */
if (DEBUG_FAOSAK) fprintf (stdout, "idx: %d\n", idx);
if (!idx) break;
idx--;
}
/*****************************/
/* end nested format strings */
/*****************************/
if (VMSnok (status))
{
if (WATCHMOD (rqptr, WATCH_MOD_FAO))
WatchThis (WATCHITM(rqptr), WATCH_MOD_FAO, "ERROR !AZ", LastFptr);
/* if an error was detected append from the offending directive */
fptr = LastFptr;
while (*fptr)
{
if (bptr < bzptr)
{
*bptr++ = *fptr++;
fw--;
ofw--;
continue;
}
if (STR_DSC_IS_EXTERNAL(sdptr)) goto FaolSAKovf;
STR_DSC_LEN(sdptr) = bptr - STR_DSC_PTR(sdptr);
sdptr = StrDscBuffer (StrDscPtr);
bptr = STR_DSC_PTR(sdptr) + STR_DSC_LEN(sdptr);
bzptr = STR_DSC_PTR(sdptr) + STR_DSC_SIZE(sdptr);
}
}
*bptr = '\0';
STR_DSC_LEN(sdptr) = bptr - STR_DSC_PTR(sdptr);
if (LengthPtr)
{
if (STR_DSC_LEN(sdptr) > 65535)
{
/* indicate that we can't represent what we've written to buffer */
*LengthPtr = 65535;
status = SS$_BUFFEROVF;
}
else
*LengthPtr = (ushort)STR_DSC_LEN(sdptr);
}
if (Watch.Category)
{
/* if we're WATCHing anything at all */
if (VMSnok (status))
{
/* and an error is being reported */
int cnt;
WatchThis (WATCHITM(rqptr), WATCH_MOD_FAO, "!&S", status);
WatchDataFormatted ("!&Z\n", FormatString);
for (cnt = 0; cnt <= idx; cnt++)
WatchDataFormatted ("!UL !&Z\n", cnt, FormatStack[cnt]);
}
}
return (status);
FaolSAKovf:
{
/* writing to storage and it's overflowed */
*bptr = '\0';
STR_DSC_LEN(sdptr) = bptr - STR_DSC_PTR(sdptr);
if (LengthPtr) *LengthPtr = (ushort)STR_DSC_LEN(sdptr);
return (SS$_BUFFEROVF);
}
}
/*****************************************************************************/
/*
Sanity bugchecks if |VectorPtr| has overflowed the |FaoVector| space.
Should be called immedaitely before the FaoToBuffer() call for writes that have
the potential to become buggy because of code modifications (and yes, I got
caught, and yes it cost me a few hours).
*/
FaoCheck
(
int SizeOfFaoVector,
ulong *FaoVectorPtr,
ulong *VectorPtr,
char *SourceModuleName,
int SourceLineNumber
)
{
char String [64];
/*********/
/* begin */
/*********/
if ((uchar*)VectorPtr - (uchar*)FaoVectorPtr <= SizeOfFaoVector) return;
sprintf (String, "storage: %d vector: %d (longwords)",
SizeOfFaoVector/ sizeof(ulong),
((uchar*)VectorPtr - (uchar*)FaoVectorPtr) / sizeof(ulong));
ErrorExitVmsStatus (SS$_BUGCHECK, String,
SourceModuleName, SourceLineNumber);
}
/*****************************************************************************/
/*
This is a variable-argument wrapper for FaolSAK(), see that for greater
detail. This function just gets all the arguments from the call stack and puts
them into a longword vector that FaolSAK() can use. 'LengthPtr'
provides storage for returning the length of the generated string. The
resultant string is always null-terminated (unless an error), hence the
'BufferSize' can always only store 'BufferSize'-1 characters. 'LengthPtr'
provides storage for the number of characters minus the null-termination. If
'BufferSize' is passed containing -1 then the 'BufferPtr' specifies a STR_DSC
structure.
*/
int FaoToBuffer
(
char *BufferPtr,
int BufferSize,
ushort *LengthPtr,
char *FormatString,
...
)
{
int status,
argcnt;
ulong *vecptr;
ulong FaoVector [128];
va_list argptr;
/*********/
/* begin */
/*********/
va_count (argcnt);
if WATCH_MODULE(WATCH_MOD_FAO)
WatchThis (WATCHALL, WATCH_MOD_FAO, "FaoToBuffer() !UL !8XL !SL",
argcnt, BufferPtr, BufferSize);
if (argcnt > 128+4) return (SS$_OVRMAXARG);
vecptr = FaoVector;
va_start (argptr, FormatString);
for (argcnt -= 4; argcnt; argcnt--)
*vecptr++ = va_arg (argptr, ulong);
va_end (argptr);
status = FaolSAK (NULL, BufferPtr, BufferSize, LengthPtr,
FormatString, &FaoVector);
if WATCH_MODULE(WATCH_MOD_FAO)
WatchThis (WATCHALL, WATCH_MOD_FAO, "!&S", status);
return (status);
}
/*****************************************************************************/
/*
This is a variable-argument wrapper for FaolSAK(), see that for greater
detail. This function just gets all the arguments from the call stack and puts
them into a longword vector that FaolSAK() can use. Output is to the client
network write descriptor.
*/
int FaoToNet
(
REQUEST_STRUCT *rqptr,
char *FormatString,
...
)
{
int status,
argcnt;
ulong *vecptr;
ulong FaoVector [128];
va_list argptr;
/*********/
/* begin */
/*********/
va_count (argcnt);
if (WATCHMOD (rqptr, WATCH_MOD_FAO))
WatchThis (WATCHITM(rqptr), WATCH_MOD_FAO, "FaoToNet() !UL", argcnt);
if (argcnt > 128+2) return (SS$_OVRMAXARG);
vecptr = FaoVector;
va_start (argptr, FormatString);
for (argcnt -= 2; argcnt; argcnt--)
*vecptr++ = va_arg (argptr, ulong);
va_end (argptr);
status = FaolSAK (rqptr, NULL, 0, NULL, FormatString, &FaoVector);
if (WATCHMOD (rqptr, WATCH_MOD_FAO))
WatchThis (WATCHITM(rqptr), WATCH_MOD_FAO, "!&S", status);
return (status);
}
/****************************************************************************/
/*
A fixed-size, internal buffer of 986 bytes maximum is used and the result
output as an OPCOM message.
*/
int FaoToOpcom
(
char *FormatString,
...
)
{
static $DESCRIPTOR (OpcomDsc, "");
int status,
argcnt;
ushort Length;
ulong *vecptr;
ulong FaoVector [128+2];
va_list argptr;
struct
{
ulong TargetType;
ulong RequestId;
char MsgText [986+1];
} OpcomMsg;
/*********/
/* begin */
/*********/
va_count (argcnt);
if WATCH_MODULE(WATCH_MOD_FAO)
WatchThis (WATCHALL, WATCH_MOD_FAO,
"FaoToOpcom() !UL !AZ", argcnt, FormatString);
if (argcnt > 128+1) return (SS$_OVRMAXARG);
vecptr = FaoVector;
*vecptr++ = HttpdProcess.PrcNam;
*vecptr++ = FormatString;
va_start (argptr, FormatString);
for (argcnt -= 1; argcnt; argcnt--)
*vecptr++ = va_arg (argptr, ulong);
va_end (argptr);
status = FaolSAK (NULL, OpcomMsg.MsgText, sizeof(OpcomMsg.MsgText), &Length,
"Process !AZ reports\r\n!&@", &FaoVector);
if (VMSnok (status)) FaoErrorNoticed (status, NULL, FI_LI);
if (DEBUG_FAOSAK)
fprintf (stdout, "%d |%s|\n", Length, OpcomMsg.MsgText);
OpcomMsg.TargetType = OPC$_RQ_RQST + ((OpcomTarget & 0xffffff) << 8);
OpcomMsg.RequestId = 0;
OpcomDsc.dsc$a_pointer = &OpcomMsg;
OpcomDsc.dsc$w_length = Length + 8;
status = sys$sndopr (&OpcomDsc, 0);
if (VMSnok (status)) FaoErrorNoticed (status, NULL, FI_LI);
return (status);
}
/****************************************************************************/
/*
A fixed-size, (fairly large) internal buffer is used and the result output to
the stream.
*/
int FaoToStdout
(
char *FormatString,
...
)
{
int status,
argcnt;
ushort Length;
ulong *vecptr;
ulong FaoVector [128];
char Buffer [32767];
va_list argptr;
/*********/
/* begin */
/*********/
va_count (argcnt);
if WATCH_MODULE(WATCH_MOD_FAO)
WatchThis (WATCHALL, WATCH_MOD_FAO,
"FaoToStdout() !UL !AZ", argcnt, FormatString);
if (argcnt > 128+1) return (SS$_OVRMAXARG);
vecptr = FaoVector;
va_start (argptr, FormatString);
for (argcnt -= 1; argcnt; argcnt--)
*vecptr++ = va_arg (argptr, ulong);
va_end (argptr);
status = FaolSAK (NULL, Buffer, sizeof(Buffer), &Length,
FormatString, &FaoVector);
if (VMSnok (status)) FaoErrorNoticed (status, NULL, FI_LI);
fputs (Buffer, stdout);
return (status);
}
/*****************************************************************************/
/*
ErrorNoticed() uses FaoToStdout() and FaoToOpcom().
Let's not potentially compound our problems by trying to use ErrorNoticed()
from within those functions!
*/
FaoErrorNoticed
(
int StatusValue,
char *Explanation,
char *SourceModuleName,
int SourceLineNumber
)
{
static char CurrentTime64 [24],
GetMsgBuffer [256];
static $DESCRIPTOR (CurrentTime64Dsc, CurrentTime64);
static $DESCRIPTOR (GetMsgDsc, GetMsgBuffer);
static $DESCRIPTOR (TimeFaoDsc, "!20%D\0");
ushort ShortLength;
/*********/
/* begin */
/*********/
if WATCH_MODULE(WATCH_MOD_FAO)
WatchThis (WATCHALL, WATCH_MOD_FAO, "FaoErrorNoticed()");
sys$fao (&TimeFaoDsc, NULL, &CurrentTime64Dsc, 0);
sys$getmsg (StatusValue, &ShortLength, &GetMsgDsc, 0, 0);
GetMsgBuffer[ShortLength] = '\0';
fprintf (stdout, "%%HTTPD-W-NOTICED, %s, %s:%d, %s, %%X%08.08X\n-%s\n",
CurrentTime64, SourceModuleName, SourceLineNumber,
Explanation, StatusValue, GetMsgBuffer+1);
}
/****************************************************************************/