1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
/****************************************************************
* *
* Copyright (c) 2014-2022 Fidelity National Information *
* Services, Inc. and/or its subsidiaries. All rights reserved. *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
* under a license. If you do not know the terms of *
* the license, please stop and do not read further. *
* *
****************************************************************/
#include "mdef.h"
#ifdef GTM_TRIGGER
#include "gtm_string.h"
#include "gtm_multi_thread.h"
#include "util.h" /* for FLUSH and util_out_print */
#include "util_out_print_vaparm.h"
#include "op.h" /* for op_write prototype */
#include "io.h" /* needed for io_pair typedef */
#include "gtmimagename.h" /* for IS_MCODE_RUNNING */
GBLREF uint4 dollar_tlevel;
#define ZTRIGBUFF_INIT_ALLOC 1024 /* start at 1K */
#define ZTRIGBUFF_INIT_MAX_GEOM_ALLOC 1048576 /* stop geometric growth at this value */
/* Used by MUPIP TRIGGER or $ZTRIGGER routines to buffer trigger output until TCOMMIT time
* (as otherwise we might display stale output due to a restarted try).
*/
void util_out_print_gtmio(caddr_t message, int flush, ...)
{
va_list var;
char *src, *dst, *newdst;
int srclen, dstlen, dstalloc, newlen, ptrlen;
caddr_t msg;
int4 msglen;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
ASSERT_SAFE_TO_UPDATE_THREAD_GBLS;
/* we expect all trigger operations (SELECT, LOAD, etc.) to happen inside TP. exceptions should set TREF variable */
assert(dollar_tlevel || TREF(gtmio_skip_tlevel_assert));
va_start(var, flush);
/* If "!AD" has been specified as the message, skip the util_out_print_vaparm call as it is possible
* the input string length is > the maximum length util_out_* routines are designed to handle.
* In that case, we dont need the parameter substitution anyways so do a memcpy instead.
*/
if (STRCMP(message, "!AD") || (FLUSH != flush))
{
util_out_print_vaparm(message, NOFLUSH_OUT, var, MAXPOSINT4); /* WARNING: UNCHECKED faocnt - internal use only */
src = TREF(util_outbuff_ptr);
assert(NULL != TREF(util_outptr));
srclen = INTCAST(TREF(util_outptr) - src) + 1; /* 1 is for '\n' */
assert(OUT_BUFF_SIZE >= srclen);
} else
{
srclen = (int)va_arg(var, int4) + 1;
src = (char *)va_arg(var, caddr_t);
}
if (FLUSH == flush)
{
dstalloc = TREF(ztrigbuffAllocLen);
dstlen = TREF(ztrigbuffLen);
/* Leave room for terminating '\0' (after the \n) for later use in FPRINTF in tp_ztrigbuff_print.
* Hence the use of "<=" instead of a "<" in the "if (dstalloc <= (dstlen + srclen))" check below.
*/
if (dstalloc <= (dstlen + srclen))
{ /* reallocate */
dst = TREF(ztrigbuff);
do
{
if (!dstalloc)
dstalloc = ZTRIGBUFF_INIT_ALLOC; /* Allocate a 1K buffer at start */
else if (ZTRIGBUFF_INIT_MAX_GEOM_ALLOC <= dstalloc)
dstalloc += ZTRIGBUFF_INIT_MAX_GEOM_ALLOC;
else
dstalloc = dstalloc * 2; /* grow geometrically until a limit and linearly after that */
} while (dstalloc <= (dstlen + srclen));
newdst = malloc(dstalloc);
if (dstlen)
memcpy(newdst, dst, dstlen);
TREF(ztrigbuff) = newdst;
TREF(ztrigbuffAllocLen) = dstalloc;
if (NULL != dst)
free(dst);
}
dst = TREF(ztrigbuff);
memcpy(dst + dstlen, src, srclen - 1);
dst[dstlen + srclen - 1] = '\n';
TREF(ztrigbuffLen) += srclen;
TREF(util_outptr) = TREF(util_outbuff_ptr); /* Signal text is flushed */
}
va_end(TREF(last_va_list_ptr));
va_end(var);
}
void tp_ztrigbuff_print(void)
{
mval flushtxt;
char *ptr, *ptrtop, *ptr2;
int len;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
/* If mumps process doing trigger operations, use GTM IO routines. If not use util_out_print. The only
* exception is if the MUPIP caller wants to use current IO device (i.e. it has it all set up). In that
* case the TREF ztrig_use_io_curr_device would have been set to TRUE.
*/
if (IS_MCODE_RUNNING || TREF(ztrig_use_io_curr_device))
{
ptr = TREF(ztrigbuff);
assert('\n' == ptr[TREF(ztrigbuffLen) - 1]);
ptrtop = ptr + TREF(ztrigbuffLen);
flushtxt.mvtype = MV_STR;
do
{
len = INTCAST(ptrtop - ptr);
ptr2 = memchr(ptr, '\n', len);
assert(NULL != ptr2);
flushtxt.str.addr = ptr;
flushtxt.str.len = ptr2 - ptr;
op_write(&flushtxt);
op_wteol(1);
ptr = ptr2 + 1;
} while (ptr < ptrtop);
} else
{ /* Use util_out_print but since you pass TRUE for flush, use -1 to prevent duplicate newline */
assert('\n' == (TREF(ztrigbuff))[TREF(ztrigbuffLen) - 1]);
assert(TREF(ztrigbuffLen) < TREF(ztrigbuffAllocLen));
(TREF(ztrigbuff))[TREF(ztrigbuffLen)] = '\0';
FPRINTF(stderr, "%s", TREF(ztrigbuff));
}
}
#endif
|