nats.zig/deps/nats.c/src/micro_error.c
torque 41fbdf886b
git subrepo pull --branch=v3.7.0 deps/nats.c
subrepo:
  subdir:   "deps/nats.c"
  merged:   "5d057f6"
upstream:
  origin:   "https://github.com/nats-io/nats.c.git"
  branch:   "v3.7.0"
  commit:   "5d057f6"
git-subrepo:
  version:  "0.4.6"
  commit:   "affc4c01a"
2023-10-14 13:22:13 -07:00

234 lines
5.3 KiB
C

// Copyright 2023 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdarg.h>
#include "microp.h"
static microError _errorOutOfMemory = {
.is_internal = true,
.status = NATS_NO_MEMORY,
.message = "out of memory",
};
static microError _errorInvalidArg = {
.is_internal = true,
.status = NATS_INVALID_ARG,
.message = "invalid function argument",
};
static microError _errorInvalidFormat = {
.is_internal = true,
.status = NATS_INVALID_ARG,
.message = "invalid format string",
};
microError *micro_ErrorOutOfMemory = &_errorOutOfMemory;
microError *micro_ErrorInvalidArg = &_errorInvalidArg;
static microError *
verrorf(natsStatus s, int code, const char *format, va_list args)
{
microError *err = NULL;
char *ptr;
int message_len = 0;
va_list args2;
va_copy(args2, args);
if (format == NULL)
format = "";
// Do not use nats_vsnprintf here since we want to calculate the size of
// the resulting formatted string. On Windows, that would fail. Use
// that instead.
message_len = nats_vscprintf(format, args);
if (message_len < 0)
{
va_end(args2);
return &_errorInvalidFormat;
}
err = NATS_CALLOC(1, sizeof(microError) + message_len + 1);
if (err == NULL)
{
va_end(args2);
return &_errorOutOfMemory;
}
ptr = (char *)(err) + sizeof(microError);
nats_vsnprintf(ptr, message_len + 1, format, args2);
va_end(args2);
err->message = (const char *)ptr;
err->code = code;
err->status = s;
return err;
}
microError *
micro_Errorf(const char *format, ...)
{
microError *err = NULL;
va_list args;
va_start(args, format);
err = verrorf(NATS_OK, 0, format, args);
va_end(args);
return err;
}
microError *
micro_ErrorfCode(int code, const char *format, ...)
{
microError *err = NULL;
va_list args;
va_start(args, format);
err = verrorf(NATS_OK, code, format, args);
va_end(args);
return err;
}
microError *
micro_ErrorFromStatus(natsStatus s)
{
microError *err = NULL;
const char *message = natsStatus_GetText(s);
size_t message_len = strlen(message);
char *ptr;
if (s == NATS_OK)
return NULL;
err = NATS_CALLOC(1, sizeof(microError) + message_len + 1);
if (err == NULL)
return &_errorOutOfMemory;
ptr = (char *)(err) + sizeof(microError);
memcpy(ptr, message, message_len + 1);
err->message = ptr;
err->status = s;
return err;
}
microError *
micro_is_error_message(natsStatus status, natsMsg *msg)
{
microError *err = NULL;
const char *c = NULL, *d = NULL;
bool is_service_error;
bool is_nats_error = (status != NATS_OK);
int code = 0;
if (msg != NULL)
{
natsMsgHeader_Get(msg, MICRO_ERROR_CODE_HDR, &c);
natsMsgHeader_Get(msg, MICRO_ERROR_HDR, &d);
}
if (!nats_IsStringEmpty(c))
{
code = atoi(c);
}
is_service_error = (code != 0) || !nats_IsStringEmpty(d);
if (is_service_error && !is_nats_error)
{
return micro_ErrorfCode(code, d);
}
else if (!is_service_error && is_nats_error)
{
return micro_ErrorFromStatus(status);
}
else if (is_service_error && is_nats_error)
{
err = microError_Wrapf(micro_ErrorFromStatus(status), d);
err->code = code;
return err;
}
return NULL;
}
microError *
microError_Wrapf(microError *err, const char *format, ...)
{
va_list args;
microError *new_err = NULL;
if (err == NULL)
return NULL;
va_start(args, format);
new_err = verrorf(NATS_OK, 0, format, args);
va_end(args);
new_err->cause = err;
return new_err;
}
const char *
microError_String(microError *err, char *buf, size_t size)
{
size_t used = 0;
const char *caused;
if (buf == NULL)
return "";
if (err == NULL)
{
snprintf(buf, size, "null");
return buf;
}
if (err->status != NATS_OK)
{
used += snprintf(buf + used, size - used, "status %u: ", err->status);
}
if (err->code != 0)
{
used += snprintf(buf + used, size - used, "code %d: ", err->code);
}
used += snprintf(buf + used, size - used, "%s", err->message);
if (err->cause != NULL)
{
used += snprintf(buf + used, size - used, ": ");
caused = microError_String(err->cause, buf + used, size - used);
used += strlen(caused);
}
return buf;
}
natsStatus
microError_Status(microError *err)
{
if (err == NULL)
return NATS_OK;
if (err->status != NATS_OK)
return err->status;
return microError_Status(err->cause);
}
void microError_Destroy(microError *err)
{
if ((err == NULL) || err->is_internal)
return;
microError_Destroy(err->cause);
NATS_FREE(err);
}