/*******************************************************************************
*
* MODULE: cterror.c
*
********************************************************************************
*
* DESCRIPTION: Error reporting for the ctlib
*
********************************************************************************
*
* Copyright (c) 2002-2024 Marcus Holland-Moritz. All rights reserved.
* This program is free software; you can redistribute it and/or modify
* it under the same terms as Perl itself.
*
*******************************************************************************/
/*===== GLOBAL INCLUDES ======================================================*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
/*===== LOCAL INCLUDES =======================================================*/
#include "cterror.h"
#include "util/memalloc.h"
#include "ucpp/cpp.h"
#include "ucpp/mem.h"
#include "cppreent.h"
/*===== DEFINES ==============================================================*/
#define INIT_CHECK \
do { \
if (!initialized) \
{ \
fprintf(stderr, "FATAL: print functions have not been set!\n"); \
abort(); \
} \
} while(0)
/*===== TYPEDEFS =============================================================*/
/*===== STATIC FUNCTION PROTOTYPES ===========================================*/
static CTLibError *error_new(enum CTErrorSeverity severity, void *str);
static void error_delete(CTLibError *error);
static void push_str(CParseInfo *pCPI, enum CTErrorSeverity severity, void *str);
static void push_verror(CParseInfo *pCPI, enum CTErrorSeverity severity,
const char *fmt, va_list *pap);
/*===== EXTERNAL VARIABLES ===================================================*/
/*===== GLOBAL VARIABLES =====================================================*/
/*===== STATIC VARIABLES =====================================================*/
static int initialized = 0;
static PrintFunctions F;
/*===== STATIC FUNCTIONS =====================================================*/
/*******************************************************************************
*
* ROUTINE: error_new
*
* WRITTEN BY: Marcus Holland-Moritz ON: Nov 2003
* CHANGED BY: ON:
*
********************************************************************************
*
* DESCRIPTION:
*
* ARGUMENTS:
*
* RETURNS:
*
*******************************************************************************/
static CTLibError *error_new(enum CTErrorSeverity severity, void *str)
{
CTLibError *perr;
const char *string;
size_t len;
string = F.cstring(str, &len);
AllocF(CTLibError *, perr, sizeof(CTLibError));
AllocF(char *, perr->string, len + 1);
perr->severity = severity;
strncpy(perr->string, string, len);
perr->string[len] = '\0';
return perr;
}
/*******************************************************************************
*
* ROUTINE: error_delete
*
* WRITTEN BY: Marcus Holland-Moritz ON: Nov 2003
* CHANGED BY: ON:
*
********************************************************************************
*
* DESCRIPTION:
*
* ARGUMENTS:
*
* RETURNS:
*
*******************************************************************************/
static void error_delete(CTLibError *error)
{
if (error)
{
if (error->string)
Free(error->string);
Free(error);
}
}
/*******************************************************************************
*
* ROUTINE: push_str
*
* WRITTEN BY: Marcus Holland-Moritz ON: Nov 2003
* CHANGED BY: ON:
*
********************************************************************************
*
* DESCRIPTION:
*
* ARGUMENTS:
*
* RETURNS:
*
*******************************************************************************/
static void push_str(CParseInfo *pCPI, enum CTErrorSeverity severity, void *str)
{
if (pCPI == NULL || pCPI->errorStack == NULL)
F.fatalerr(str);
LL_push(pCPI->errorStack, error_new(severity, str));
}
/*******************************************************************************
*
* ROUTINE: push_verror
*
* WRITTEN BY: Marcus Holland-Moritz ON: Nov 2003
* CHANGED BY: ON:
*
********************************************************************************
*
* DESCRIPTION:
*
* ARGUMENTS:
*
* RETURNS:
*
*******************************************************************************/
static void push_verror(CParseInfo *pCPI, enum CTErrorSeverity severity,
const char *fmt, va_list *pap)
{
void *str = F.newstr();
F.vscatf(str, fmt, pap);
push_str(pCPI, severity, str);
F.destroy(str);
}
/*===== FUNCTIONS ============================================================*/
/*******************************************************************************
*
* ROUTINE: set_print_functions
*
* WRITTEN BY: Marcus Holland-Moritz ON: Mar 2002
* CHANGED BY: ON:
*
********************************************************************************
*
* DESCRIPTION:
*
* ARGUMENTS:
*
* RETURNS:
*
*******************************************************************************/
void set_print_functions(PrintFunctions *pPF)
{
if (pPF->newstr == NULL ||
pPF->destroy == NULL ||
pPF->scatf == NULL ||
pPF->vscatf == NULL ||
pPF->cstring == NULL ||
pPF->fatalerr == NULL)
{
fprintf(stderr, "FATAL: all print functions must be set!\n");
abort();
}
F = *pPF;
initialized = 1;
}
/*******************************************************************************
*
* ROUTINE: pop_all_errors
*
* WRITTEN BY: Marcus Holland-Moritz ON: Nov 2003
* CHANGED BY: ON:
*
********************************************************************************
*
* DESCRIPTION:
*
* ARGUMENTS:
*
* RETURNS:
*
*******************************************************************************/
void pop_all_errors(CParseInfo *pCPI)
{
LL_flush(pCPI->errorStack, (LLDestroyFunc) error_delete);
}
/*******************************************************************************
*
* ROUTINE: push_error
*
* WRITTEN BY: Marcus Holland-Moritz ON: Nov 2003
* CHANGED BY: ON:
*
********************************************************************************
*
* DESCRIPTION:
*
* ARGUMENTS:
*
* RETURNS:
*
*******************************************************************************/
void push_error(CParseInfo *pCPI, const char *fmt, ...)
{
va_list ap;
INIT_CHECK;
va_start(ap, fmt);
push_verror(pCPI, CTES_ERROR, fmt, &ap);
va_end(ap);
}
/*******************************************************************************
*
* ROUTINE: push_warning
*
* WRITTEN BY: Marcus Holland-Moritz ON: Nov 2003
* CHANGED BY: ON:
*
********************************************************************************
*
* DESCRIPTION:
*
* ARGUMENTS:
*
* RETURNS:
*
*******************************************************************************/
void push_warning(CParseInfo *pCPI, const char *fmt, ...)
{
va_list ap;
INIT_CHECK;
va_start(ap, fmt);
push_verror(pCPI, CTES_WARNING, fmt, &ap);
va_end(ap);
}
/*******************************************************************************
*
* ROUTINE: fatal_error
*
* WRITTEN BY: Marcus Holland-Moritz ON: Nov 2003
* CHANGED BY: ON:
*
********************************************************************************
*
* DESCRIPTION:
*
* ARGUMENTS:
*
* RETURNS:
*
*******************************************************************************/
void fatal_error(const char *fmt, ...)
{
va_list ap;
void *str;
INIT_CHECK;
va_start(ap, fmt);
str = F.newstr();
F.vscatf(str, fmt, &ap);
va_end(ap);
F.fatalerr(str);
}
/*******************************************************************************
*
* ROUTINE: my_ucpp_ouch
*
* WRITTEN BY: Marcus Holland-Moritz ON: Mar 2002
* CHANGED BY: ON:
*
********************************************************************************
*
* DESCRIPTION:
*
* ARGUMENTS:
*
* RETURNS:
*
*******************************************************************************/
void my_ucpp_ouch(pUCPP_ char *fmt, ...)
{
va_list ap;
void *str;
INIT_CHECK;
va_start(ap, fmt);
str = F.newstr();
F.scatf(str, "%s: (FATAL) ", r_current_filename);
F.vscatf(str, fmt, &ap);
va_end(ap);
F.fatalerr(str);
}
/*******************************************************************************
*
* ROUTINE: my_ucpp_error
*
* WRITTEN BY: Marcus Holland-Moritz ON: Mar 2002
* CHANGED BY: ON:
*
********************************************************************************
*
* DESCRIPTION:
*
* ARGUMENTS:
*
* RETURNS:
*
*******************************************************************************/
void my_ucpp_error(pUCPP_ long line, char *fmt, ...)
{
va_list ap;
void *str;
INIT_CHECK;
va_start(ap, fmt);
str = F.newstr();
if (line > 0)
F.scatf(str, "%s, line %ld: ", r_current_filename, line);
else if (line == 0)
F.scatf(str, "%s: ", r_current_filename);
F.vscatf(str, fmt, &ap);
if (line >= 0)
{
struct stack_context *sc = report_context(aUCPP);
size_t i;
for (i = 0; sc[i].line >= 0; i++)
F.scatf(str, "\n\tincluded from %s:%ld",
sc[i].long_name ? sc[i].long_name : sc[i].name,
sc[i].line);
freemem(sc);
}
va_end(ap);
push_str(r_callback_arg, CTES_ERROR, str);
F.destroy(str);
}
/*******************************************************************************
*
* ROUTINE: my_ucpp_warning
*
* WRITTEN BY: Marcus Holland-Moritz ON: Mar 2002
* CHANGED BY: ON:
*
********************************************************************************
*
* DESCRIPTION:
*
* ARGUMENTS:
*
* RETURNS:
*
*******************************************************************************/
void my_ucpp_warning(pUCPP_ long line, char *fmt, ...)
{
va_list ap;
void *str;
INIT_CHECK;
va_start(ap, fmt);
str = F.newstr();
if (line > 0)
F.scatf(str, "%s, line %ld: (warning) ",
r_current_filename, line);
else if (line == 0)
F.scatf(str, "%s: (warning) ", r_current_filename);
else
F.scatf(str, "(warning) ");
F.vscatf(str, fmt, &ap);
if (line >= 0)
{
struct stack_context *sc = report_context(aUCPP);
size_t i;
for (i = 0; sc[i].line >= 0; i++)
F.scatf(str, "\n\tincluded from %s:%ld",
sc[i].long_name ? sc[i].long_name : sc[i].name,
sc[i].line);
freemem(sc);
}
va_end(ap);
push_str(r_callback_arg, CTES_WARNING, str);
F.destroy(str);
}