/**************************************************************** * * * Copyright 2001, 2010 Fidelity Information Services, Inc * * * * 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" #include <stdarg.h> #include "gtmmsg.h" #include "error.h" #include "fao_parm.h" #include "util.h" #include "util_out_print_vaparm.h" #include "send_msg.h" #include "caller_id.h" #include "gtmsiginfo.h" GBLREF bool caller_id_flag; GBLREF va_list last_va_list_ptr; GBLREF volatile int4 exit_state; #ifdef DEBUG static uint4 nesting_level = 0; #endif #define NOFLUSH 0 #define FLUSH 1 #define RESET 2 #define OPER 4 /* ** WARNING: For chained error messages, all messages MUST be followed by an fao count; ** ======= zero MUST be specified if there are no parameters. */ /* This routine is a variation on the unix version of rts_error, and has an identical interface */ void send_msg(int arg_count, ...) { va_list var; int dummy, fao_actual, fao_count, i, msg_id; char msg_buffer[1024]; mstr msg_string; /* Since send_msg uses a global variable buffer, reentrant calls to send_msg will use the same buffer. * Ensure we never overwrite an under-construction send_msg buffer with a nested send_msg call. The * only exception to this is if the nested call to send_msg is done by exit handling code in which case * the latest send_msg call prevails and it is ok since we will never return to the original send_msg() * call again. Detect if ever this assmption gets violated with an assert. */ assert((0 == nesting_level) || (EXIT_IMMED == exit_state)); DEBUG_ONLY(nesting_level++;) VAR_START(var, arg_count); assert(arg_count > 0); util_out_save(); util_out_print(NULL, RESET); for (;;) { msg_id = (int) va_arg(var, VA_ARG_TYPE); --arg_count; msg_string.addr = msg_buffer; msg_string.len = SIZEOF(msg_buffer); gtm_getmsg(msg_id, &msg_string); if (arg_count > 0) { fao_actual = (int) va_arg(var, VA_ARG_TYPE); --arg_count; fao_count = fao_actual; if (fao_count > MAX_FAO_PARMS) { assert(FALSE); fao_count = MAX_FAO_PARMS; } } else fao_actual = fao_count = 0; util_out_print_vaparm(msg_string.addr, NOFLUSH, var, fao_count); va_end(var); /* need this before used as dest in copy */ VAR_COPY(var, last_va_list_ptr); va_end(last_va_list_ptr); arg_count -= fao_count; if (0 >= arg_count) { if (caller_id_flag) PRINT_CALLERID; break; } util_out_print("!/", NOFLUSH); } va_end(var); util_out_print(NULL, OPER); util_out_restore(); /* it has been suggested that this would be a place to check a view_debugN * and conditionally enter a "forever" loop on wcs_sleep for unix debugging */ DEBUG_ONLY(nesting_level--;) }