Exemple #1
0
int  odxa_errhandler(void)
{
    char buf[257]="";
    char message[513]="        ::[                , 00000000]: ";
    long error_no = 0;
    char error_text[257];
    SYSTIME     time_now;
    i4  len;

//  EXEC SQL INQUIRE_SQL(:error_no = ERRORNO,:error_text = ERRORTEXT);
        IILQisInqSqlio((short *)0,1,30,4,&error_no,2);
        IILQisInqSqlio((short *)0,1,32,256,error_text,63);

    CVlx((u_i4)error_no, buf);
    STprintf(message, ERx("        ::[%-16s, %s]: "), szFuncName, buf);
    TMnow( &time_now );
    TMstr( &time_now, buf );
    STcat(message, buf);
    STcat(message, " MS DTC Ingres XA Interface: ");

    if (STequal(szFuncName,"xa_open"))  /* dump out xa_open's xa_info string */
       {
         len = (i4)STlength(message);
         STcat(message, errlog_xa_info);
         WriteDTCerrToEventLog(S_OK, message);
         message[len] = '\0';   /* chop back to the message header */
       }

    STcat(message, error_text);

    WriteDTCerrToEventLog(S_OK, message);
    return 0;
}
Exemple #2
0
/*
**  close_log
*/
STATUS
close_log()
{
    STATUS                 ret_val = OK ;
    SYSTIME                atime ;
    char                   buffer [TEST_LINE] ;
    char                   timestr [TEST_LINE] ;

    append_line((char *)ERx("\n"),(i4)1);
    TMnow(&atime);
    TMstr(&atime,timestr);
    STprintf(buffer,ERx("Ending at: %s"),timestr);
    append_line(buffer,1);
    SIclose(logptr);

    return (ret_val);
}
Exemple #3
0
STATUS
ERmsg_hdr( char *svr_id, SCALARP session, char *msg_header)
{
    char        host_name[65];
    i4		length;
    SYSTIME	stime;

    GChostname( host_name, sizeof( host_name ) );
    STprintf( msg_header, "%-8.8s::[%-16.16s, %08.8x]: ",
	host_name, svr_id, session );
    TMnow(&stime);
    TMstr(&stime,msg_header + STlength(msg_header));
    length = STlength(msg_header);
    msg_header[length++] = ' ';
    msg_header[length] = EOS;
    return (OK);
}
Exemple #4
0
/*{
** Name:	RScommit - two-phase commit processing
**
** Description:
**	Prepares to commit locally, commits remotely, commits locally.
**	Logs each step of the commit so that a reasonable attempt can
**	be made to recover if it does not complete.
**
** Inputs:
**	target	- target database, CDDS and connection number
**	row	- distribution queue row
**
** Outputs:
**	none
**
** Returns:
**	OK or Ingres error
**
** Side effects:
**	A distributed transaction is committed using incomplete two-phase
**	commit (a prepare is only done on the local database, so the target
**	database is not aware it is part of a distributed transaction).
*/
STATUS
RScommit(
RS_TARGET	*target,
RS_TRANS_ROW	*row)
{
	i4			high = (i4)RSlocal_conn.db_no;
	SYSTIME			now;
	char			timestamp[21];
	char			timestr[27];
	i4			start_entry_no;
	i4			prepare_entry_no;
	i4			remote_entry_no;
	i4			complete_entry_no;
	RS_TBLDESC		*tbl = row->tbl_desc;
	RS_CONN			*local_conn = &RSlocal_conn;
	RS_CONN			*target_conn = &RSconns[target->conn_no];
	IIAPI_GETEINFOPARM	errParm;
	IIAPI_STATUS		status;

	if (RStwo_phase)	/* two-phase commit is on */
	{
		start_entry_no = RS_2PC_BEGIN;
		prepare_entry_no = RS_PREP_COMMIT;
		remote_entry_no = RS_REMOTE_COMMIT;
		complete_entry_no = RS_2PC_END;
	}
	else			/* two-phase commit is off */
	{
		start_entry_no = RS_NPC_BEGIN;
		remote_entry_no = RS_NPC_REM_COMMIT;
		complete_entry_no = RS_NPC_END;
	}

	TMnow(&now);
	TMstr(&now, timestr);
	mktimestamp(timestr, timestamp);

	SIfprintf(RScommit_fp, log_format, start_entry_no, high, low,
		(i4)target->db_no, tbl->table_owner, tbl->table_name,
		tbl->table_no, row->rep_key.trans_id, row->rep_key.seq_no,
		timestamp, "Start of commit");
	SIflush(RScommit_fp);

	if (RStwo_phase)	/* only prepare to commit if two-phase is on */
	{
		/*
		** Prepare to commit. The high value is %d, The low value is %d
		*/
		messageit(5, 1277, high, low);

		status = IIsw_prepareCommit(&local_conn->tranHandle, &errParm);
		if (status != IIAPI_ST_SUCCESS)
		{
			messageit(1, 1214);
			IIsw_rollback(&target_conn->tranHandle, &errParm);
			IIsw_rollback(&local_conn->tranHandle, &errParm);
			IIsw_releaseXID(&dtrans_id_handle);
			return (status);
		}

		SIfprintf(RScommit_fp, log_format, prepare_entry_no, high, low,
			(i4)target->db_no, tbl->table_owner, tbl->table_name,
			tbl->table_no, row->rep_key.trans_id,
			row->rep_key.seq_no, timestamp, "Prepare to commit");
		SIflush(RScommit_fp);
	}

	status = IIsw_commit(&target_conn->tranHandle, &errParm);
	if (status != IIAPI_ST_SUCCESS)
	{
		IIsw_rollback(&target_conn->tranHandle, &errParm);
		if (IIsw_rollback(&local_conn->tranHandle, &errParm) !=
			IIAPI_ST_SUCCESS)
		{
			RSdo_recover = TRUE;
			messageit(1, 1215);
			messageit(1, 1216);
		}
		else
		{
			messageit(1, 1215);
		}
		IIsw_releaseXID(&dtrans_id_handle);

		SIfprintf(RScommit_fp, log_format, remote_entry_no, high,
			low, (i4)target->db_no, tbl->table_owner,
			tbl->table_name, tbl->table_no, row->rep_key.trans_id,
			row->rep_key.seq_no, timestamp, "Local rollback");
		SIfprintf(RScommit_fp, log_format, complete_entry_no, high,
			low, (i4)target->db_no, tbl->table_owner,
			tbl->table_name, tbl->table_no, row->rep_key.trans_id,
			row->rep_key.seq_no, timestamp, "Commit complete");
		SIflush(RScommit_fp);
		return (status);
	}

	SIfprintf(RScommit_fp, log_format, remote_entry_no, high, low,
		(i4)target->db_no, tbl->table_owner, tbl->table_name,
		tbl->table_no, row->rep_key.trans_id, row->rep_key.seq_no,
		timestamp, "Remote commit");
	SIflush(RScommit_fp);

	status = IIsw_commit(&local_conn->tranHandle, &errParm);
	if (status != IIAPI_ST_SUCCESS)
	{
		RSdo_recover = TRUE;
		IIsw_releaseXID(&dtrans_id_handle);
		return (status);
	}
	IIsw_releaseXID(&dtrans_id_handle);

	SIfprintf(RScommit_fp, log_format, complete_entry_no, high, low,
		(i4)target->db_no, tbl->table_owner, tbl->table_name,
		tbl->table_no, row->rep_key.trans_id, row->rep_key.seq_no,
		timestamp, "Commit complete");
	SIflush(RScommit_fp);

	return (OK);
}
Exemple #5
0
STATUS
open_log(char *testPrefix,char *testSufix,char *username,char *errbuff)
{
    SYSTIME                atime ;
    char                   uname [20] ;
    char                   logFileName [MAX_LOC+1] ;
    char                   timestr [TEST_LINE] ;
    char                   buffer [MAX_LOC+1] ;
    char                  *dot = NULL ;
    char                  *cptr = NULL ;
	char				   year[5];

    if (shellMode)
        STpolycat(3, testPrefix, ERx("."), testSufix, logFileName);
    else if (updateMode)
            STpolycat(2, testPrefix, ERx(".upd"), logFileName);
         else
            STpolycat(2, testPrefix, ERx(".log"), logFileName);

    if (outputDir)
    {
	if (outputDir_type == PATH)
	{
	    STcopy(outputDir, buffer);
	    LOfroms(PATH, buffer, &logloc);
	    LOfstfile(logFileName, &logloc);
	    LOtos(&logloc, &cptr);
	}
	else
	{
	    LOtos(&outLoc,&cptr);
	}
	STcopy(cptr, logname);
    }
    else
        STcopy(logFileName, logname);
    
    
    if (LOfroms(FILENAME & PATH, logname, &logloc) != OK)
    {
	STprintf(errbuff,ERx("ERROR: could not get location for log file"));
	return(FAIL);
    }
    if (SIopen(&logloc,ERx("w"),&logptr) != OK)
    {
	STprintf(errbuff,ERx("ERROR: could not open log file"));
	return(FAIL);
    }

    if (!updateMode)
    {
	append_line(ERx("/*"),1);

	copyright_year(&year[0]);
	STprintf(buffer, ERx("Copyright (c) %s Ingres Corporation"), &year);
	append_line(buffer, 1);
	append_line(ERx(" "), 1);

	STprintf(buffer,ERx("\tTest Name: %s.%s"), testPrefix, testSufix);
	append_line(buffer,1);
	TMnow(&atime);
	TMstr(&atime,timestr);
	STprintf(buffer,ERx("\tTime: %s"),timestr);
	append_line(buffer,1);
	dot = uname;
	if (username == NULL || *username == '\0')
	    IDname(&dot);
	else
	    STcopy(username,uname);
	STprintf(buffer,ERx("\tUser Name: %s"),uname);
	append_line(buffer,1);
	STprintf(buffer, ERx("\tTerminal type: %s"), terminalType);
	append_line(buffer,1);
	append_line(ERx(" "),1);
    }

    return(OK);
}
Exemple #6
0
void 
main(int argc, char **argv)
{
	int		i;
	char		buf[MAX_LOC];
	FILE		*fp;
	STATUS		status;
	char		*callstmt;
	i4 		casef;
	char		timestr[512];
	SYSTIME		timeval;
	char		path[512];
	char		drive[2];
	char		current_path[512];

	if (argc < 3)
	{
		SIfprintf(stdout,"Not enough parameters\n");
		PCexit(FAIL);
	}

	/*
	**
	*/
	if (!STbcompare(*++argv, STlength("Net"),
			 "Net", STlength("Net"), casef ))

		callstmt = "@call %II_SYSTEM%\\ingres\\utility\\iisunet";

	else if (!STbcompare(*argv, STlength("Dbms"),
			       "Dbms", STlength("Dbms"), casef ))

		callstmt = "@call %II_SYSTEM%\\ingres\\utility\\iisudbms";

	else if (!STbcompare(*argv, STlength("Star"), 
				"Star", STlength("Star"), casef ))

		callstmt = "@call %II_SYSTEM%\\ingres\\utility\\iisustar";

	else if (!STbcompare(*argv, STlength("Vision"),
				 "Vision", STlength("Vision"), casef ))

		callstmt = "@call %II_SYSTEM%\\ingres\\utility\\iisuabf";

	else if (!STbcompare(*argv, STlength("ESQL"),
				 "ESQL", STlength("ESQL"), casef ))

		callstmt = "@call %II_SYSTEM%\\ingres\\utility\\iisutm";

	else 
		PCexit(FAIL);

	/*
	** 	Set location and file name for the subsequent open.
	*/
	strcpy(path,*++argv);
	strcpy(current_path,*argv+2);
	strcat(path,"\\ingres\\bin\\ipsetup.bat");
	LOfroms(PATH & FILENAME, path, &location);

	
	/*
	** 	Open ipsetup.bat so we can append another line.
	*/
	if ((status = SIopen(&location, "a", &fp)) != OK)
	{
		printf("error opening file\n");
	}

	/*
	** 	Append another line that will call the setup bat files.
	*/
	TMnow(&timeval);
	TMstr(&timeval,&timestr);
	drive[0] = path[0];
	drive[1] = '\0';

	/*
	** Write a statement in the batch file that will set
	** the current drive to the drive passed to us.
	*/
	SIfprintf(fp,"@%s:\n",drive);

	/*
	** Write a statement in the batch file that will set
	** the current path to the path passed to us.
	*/
	SIfprintf(fp,"@cd %s\n",current_path);

	/* 
	** Write a Remark as a primitive log.
	*/
	SIfprintf(fp,"@REM %s installed at %s\n",*argv,timestr);
	
	/*
	** Now write the call statement that will call the appropiate
	** iisu batch file.
	*/
	SIfprintf(fp,"%s\n",callstmt);
}
Exemple #7
0
static VOID
IILQgtfGcaTraceFile( II_LBQ_CB *IIlbqcb, i4  action )
{
    IILQ_TRACE		*msgtrc = &IIglbcb->iigl_msgtrc;
    FILE		*trace_file = (FILE *)msgtrc->ii_tr_file;
    char		*title = ERx("off");
    SYSTIME		now;
    char		nowbuf[100];
    i4			nowend;

    /*
    ** Check to see that we actually need to open
    ** or close the trace file.
    */
    if ( (action == IITRC_ON  &&  trace_file)    ||
	 (action == IITRC_OFF  &&  ! trace_file)  ||
	 (action == IITRC_SWITCH  &&  ! trace_file) )
	return;

    if ( action == IITRC_SWITCH )  title = ERx("switched");

    if ( action == IITRC_ON )
    {
	LOCATION	trace_loc;
	STATUS		stat;

	/*
	** If trace file name not provided, use default.
	*/
	if ( ! msgtrc->ii_tr_fname )
	    msgtrc->ii_tr_fname = STalloc( GCTRACEFILE );

	LOfroms(FILENAME, msgtrc->ii_tr_fname, &trace_loc );
# ifdef hp9_mpe
	if ( msgtrc->ii_tr_flags & II_TR_APPEND )
	    stat = SIfopen(&trace_loc, ERx("a"), SI_TXT, 252, &trace_file);
	else
	    stat = SIfopen(&trace_loc, ERx("w"), SI_TXT, 252, &trace_file);
# else
	if ( msgtrc->ii_tr_flags & II_TR_APPEND )
	    stat = SIopen(&trace_loc, ERx("a"), &trace_file);
	else
	    stat = SIopen(&trace_loc, ERx("w"), &trace_file);
# endif
	if (stat != OK)
	{
	    /* Simplest error path; don't want IIlocerr functionality */
	    IIUGerr(E_LQ0007_PRINTQRY, 0, 1, msgtrc->ii_tr_fname);

	    /*
	    ** We can't call IILQgstGcaSetTrace() because
	    ** of possible conflicts with the tracing
	    ** semaphore, so just turn off tracing here.
	    */
	    msgtrc->ii_tr_flags &= ~II_TR_FILE;
	    if ( ! (msgtrc->ii_tr_flags & II_TR_HDLR) )
		IIcgct1_set_trace( IIlbqcb->ii_lq_gca, 0, NULL, NULL );
	    return;
	}

	msgtrc->ii_tr_file = (PTR)trace_file;
	title = ERx("on ");
    }

    /* Get time stamp */
    TMnow(&now);
    TMstr(&now, nowbuf);
    nowend = STlength( nowbuf );
    if ( nowbuf[ nowend - 1 ] == '\n' )  nowbuf[ nowend - 1 ] = EOS;

    SIfprintf( trace_file, ERx("---- printgca = %s session %d (%s) ---\n\n"),
	       title, IIlbqcb->ii_lq_sid, nowbuf );
    SIflush( trace_file );

    if ( action != IITRC_OFF )
	msgtrc->ii_tr_sid = IIlbqcb->ii_lq_sid;
    else
    {
	SIclose( trace_file );
	msgtrc->ii_tr_file = NULL;
	msgtrc->ii_tr_sid = 0;
	msgtrc->ii_tr_flags |= II_TR_APPEND;  /* Don't overwrite if reopened */
    }

    return;
} /* IILQgtfGcaTraceFile */
Exemple #8
0
STATUS
ERslookup(
    i4		    msg_number,
    CL_ERR_DESC	    *clerror,
    i4		    flags,
    char	    *sqlstate,
    char	    *msg_buf,
    i4		    msg_buf_size,
    i4		    language,
    i4		    *msg_length,
    CL_ERR_DESC	    *err_code,
    i4		    num_param,
    ER_ARGUMENT	    *param )
{
    i4			erindex;	/* index of ERmulti table */
    i4		status;
    i4			length = 0;
    ER_ARGUMENT		*p;
    ER_ARGUMENT		hidden[CLE_INFO_ITEMS];	/* to access info in clerror */
    char		tempbuf[ER_MAX_LEN+ER_MAX_NAME+2];
    i4			templen;
    char		*p_msg_buf;
    char		*p_tempbuf;
    SYSTIME		stime;
    char		langbuf[ER_MAX_LANGSTR];
    EX_CONTEXT		context;
    ER_SEMFUNCS		*sems;

#define			    D_WIDTH	    23
#define			    F_WIDTH	    20
#define			    X_WIDTH	    18


    /*	Validate the parameters. */

    if (msg_buf == 0 || msg_buf_size == 0 || msg_length == 0)
    {
	return (ER_BADPARAM);
    }
    if (language != -1 && ERlangstr(language,langbuf) != OK)
    {
	return (ER_BADLANGUAGE);
    }
 
    if (!(flags & ER_NAMEONLY))
    {
        EXdump(msg_number,0);
    }
 

    /*	Insert timestamp if requested. */

    if (flags & ER_TIMESTAMP)
    {
	if (msg_buf_size < 21)
	{
	    return (ER_TOOSMALL);
	}
	TMnow(&stime);
	TMstr(&stime,msg_buf);

	length = (i4)STlength(msg_buf);	
	msg_buf[length++] = ' ';
    }

    /*
    **    if (clerror && msg_number)
    **        look up msg_number, optional parameters in clerror->moreinfo
    **    else if (clerror)
    **    {
    **        if (clerror->intern)
    **            look up clerror.intern, optional params in clerror->moreinfo
    **        if (clerror->callid)
    **            look up system error message
    **    }
    */
    if (clerror)
    {
	if (msg_number)	/* Look up message after system error */
	{
	    /*
	    ** Set up an ER_ARGUMENT that references system-dependent
	    ** information in `clerror', and point `param' at it.
	    */
	    i4  i;

	    for (i = 0; i < CLE_INFO_ITEMS; ++i)
	    {
	        /* "...all of whose members begin at offset 0..." (K&R) */

	        hidden[i].er_value = (PTR)&clerror->moreinfo[i].data._i4;
	        hidden[i].er_size = clerror->moreinfo[i].size;
	    }

	    param = &hidden[0];
	    num_param = CLE_INFO_ITEMS;
	}
        else		/* retrieve system-dependent error messages */
	{
	    i4	        len;
	    ER_ARGUMENT	argv[3];

	    if (clerror->intern)    /* look up internal CL error */
	    {
	        i4  i;

	        for (i = 0; i < CLE_INFO_ITEMS; ++i)
	        {
	            argv[i].er_value = (PTR)&clerror->moreinfo[i].data._i4;
	            argv[i].er_size = clerror->moreinfo[i].size;
	        }

	        /*
	        ** Don't timestamp on recursive call, since it's been done
	        ** already (if requested).
	        */
	        if ((status = ERslookup((i4) clerror->intern,
		    (CL_ERR_DESC*) NULL, flags & ~ER_TIMESTAMP | ER_TEXTONLY,
		    NULL, &msg_buf[length], msg_buf_size-length, language, &len,
		    err_code, CLE_INFO_ITEMS, argv)) != OK)
	        {
	            return (status);
	        }
	        length += len;

		if (clerror->callid)
		    msg_buf[length++] = '\n';
	    }

	    if (clerror->callid)    /* look up system error message text */
	    {
                DESCRIPTOR	msg_desc;

    	        msg_desc.desc_length = sizeof(tempbuf) - 1;
	        msg_desc.desc_value = tempbuf;
	        if ((status = cer_sysgetmsg(clerror, &len, &msg_desc, err_code))
		    != OK)
	        {
	            return(status);
	        }

	        argv[0].er_size = argv[1].er_size = argv[2].er_size =
		    ER_PTR_ARGUMENT;

	        argv[0].er_value = (PTR)&clerror->errnum;
	        argv[1].er_value = (PTR)ERNAME((i4) clerror->callid);
	        argv[2].er_value = (PTR)tempbuf;

	        if ((status = ERslookup(ER_UNIXERROR, (CL_ERR_DESC*) NULL,
	                flags & ~ER_TIMESTAMP | ER_TEXTONLY, NULL,
			&msg_buf[length], msg_buf_size - length, language,
			&len,err_code, 3, argv))
		    != OK)
	        {
	            return (status);
	        }
	        length += len;
	    }

	    msg_buf[*msg_length = length] = EOS;
	    return (OK);
        }
    }


    /*
    **	Check if error message file is already opened or not yet. 
    **  First see if the language is initialized.  If not, initialize
    **  it and the message files.
    **	If it is already opened, cer_fndindex function returns the index of
    **	ERmulti table that internal language code is parameter 'language'.
    **  If not yet, it returns '-1'.
    */

    if (cer_issem(&sems))
    {
	if (((sems->sem_type & MU_SEM) ?
	    (*sems->er_p_semaphore)(&sems->er_mu_sem) :
	    (*sems->er_p_semaphore)(1, &sems->er_sem)) != OK)
	{
	    sems = NULL;
	}
    }

    if ((erindex = cer_fndindex(language)) == -1)
    {
	if ((status = cer_nxtindex(language,&erindex)) != OK)
	{   /* Error in initializing the language */
	    if (sems)
	    {
		if (sems->sem_type & MU_SEM)
		    _VOID_ (*sems->er_v_semaphore)(&sems->er_mu_sem);
		else
		    _VOID_ (*sems->er_v_semaphore)(&sems->er_sem);
	    }
	    return (status);
	}
    }

    /*  If the error message file is not opened, open the message file. */

    if (!cer_isopen(erindex,ER_SLOWSIDE))
    {
        if ((status = cer_sinit(language,msg_number,erindex,err_code)) != OK)
        {
	    if (sems)
	    {
		if (sems->sem_type & MU_SEM)
		    _VOID_ (*sems->er_v_semaphore)(&sems->er_mu_sem);
		else
		    _VOID_ (*sems->er_v_semaphore)(&sems->er_sem);
	    }
            return (status);
        }
    }

    /*	If not open then just return. */
    if (!cer_isopen(erindex,ER_SLOWSIDE))
    {
	if (sems)
	{
	    if (sems->sem_type & MU_SEM)
		_VOID_ (*sems->er_v_semaphore)(&sems->er_mu_sem);
	    else
		_VOID_ (*sems->er_v_semaphore)(&sems->er_sem);
	}
	/*
	**  As internal file id is '0', openning file will fail.
	**  In her,return status 'ER_BADOPEN' to show open fail.
	*/
	return (ER_BADOPEN);
    }
	
    /*
    **  Search message string from file and set to buffer.
    **	Error status on system call set to 'err_code'.
    */

    status = cer_sstr(msg_number, sqlstate, tempbuf,
			msg_buf_size - length, erindex, err_code,
			flags & ER_TEXTONLY? ER_GET : ER_LOOKUP);
    if (sems)
    {
	if (sems->sem_type & MU_SEM)
	    _VOID_ (*sems->er_v_semaphore)(&sems->er_mu_sem);
	else
	    _VOID_ (*sems->er_v_semaphore)(&sems->er_sem);
    }

    if (status != OK)
    {
	return (status);
    }

    /*
    **	Format the text with parameters into the callers buffer.
    **  The message is truncated if it will not fit.
    */

    /*  Insert part of name from temporary buffer to buffer */

    status = OK;
    templen = (i4)STlength(tempbuf);
    p_msg_buf = &msg_buf[length];
    p_tempbuf = tempbuf;
    if (!(flags & ER_TEXTONLY))
    {
        while(*p_tempbuf != '\t')
        {
	    CMcpyinc(p_tempbuf,p_msg_buf);
        }
        CMcpyinc(p_tempbuf,p_msg_buf);
    }
    

    /* ============================================ */
    /* Copy text to message substituting arguments. */
    /* -------------------------------------------- */
    /* (But first, declare an exception handler to  */
    /*  catch bad params that may access violate.)  */
    /* ============================================ */

    if (EXdeclare(er_exhandler, &context))
    {
	u_i4	res_len;
	u_i4	bytes_left_in_buf;

	bytes_left_in_buf = (u_i4)(msg_buf_size - (p_msg_buf - msg_buf));
	res_len = STlen( STncpy(p_msg_buf,
   ERx("*** ERslookup() ERROR: Missing or bad parameter for this message. ***"),
	bytes_left_in_buf ));
	p_msg_buf[ bytes_left_in_buf - 1 ] = EOS;
	p_msg_buf += res_len;
	*msg_length = (i4)(p_msg_buf - msg_buf);
	EXdelete();
	return (OK);
    }


    for( ;p_tempbuf - tempbuf < templen; CMnext(p_tempbuf))
    {
        long		number;
        u_long    	unumber;
        double		fnumber;
	i4		i;
	i4		pnum;
 
	if ( (*p_tempbuf != '%') || (flags & ER_NOPARAM) )
	{
	    if ((p_msg_buf - msg_buf) >= msg_buf_size)
		break;
	    CMcpychar(p_tempbuf,p_msg_buf);
	    CMnext(p_msg_buf);
	    continue;
	}
	if (p_tempbuf - tempbuf + 2 >= templen)
	    continue;
	CMnext(p_tempbuf);
	if (*p_tempbuf == '!')
	{
	    if ((p_msg_buf - msg_buf) + 3 >= msg_buf_size)
		continue;
	    CMcpychar(ERx("\r"),p_msg_buf);
	    CMnext(p_msg_buf);
	    CMcpychar(ERx("\n"),p_msg_buf);
	    CMnext(p_msg_buf);
	    CMcpychar(ERx("\t"),p_msg_buf);
	    CMnext(p_msg_buf);
	    continue;
	}
	/*
	** Only works for up to 10 parameters, and makes character set
	** assumptions - should be fixed.
	*/
	if ( *p_tempbuf < '0' || *p_tempbuf > '9' )
	{
	    /* treat any other character as a literal */
	    if ((p_msg_buf - msg_buf) >= msg_buf_size)
		break;
	    if ( *p_tempbuf != '%' )
	    {
	        CMcpychar("%",p_msg_buf);
	        CMnext(p_msg_buf);
	    }
	    CMcpychar(p_tempbuf,p_msg_buf);
	    CMnext(p_msg_buf);
	    continue;
	}
	pnum = *p_tempbuf - '0';
	if (pnum >= num_param)
	{
		EXdelete();
		return(ER_BADPARAM);
	}
	p = &param[pnum];
	CMnext(p_tempbuf);
	switch (*p_tempbuf)
	{
	  case 'd':
	    /* Convert an integer into the buffer with width D_WIDTH */

	    if (p->er_size == ER_PTR_ARGUMENT) /* this is ptr to i4 */
		number = *(i4 *)p->er_value;
	    else if (p->er_size == 0)   /* this is a i4 */
		number = (i4)(SCALARP)p->er_value;
	    else if (p->er_size == 1)
		number = *(i1 *)p->er_value;
	    else if (p->er_size == 2)
		number = *(i2 *)p->er_value;
	    else if (p->er_size == 4)
		number = *(i4 *)p->er_value;
	    else if (p->er_size == 8)
		number = *(i8 *)p->er_value;
	    else
		continue;

	    if (p_msg_buf - msg_buf + D_WIDTH >= msg_buf_size)
	        continue;

	    if (p->er_size == 8)
	    {
	        CVla8(number, p_msg_buf);
	    }
	    else
	    {
	        CVla((i4)number, p_msg_buf);
	    }
	    while (*p_msg_buf)
		CMnext(p_msg_buf);
	    continue;

	  case 'u':
	    /* Convert an integer into the buffer with width D_WIDTH */

	    if (p->er_size == ER_PTR_ARGUMENT) /* this is ptr to u_i4 */
		number = *(u_i4 *)p->er_value;
	    else if (p->er_size == 0)   /* this is a u_i4 */
		number = (u_i4)(SCALARP)p->er_value;
	    else if (p->er_size == 1)
		number = *(u_i1 *)p->er_value;
	    else if (p->er_size == 2)
		number = *(u_i2 *)p->er_value;
	    else if (p->er_size == 4)
		number = *(u_i4 *)p->er_value;
	    else if (p->er_size == 8)
		number = *(u_i8 *)p->er_value;
	    else
		continue;

	    if (p_msg_buf - msg_buf + D_WIDTH >= msg_buf_size)
	        continue;

	    if (p->er_size == 8)
	    {
	        CVula8(number, p_msg_buf);
	    }
	    else
	    {
	        CVula((u_i4)number, p_msg_buf);
	    }
	    while (*p_msg_buf)
		CMnext(p_msg_buf);
	    continue;

	  case 'f':
	  {
	    i2	    res_width;

	    /* Convert a float into the buffer with width F_WIDTH */

	    if (p->er_size == ER_PTR_ARGUMENT) /* Pointer to a double */
		fnumber = *(double *)p->er_value;
	    else if (p->er_size == 4)
		fnumber = *(f4 *)p->er_value;
	    else if (p->er_size == 8)
		fnumber = *(f8 *)p->er_value;
	    else
		continue;

	    if (p_msg_buf - msg_buf + F_WIDTH >= msg_buf_size)
		continue;

	    /* Always convert to 'e' format. */

	    CVfa(fnumber, (i4) 20, (i4) 5, 'e', '.', p_msg_buf, &res_width);
	    p_msg_buf += F_WIDTH;
	    continue;
	  }
	  case 'c':
	    /* Convert a character array into buffer. */

	    if (p->er_value == 0)
		p->er_value = (PTR)ERx("<missing>");
	    if ((p->er_size == 0) || (p->er_size == ER_PTR_ARGUMENT))
	    {
		for (i = 0; ((char *)p->er_value)[i]; i++)
		    ;
		p->er_size = i;
	    }
             
	    if (p_msg_buf - msg_buf + p->er_size >= msg_buf_size)
		continue;

	    if (p->er_size > msg_buf_size - (p_msg_buf - msg_buf))
		p->er_size = (i4)(msg_buf_size - (p_msg_buf - msg_buf));
/*	    p->er_size=STtrmwhite(p_msg_buf);*/
	    MEcopy(p->er_value, p->er_size, p_msg_buf);
	    p->er_size = (i4)STtrmnwhite(p_msg_buf, p->er_size);
	    p_msg_buf += p->er_size;
	    continue;

	  case 'x':
	    /* Convert an integer into the buffer with width D_WIDTH */

	    if (p->er_size == ER_PTR_ARGUMENT)
		unumber = *(u_i4 *)p->er_value;
	    else if (p->er_size == 0)
		unumber = (u_i4)(SCALARP)p->er_value;
	    else if (p->er_size == 1)
		unumber = *(u_i1 *)p->er_value;
	    else if (p->er_size == 2)
		unumber = *(u_i2 *)p->er_value;
	    else if (p->er_size == 4)
		unumber = *(u_i4 *)p->er_value;
	    else if (p->er_size == 8)
		unumber = *(u_i8 *)p->er_value;

	    if (p_msg_buf - msg_buf + X_WIDTH >= msg_buf_size)
		continue;

	    for (i = 8; --i >= 0; )
	    {
		/* {@fix_me@}
		** This is *NOT* machine independent.  This relys on an
		** ASCII-like character set, where the digits '0'-'9' are
		** contiguous and sequential, and the characters 'A'-'F'
		** are contiguous and sequential.  Both ASCII and EBCDIC
		** happen to be this way.
		*/
		if ((*(p_msg_buf + i) = (unumber & 0x0f) + '0') > '9')
		    *(p_msg_buf + i) += 'A' - '9' - 1;
		unumber >>= 4;
	    }
	    p_msg_buf += 8;
	    continue;

	default:
	    continue;
	}
    }
    *msg_length = (i4)(p_msg_buf - msg_buf);
    *p_msg_buf = EOS;
    EXdelete();
    return (OK);
}